akemin-dayo / simject

simject is a command-line tool and iOS dynamic library that allows developers to easily test their tweaks on the iOS Simulator.
BSD 2-Clause "Simplified" License
486 stars 55 forks source link

Segmentation Fault on "MSFindSymbol" #65

Closed WhyToFly closed 3 years ago

WhyToFly commented 3 years ago

I wanted to hook the MGCopyAnswer_internal function on the simulator to log its calls so I modified code from https://github.com/Tonyk7/MGSpoof to hook the function:

%ctor {
    // get image
    NSLog(@"SimHooker: Before get image.");
    MSImageRef libGestalt = MSGetImageByName("/usr/lib/libMobileGestalt.dylib");

    // Get "_MGCopyAnswer" symbol
    NSLog(@"SimHooker: Before get symbol.");
    void * Symbol=MSFindSymbol(libGestalt, "_MGCopyAnswer");
    /*
     * get address of MGCopyAnswer_internal by doing symbol + offset (should be 8 bytes)
     * note: hex implementation of MGCopyAnswer: 01 00 80 d2 01 00 00 14 (from iOS 9+)
     * so address of MGCopyAnswer + offset = MGCopyAnswer_internal. MGCopyAnswer_internal *always follows MGCopyAnswer (*from what I've checked)
     */
    NSLog(@"SimHooker: Before pointer.");
    const uint8_t *MGCopyAnswer_ptr = (const uint8_t *)MGCopyAnswer;
    NSLog(@"SimHooker: Before find branch.");
    addr_t branch = find_branch64(MGCopyAnswer_ptr, 0, 8);
    NSLog(@"SimHooker: Before follow branch.");
    addr_t branch_offset = follow_branch64(MGCopyAnswer_ptr, branch);
    NSLog(@"SimHooker: Before hook.");
    MSHookFunction(((void *)((const uint8_t *)Symbol + branch_offset)), (void *)new_MGCopyAnswer_internal, (void **)&orig_MGCopyAnswer_internal);
    NSLog(@"SimHooker: After hook.");
}

It works fine on my device, but on the simulator Springboard crashes on startup:

https://pastebin.com/SL0WAwAR

It seems to happen on the void * Symbol=MSFindSymbol(libGestalt, "_MGCopyAnswer"); line. To get it to compile, I had to copy /opt/simject/Frameworks/CydiaSubstrate.framework to /Users/christopherh/theos/lib/CydiaSubstrate.framework and add "SimHooker_EXTRA_FRAMEWORKS = CydiaSubstrate" to my Makefile.

Does MSFindSymbol not work on the simulator?

PoomSmart commented 3 years ago

I will first assume that MSFindSymbol couldn't find the symbol given the path. For iOS simulator environment, you need to be specific to the path argument. Simply using /usr/lib/libMobileGestalt.dylib means that dylib inside /usr/lib of your macOS. If you need to get to the root of your target iOS simulator, use UISystemRootDirectory().

Have this helper macro:

#if TARGET_OS_SIMULATOR

#import <UIKit/UIFunctions.h>

#define realPath(path) [UISystemRootDirectory() stringByAppendingPathComponent:path]
#define realPath2(path) [realPath(path) UTF8String]

#else

#define realPath(path) (path)
#define realPath2(path) ([path UTF8String])

#endif

Usage:

MSImageRef libGestalt = MSGetImageByName(realPath2("/usr/lib/libMobileGestalt.dylib"));
...
PoomSmart commented 3 years ago

As for your second issue, getting the tweak to compile. The CydiaSubstrate.framework provided by theos/lib doesn't contain x86_64 slice. It's only natural that you will need one from simject to be used instead.

WhyToFly commented 3 years ago

Thanks for the quick reply! I didn't even think about the different directories. I used your code but sadly I'm still having the same issue.

WhyToFly commented 3 years ago

I was able to get it to work using the following code:

extern "C" CFPropertyListRef MGCopyAnswer(CFStringRef);
%ctor {
    const uint8_t *MGCopyAnswer_ptr = (const uint8_t *)MGCopyAnswer;
    // from Ghidra: MGCopyAnswer_internal is 12 bytes from MGCopyAnswer
    addr_t branch_offset = 12;
    MSHookFunction(((void *)((const uint8_t *)MGCopyAnswer_ptr + branch_offset)), (void *)new_MGCopyAnswer_internal, (void **)&orig_MGCopyAnswer_internal);
}

It's probably not the most elegant solution but it does what it's supposed to in my case. I realized that the functions from my previous code (find_branch64 etc.) wouldn't have worked anyways since they were dependent on arm instructions.

PoomSmart commented 3 years ago

The offset could be different between ARM and x86 architecture. It makes sense it crashes with the wrong offset provided.