preface

I. Overview of InlineHook

InlineHook (inlineHook) : the so-called inlineHook is to directly modify the header code of the target function, so that it can jump to our self-defined function to execute our code, so as to achieve the purpose of Hook. This Hook technique is commonly used in static language hooks.

An Inline Hook is a way to rob a running process by inserting a jump instruction into the running process. It can be roughly divided into three steps πŸ‘‡

  1. willThe functionThe first N bytes ofhandlingtoHook functionThe first N bytes of;
  2. thenThe functionThe first N bytes offillInstruction to jump to Hook function;
  3. inHookThe last few bytes of the functionfillJump back to the original function +N jump instruction;

InlineHook was also introduced in fishHook in the previous article 14-Hook Principle (I).

Dobby frames

Dobby is a full-platform InlineHook framework, which is available in the documentation.

2.1 Dobby framework is built

To learn Dobby, of course, is to frame πŸ‘‡

  1. First, Clone Project
# the depth is used to specify the depth of the cloning for 1 indicates that the cloned the latest commit. Git clone https://github.com/jmpews/Dobby.git -- the depth = 1Copy the code
  1. Due to theDobbyIt’s cross-platform, so it’s not one projectThe Xcode project, in order to usecmakeCompile this project intoXcodeEngineering. The related instructions are as follows: πŸ‘‡
// Enter the directory 'Dobby', Directory 'build_for_iOS_ARM64' CD Dobby && mkdir build_for_iOS_ARM64&& CD build_for_iOS_ARM64 // then 'cmake' compiles to generate the XCode project cmake .. -G Xcode \ -DCMAKE_TOOLCHAIN_FILE=cmake/ios.toolchain.cmake \ -DPLATFORM=OS64 -DARCHS="arm64" -dcmake_system_processor =arm64 \ -denable_bitcode =0 -DENABLE_ARC=0 -DENABLE_VISIBILITY=1 -DDEPLOYMENT_TARGET=9.3 \ -DDynamicBinaryInstrument=ON -DNearBranch=ON -DPlugin.SymbolResolver=ON -DPlugin.Darwin.HideLibrary=ON -DPlugin.Darwin.ObjectiveC=ONCopy the code

After command execution is complete, the project should look like πŸ‘‡

  1. compileThe Xcode projectπŸ‘‡

We generate the dynamic library dobbyx.framework πŸ‘‡

2.2 Project Demonstration

The use of Dobby

  1. Create a new projectDoddyDemo, importDobbyX.frameworkπŸ‘‡

Import Dobbyx. framework into the project. If you encounter Bitcode problems, there are two solutions πŸ‘‡

  • Close the current projectDoddyDemotheBitcode
  • compileDobbyX.frameworkWhen openBitcode

Bitcode Settings πŸ‘‡

  1. Open theViewController.mFile, write the following code πŸ‘‡
  • defineBy HOOKStatic function of
int sum(int a,int b){
   return a + b;
}
Copy the code
  • Defines a function pointer for savingSubstituted functiontheaddress
static int (*sum_p)(int a,int b);
Copy the code
  • defineThe new functionReplace the function that will HOOK with this functionReturn values and parametersMust beconsistent
Int mySum (int a, int b) {NSLog (@ "Sum: % d, 🍺 🍺 🍺 🍺 🍺", sum_p (a, b)); return a - b; }Copy the code
  1. callDobbyHookFunctionallyHookπŸ‘‡
int DobbyHook(void *address, void *replace_call, void **origin_call);
Copy the code

Dobby’s core function πŸ‘‡

Parameter names paraphrase
address The address of the function that needs the HOOK
replace_call New function address
origin_call Preserves the address of the pointer to the original function

HookπŸ‘‡ in viewDidLoad

- (void)viewDidLoad {
   [super viewDidLoad];

   DobbyHook((void *)sum, mySum, (void *)&sum_p);    
}
Copy the code
  1. intouchesBeganIn the callThe sum functionπŸ‘‡
-(void) Touch began :(NSSet< touch *> *) Touches withEvent:(UIEvent *) view {NSLog(@"Sum: %d", Sum (10, 20)); }Copy the code
  1. To run the project, click on the screen πŸ‘‡

The sum functionHOOK success! 🍺 🍺 🍺 🍺 🍺

Dobby Hook principle

Next, Dobby Hook works.

  1. In the case abovetouchesBeganMethod set a breakpoint πŸ‘‡

2. Open the assembly, run the project on the real machine, and click the screen to entertouchesBeganMethods πŸ‘‡

Step into, enter the sum function πŸ‘‡

We found that πŸ‘‡

  • Stretch stack spaceThe code is gone
  • The first three words ofThe code has been replaced
  1. Single stepDebug, execute downStep 3. throughbr x17Command to jump tomySumFunction πŸ‘‡

If you look at the first line of code, it’sStretch stack spaceThe code. thenbr x17And will come back tosumFunction πŸ‘‡

And then we execute the logic of sum, and then at the endRestore stack balance.

  1. whenThe sum functionperformRet instructionTo return toMySum functionTo execute the following code πŸ‘‡

To sum up πŸ‘‡

  • Static functionsHOOK, instead of adding code to the original function, willThree sentences of code stretching stack spacethereplace
  • When callingThe original functionTo beStretch stack balance. Then, inThe original functionIn the code of,Restore stack balance

Case modification

Let’s change the example πŸ‘‰ mySum, instead of calling the original πŸ‘‡ function

Int mySum (int a, int b) {/ / NSLog (@ "Sum: % d, 🍺 🍺 🍺 🍺 🍺", sum_p (a, b)); return a - b; }Copy the code

Run the project on a real machine and view a compilation of the sum function πŸ‘‡

In the figure above, the code does not change.

Next, enter the mySum function πŸ‘‡

Jump to the code at the specified addressblr x18No more.

When mySum executes ret, it returns directly to touchesBegan πŸ‘‡

At this timesumThe original code of the function isWill not be enforced. This situation πŸ‘‡

The stack space is not stretched, the original code for sum is not executed, and thus the stack balance is not restored.

3.1 Address of Hook Function

In reverse development, a normal App will strip the symbol table, so we can’t get the symbol name, so there is no Hook method name, smart Hook address. However, the ASLR offset address is different each time the application is started, so you cannot Hook the address directly. The right way πŸ‘‡

Find the offset address of the function in MachO, plus the 0x100000000 of PAGEZERO, plus the ASLR offset address of this startup

Case presentation

Continuing with the example above, find the address of the sum function πŸ‘‡

The function implementation address is πŸ‘‰0x104221bcc. Then use theimage listTo find the base address of the main program πŸ‘‡

The base address is πŸ‘‰ 0x10421C000. So the offset address of the function in MachO πŸ‘‰ function implementation address – main program base address πŸ‘‡

0x104221bcc - 0x10421c000 = 0x5BCC
Copy the code

The offset address is πŸ‘‰ 0x5BCC. In the MachO file, look at the offset address πŸ‘‡

The figure above is clearly the assembly code for the sum function.

rightFunction addressesTo Hook

  1. Open theViewController.mFile, write the following code πŸ‘‡
#import "ViewController.h" #import <DobbyX/dobby.h> #import <mach-o/dyld.h> @implementation ViewController int sum(int a,int b){ return a + b; } static uintptr_t sumP = 0x5BCC + 0x100000000; - (void)viewDidLoad { [super viewDidLoad]; sumP += _dyld_get_image_vmaddr_slide(0); DobbyHook((void *)sumP, mySum, (void *)&sum_p); } static int (*sum_p)(int a,int b); Int mySum (int a, int b) {NSLog (@ "Sum: % d, 🍺 🍺 🍺 🍺 🍺", sum_p (a, b)); return a - b; } -(void) Touch began :(NSSet< touch *> *)touches :(UIEvent *) view {NSLog(@"Sum: %d", Sum (10, 20)); } @endCopy the code

⚠️ Note: The offset address of the sum function in Mach -o is changed because of the code modification and recompilation.

  1. Recompile and look at mach-oThe sum functiontheoffsetπŸ‘‡

The offset address is πŸ‘‰ 0x5B34, then change the code πŸ‘‡

static uintptr_t sumP = 0x5B34 + 0x100000000;
Copy the code
  1. To run the project, click on the screen πŸ‘‡

Sure enough, Hook success! 🍺 🍺 🍺 🍺 🍺 🍺

3.2 Dobby injection

Finally, let’s look at how Dobby can inject code.

  1. createFuncDemoProject, openViewController.mFile, write the following code πŸ‘‡
#import "ViewController.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } -(void)touch began :(NSSet< touch *> *)touches :(UIEvent *) view {NSLog(@"Sum: %d", Sum (10,15)); } int sum(int a,int b){ return a + b; } @endCopy the code
  1. Real machine run the project, useFunction implementation address - main program base addressTo calculate theThe sum functionIn the MachOoffsetπŸ‘‡

Calculate the offset address πŸ‘‰0x5D68

⚠️ Note: since symbols will be stripped in real scenarios, set πŸ‘‡ in build Setting

Stripping symbolsAfter the real machine runs, throughsuspendedπŸ‘‡

Then enter image list in LLDB to obtain the base address πŸ‘‡

To calculate theThe sum functionThe address of the πŸ‘‰0x1000dc000 + 0x5D68 = 0x1000E1D68.

  1. To address0x1000E1D68Set breakpoints πŸ‘‡

The breakpoint succeededThe sum functionThe implementation address of the.

rightFuncDemo.appCode injection

  1. Set upHookDemoThe project,Yololib, AppSign.sh, Dobbyx.frameworkTo the project root directory πŸ‘‡

Where, scriptappSign.shπŸ‘‡

${SRCROOT}/Temp =" TEMP_PATH="${SRCROOT}/Temp" ASSETS_PATH="${SRCROOT}/APP" # App_path =$(set -- "${ASSETS_PATH}/"*.app; Echo "$1") # # target of ipa package path TARGET_IPA_PATH = "${ASSETS_PATH} / *. Ipa" # TEMP_APP_PATH = $(set -- "${ASSETS_PATH} /" *. The app; #rm -rf "${SRCROOT}/Temp" #mkdir -p "${SRCROOT}/Temp" # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # 1. #unzip -oqq "$TARGET_IPA_PATH" -d "$TEMP_PATH" #TEMP_APP_PATH=$(set -- "${ASSETS_PATH}/"*.app; Echo "$1") #TEMP_APP_PATH=$(echo "${ASSETS_PATH}/"*.app) $TEMP_APP_PATH =$(echo "${ASSETS_PATH}/"*.app "Tempapp path: $TEMP_APP_PATH / #" echo "path is: $TEMP_APP_PATH" # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # 2. # TARGET_NAME Target name of the app package generated by # BUILT_PRODUCTS_DIR TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$target_name. app" echo "app path :$TARGET_APP_PATH" rm -rf $TARGET_APP_PATH mkdir -p $TARGET_APP_PATH cp -rf $TEMP_APP_PATH/ $TARGET_APP_PATH #---------------------------------------- # 3. Rm -rf "$TARGET_APP_PATH/PlugIns" rm -rf "$TARGET_APP_PATH/Watch" # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # 4. Update info. Plist file CFBundleIdentifier # Set: /usr/libexec/plistbuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist" #---------------------------------------- # 5. To execute permissions on MachO file # to MachO file path APP_BINARY = ` plutil - convert xml1 - o - $TARGET_APP_PATH/Info. The plist | grep - A1 Exec | tail - n1 | the cut - f2 - d \ > | the cut - f1 - d \ < ` # on executable permissions chmod + x "$TARGET_APP_PATH / $APP_BINARY" # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # 6. $frameworks_path ="$frameworks_path/FrameWorks "if [-d "$TARGET_APP_FRAMEWORKS_PATH"]; Then for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"* do # $usr/bin/coDesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK" done fi # infuse./yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/Hook.framework/Hook"Copy the code
  1. In the project root directory, createApp directoryThat will beFuncDemo.appCopy to App directory πŸ‘‡

In 3.HookDemoAdd target to main project, which is the injected dynamic library, namedHOOKIn theHOOKDynamic library, createInjectclass

In 4.HookDemoMain project in towDobbyX.frameworkTo check theHookDemoπŸ‘‡

  1. inHookDemo, found inEmbed FramewordsTo addDobbyX.frameworkπŸ‘‡

Then, inHook.frameworkThe Target configuration πŸ‘‡

  1. Open theInject.mFile, write the following code πŸ‘‡
#import "Inject.h" #import <DobbyX/dobby.h> #import <mach-o/dyld.h> @implementation Inject static uintptr_t sumP = 0x5D68 + 0x100000000; +(void)load{ sumP += _dyld_get_image_vmaddr_slide(0); DobbyHook((void *)sumP, mySum, (void *)&sum_p); } static int (*sum_p)(int a,int b); Int mySum (int a, int b) {NSLog (@ "Sum: % d, 🍺 🍺 🍺 🍺 🍺", sum_p (a, b)); return a - b; } @endCopy the code
  1. To run the project, click on the screen πŸ‘‡
FuncDemo[11452:2162229] Sum: 25, 🍺🍺🍺🍺 function FuncDemo[11452:2162229] Sum: -5Copy the code

conclusion

  • DobbyPrinciple πŸ‘‰ runtime to the target function of assembly code replacement, modify is in memoryCode snippet for MachO
  • DobbyWhen replacing assembly code, the call to the original function affectsStack stretching and balancing
  • In a real Hook scenario, weCould not get symbol nameOnly addresses can be hooked
  • Hook address is requiredPAGEZEROandASLR