Beispiel #1
0
    def test_no_space_for_new_load_command(self) -> None:
        # Given a binary with 0x5630 bytes of free space at the end of the Mach-O header
        binary = MachoParser(self.THIN_PATH).get_arm64_slice()
        assert binary

        dylib_path = "@rpath/load_cmd_with_32_chrcters"
        # If I have a dylib load command which will take up `0x20 + len(dylib_path) = 0x38` bytes
        # Then I should be able to add this load command exactly 344 times before the binary runs out of space
        for _ in range(344):
            binary = binary.insert_load_dylib_cmd(dylib_path)
        with pytest.raises(NoEmptySpaceForLoadCommandError):
            binary.insert_load_dylib_cmd(dylib_path)
Beispiel #2
0
    def test_add_load_command(self) -> None:
        # Given a binary with some known load-commands
        binary = MachoParser(self.CLASSLIST_DATA_CONST).get_arm64_slice()
        assert binary
        original_dylibs = [
            "/System/Library/Frameworks/Foundation.framework/Foundation",
            "/usr/lib/libobjc.A.dylib",
            "/usr/lib/libSystem.B.dylib",
            "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation",
            "/System/Library/Frameworks/Security.framework/Security",
            "/System/Library/Frameworks/UIKit.framework/UIKit",
        ]
        found_dylibs = [binary.dylib_name_for_library_ordinal(i + 1) for i in range(len(binary.load_dylib_commands))]
        assert found_dylibs == original_dylibs

        # If I create a new binary with an inserted load command
        modified_binary = binary.insert_load_dylib_cmd("@rpath/Frameworks/Interject.framework/Interject")
        modified_dylibs = [
            "/System/Library/Frameworks/Foundation.framework/Foundation",
            "/usr/lib/libobjc.A.dylib",
            "/usr/lib/libSystem.B.dylib",
            "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation",
            "/System/Library/Frameworks/Security.framework/Security",
            "/System/Library/Frameworks/UIKit.framework/UIKit",
            "@rpath/Frameworks/Interject.framework/Interject",
        ]
        found_dylibs = [
            modified_binary.dylib_name_for_library_ordinal(i + 1)
            for i in range(len(modified_binary.load_dylib_commands))
        ]
        assert found_dylibs == modified_dylibs
Beispiel #3
0
    def test_write_thin_binary(self) -> None:
        binary = MachoParser(self.THIN_PATH).get_arm64_slice()
        assert binary
        original_dylibs = [binary.dylib_name_for_library_ordinal(i + 1) for i in range(len(binary.load_dylib_commands))]
        # Given I add a load command to a binary
        new_dylib_name = "@rpath/Frameworks/Interject.framework/Interject"
        modified_binary = binary.insert_load_dylib_cmd(new_dylib_name)

        with TemporaryDirectory() as tempdir:
            output_binary_path = pathlib.Path(tempdir) / "modified_binary"
            # If I write the binary to disk, then parse the on-disk version
            modified_binary.write_binary(output_binary_path)
            on_disk_binary = MachoParser(output_binary_path).get_arm64_slice()
            assert on_disk_binary

            # Then the new on-disk binary contains the modification
            new_dylibs = [
                on_disk_binary.dylib_name_for_library_ordinal(i + 1)
                for i in range(len(on_disk_binary.load_dylib_commands))
            ]
            assert new_dylibs == original_dylibs + [new_dylib_name]