def test_write_fat_binary(self) -> None: # Given I add a load command to the arm64 slice of an armv7/arm64 FAT file parser = MachoParser(self.FAT_PATH) binary = parser.get_arm64_slice() assert binary original_dylibs = [binary.dylib_name_for_library_ordinal(i + 1) for i in range(len(binary.load_dylib_commands))] 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_fat" armv7_binary = parser.get_armv7_slice() assert armv7_binary # If I write the FAT to disk with both slices, then parse the on-disk version MachoBinary.write_fat([armv7_binary, modified_binary], output_binary_path) on_disk_fat_parser = MachoParser(output_binary_path) assert len(on_disk_fat_parser.slices) == 2 # Then I get a FAT with valid slices armv7 = on_disk_fat_parser.get_armv7_slice() assert armv7 is not None assert len(armv7.segments) == 4 arm64 = on_disk_fat_parser.get_arm64_slice() assert arm64 is not None assert len(arm64.segments) == 4 # And the arm64 segment contains the new load command new_dylibs = [arm64.dylib_name_for_library_ordinal(i + 1) for i in range(len(arm64.load_dylib_commands))] assert new_dylibs == original_dylibs + [new_dylib_name]
def test_protocol_32bit(self) -> None: parser = MachoParser(TestObjcRuntimeDataParser.PROTOCOL_32BIT_PATH) binary = parser.get_armv7_slice() assert binary dyld_info_parser = DyldInfoParser(binary) objc_parser = ObjcRuntimeDataParser(binary, dyld_info_parser) assert len(objc_parser.classes) == 66 test_cls = [ x for x in objc_parser.classes if x.name == "Pepsico_iPhoneAppDelegate" ][0] assert len(test_cls.protocols) == 2 proto_names = [x.name for x in test_cls.protocols] assert proto_names == [ "UIApplicationDelegate", "UITabBarControllerDelegate" ]
from strongarm.macho import CPU_TYPE, MachoAnalyzer, MachoParser def find_selector_implementations(binary): print(f"Analyzing Mach-O slice built for {CPU_TYPE(binary.cpu_type).name}") analyzer = MachoAnalyzer(binary) desired_selector = "URLSession:didReceiveChallenge:completionHandler:" implementations = analyzer.get_imps_for_sel(desired_selector) for imp_function in implementations: instruction_size = 4 instruction_count = int( (imp_function.end_address - imp_function.start_address) / instruction_size) print( f"Found implementation of @selector({desired_selector}) at [{hex(imp_function.start_address)}" f" - {hex(imp_function.end_address)}] ({instruction_count} instructions)" ) parser = MachoParser("./tests/bin/TestBinary4") binary_64 = parser.get_arm64_slice() binary_32 = parser.get_armv7_slice() for binary in [binary_64, binary_32]: # equivalent to parser.slices find_selector_implementations(binary)