Beispiel #1
0
    def test_libadd_api2(self):
        _, binaddc = tempfile.mkstemp(prefix="binadd_", suffix=".c")
        _, libaddc = tempfile.mkstemp(prefix="libadd_", suffix=".c")

        self._logger.debug(binaddc)
        self._logger.debug(libaddc)

        fd, binadd = tempfile.mkstemp(prefix="binadd_", suffix=".bin")
        _, libadd = tempfile.mkstemp(prefix="libadd_", suffix=".so")
        _, libadd2 = tempfile.mkstemp(prefix="libadd2_", suffix=".so")

        self._logger.debug(binadd)
        self._logger.debug(libadd)
        self._logger.debug(libadd2)

        with open(binaddc, 'w') as f:
            f.write(BINADD)

        with open(libaddc, 'w') as f:
            f.write(LIBADD)

        compiler = get_compiler()

        fmt = ""
        if is_x86_64():
            fmt = "{compiler} -Wl,--export-dynamic -mcmodel=large -fPIE -pie -o {output} {input}"

        if is_aarch64():
            fmt = "{compiler} -Wl,--export-dynamic -fPIE -pie -o {output} {input}"

        # Compile libadd
        r = self.run_cmd(
            fmt.format(compiler=compiler, output=libadd, input=libaddc))
        self.assertTrue(r, msg="Unable to compile libadd")

        libadd = lief.parse(libadd)
        add_hidden_static = libadd.get_static_symbol("add_hidden")
        libadd.add_exported_function(add_hidden_static.value,
                                     add_hidden_static.name)
        libadd.write(libadd2)

        lib_directory = os.path.dirname(libadd2)
        libname = os.path.basename(libadd2)[3:-3]  # libadd.so ---> add

        r = self.run_cmd(
            "{compiler} -Wl,--export-dynamic -mcmodel=large -fPIE -pie -Wl,-rpath={libdir} -L{libdir} -o {output} {input} -l{libadd2}"
            .format(compiler=compiler,
                    libdir=lib_directory,
                    libadd2=libname,
                    output=binadd,
                    input=binaddc))
        self.assertTrue(r, msg="Unable to compile binadd")

        os.close(fd)
        st = os.stat(binadd)
        os.chmod(binadd, st.st_mode | stat.S_IEXEC)

        r = self.run_cmd(binadd + " 1 2")
        self.assertTrue(r)
        self.assertIn("From [email protected] a + b = 3", r.output)
Beispiel #2
0
    def test_ssh(self):
        stub = None
        if is_x86_64():
            stub = lief.parse(os.path.join(CURRENT_DIRECTORY,
                                           "hello_lief.bin"))
        elif is_aarch64():
            stub = lief.parse(
                os.path.join(CURRENT_DIRECTORY, "hello_lief_aarch64.bin"))

        output = os.path.join(self.tmp_dir, "ssh.replace_segment")
        target = lief.parse("/usr/bin/ssh")

        if not lief.ELF.SEGMENT_TYPES.NOTE in target:
            self.logger.error("Note not found!")
            return

        segment = stub.segments[0]
        original_va = segment.virtual_address
        segment.virtual_address = 0
        segment = target.replace(segment, target[lief.ELF.SEGMENT_TYPES.NOTE])
        new_ep = (stub.header.entrypoint -
                  original_va) + segment.virtual_address

        target.header.entrypoint = new_ep
        target.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'LIEF is Working', stdout.decode("utf8")))
Beispiel #3
0
class TestRemoveSection(TestCase):
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.tmp_dir = tempfile.mkdtemp(suffix='_lief_test_section')
        self.logger.debug("temp dir: {}".format(self.tmp_dir))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_simple(self):
        sample_path = get_sample('ELF/ELF64_x86-64_binary_ls.bin')
        output = os.path.join(self.tmp_dir, "ls.section")

        ls = lief.parse(sample_path)
        ls.remove_section(".text", clear=False)
        ls.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen([output, "--help"],
                  stdout=subprocess.PIPE,
                  stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(re.search(r'GNU coreutils',
                                       stdout.decode("utf8")))

    def tearDown(self):
        # Delete it
        if os.path.isdir(self.tmp_dir):
            shutil.rmtree(self.tmp_dir)
Beispiel #4
0
    def test_ssh(self):
        original = lief.parse(get_sample('MachO/MachO64_x86-64_binary_sshd.bin'))
        _, output = tempfile.mkstemp(prefix="lief_ssh_")

        original.add_library(self.library_path)

        original.write(output)

        if is_osx() and is_x86_64():
            stdout = run_program(output, ["--help"])
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'CTOR CALLED', stdout))
Beispiel #5
0
class TestGOTPatch(TestCase):
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.tmp_dir = tempfile.mkdtemp(suffix='_lief_test_466')
        self.logger.debug("temp dir: {}".format(self.tmp_dir))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_freebl(self):
        libfreebl3_path = get_sample('ELF/ELF64_x86-64_library_libfreebl3.so')
        output_ls = os.path.join(self.tmp_dir, "ls.new")
        output_libfreebl3 = os.path.join(self.tmp_dir, "libfreebl3.so")

        libfreebl3 = lief.parse(libfreebl3_path)
        ls = lief.parse("/usr/bin/ls")

        if lief.ELF.DYNAMIC_TAGS.FLAGS_1 in ls and ls[
                lief.ELF.DYNAMIC_TAGS.FLAGS_1].has(
                    lief.ELF.DYNAMIC_FLAGS_1.PIE):
            ls[lief.ELF.DYNAMIC_TAGS.FLAGS_1].remove(
                lief.ELF.DYNAMIC_FLAGS_1.PIE)

        ls.add_library("libfreebl3.so")

        ls += lief.ELF.DynamicEntryRunPath("$ORIGIN")
        libfreebl3 += lief.ELF.DynamicEntryRunPath("$ORIGIN")

        ls.write(output_ls)
        libfreebl3.write(output_libfreebl3)

        st = os.stat(output_ls)
        os.chmod(output_ls, st.st_mode | stat.S_IEXEC)

        st = os.stat(output_libfreebl3)
        os.chmod(output_libfreebl3, st.st_mode | stat.S_IEXEC)

        p = Popen([output_ls, "--version"],
                  stdout=subprocess.PIPE,
                  stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'ls \(GNU coreutils\) ', stdout.decode("utf8")))
        self.assertEqual(p.returncode, 0)

    def tearDown(self):
        # Delete it
        if os.path.isdir(self.tmp_dir):
            shutil.rmtree(self.tmp_dir)
Beispiel #6
0
    def test_all(self):
        sample = None
        if is_apple_m1():
            sample = get_sample('MachO/MachO64_Aarch64_binary_all.bin')

        if is_x86_64():
            sample = get_sample('MachO/MachO64_x86-64_binary_all.bin')

        original = lief.parse(sample)
        _, output = tempfile.mkstemp(prefix="lief_all_")

        original.add_library(self.library_path)

        original.write(output)

        if is_osx():
            stdout = run_program(output)
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'CTOR CALLED', stdout))
Beispiel #7
0
class TestEmptyGNUHash(TestCase):
    SYMBOLS = {
        "myinstance": 0x1159,
        "myinit": 0x1175,
        "mycalc": 0x1199,
        "mydelete": 0x1214,
    }

    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.tmp_dir = tempfile.mkdtemp(suffix='_lief_test_empty_gnu_hash')
        self.logger.debug("temp dir: {}".format(self.tmp_dir))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_export(self):
        target_path = get_sample('ELF/ELF64_x86-64_binary_empty-gnu-hash.bin')
        output = os.path.join(self.tmp_dir, "libnoempty.so")

        binary = lief.parse(target_path)

        binary[lief.ELF.DYNAMIC_TAGS.FLAGS_1].remove(
            lief.ELF.DYNAMIC_FLAGS_1.PIE)

        for name, addr in TestEmptyGNUHash.SYMBOLS.items():
            binary.add_exported_function(addr, name)
        binary.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        lib = ctypes.cdll.LoadLibrary(output)
        # Raise 'AttributeError' if not exported
        print(lib.myinstance)
        self.assertIsNotNone(lib.myinstance)

    def tearDown(self):
        # Delete it
        if os.path.isdir(self.tmp_dir):
            shutil.rmtree(self.tmp_dir)
Beispiel #8
0
    def run_add_segment(self, target):
        if not os.path.isfile(target):
            self.logger.debug("%s does not exists. Skip!", target)
            return

        stub = None
        if is_x86_64():
            stub = lief.parse(os.path.join(CURRENT_DIRECTORY,
                                           "hello_lief.bin"))
        elif is_aarch64():
            stub = lief.parse(
                os.path.join(CURRENT_DIRECTORY, "hello_lief_aarch64.bin"))

        name = os.path.basename(target)
        target = lief.parse(target)
        output = os.path.join(self.tmp_dir, "{}.segment".format(name))
        for i in range(6):
            stub_segment = stub.segments[0]
            segment = lief.ELF.Segment()
            segment.content = stub.segments[0].content
            segment.type = stub_segment.type
            segment.alignment = stub_segment.alignment
            segment.flags = stub_segment.flags

            new_segment = target.add(segment)
            new_ep = (stub.header.entrypoint - stub.imagebase -
                      stub_segment.file_offset) + new_segment.virtual_address

            target.header.entrypoint = new_ep
        target.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'LIEF is Working', stdout.decode("utf8")))
Beispiel #9
0
    def test_all(self):
        binary_name = "544ca2035a9c15e7756ed8d8067d860bd3157e4eeaa39b4ee932458eebe2434b.elf"
        target: lief.ELF.Binary = lief.parse(
            get_sample("ELF/{}".format(binary_name)))
        bss = target.get_section(".bss")
        self.assertEqual(bss.virtual_address, 0x65a3e0)
        self.assertEqual(bss.size, 0x1ccb6330)
        self.assertEqual(bss.file_offset, 0x05a3e0)
        self.assertEqual(len(bss.content), 0)

        target.add_library("libcap.so.2")
        # Add segment
        new_segment = lief.ELF.Segment()
        new_segment.type = lief.ELF.SEGMENT_TYPES.LOAD
        new_segment.content = [0xCC] * 0x50
        target.add(new_segment)

        tmp_dir = tempfile.mkdtemp(prefix="lief_",
                                   suffix='_{}'.format(
                                       self.__class__.__name__))
        self.logger.debug("temp dir: {}".format(tmp_dir))
        output = "{}/{}.built".format(tmp_dir, binary_name)
        target.write(output)

        if is_linux() and is_x86_64():
            st = os.stat(output)
            os.chmod(output, st.st_mode | stat.S_IEXEC)

            p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            stdout, _ = p.communicate()
            self.logger.debug(stdout.decode("utf8"))
            self.assertTrue(len(stdout) > 0)

        # Check that the written binary contains our modifications
        new: lief.ELF.Binary = lief.parse(output)
        self.assertEqual(new.get_library("libcap.so.2").name, "libcap.so.2")
Beispiel #10
0
    def test_issue_671(self):
        """
        Test on the support of bss-like segments where virtual_address - imagebase != offset
        cf. https://github.com/lief-project/LIEF/issues/671
        """
        binary_name = "nopie_bss_671.elf"
        target: lief.ELF.Binary = lief.parse(
            get_sample("ELF/{}".format(binary_name)))

        for s in filter(lambda e: e.exported, target.static_symbols):
            target.add_dynamic_symbol(s)

        tmp_dir = tempfile.mkdtemp(prefix="lief_",
                                   suffix='_{}'.format(
                                       self.__class__.__name__))
        self.logger.debug("temp dir: {}".format(tmp_dir))
        output = "{}/{}.built".format(tmp_dir, binary_name)
        target.write(output)

        # Make sure that the PHDR has been relocated at the end:
        built = lief.parse(output)
        self.assertEqual(built[lief.ELF.SEGMENT_TYPES.PHDR].file_offset,
                         0x3000)
        self.assertEqual(built[lief.ELF.SEGMENT_TYPES.PHDR].physical_size,
                         0x1f8)
        self.assertEqual(built[lief.ELF.SEGMENT_TYPES.PHDR].virtual_address,
                         0x403000)

        if is_linux() and is_x86_64():
            st = os.stat(output)
            os.chmod(output, st.st_mode | stat.S_IEXEC)

            p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            stdout, _ = p.communicate()
            self.logger.debug(stdout.decode("utf8"))
            self.assertTrue(len(stdout) > 0)
Beispiel #11
0
class TestBin2Lib(unittest.TestCase):
    LOGGER = logging.getLogger(__name__)

    def setUp(self):
        self._logger = logging.getLogger(__name__)

    @staticmethod
    def run_cmd(cmd):
        TestBin2Lib.LOGGER.debug("Running: '{}'".format(cmd))
        cmd = shlex.split(cmd)
        p = subprocess.Popen(cmd,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE,
                             universal_newlines=True)
        stdout, stderr = p.communicate()

        if stdout:
            TestBin2Lib.LOGGER.debug(stdout)

        if stderr:
            TestBin2Lib.LOGGER.error(stderr)

        return CommandResult(stdout, stderr, p.returncode)

    @unittest.skipUnless(is_linux(), "requires Linux")
    def test_libadd(self):

        _, binaddc = tempfile.mkstemp(prefix="binadd_", suffix=".c")
        _, libaddc = tempfile.mkstemp(prefix="libadd_", suffix=".c")

        self._logger.debug(binaddc)
        self._logger.debug(libaddc)

        fd, binadd = tempfile.mkstemp(prefix="binadd_", suffix=".bin")
        _, libadd = tempfile.mkstemp(prefix="libadd_", suffix=".so")
        _, libadd2 = tempfile.mkstemp(prefix="libadd2_", suffix=".so")

        self._logger.debug(binadd)
        self._logger.debug(libadd)
        self._logger.debug(libadd2)

        with open(binaddc, 'w') as f:
            f.write(BINADD)

        with open(libaddc, 'w') as f:
            f.write(LIBADD)

        compiler = get_compiler()

        fmt = ""
        if is_x86_64():
            fmt = "{compiler} -Wl,--export-dynamic -mcmodel=large -fPIE -pie -o {output} {input}"

        if is_aarch64():
            fmt = "{compiler} -Wl,--export-dynamic -fPIE -pie -o {output} {input}"

        # Compile libadd
        r = self.run_cmd(
            fmt.format(compiler=compiler, output=libadd, input=libaddc))
        self.assertTrue(r, msg="Unable to compile libadd")

        libadd = lief.parse(libadd)

        libadd_hidden = libadd.get_symbol("add_hidden")
        libadd_hidden.binding = lief.ELF.SYMBOL_BINDINGS.GLOBAL
        libadd_hidden.visibility = lief.ELF.SYMBOL_VISIBILITY.DEFAULT
        libadd_hidden = libadd.add_dynamic_symbol(
            libadd_hidden, lief.ELF.SymbolVersion.global_)
        if libadd.has(lief.ELF.DYNAMIC_TAGS.FLAGS_1):
            libadd[lief.ELF.DYNAMIC_TAGS.FLAGS_1].remove(
                lief.ELF.DYNAMIC_FLAGS_1.PIE)

        self._logger.debug(libadd_hidden)

        libadd.add(lief.ELF.DynamicSharedObject(os.path.basename(libadd2)))

        libadd.write(libadd2)

        lib_directory = os.path.dirname(libadd2)
        libname = os.path.basename(libadd2)[3:-3]  # libadd.so ---> add

        fmt = ""
        if is_x86_64():
            fmt = "{compiler} -Wl,--export-dynamic -mcmodel=large -fPIE -pie -Wl,-rpath={libdir} -L{libdir} -o {output} {input} -l{libadd2}"

        if is_aarch64():
            fmt = "{compiler} -Wl,--export-dynamic -fPIE -pie -Wl,-rpath={libdir} -L{libdir} -o {output} {input} -l{libadd2}"

        r = self.run_cmd(
            fmt.format(compiler=compiler,
                       libdir=lib_directory,
                       libadd2=libname,
                       output=binadd,
                       input=binaddc))
        self.assertTrue(r, msg="Unable to compile binadd")

        os.close(fd)
        st = os.stat(binadd)
        os.chmod(binadd, st.st_mode | stat.S_IEXEC)

        r = self.run_cmd(binadd + " 1 2")
        self.assertTrue(r)
        self.assertIn("From [email protected] a + b = 3", r.output)

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux")
    def test_libadd_api(self):
        _, binaddc = tempfile.mkstemp(prefix="binadd_", suffix=".c")
        _, libaddc = tempfile.mkstemp(prefix="libadd_", suffix=".c")

        self._logger.debug(binaddc)
        self._logger.debug(libaddc)

        fd, binadd = tempfile.mkstemp(prefix="binadd_", suffix=".bin")
        _, libadd = tempfile.mkstemp(prefix="libadd_", suffix=".so")
        _, libadd2 = tempfile.mkstemp(prefix="libadd2_", suffix=".so")

        self._logger.debug(binadd)
        self._logger.debug(libadd)
        self._logger.debug(libadd2)

        with open(binaddc, 'w') as f:
            f.write(BINADD)

        with open(libaddc, 'w') as f:
            f.write(LIBADD)

        compiler = get_compiler()

        # Compile libadd
        fmt = ""
        if is_x86_64():
            fmt = "{compiler} -Wl,--export-dynamic -mcmodel=large -fPIE -pie -o {output} {input}"

        if is_aarch64():
            fmt = "{compiler} -Wl,--export-dynamic -fPIE -pie -o {output} {input}"

        r = self.run_cmd(
            fmt.format(compiler=compiler, output=libadd, input=libaddc))
        self.assertTrue(r, msg="Unable to compile libadd")

        libadd = lief.parse(libadd)
        libadd.export_symbol("add_hidden")
        libadd.write(libadd2)

        lib_directory = os.path.dirname(libadd2)
        libname = os.path.basename(libadd2)[3:-3]  # libadd.so ---> add

        fmt = ""
        if is_x86_64():
            fmt = "{compiler} -Wl,--export-dynamic -mcmodel=large -fPIE -pie -Wl,-rpath={libdir} -L{libdir} -o {output} {input} -l{libadd2}"

        if is_aarch64():
            fmt = "{compiler} -Wl,--export-dynamic -fPIE -pie -Wl,-rpath={libdir} -L{libdir} -o {output} {input} -l{libadd2}"

        r = self.run_cmd(
            fmt.format(compiler=compiler,
                       libdir=lib_directory,
                       libadd2=libname,
                       output=binadd,
                       input=binaddc))
        self.assertTrue(r, msg="Unable to compile binadd")

        os.close(fd)
        st = os.stat(binadd)
        os.chmod(binadd, st.st_mode | stat.S_IEXEC)

        r = self.run_cmd(binadd + " 1 2")
        self.assertTrue(r)
        self.assertIn("From [email protected] a + b = 3", r.output)

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux")
    def test_libadd_api2(self):
        _, binaddc = tempfile.mkstemp(prefix="binadd_", suffix=".c")
        _, libaddc = tempfile.mkstemp(prefix="libadd_", suffix=".c")

        self._logger.debug(binaddc)
        self._logger.debug(libaddc)

        fd, binadd = tempfile.mkstemp(prefix="binadd_", suffix=".bin")
        _, libadd = tempfile.mkstemp(prefix="libadd_", suffix=".so")
        _, libadd2 = tempfile.mkstemp(prefix="libadd2_", suffix=".so")

        self._logger.debug(binadd)
        self._logger.debug(libadd)
        self._logger.debug(libadd2)

        with open(binaddc, 'w') as f:
            f.write(BINADD)

        with open(libaddc, 'w') as f:
            f.write(LIBADD)

        compiler = get_compiler()

        fmt = ""
        if is_x86_64():
            fmt = "{compiler} -Wl,--export-dynamic -mcmodel=large -fPIE -pie -o {output} {input}"

        if is_aarch64():
            fmt = "{compiler} -Wl,--export-dynamic -fPIE -pie -o {output} {input}"

        # Compile libadd
        r = self.run_cmd(
            fmt.format(compiler=compiler, output=libadd, input=libaddc))
        self.assertTrue(r, msg="Unable to compile libadd")

        libadd = lief.parse(libadd)
        add_hidden_static = libadd.get_static_symbol("add_hidden")
        libadd.add_exported_function(add_hidden_static.value,
                                     add_hidden_static.name)
        libadd.write(libadd2)

        lib_directory = os.path.dirname(libadd2)
        libname = os.path.basename(libadd2)[3:-3]  # libadd.so ---> add

        r = self.run_cmd(
            "{compiler} -Wl,--export-dynamic -mcmodel=large -fPIE -pie -Wl,-rpath={libdir} -L{libdir} -o {output} {input} -l{libadd2}"
            .format(compiler=compiler,
                    libdir=lib_directory,
                    libadd2=libname,
                    output=binadd,
                    input=binaddc))
        self.assertTrue(r, msg="Unable to compile binadd")

        os.close(fd)
        st = os.stat(binadd)
        os.chmod(binadd, st.st_mode | stat.S_IEXEC)

        r = self.run_cmd(binadd + " 1 2")
        self.assertTrue(r)
        self.assertIn("From [email protected] a + b = 3", r.output)
Beispiel #12
0
class TestELF(TestCase):

    def setUp(self):
        self.logger = logging.getLogger(__name__)

    def test_rpath(self):
        etterlog = lief.parse(get_sample('ELF/ELF64_x86-64_binary_etterlog.bin'))

        dynamic_entries = etterlog.dynamic_entries

        rpath = [e for e in dynamic_entries if e.tag == lief.ELF.DYNAMIC_TAGS.RPATH]

        self.assertEqual(len(rpath), 1)
        rpath = rpath.pop()

        self.assertEqual(rpath.name, "/usr/lib")

    def test_runpath(self):
        etterlog = lief.parse(get_sample('ELF/ELF64_x86-64_binary_systemd-resolve.bin'))

        dynamic_entries = etterlog.dynamic_entries

        runpath = [e for e in dynamic_entries if e.tag == lief.ELF.DYNAMIC_TAGS.RUNPATH]

        self.assertEqual(len(runpath), 1)
        runpath = runpath.pop()

        self.assertEqual(runpath.name, "/usr/lib/systemd")


    def test_gnuhash(self):
        ls = lief.parse(get_sample('ELF/ELF64_x86-64_binary_ls.bin'))
        gnu_hash = ls.gnu_hash

        self.assertEqual(gnu_hash.nb_buckets, 33)
        self.assertEqual(gnu_hash.symbol_index, 109)
        self.assertEqual(gnu_hash.shift2, 7)

        bloom_filters = gnu_hash.bloom_filters

        self.assertEqual(len(bloom_filters), 2)
        self.assertIn(0x3FAE01120C48A1A6, bloom_filters)
        self.assertIn(0x900004A81310D428, bloom_filters)

        buckets = gnu_hash.buckets
        self.assertEqual(len(buckets), 33)

        buckets_test = [109, 110, 0, 0, 0, 0, 0, 111, 113, 114, 0, 0, 0, 115, 0, 116, 0, 0, 117, 118, 119, 0, 120, 0, 0, 121, 123, 124, 126, 128, 129, 130, 0]
        self.assertEqual(buckets_test, buckets)


        hash_values = gnu_hash.hash_values
        hash_values_test = [0x60E0C78D, 0xF54162E5, 0x7FFD8E4E, 0x1C8BF239, 0xEEFD3EB, 0x1C8C1D29, 0x1C5871D9,
                0x5B7F3E03, 0x759A6A7F, 0xEF18DB9, 0xBA53E4D, 0x9789A097, 0x9E7650BC, 0xD39AD3D,
                0x12F7C433, 0xEB01FAB6, 0xECD54543, 0xAD3C9892, 0x72632CCF, 0x12F7A2B3, 0x7C92E3BB, 0x7C96F087]
        self.assertEqual(hash_values, hash_values_test)

        #for s in list(ls.dynamic_symbols)[gnu_hash.symbol_index:]:
        #    print(gnu_hash.check(s.name), s.name)
        self.assertTrue(all(gnu_hash.check(x.name) for x in list(ls.dynamic_symbols)[gnu_hash.symbol_index:]))

        self.assertFalse(gnu_hash.check("foofdsfdsfds"))
        self.assertFalse(gnu_hash.check("fazertrvkdfsrezklqpfjeopqdi"))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_permutation(self):
        samples = [
                "ELF/ELF64_x86-64_binary_ls.bin",
                #"ELF/ELF64_x86-64_binary_gcc.bin",
                #"ELF/ELF64_x86-64_binary_openssl.bin",
        ]
        tmp_dir = tempfile.mkdtemp(suffix='_lief_test_permutation')
        for sample in samples:
            binary = lief.parse(get_sample(sample))
            dynamic_symbols = binary.dynamic_symbols

            gnu_hash_table = binary.gnu_hash

            idx = gnu_hash_table.symbol_index

            permutation = [i for i in range(1, len(dynamic_symbols))]
            random.shuffle(permutation)
            permutation = [0] + permutation
            binary.permute_dynamic_symbols(permutation)

            builder = lief.ELF.Builder(binary)
            builder.empties_gnuhash(True)
            builder.build()
            output = os.path.join(tmp_dir, "{}.permutated".format(binary.name))
            self.logger.debug("Output: {}".format(output))
            builder.write(output)

            if not sys.platform.startswith("linux"):
                return

            st = os.stat(output)
            os.chmod(output, st.st_mode | stat.S_IEXEC)

            p = Popen([output, "--help"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            stdout, _ = p.communicate()
            self.logger.debug(stdout.decode("utf8"))
            self.assertEqual(p.returncode, 0)

    def test_notes(self):
        systemd_resolve = lief.parse(get_sample('ELF/ELF64_x86-64_binary_systemd-resolve.bin'))
        notes = systemd_resolve.notes
        self.assertEqual(len(notes), 3)

        n1 = notes[0]
        n2 = notes[1]
        n3 = notes[2]

        self.assertEqual(n1.name, "GNU")
        self.assertEqual(n2.name, "GNU")
        self.assertEqual(n3.name, "GNU")

        self.assertEqual(n1.type, lief.ELF.NOTE_TYPES.ABI_TAG)
        self.assertEqual(n2.type, lief.ELF.NOTE_TYPES.BUILD_ID)
        self.assertEqual(n3.type, lief.ELF.NOTE_TYPES.GOLD_VERSION)

        self.assertEqual(n1.details.abi, lief.ELF.NOTE_ABIS.LINUX)
        self.assertEqual(n1.details.version, [2, 6, 32])

        self.assertEqual(list(n2.description), [
            0x7e, 0x68, 0x6c, 0x7d,
            0x79, 0x9b, 0xa4, 0xcd,
            0x32, 0xa2, 0x34, 0xe8,
            0x4f, 0xd7, 0x45, 0x98,
            0x21, 0x32, 0x9d, 0xc8
            ])

        self.assertEqual("".join(map(chr, n3.description)), "gold 1.12")

    def test_symbols_access(self):
        hello = lief.parse(get_sample('ELF/ELF64_x86-64_binary_hello-gdb.bin'))

        symbols         = hello.symbols
        dynamic_symbols = hello.dynamic_symbols
        static_symbols  = hello.static_symbols

        self.assertTrue(all(s in symbols for s in dynamic_symbols))
        self.assertTrue(all(s in symbols for s in static_symbols))

    def test_relocation_size(self):
        aarch64_toybox = lief.parse(get_sample('ELF/ELF64_AARCH64_piebinary_toybox.pie'))
        arm_ls         = lief.parse(get_sample('ELF/ELF32_ARM_binary_ls.bin'))
        x86_ls         = lief.parse(get_sample('ELF/ELF32_x86_binary_ls.bin'))
        x86_64_ls      = lief.parse(get_sample('ELF/ELF64_x86-64_binary_ld.bin'))

        for r in itertools.chain(aarch64_toybox.dynamic_relocations, aarch64_toybox.pltgot_relocations):
            if lief.ELF.RELOCATION_AARCH64(r.type) == lief.ELF.RELOCATION_AARCH64.RELATIVE:
                self.assertEqual(r.size, 64)

            if lief.ELF.RELOCATION_AARCH64(r.type) == lief.ELF.RELOCATION_AARCH64.GLOB_DAT:
                self.assertEqual(r.size, 64)

            if lief.ELF.RELOCATION_AARCH64(r.type) == lief.ELF.RELOCATION_AARCH64.JUMP_SLOT:
                self.assertEqual(r.size, 64)

        for r in itertools.chain(arm_ls.dynamic_relocations, arm_ls.pltgot_relocations):
            if lief.ELF.RELOCATION_ARM(r.type) == lief.ELF.RELOCATION_ARM.RELATIVE:
                self.assertEqual(r.size, 32)

            if lief.ELF.RELOCATION_ARM(r.type) == lief.ELF.RELOCATION_ARM.GLOB_DAT:
                self.assertEqual(r.size, 32)

            if lief.ELF.RELOCATION_ARM(r.type) == lief.ELF.RELOCATION_ARM.ABS32:
                self.assertEqual(r.size, 32)

            if lief.ELF.RELOCATION_ARM(r.type) == lief.ELF.RELOCATION_ARM.JUMP_SLOT:
                self.assertEqual(r.size, 32)


        for r in itertools.chain(x86_ls.dynamic_relocations, x86_ls.pltgot_relocations):
            if lief.ELF.RELOCATION_i386(r.type) == lief.ELF.RELOCATION_i386.GLOB_DAT:
                self.assertEqual(r.size, 32)

            if lief.ELF.RELOCATION_i386(r.type) == lief.ELF.RELOCATION_i386.COPY:
                self.assertEqual(r.size, 32)

            if lief.ELF.RELOCATION_i386(r.type) == lief.ELF.RELOCATION_i386.JUMP_SLOT:
                self.assertEqual(r.size, 32)


        for r in itertools.chain(x86_64_ls.dynamic_relocations, x86_64_ls.pltgot_relocations):
            if lief.ELF.RELOCATION_X86_64(r.type) == lief.ELF.RELOCATION_X86_64.GLOB_DAT:
                self.assertEqual(r.size, 64)

            if lief.ELF.RELOCATION_X86_64(r.type) == lief.ELF.RELOCATION_X86_64.COPY:
                self.assertEqual(r.size, 32)

            if lief.ELF.RELOCATION_X86_64(r.type) == lief.ELF.RELOCATION_X86_64.JUMP_SLOT:
                self.assertEqual(r.size, 64)

    def test_sectionless(self):
        sample = "ELF/ELF64_x86-64_binary_rvs.bin"
        rvs = lief.parse(get_sample(sample))
        dynsym = list(rvs.dynamic_symbols)
        self.assertEqual(len(dynsym), 10)

    def test_dynamic_flags(self):
        sample = "ELF/ELF32_ARM_binary_ls.bin"
        ls = lief.parse(get_sample(sample))
        d_flags = ls.get(lief.ELF.DYNAMIC_TAGS.FLAGS)
        d_flags_1 = ls.get(lief.ELF.DYNAMIC_TAGS.FLAGS_1)

        self.assertIn(lief.ELF.DYNAMIC_FLAGS.BIND_NOW, d_flags)
        self.assertIn(lief.ELF.DYNAMIC_FLAGS_1.NOW, d_flags_1)


    def test_unwind_arm(self):
        sample = "ELF/ELF32_ARM_binary_ls.bin"
        ls = lief.parse(get_sample(sample))

        functions = sorted(ls.functions, key=lambda f: f.address)

        self.assertEqual(len(functions), 265)

        self.assertEqual(functions[0].address, 19684)
        self.assertEqual(functions[0].size,    0)
        self.assertEqual(functions[0].name,    "open")

        self.assertEqual(functions[-1].address, 102372)
        self.assertEqual(functions[-1].size,    0)
        self.assertEqual(functions[-1].name,    "")


    def test_unwind_x86(self):
        sample = "ELF/ELF64_x86-64_binary_ld.bin"
        ld = lief.parse(get_sample(sample))

        functions = sorted(ld.functions, key=lambda f: f.address)

        self.assertEqual(len(functions), 503)

        self.assertEqual(functions[0].address, 4209304)
        self.assertEqual(functions[0].size,    0)
        self.assertEqual(functions[0].name,    "_init")

        self.assertEqual(functions[10].size,    174)
        self.assertEqual(functions[10].name,    "")

        self.assertEqual(functions[-1].address, 4409396)
        self.assertEqual(functions[-1].size,    0)
        self.assertEqual(functions[-1].name,    "_fini")


    def test_misc(self):
        sample = "ELF/ELF64_x86-64_binary_ld.bin"
        ld = lief.parse(get_sample(sample))

        text = ld.get_section(".text")

        self.assertFalse(ld.has_section_with_offset(0))
        self.assertFalse(ld.has_section_with_va(0xFFFFFFFF))

        self.assertTrue(ld.has_section_with_offset(text.offset + 10))
        self.assertTrue(ld.has_section_with_va(text.virtual_address + 10))
Beispiel #13
0
class TestAddSegment(TestCase):
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.tmp_dir = tempfile.mkdtemp(suffix='_lief_test_add_segment')
        self.logger.debug("temp dir: {}".format(self.tmp_dir))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_simple(self):
        sample_path = get_sample('ELF/ELF64_x86-64_binary_ls.bin')
        stub = lief.parse(os.path.join(CURRENT_DIRECTORY, "hello_lief.bin"))
        output = os.path.join(self.tmp_dir, "ls.segment")

        target = lief.parse(sample_path)
        for i in range(4):
            segment = stub.segments[0]
            original_va = segment.virtual_address
            segment.virtual_address = 0
            segment = target.add(segment)
            new_ep = (stub.header.entrypoint -
                      original_va) + segment.virtual_address

            target.header.entrypoint = new_ep
        target.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'LIEF is Working', stdout.decode("utf8")))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_gcc(self):
        sample_path = get_sample('ELF/ELF64_x86-64_binary_gcc.bin')
        stub = lief.parse(os.path.join(CURRENT_DIRECTORY, "hello_lief.bin"))
        output = os.path.join(self.tmp_dir, "gcc.segment")

        target = lief.parse(sample_path)
        segment = stub.segments[0]
        original_va = segment.virtual_address
        segment.virtual_address = 0
        segment = target.add(segment)
        new_ep = (stub.header.entrypoint -
                  original_va) + segment.virtual_address

        target.header.entrypoint = new_ep
        target.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'LIEF is Working', stdout.decode("utf8")))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    def test_static(self):
        sample_path = get_sample('ELF/ELF64_x86-64_binary_static-binary.bin')
        stub = lief.parse(os.path.join(CURRENT_DIRECTORY, "hello_lief.bin"))
        output = os.path.join(self.tmp_dir, "static.segment")

        target = lief.parse(sample_path)
        segment = stub.segments[0]
        original_va = segment.virtual_address
        segment.virtual_address = 0
        segment = target.add(segment)
        new_ep = (stub.header.entrypoint -
                  original_va) + segment.virtual_address

        target.header.entrypoint = new_ep
        target.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'LIEF is Working', stdout.decode("utf8")))

    @unittest.skipUnless(is_linux(), "requires Linux")
    def test_misc(self):
        list_binaries = [
            '/usr/bin/ls',
            '/usr/bin/ssh',
            '/usr/bin/nm',
            '/usr/bin/openssl',
            '/usr/bin/bc',
            '/usr/bin/bzip2',
            '/usr/bin/cp',
            '/usr/bin/find',
            '/usr/bin/file',
        ]
        for binary in list_binaries:
            self.logger.debug("Test with '{}'".format(binary))
            self.run_add_segment(binary)

    def run_add_segment(self, target):
        if not os.path.isfile(target):
            self.logger.debug("%s does not exists. Skip!", target)
            return

        stub = None
        if is_x86_64():
            stub = lief.parse(os.path.join(CURRENT_DIRECTORY,
                                           "hello_lief.bin"))
        elif is_aarch64():
            stub = lief.parse(
                os.path.join(CURRENT_DIRECTORY, "hello_lief_aarch64.bin"))

        name = os.path.basename(target)
        target = lief.parse(target)
        output = os.path.join(self.tmp_dir, "{}.segment".format(name))
        for i in range(6):
            stub_segment = stub.segments[0]
            segment = lief.ELF.Segment()
            segment.content = stub.segments[0].content
            segment.type = stub_segment.type
            segment.alignment = stub_segment.alignment
            segment.flags = stub_segment.flags

            new_segment = target.add(segment)
            new_ep = (stub.header.entrypoint - stub.imagebase -
                      stub_segment.file_offset) + new_segment.virtual_address

            target.header.entrypoint = new_ep
        target.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'LIEF is Working', stdout.decode("utf8")))

    # TODO(romain): To fix
    #@unittest.skipUnless(is_linux(), "requires Linux x86-64")
    #def test_libc(self):
    #    stub = None
    #    if is_x86_64():
    #        stub = lief.parse(os.path.join(CURRENT_DIRECTORY, "hello_lief.bin"))
    #    elif is_aarch64():
    #        stub = lief.parse(os.path.join(CURRENT_DIRECTORY, "hello_lief_aarch64.bin"))
    #    tmp_dir = tempfile.mkdtemp(suffix='_lief_test_add_segment_libc')
    #    self.logger.debug("temp dir: {}".format(tmp_dir))

    #    libc_name = "libc.so.6"
    #    for e in lief.parse("/bin/ls").libraries:
    #        if e.startswith("libc."):
    #            libc_name = e
    #            break

    #    libc_path = '/usr/lib/{}'.format(libc_name)
    #    if not os.path.isfile(libc_path):
    #        libc_path = '/usr/lib/aarch64-linux-gnu/{}'.format(libc_name)

    #    self.logger.debug("libc used: {}".format(libc_path))

    #    libc = lief.parse(libc_path)
    #    out = os.path.join(tmp_dir, libc_name)

    #    stub_segment      = stub.segments[0]
    #    for i in range(10):
    #        segment           = lief.ELF.Segment()
    #        segment.content   = stub.segments[0].content
    #        segment.type      = stub_segment.type
    #        segment.alignment = stub_segment.alignment
    #        segment.flags     = stub_segment.flags

    #        new_segment       = libc.add(segment)
    #        new_ep            = (stub.header.entrypoint - stub.imagebase - stub_segment.file_offset) + new_segment.virtual_address

    #        libc.header.entrypoint = new_ep

    #        if libc.has(lief.ELF.DYNAMIC_TAGS.INIT_ARRAY):
    #            init_array = libc.get(lief.ELF.DYNAMIC_TAGS.INIT_ARRAY)
    #            callbacks = init_array.array
    #            callbacks[0] = new_ep
    #            init_array.array = callbacks

    #        if libc.has(lief.ELF.DYNAMIC_TAGS.INIT):
    #            init = libc.get(lief.ELF.DYNAMIC_TAGS.INIT)
    #            init.value = new_ep

    #    libc.write(out)

    #    st = os.stat(out)
    #    os.chmod(out, st.st_mode | stat.S_IEXEC)

    #    p = Popen(["/usr/bin/ls"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env={"LD_LIBRARY_PATH": tmp_dir})
    #    stdout, _ = p.communicate()
    #    self.logger.debug(stdout.decode("utf8"))

    #    self.assertIsNotNone(re.search(r'LIEF is Working', stdout.decode("utf8")))

    #    if os.path.isdir(tmp_dir):
    #        shutil.rmtree(tmp_dir)

    def tearDown(self):
        # Delete it
        if os.path.isdir(self.tmp_dir):
            shutil.rmtree(self.tmp_dir)
Beispiel #14
0
class TestAddSegment(TestCase):
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.tmp_dir = tempfile.mkdtemp(suffix='_lief_test_add_segment')
        self.logger.debug("temp dir: {}".format(self.tmp_dir))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_simple(self):
        sample_path = get_sample('ELF/ELF64_x86-64_binary_ls.bin')
        stub = lief.parse(os.path.join(CURRENT_DIRECTORY, "hello_lief.bin"))
        output = os.path.join(self.tmp_dir, "ls.replace_segment")
        target = lief.parse(sample_path)

        if not lief.ELF.SEGMENT_TYPES.NOTE in target:
            self.logger.error("Note not found!")
            return

        segment = stub.segments[0]
        original_va = segment.virtual_address
        segment.virtual_address = 0
        segment = target.replace(segment, target[lief.ELF.SEGMENT_TYPES.NOTE])
        new_ep = (stub.header.entrypoint -
                  original_va) + segment.virtual_address

        target.header.entrypoint = new_ep
        target.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'LIEF is Working', stdout.decode("utf8")))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_gcc(self):
        sample_path = get_sample('ELF/ELF64_x86-64_binary_gcc.bin')
        stub = lief.parse(os.path.join(CURRENT_DIRECTORY, "hello_lief.bin"))
        output = os.path.join(self.tmp_dir, "gcc.replace_segment")
        target = lief.parse(sample_path)

        if not lief.ELF.SEGMENT_TYPES.NOTE in target:
            self.logger.error("Note not found!")
            return

        segment = stub.segments[0]
        original_va = segment.virtual_address
        segment.virtual_address = 0
        segment = target.replace(segment, target[lief.ELF.SEGMENT_TYPES.NOTE])
        new_ep = (stub.header.entrypoint -
                  original_va) + segment.virtual_address

        target.header.entrypoint = new_ep
        target.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'LIEF is Working', stdout.decode("utf8")))

    @unittest.skipUnless(is_linux(), "requires Linux")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_ssh(self):
        stub = None
        if is_x86_64():
            stub = lief.parse(os.path.join(CURRENT_DIRECTORY,
                                           "hello_lief.bin"))
        elif is_aarch64():
            stub = lief.parse(
                os.path.join(CURRENT_DIRECTORY, "hello_lief_aarch64.bin"))

        output = os.path.join(self.tmp_dir, "ssh.replace_segment")
        target = lief.parse("/usr/bin/ssh")

        if not lief.ELF.SEGMENT_TYPES.NOTE in target:
            self.logger.error("Note not found!")
            return

        segment = stub.segments[0]
        original_va = segment.virtual_address
        segment.virtual_address = 0
        segment = target.replace(segment, target[lief.ELF.SEGMENT_TYPES.NOTE])
        new_ep = (stub.header.entrypoint -
                  original_va) + segment.virtual_address

        target.header.entrypoint = new_ep
        target.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'LIEF is Working', stdout.decode("utf8")))

    def tearDown(self):
        # Delete it
        if os.path.isdir(self.tmp_dir):
            shutil.rmtree(self.tmp_dir)
Beispiel #15
0
import re
import subprocess
import tempfile
import shutil
from subprocess import Popen

import lief
from lief.ELF import Section

from unittest import TestCase
from utils import get_sample, has_recent_glibc, is_linux, is_x86_64, is_aarch64

CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__))

STUB_FILE = None
if is_x86_64():
    STUB_FILE = "hello_lief.bin"
elif is_aarch64():
    STUB_FILE = "hello_lief_aarch64.bin"

STUB = lief.parse(os.path.join(CURRENT_DIRECTORY, STUB_FILE))

class TestAddSection(TestCase):
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.tmp_dir = tempfile.mkdtemp(suffix='_lief_test_section')
        self.logger.debug("temp dir: {}".format(self.tmp_dir))


    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
Beispiel #16
0
class TestAddSection(TestCase):
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.tmp_dir = tempfile.mkdtemp(suffix='_lief_test_section')
        self.logger.debug("temp dir: {}".format(self.tmp_dir))


    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_simple(self):
        sample_path = get_sample('ELF/ELF64_x86-64_binary_ls.bin')
        output      = os.path.join(self.tmp_dir, "ls.section")

        ls = lief.parse(sample_path)
        for i in range(10):
            section = Section(".test.{:d}".format(i), lief.ELF.SECTION_TYPES.PROGBITS)
            section += lief.ELF.SECTION_FLAGS.EXECINSTR
            section += lief.ELF.SECTION_FLAGS.WRITE
            section.content   = STUB.segments[0].content # First LOAD segment which holds payload
            if i % 2 == 0:
                section = ls.add(section, loaded=True)
                ls.header.entrypoint = section.virtual_address + STUB.header.entrypoint
            else:
                section = ls.add(section, loaded=False)

        ls.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(re.search(r'LIEF is Working', stdout.decode("utf8")))


    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_gcc(self):
        sample_path = get_sample('ELF/ELF64_x86-64_binary_gcc.bin')
        output      = os.path.join(self.tmp_dir, "gcc.section")

        gcc = lief.parse(sample_path)
        for i in range(10):
            section = Section(".test.{:d}".format(i), lief.ELF.SECTION_TYPES.PROGBITS)
            section.type     = lief.ELF.SECTION_TYPES.PROGBITS
            section         += lief.ELF.SECTION_FLAGS.EXECINSTR
            section         += lief.ELF.SECTION_FLAGS.WRITE
            section.content  = STUB.segments[0].content # First LOAD segment which holds payload

            if i % 2 == 0:
                section = gcc.add(section, loaded=True)
                gcc.header.entrypoint = section.virtual_address + STUB.header.entrypoint
            else:
                section = gcc.add(section, loaded=False)

        gcc.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen(output, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(re.search(r'LIEF is Working', stdout.decode("utf8")))


    def tearDown(self):
        # Delete it
        if os.path.isdir(self.tmp_dir):
            shutil.rmtree(self.tmp_dir)
Beispiel #17
0
#!/usr/bin/env python
import stat
import re
import subprocess
from subprocess import Popen
import pytest

import lief
import pathlib

from utils import get_sample, has_recent_glibc, is_linux, is_x86_64


@pytest.mark.skipif(not (is_linux() and is_x86_64() and has_recent_glibc()),
                    reason="incompatible env")
def test_freebl(tmp_path):
    tmp = pathlib.Path(tmp_path)

    libfreebl3_path = get_sample('ELF/ELF64_x86-64_library_libfreebl3.so')

    output_ls = tmp / "ls.new"
    output_libfreebl3 = tmp / "libfreebl3.so"

    libfreebl3 = lief.parse(libfreebl3_path)
    ls = lief.parse("/usr/bin/ls")
    if ls is None:
        ls = lief.parse("/bin/ls")

    if lief.ELF.DYNAMIC_TAGS.FLAGS_1 in ls and ls[
            lief.ELF.DYNAMIC_TAGS.FLAGS_1].has(lief.ELF.DYNAMIC_FLAGS_1.PIE):
        ls[lief.ELF.DYNAMIC_TAGS.FLAGS_1].remove(lief.ELF.DYNAMIC_FLAGS_1.PIE)
Beispiel #18
0
import stat
import ctypes
import lief
import pytest

from utils import get_sample, has_recent_glibc, is_linux, is_x86_64

SYMBOLS = {
    "myinstance": 0x1159,
    "myinit": 0x1175,
    "mycalc": 0x1199,
    "mydelete": 0x1214,
}


@pytest.mark.skipif(not is_linux() or not is_x86_64(),
                    reason="requires Linux x86-64")
@pytest.mark.skipif(not has_recent_glibc(),
                    reason="needs a recent GLIBC version")
def test_gnu_hash(tmpdir):
    target_path = get_sample('ELF/ELF64_x86-64_binary_empty-gnu-hash.bin')
    output = os.path.join(tmpdir, "libnoempty.so")

    binary = lief.parse(target_path)
    binary[lief.ELF.DYNAMIC_TAGS.FLAGS_1].remove(lief.ELF.DYNAMIC_FLAGS_1.PIE)

    for name, addr in SYMBOLS.items():
        binary.add_exported_function(addr, name)
    binary.write(output)

    st = os.stat(output)
Beispiel #19
0
class TestRelocations(TestCase):
    def setUp(self):
        self.logger = logging.getLogger(__name__)
        self.tmp_dir = tempfile.mkdtemp(suffix='_lief_test_relocations')
        self.logger.debug("temp dir: {}".format(self.tmp_dir))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    @unittest.skipUnless(has_recent_glibc(), "Need a recent GLIBC version")
    def test_simple(self):
        sample_path = get_sample('ELF/ELF64_x86-64_binary_ls.bin')
        output = os.path.join(self.tmp_dir, "ls.relocation")

        ls = lief.parse(sample_path)

        relocation = lief.ELF.Relocation(
            0x61D370, type=lief.ELF.RELOCATION_X86_64.JUMP_SLOT, is_rela=True)

        symbol = lief.ELF.Symbol()
        symbol.name = "printf123"

        relocation.symbol = symbol

        ls.add_pltgot_relocation(relocation)

        ls.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen([output, "--version"],
                  stdout=subprocess.PIPE,
                  stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'ls \(GNU coreutils\) ', stdout.decode("utf8")))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    def test_all(self):
        sample_path = get_sample('ELF/ELF64_x86-64_binary_all.bin')
        output = os.path.join(self.tmp_dir, "all.relocation")

        target = lief.parse(sample_path)

        relocation = lief.ELF.Relocation(
            0x201028, type=lief.ELF.RELOCATION_X86_64.JUMP_SLOT, is_rela=True)

        symbol = lief.ELF.Symbol()
        symbol.name = "printf123"

        relocation.symbol = symbol
        target.add_pltgot_relocation(relocation)

        target.write(output)

        st = os.stat(output)
        os.chmod(output, st.st_mode | stat.S_IEXEC)

        p = Popen([output], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout, _ = p.communicate()
        self.logger.debug(stdout.decode("utf8"))
        self.assertIsNotNone(
            re.search(r'Hello World: 1', stdout.decode("utf8")))

    @unittest.skipUnless(is_linux() and is_x86_64(), "requires Linux x86-64")
    def test_all32(self):
        sample_path = get_sample('ELF/ELF32_x86_binary_all.bin')
        output = os.path.join(self.tmp_dir, "all32.relocation")

        target = lief.parse(sample_path)

        relocation = lief.ELF.Relocation(
            0x2018, type=lief.ELF.RELOCATION_i386.JUMP_SLOT, is_rela=False)

        symbol = lief.ELF.Symbol()
        symbol.name = "printf123"

        relocation.symbol = symbol
        target.add_pltgot_relocation(relocation)

        target.write(output)

        new = lief.parse(output)
        self.assertTrue(new.has_symbol("printf123"))

        #st = os.stat(output)
        #os.chmod(output, st.st_mode | stat.S_IEXEC)

        #p = Popen([output], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        #stdout, _ = p.communicate()
        #self.logger.debug(stdout.decode("utf8"))
        #self.assertIsNotNone(re.search(r'Hello World: 1', stdout.decode("utf8")))

    def tearDown(self):
        # Delete it
        if os.path.isdir(self.tmp_dir):
            shutil.rmtree(self.tmp_dir)
Beispiel #20
0
    def test_libadd(self):

        _, binaddc = tempfile.mkstemp(prefix="binadd_", suffix=".c")
        _, libaddc = tempfile.mkstemp(prefix="libadd_", suffix=".c")

        self._logger.debug(binaddc)
        self._logger.debug(libaddc)

        fd, binadd = tempfile.mkstemp(prefix="binadd_", suffix=".bin")
        _, libadd = tempfile.mkstemp(prefix="libadd_", suffix=".so")
        _, libadd2 = tempfile.mkstemp(prefix="libadd2_", suffix=".so")

        self._logger.debug(binadd)
        self._logger.debug(libadd)
        self._logger.debug(libadd2)

        with open(binaddc, 'w') as f:
            f.write(BINADD)

        with open(libaddc, 'w') as f:
            f.write(LIBADD)

        compiler = get_compiler()

        fmt = ""
        if is_x86_64():
            fmt = "{compiler} -Wl,--export-dynamic -mcmodel=large -fPIE -pie -o {output} {input}"

        if is_aarch64():
            fmt = "{compiler} -Wl,--export-dynamic -fPIE -pie -o {output} {input}"

        # Compile libadd
        r = self.run_cmd(
            fmt.format(compiler=compiler, output=libadd, input=libaddc))
        self.assertTrue(r, msg="Unable to compile libadd")

        libadd = lief.parse(libadd)

        libadd_hidden = libadd.get_symbol("add_hidden")
        libadd_hidden.binding = lief.ELF.SYMBOL_BINDINGS.GLOBAL
        libadd_hidden.visibility = lief.ELF.SYMBOL_VISIBILITY.DEFAULT
        libadd_hidden = libadd.add_dynamic_symbol(
            libadd_hidden, lief.ELF.SymbolVersion.global_)
        if libadd.has(lief.ELF.DYNAMIC_TAGS.FLAGS_1):
            libadd[lief.ELF.DYNAMIC_TAGS.FLAGS_1].remove(
                lief.ELF.DYNAMIC_FLAGS_1.PIE)

        self._logger.debug(libadd_hidden)

        libadd.add(lief.ELF.DynamicSharedObject(os.path.basename(libadd2)))

        libadd.write(libadd2)

        lib_directory = os.path.dirname(libadd2)
        libname = os.path.basename(libadd2)[3:-3]  # libadd.so ---> add

        fmt = ""
        if is_x86_64():
            fmt = "{compiler} -Wl,--export-dynamic -mcmodel=large -fPIE -pie -Wl,-rpath={libdir} -L{libdir} -o {output} {input} -l{libadd2}"

        if is_aarch64():
            fmt = "{compiler} -Wl,--export-dynamic -fPIE -pie -Wl,-rpath={libdir} -L{libdir} -o {output} {input} -l{libadd2}"

        r = self.run_cmd(
            fmt.format(compiler=compiler,
                       libdir=lib_directory,
                       libadd2=libname,
                       output=binadd,
                       input=binaddc))
        self.assertTrue(r, msg="Unable to compile binadd")

        os.close(fd)
        st = os.stat(binadd)
        os.chmod(binadd, st.st_mode | stat.S_IEXEC)

        r = self.run_cmd(binadd + " 1 2")
        self.assertTrue(r)
        self.assertIn("From [email protected] a + b = 3", r.output)
Beispiel #21
0
#!/usr/bin/env python
import stat
import re
import subprocess
from subprocess import Popen
import pytest

import lief
import pathlib

from utils import get_sample, has_recent_glibc, is_linux, is_x86_64

@pytest.mark.skipif(not (is_linux() and is_x86_64() and has_recent_glibc()), reason="incompatible env")
def test_freebl(tmp_path):
    tmp = pathlib.Path(tmp_path)

    libfreebl3_path   = get_sample('ELF/ELF64_x86-64_library_libfreebl3.so')

    output_ls         = tmp / "ls.new"
    output_libfreebl3 = tmp / "libfreebl3.so"

    libfreebl3 = lief.parse(libfreebl3_path)
    ls         = lief.parse("/usr/bin/ls")
    if ls is None:
        ls = lief.parse("/bin/ls")

    if lief.ELF.DYNAMIC_TAGS.FLAGS_1 in ls and ls[lief.ELF.DYNAMIC_TAGS.FLAGS_1].has(lief.ELF.DYNAMIC_FLAGS_1.PIE):
        ls[lief.ELF.DYNAMIC_TAGS.FLAGS_1].remove(lief.ELF.DYNAMIC_FLAGS_1.PIE)

    ls.add_library("libfreebl3.so")