예제 #1
0
def test_add_command(tmp_path):
    bin_path = pathlib.Path(get_sample('MachO/MachO64_x86-64_binary_id.bin'))
    original = lief.parse(bin_path.as_posix())

    output = f"{tmp_path}/test_add_command.id.bin"

    LIB_NAME = "/usr/lib/libSystem.B.dylib"

    dylib_1 = lief.MachO.DylibCommand.lazy_load_dylib(LIB_NAME)
    dylib_2 = lief.MachO.DylibCommand.weak_lib(LIB_NAME)

    original.add(dylib_1)
    original.add(dylib_2, 0)

    original.remove_signature()

    original.write(output)

    new = lief.parse(output)

    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    assert len([l for l in new.libraries if l.name == LIB_NAME]) > 0

    if is_osx():
        assert run_program(bin_path.as_posix())

        stdout = run_program(output)
        print(stdout)
        assert re.search(r'uid=', stdout) is not None
예제 #2
0
def compile(output, extra_flags=None):
    if not is_osx():
        return

    extra_flags = extra_flags if extra_flags else []
    with tempfile.NamedTemporaryFile(prefix="libexample_",
                                     suffix=".c",
                                     delete=False) as ftmp:
        with open(ftmp.name, 'w') as f:
            f.write(LIBRARY_CODE)

    COMPILER = "/usr/bin/clang"
    CC_FLAGS = ['-fPIC', '-shared']
    extra_flags = [] if extra_flags is None else extra_flags
    cmd = [COMPILER] + extra_flags + CC_FLAGS + ['-o', output] + [ftmp.name]
    print("Compile 'libexample' with: {}".format(" ".join(cmd)))

    with Popen(cmd,
               universal_newlines=True,
               stdout=subprocess.PIPE,
               stderr=subprocess.STDOUT) as proc:
        output = proc.stdout.read()
        print(output)
        return output
    return None
예제 #3
0
def load(config):
    """Returns a dictonary (key=path, value=weight) loaded from data file."""
    xdg_aj_home = os.path.join(
            os.path.expanduser('~'),
            '.local',
            'share',
            'autojump')

    if is_osx() and os.path.exists(xdg_aj_home):
        migrate_osx_xdg_data(config)

    if os.path.exists(config['data_path']):
        # example: u'10.0\t/home/user\n' -> ['10.0', u'/home/user']
        parse = lambda line: line.strip().split('\t')

        correct_length = lambda x: len(x) == 2

        # example: ['10.0', u'/home/user'] -> (u'/home/user', 10.0)
        tupleize = lambda x: (x[1], float(x[0]))

        try:
            with open(
                    config['data_path'],
                    'r', encoding='utf-8',
                    errors='replace') as f:
                return dict(
                        imap(
                            tupleize,
                            ifilter(correct_length, imap(parse, f))))
        except (IOError, EOFError):
            return load_backup(config)

    return {}
예제 #4
0
    def test_id(self):
        original = lief.parse(get_sample("MachO/MachO64_x86-64_binary_id.bin"))
        _, output = tempfile.mkstemp(prefix="lief_id_remove_cmd")

        # Extend UUID
        uuid_cmd = original[lief.MachO.LOAD_COMMAND_TYPES.UUID]
        original_size = uuid_cmd.size
        original.extend(uuid_cmd, 0x100)

        # Extend __LINKEDIT (last one)
        original_linkedit_size = original.get_segment("__LINKEDIT").file_size
        original.extend_segment(original.get_segment("__LINKEDIT"), 0x30000)

        original.remove_signature()
        original.write(output)

        new = lief.parse(output)

        self.assertEqual(
            new.get_segment("__LINKEDIT").file_size,
            original_linkedit_size + 0x30000)
        self.assertEqual(new[lief.MachO.LOAD_COMMAND_TYPES.UUID].size,
                         original_size + 0x100)

        if is_osx() and not is_aarch64():
            stdout = run_program(output)
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'uid=', stdout))
예제 #5
0
def test_bin2lib(tmp_path):
    file_path = "MachO/mbedtls_selftest_arm64.bin" if is_aarch64(
    ) else "MachO/mbedtls_selftest_x86_64.bin"
    bin_path = pathlib.Path(get_sample(file_path))
    original = lief.parse(bin_path.as_posix())
    output = f"{tmp_path}/libtest.dylib"

    header: lief.MachO.Header = original.header
    header.file_type = lief.MachO.FILE_TYPES.DYLIB

    # Create LC_ID_DYLIB command
    original.add(lief.MachO.DylibCommand.id_dylib(output, 0, 1, 2))

    # Create a new export :)
    ADDR = 0x10000D782 if header.cpu_type == lief.MachO.CPU_TYPES.x86_64 else 0x10004F3F4
    assert original.add_exported_function(ADDR, "_lief_test_export")

    original.write(output)

    new = lief.parse(output)
    checked, err = lief.MachO.check_layout(new)
    assert checked, err
    if is_osx():
        sign(output)
        print(f"Loading {output}")
        lib = ctypes.cdll.LoadLibrary(output)
        assert lib
        assert lib.lief_test_export
예제 #6
0
def test_add_section_ssh(tmp_path):
    bin_path = pathlib.Path(get_sample("MachO/MachO64_x86-64_binary_sshd.bin"))
    original = lief.parse(bin_path.as_posix())
    output = f"{tmp_path}/test_add_section_sshd.sshd.bin"
    page_size = original.page_size

    # Add 3 section into __TEXT
    __text = original.get_segment("__TEXT")
    for i in range(3):
        section = lief.MachO.Section(f"__text_{i}")
        section.content = [0xC3] * 0x100
        original.add_section(__text, section)

    assert original.virtual_size % page_size == 0
    assert __text.virtual_size % page_size == 0

    original.remove_signature()
    original.write(output)

    new = lief.parse(output)

    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    if is_osx():
        assert run_program(bin_path.as_posix(), args=["--help"])
        stdout = run_program(output, args=["--help"])

        print(stdout)
        assert re.search(r'OpenSSH_6.9p1, LibreSSL 2.1.8', stdout) is not None
예제 #7
0
def test_remove_cmd(tmp_path):
    bin_path = pathlib.Path(get_sample('MachO/MachO64_x86-64_binary_id.bin'))
    original = lief.parse(bin_path.as_posix())

    output = f"{tmp_path}/test_remove_cmd.id.bin"

    uuid_cmd = original[lief.MachO.LOAD_COMMAND_TYPES.UUID]
    original.remove(uuid_cmd)
    original.remove_command(len(original.commands) - 1)

    original.write(output)

    new = lief.parse(output)

    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    assert lief.MachO.LOAD_COMMAND_TYPES.UUID not in new
    assert lief.MachO.LOAD_COMMAND_TYPES.CODE_SIGNATURE not in new

    if is_osx():
        assert run_program(bin_path.as_posix())

        stdout = run_program(output)
        print(stdout)
        assert re.search(r'uid=', stdout) is not None
예제 #8
0
def test_rm_symbols(tmp_path):
    bin_path = pathlib.Path(
        get_sample("MachO/MachO64_x86-64_binary_sym2remove.bin"))
    original = lief.parse(bin_path.as_posix())
    output = f"{tmp_path}/{bin_path.name}"

    for s in ["__ZL6BANNER", "_remove_me"]:
        assert original.can_remove_symbol(s)
        original.remove_symbol(s)

    original.write(output)
    new = lief.parse(output)

    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    assert new.get_symbol("__ZL6BANNER") is None
    assert new.get_symbol("_remove_me") is None

    if is_osx():
        assert run_program(bin_path.as_posix())
        stdout = run_program(output)

        print(stdout)
        assert re.search(r'Hello World', stdout) is not None
예제 #9
0
def test_unexport(tmp_path):
    bin_path = pathlib.Path(
        get_sample("MachO/MachO64_x86-64_binary_sym2remove.bin"))
    original = lief.parse(bin_path.as_posix())
    output = f"{tmp_path}/{bin_path.name}"
    exported = {s.name for s in original.symbols if s.has_export_info}

    assert "_remove_me" in exported

    original.unexport("_remove_me")

    original.write(output)
    new = lief.parse(output)

    exported = {s.name for s in new.symbols if s.has_export_info}
    assert "_remove_me" not in exported

    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    if is_osx():
        assert run_program(bin_path.as_posix())
        stdout = run_program(output)

        print(stdout)
        assert re.search(r'Hello World', stdout) is not None
예제 #10
0
def test_objc_x86_64(tmp_path):
    bin_path = pathlib.Path(get_sample("MachO/test_objc_x86_64.macho"))
    original = lief.parse(bin_path.as_posix())
    output = f"{tmp_path}/{bin_path.name}"

    for i in range(50):
        segment = lief.MachO.SegmentCommand(f"__LIEF_{i}", [i] * (0x457 + i))
        segment = original.add(segment)

    # Extend the symbols table
    for i in range(10):
        sym = f"_foooo_{i}"
        original.add_exported_function(original.imagebase + i * 8, sym)

        sym = f"_foooo2_{i}"
        original.add_local_symbol(original.entrypoint + i * 8, sym)

    functions = original.function_starts.functions
    functions *= 2
    sorted(functions)
    original.function_starts.functions = functions

    original.write(output)
    new = lief.parse(output)

    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    if is_osx():
        assert run_program(bin_path.as_posix())
        stdout = run_program(output)

        print(stdout)
        assert re.search(r'Printing Process Completed', stdout) is not None
예제 #11
0
    def test_unexport(self):
        original = lief.parse(get_sample('MachO/MachO64_x86-64_binary_sym2remove.bin'))
        _, output = tempfile.mkstemp(prefix="lief_sym_remove_")

        original.unexport("_remove_me")
        original.write(output)

        if is_osx():
            stdout = run_program(output)
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'Hello World', stdout))
예제 #12
0
def test_ssh(tmp_path):
    bin_path = pathlib.Path(get_sample("MachO/MachO64_x86-64_binary_sshd.bin"))
    output = patch(tmp_path, bin_path)
    new = lief.parse(output)

    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    if is_osx():
        stdout = run_program(output, args=["--help"])
        print(stdout)
        assert re.search(r'LIEF says hello :\)', stdout) is not None
예제 #13
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))
예제 #14
0
    def test_nm(self):
        original = lief.parse(get_sample('MachO/MachO64_x86-64_binary_nm.bin'))
        _, output = tempfile.mkstemp(prefix="lief_nm_")

        # Add segment without section
        segment = lief.MachO.SegmentCommand("__LIEF", [0x60] * 0x100)
        segment = original.add(segment)

        original.write(output)

        if is_osx():
            stdout = run_program(output, ["-version"])
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'Default target:', stdout))
예제 #15
0
    def test_id(self):
        original = lief.parse(get_sample('MachO/MachO64_x86-64_binary_id.bin'))
        _, output = tempfile.mkstemp(prefix="lief_id_")

        # Add 50 sections
        for i in range(50):
            section = lief.MachO.Section("__lief_{:d}".format(i), [0x90] * 0x100)
            original.add_section(section)

        original.write(output)

        if is_osx():
            stdout = run_program(output)
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'uid=', stdout))
예제 #16
0
    def test_all(self):
        original = lief.parse(get_sample('MachO/MachO64_x86-64_binary_all.bin'))
        _, output = tempfile.mkstemp(prefix="lief_all_")

        # Add segment with sections
        segment = lief.MachO.SegmentCommand("__LIEF_2")
        for i in range(5):
            section = lief.MachO.Section("__lief_2_{:d}".format(i), [i] * 0x100)
            segment.add_section(section)
        segment = original.add(segment)

        original.write(output)

        if is_osx():
            stdout = run_program(output)
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'Hello World: 1', stdout))
예제 #17
0
def test_all(tmp_path):
    bin_path = pathlib.Path(get_sample("MachO/FAT_MachO_x86-x86-64-binary_fatall.bin"))
    original = lief.MachO.parse(bin_path.as_posix())
    output = f"{tmp_path}/{bin_path.name}"

    assert len(original) == 2
    original.write(output)

    new = lief.MachO.parse(output)

    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    if is_osx():
        stdout = run_program(output)
        print(stdout)
        assert re.search(r'Hello World', stdout) is not None
예제 #18
0
    def test_rm_symbol(self):
        original = lief.parse(get_sample('MachO/MachO64_x86-64_binary_sym2remove.bin'))
        _, output = tempfile.mkstemp(prefix="lief_sym_remove_")

        for s in ["__ZL6BANNER", "_remove_me"]:
            self.assertTrue(original.can_remove_symbol(s))
            original.remove_symbol(s)

        original.write(output)
        new = lief.parse(output)
        ok, err = lief.MachO.check_layout(new)
        self.assertTrue(ok, err)

        if is_osx():
            stdout = run_program(output)
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'Hello World', stdout))
예제 #19
0
    def test_id(self):
        original = lief.parse(get_sample('MachO/MachO64_x86-64_binary_id.bin'))
        _, output = tempfile.mkstemp(prefix="lief_id_remove_cmd")

        uuid_cmd = original[lief.MachO.LOAD_COMMAND_TYPES.UUID]
        original.remove(uuid_cmd)
        original.remove_command(len(original.commands) - 1)

        original.write(output)

        new = lief.parse(output)
        self.assertFalse(lief.MachO.LOAD_COMMAND_TYPES.UUID in new)
        self.assertFalse(lief.MachO.LOAD_COMMAND_TYPES.CODE_SIGNATURE in new)

        if is_osx():
            stdout = run_program(output)
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'uid=', stdout))
예제 #20
0
    def test_ssh(self):
        original = lief.parse(get_sample('MachO/MachO64_x86-64_binary_sshd.bin'))
        _, output = tempfile.mkstemp(prefix="lief_ssh_")

        # Add 3 section into __TEXT
        __text = original.get_segment("__TEXT")
        for i in range(3):
            section = lief.MachO.Section("__text_{:d}".format(i))
            section.content = [0xC3] * 0x100
            original.add_section(__text, section)

        original.remove_signature()
        original.write(output)

        if is_osx():
            print(output)
            stdout = run_program(output, ["--help"])
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'OpenSSH_6.9p1, LibreSSL 2.1.8', stdout))
예제 #21
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))
예제 #22
0
def test_add_segment_nm(tmp_path):
    bin_path = pathlib.Path(get_sample("MachO/MachO64_x86-64_binary_nm.bin"))
    original = lief.parse(bin_path.as_posix())
    output = f"{tmp_path}/test_add_segment_nm.nm.bin"

    # Add segment without section
    segment = lief.MachO.SegmentCommand("__LIEF", [0x60] * 0x100)
    segment = original.add(segment)

    original.write(output)

    new = lief.parse(output)

    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    if is_osx():
        assert run_program(bin_path.as_posix())
        stdout = run_program(output, ["-version"])
        print(stdout)
        assert re.search(r'Default target:', stdout) is not None
예제 #23
0
def migrate_osx_xdg_data(config):
    """
    Older versions incorrectly used Linux XDG_DATA_HOME paths on OS X. This
    migrates autojump files from ~/.local/share/autojump to ~/Library/autojump
    """
    assert is_osx(), "This function should only be run on OS X."

    xdg_data_home = os.path.join(os.path.expanduser('~'), '.local', 'share')
    xdg_aj_home = os.path.join(xdg_data_home, 'autojump')
    data_path = os.path.join(xdg_aj_home, 'autojump.txt'),
    backup_path = os.path.join(xdg_aj_home, 'autojump.txt.bak'),

    if os.path.exists(data_path):
        move_file(data_path, config['data_path'])
    if os.path.exists(backup_path):
        move_file(backup_path, config['backup_path'])

    # cleanup
    shutil.rmtree(xdg_aj_home)
    if len(os.listdir(xdg_data_home)) == 0:
        shutil.rmtree(xdg_data_home)
예제 #24
0
파일: test_builder.py 프로젝트: snx90/LIEF
def test_remove_section_with_segment_name(tmp_path):
    bin_path = pathlib.Path(get_sample("MachO/MachO64_x86-64_binary_section_to_remove.bin"))
    original = lief.parse(bin_path.as_posix())
    output = f"{tmp_path}/{bin_path.name}"

    original.remove_section("__DATA", "__to_remove")

    original.write(output)
    new = lief.parse(output)

    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    assert new.get_section("__DATA", "__to_remove") is None

    if is_osx():
        assert run_program(bin_path.as_posix())
        stdout = run_program(output)

        print(stdout)
        assert re.search(r'Hello World', stdout) is not None
예제 #25
0
    def test_all(self):
        original = lief.parse(get_sample('MachO/MachO64_x86-64_binary_all.bin'))
        _, output = tempfile.mkstemp(prefix="lief_all_")

        section = lief.MachO.Section("__shell", self.shellcode)
        section.alignment = 2
        section += lief.MachO.SECTION_FLAGS.SOME_INSTRUCTIONS
        section += lief.MachO.SECTION_FLAGS.PURE_INSTRUCTIONS

        section = original.add_section(section)

        __TEXT = original.get_segment("__TEXT")

        original.main_command.entrypoint = section.virtual_address - __TEXT.virtual_address

        original.write(output)

        if is_osx():
            stdout = run_program(output)
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'Hello World!', stdout))
예제 #26
0
파일: test_builder.py 프로젝트: snx90/LIEF
def test_add_section_id(tmp_path):
    bin_path = pathlib.Path(get_sample("MachO/MachO64_x86-64_binary_id.bin"))
    original = lief.parse(bin_path.as_posix())
    output = f"{tmp_path}/test_add_section_id.id.bin"

    # Add 50 sections
    for i in range(50):
        section = lief.MachO.Section(f"__lief_{i}", [0x90] * 0x100)
        original.add_section(section)

    original.write(output)
    new = lief.parse(output)

    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    if is_osx():
        assert run_program(bin_path.as_posix())
        stdout = run_program(output)

        print(stdout)
        assert re.search(r'uid=', stdout) is not None
예제 #27
0
    def test_id(self):
        original = lief.parse(get_sample('MachO/MachO64_x86-64_binary_id.bin'))
        _, output = tempfile.mkstemp(prefix="lief_id_add_cmd")

        LIB_NAME = "/usr/lib/libSystem.B.dylib"

        dylib_1 = lief.MachO.DylibCommand.lazy_load_dylib(LIB_NAME)
        dylib_2 = lief.MachO.DylibCommand.weak_lib(LIB_NAME)

        original.add(dylib_1)
        original.add(dylib_2, 0)

        original.remove_signature()

        original.write(output)

        new = lief.parse(output)
        self.assertTrue(len([l for l in new.libraries if l.name == LIB_NAME]))

        if is_osx():
            stdout = run_program(output)
            self.logger.debug(stdout)
            self.assertIsNotNone(re.search(r'uid=', stdout))
예제 #28
0
    def compile(output, extra_flags=None):
        if not is_osx():
            return

        logger = logging.getLogger(__name__)
        extra_flags = extra_flags if extra_flags else []
        _, srcpath = tempfile.mkstemp(prefix="libexample_", suffix=".c")

        with open(srcpath, 'w') as f:
            f.write(TestLibraryInjection.LIBRARY_CODE)

        COMPILER = "/usr/bin/clang"
        CC_FLAGS = ['-fPIC', '-shared'] + extra_flags

        cmd = [COMPILER, '-o', output] + CC_FLAGS + [srcpath]
        logger.debug("Compile 'libexample' with: {}".format(" ".join(cmd)))

        p = Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

        stdout, _ = p.communicate()

        logger.debug(stdout)
        return output
예제 #29
0
def test_add_segment_all(tmp_path):
    bin_path = pathlib.Path(get_sample("MachO/MachO64_x86-64_binary_all.bin"))
    original = lief.parse(bin_path.as_posix())
    output = f"{tmp_path}/test_add_segment_all.all.bin"

    # Add segment with sections
    segment = lief.MachO.SegmentCommand("__LIEF_2")
    for i in range(5):
        section = lief.MachO.Section(f"__lief_2_{i}", [i] * 0x100)
        segment.add_section(section)
    segment = original.add(segment)

    original.write(output)

    new = lief.parse(output)
    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    if is_osx():
        assert run_program(bin_path.as_posix())
        stdout = run_program(output)
        print(stdout)
        assert re.search(r'Hello World: 1', stdout) is not None
예제 #30
0
def test_ssh_segments(tmp_path):
    bin_path = pathlib.Path(get_sample("MachO/MachO64_x86-64_binary_sshd.bin"))
    original = lief.parse(bin_path.as_posix())
    output = f"{tmp_path}/ssh_with_segments.bin"

    # Add segment with sections
    for i in range(10):
        segment = lief.MachO.SegmentCommand(f"__LIEF_{i}", [i] * (0x457 + i))
        segment = original.add(segment)

    original.write(output)

    new = lief.parse(output)
    checked, err = lief.MachO.check_layout(new)
    assert checked, err

    assert len(new.segments) == len(original.segments)

    if is_osx():
        assert run_program(bin_path.as_posix(), args=["--help"])
        stdout = run_program(output, args=["--help"])

        print(stdout)
        assert re.search(r'OpenSSH_6.9p1, LibreSSL 2.1.8', stdout) is not None
예제 #31
0
def test_break(tmp_path):
    FILES = [
        "MachO/mbedtls_selftest_arm64.bin", "MachO/mbedtls_selftest_x86_64.bin"
    ]

    def swap(target: lief.MachO.Binary, lhs: str, rhs: str):
        lhs_sec = target.get_section(lhs)
        if lhs_sec is None:
            print(f"Can't find section '{lhs_sec}'")
            return
        rhs_sec = target.get_section(rhs)
        if rhs_sec is None:
            print(f"Can't find section '{rhs_sec}'")
            return

        tmp = lhs_sec.name
        rhs_sec.name = tmp

    def shuffle(target: lief.MachO.Binary, name: str):
        section = target.get_section(name)
        if section is None:
            return
        print(f"[+] Shuffling '{name}'")
        section_content = list(section.content)
        random.shuffle(section_content)
        section.content = section_content

    def corrupt_function_starts(bin: lief.MachO.Binary,
                                break_alignment: bool = False):
        fstart = bin[lief.MachO.LOAD_COMMAND_TYPES.FUNCTION_STARTS]
        if fstart is None:
            return
        fstart.functions = [f + 5 for f in fstart.functions]

    def process_exports(bin: lief.MachO.Binary, sym: lief.MachO.Symbol):
        #print(sym.export_info.address)
        original_name = sym.export_info.symbol.name
        name = list(original_name)
        random.shuffle(name)
        new_name = "_" + "".join(name)
        address = sym.export_info.address
        bin.add_local_symbol(address, new_name)

    def process_imports(bin: lief.MachO.Binary, sym: lief.MachO.Symbol):
        original_name = sym.binding_info.symbol.name
        name = list(original_name)
        random.shuffle(name)
        new_name = "_" + "".join(name)
        address = sym.binding_info.address - bin.imagebase
        bin.add_local_symbol(address, new_name)

    def process_local_symbol(bin: lief.MachO.Binary, sym: lief.MachO.Symbol):
        original_name = sym.name
        name = list(sym.name)
        random.shuffle(name)
        sym.name = "_" + "".join(name)
        sym.type = 0xf
        sym.description = 0x300
        sym.numberof_sections = 1
        sym.value += 2

    def process_symbols(bin: lief.MachO.Binary):
        exports = []
        imports = []
        for sym in bin.symbols:
            if sym.has_export_info:
                #print(f"[EXPORT]: {sym.name}")
                exports.append(sym)
            elif sym.has_binding_info:
                #print(f"[IMPORT]: {sym.name}")
                imports.append(sym)
            else:
                # "classical" symbol
                process_local_symbol(bin, sym)

        for sym in exports:
            process_exports(bin, sym)

        for sym in imports:
            process_imports(bin, sym)

    def fake_objc(bin: lief.MachO.Binary):
        segment = lief.MachO.SegmentCommand("__DATA_LIEF")

        __objc_classlist = lief.MachO.Section(
            "__objc_classlist", [random.randint(0, 255) for _ in range(0x100)])
        __objc_imageinfo = lief.MachO.Section(
            "__objc_imageinfo", [random.randint(0, 255) for _ in range(0x100)])
        __objc_const = lief.MachO.Section(
            "__objc_const", [random.randint(0, 255) for _ in range(0x100)])
        __objc_classrefs = lief.MachO.Section(
            "__objc_classrefs", [random.randint(0, 255) for _ in range(0x100)])

        __objc_classlist = segment.add_section(__objc_classlist)
        __objc_imageinfo = segment.add_section(__objc_imageinfo)
        __objc_const = segment.add_section(__objc_const)
        __objc_classrefs = segment.add_section(__objc_classrefs)

        objc_section = [
            __objc_classlist, __objc_imageinfo, __objc_const, __objc_classrefs
        ]
        section: lief.MachO.Section
        for section in objc_section:
            section.type = lief.MachO.SECTION_TYPES.REGULAR
            section.flags = lief.MachO.SECTION_FLAGS.NO_DEAD_STRIP
            section.alignment = 0x3

        __data_lief: lief.MachO.SegmentCommand = bin.add(segment)
        __data_lief.init_protection = 3
        __data_lief.max_protection = 3

    for file in FILES:
        bin_path = pathlib.Path(get_sample(file))
        original = lief.parse(bin_path.as_posix())
        output = f"{tmp_path}/{bin_path.name}"

        SWAP_LIST = [
            ("__text", "__stubs"),
            ("__cstring", "__unwind_info"),
        ]
        for (lhs, rhs) in SWAP_LIST:
            swap(original, lhs, rhs)

        process_symbols(original)
        fake_objc(original)
        corrupt_function_starts(original)

        original.write(output)
        new = lief.parse(output)

        checked, err = lief.MachO.check_layout(new)
        assert checked, err
        should_run = (original.header.cpu_type == lief.MachO.CPU_TYPES.x86_64 and is_osx()) or \
                     (original.header.cpu_type == lief.MachO.CPU_TYPES.ARM64 and is_apple_m1())

        if should_run:
            assert run_program(bin_path.as_posix())
            stdout = run_program(output)

            print(stdout)
            assert re.search(r'All tests PASS', stdout) is not None
예제 #32
0
    CC_FLAGS = ['-fPIC', '-shared']
    extra_flags = [] if extra_flags is None else extra_flags
    cmd = [COMPILER] + extra_flags + CC_FLAGS + ['-o', output] + [ftmp.name]
    print("Compile 'libexample' with: {}".format(" ".join(cmd)))

    with Popen(cmd,
               universal_newlines=True,
               stdout=subprocess.PIPE,
               stderr=subprocess.STDOUT) as proc:
        output = proc.stdout.read()
        print(output)
        return output
    return None


@pytest.mark.skipif(not is_osx(), reason="requires OSX")
def test_ssh(tmp_path):
    bin_path = pathlib.Path(get_sample("MachO/MachO64_x86-64_binary_sshd.bin"))
    original = lief.parse(bin_path.as_posix())
    output = f"{tmp_path}/sshd_injected.bin"
    library_path = f"{tmp_path}/libexample.dylib"
    compile(library_path, extra_flags=["-arch", "x86_64"])

    original.add_library(library_path)

    original.remove_signature()
    original.write(output)
    new = lief.parse(output)

    checked, err = lief.MachO.check_layout(new)
    assert checked, err