“This is the 10th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Hi 👋

  • Wechat: RyukieW
  • Wechat official account: LabLawliet
  • 📦 Archive of technical articles
  • 🐙 making
My personal project Minesweeper Elic Endless Ladder Dream of books Privacy Access Record
type The game financial tool
AppStore Elic Umemi Privacy Access Record

More columns:

The independent development of Lawliet

Lawliet’s iOS garden party

Lawliet’s underlying iOS lab

Lawliet’s iOS Reverse lab

Lawliet’s brush book

Lawliet’s Flutter Lab

A, Dobby

GitHub:Dobby

Generate an Xcode project from the document. Get DobbyX framework. A cross-platform framework for the Hook static language.

cd Dobby && mkdir build_for_ios_arm64 && cd build_for_ios_arm64 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

Second, integrate the framework into the project

  • Get the aboveDobbyX.frameworkDrag into the project.
  • Build PhasesaddCopy fileTo addDobbyX.frameworkThat type offramework

Three, use,

3.1 int DobbyHook(void *address, void *replace_call, void **origin_call)

  • address
    • The address of the function that needs the hook
  • replace_call
    • New function address
  • origin_call
    • The address of the original function pointer

Since static languages have no symbols, hook directly through addresses

3.2 Try it out

Here’s a simple way to use it

#import "ViewController.h"
#import "DobbyX.framework/Headers/dobby.h"

@interface ViewController (a)

@end

@implementation ViewController

int test_sum(int a, int b) {
    return a + b;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor redColor];
    
    DobbyHook(test_sum, new_sum, (void *)&old_sum_p);
}

/// the original function pointer
static int (*old_sum_p)(int a, int b);
// Address of the new function
int new_sum(int a, int b) {
    int right = old_sum_p(a, b);
    NSLog(@"Hook! The correct result is: %d",right);
    return right + 1;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@Result: %d".test_sum(1.1));
}

@end

Copy the code

Console output:

[*] ================================ [*] Dobby [*] ================================ [*] dobby in debug log mode, disable with cmake flag "-DDOBBY_DEBUG=OFF" [*] [DobbyHook] Initialize at 0x104d31d90 [*] [trampoline] Generate trampoline buffer 0x104d31d90 -> 0x104d31e74 [*] [insn relocate] origin 0x104d31d90 - 12 [*] [insn relocate] relocated 0x10D2C0000-32 [*] [Intercept Routing] Active Patch 0x104D31d90 2021-05-19 08:314:00.081796 +0800 DobbyDemo [4207-1785806] Hook! Correct result: 2 2021-05-19 08:33:00.081972+0800 DobbyDemo[4207:1785806] result :3Copy the code

Iv. Process analysis

4.1 Assembly analysis of test_sum

A. A compilation of original functions

DobbyDemo`test_sum:
    0x104a71dc4 <+0>:  sub    sp, sp, #0x10             ; =0x10 
    0x104a71dc8 <+4>:  str    w0, [sp, #0xc]
    0x104a71dcc <+8>:  str    w1, [sp, #0x8]
->  0x104a71dd0 <+12>: ldr    w8, [sp, #0xc]
    0x104a71dd4 <+16>: ldr    w9, [sp, #0x8]
    0x104a71dd8 <+20>: add    w0, w8, w9
    0x104a71ddc <+24>: add    sp, sp, #0x10             ; =0x10 
    0x104a71de0 <+28>: ret    
Copy the code

B. Compilation after Hook

DobbyDemo`test_sum:
    0x104c7dd90 <+0>:  adrp   x17, 0
    0x104c7dd94 <+4>:  add    x17, x17, #0xe74          ; =0xe74 
    0x104c7dd98 <+8>:  br     x17
->  0x104c7dd9c <+12>: ldr    w8, [sp, #0xc]
    0x104c7dda0 <+16>: ldr    w9, [sp, #0x8]
    0x104c7dda4 <+20>: add    w0, w8, w9
    0x104c7dda8 <+24>: add    sp, sp, #0x10             ; =0x10 
    0x104c7ddac <+28>: ret    
Copy the code

C. analysis

We can see that the first three lines of instructions are different. Let’s start debugging by calling the method breakpoint

touchbegin

. 0x102b7df1c <+76>: bl 0x102b7e554 ; symbol stub for: objc_storeStrong 0x102b7df20 <+80>: mov w10, #0x1 0x102b7df24 <+84>: mov x0, x10 0x102b7df28 <+88>: mov x1, x10 -> 0x102b7df2c <+92>: bl 0x102b7dd90 ; test_sum at ViewController.m:17 ...Copy the code

test_sum

DobbyDemo`test_sum:
    0x102b7dd90 <+0>:  adrp   x17, 0
    0x102b7dd94 <+4>:  add    x17, x17, #0xe74          ; =0xe74 
->  0x102b7dd98 <+8>:  br     x17
    0x102b7dd9c <+12>: ldr    w8, [sp, #0xc]
    0x102b7dda0 <+16>: ldr    w9, [sp, #0x8]
    0x102b7dda4 <+20>: add    w0, w8, w9
    0x102b7dda8 <+24>: add    sp, sp, #0x10             ; =0x10 
    0x102b7ddac <+28>: ret    
Copy the code
(lldb) register read x17
     x17 = 0x0000000102b7de74  DobbyDemo`new_sum at ViewController.m:31
Copy the code

X17 is already programmed with new_sum! I’m in new_sum.

The following instruction is continued when the original function pointer is called

Principle of d.

  • This is actually a Text replacement (in memory)!
  • Text segment cannot be modified!
  • Original MachO unchanged!

5. Replace symbols with addresses

In practice, more often than not we can’t simply get the method to make the substitution as shown in the above Demo.

So we need to replace the symbol with the city address!

5.1 Locating function Addresses

->  0x1025f1f3c <+84>:  mov    x0, x10
    0x1025f1f40 <+88>:  mov    x1, x10
    0x1025f1f44 <+92>:  bl     0x1025f1dc4               ; test_sum at ViewController.m:17
Copy the code

A. Function address

By assembling the breakpoint we see that the actual function address is 0x1025f1dc4

B. Offset in Macho

We can locate its offset in MachO by the function address

ASLR

(lldb) image list [ 0] 6B1471FE-409A-37F0-93ED-86FDFDEE421E 0x00000001025ec000 /Users/RyukieW/Library/Developer/Xcode/DerivedData/DobbyDemo-fyyzoosecpnxmcakyfrtrxocpawl/Build/Products/Debug-iphoneos/ DobbyDemo.app/DobbyDemoCopy the code

offset 0x1025f1dc4 – 0x00000001025ec000 = 0x5DC4

Verify with MachOView that our calculation is ok.

5.2 Code to achieve the above reverse process

A. Obtain ASLR by code

uintptr_t aslr = _dyld_get_image_vmaddr_slide(0);
Copy the code

You may encounter the following questions

Implicit declaration of function '_dyld_get_image_vmaddr_slide' is invalid in C99

# import < Mach – o/dyld. H >

B. Get function Offset in MachO

Calculate the offset through breakpoint debugging and record it

static uintptr_t addrSum = 0x100005D40;
Copy the code

C. Hook by address

Complete HOOK code:

static uintptr_t addrSum = 0x100005D40;
uintptr_t aslr = _dyld_get_image_vmaddr_slide(0);
addrSum += aslr;
DobbyHook((void *)addrSum, new_sum, (void *)&old_sum_p);
Copy the code

D. the results

2021-05-21 11:30:34.318180+0800 DobbyDemo[5521:2140764] Hook! Correct result :2 2021-05-21 11:30:34.318525+0800 DobbyDemo[5521:2140764] result :3Copy the code

5.3 pay attention to the point

  • For my own project, every time I modify the code, the offset in MachO will change, so I need to pay attention to debugging
    • The content of the adjustment variable does not change
  • For IPA packets, the same IPA packet is not changed, but the IPA packets of different versions are different
    • So plugins can only be used for a particular version