iOS12内存patch remap bug分析

By xia0

#iOS12内存patch remap bug分析

之前在做LLDB中的内存patch的时候提到在iOS12(包括iOS11)上面remap会出现bug的问题,一直相当困扰。其他hook框架都能在最新越狱上面正常patch,为什么我写的就不行?所以这篇文章准备一探究竟,但是目前我也还么搞清楚原因。(2019/09/04终于搞清楚了原因)不过这里会先分析最新系统上面两种hook框架对于inlinehook的原理及其相关细节。先看下他们的hook框架是如何实现内存patch和hook的。

#iOS12 MSHookFunction分析(CoolStar越狱工具)

环境:iPhoneXS A12 iOS12 jailbreak by Chimera

在iOS12越狱上面CydiaSubstrate指向的是libsubstrate.dylib

/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate -> ../../../usr/lib/libsubstrate.dylib

我们常用的MSHookFunction函数的实现就是在libsubstrate.dylib这里面,不过在这里仅仅是SubHookFunction的封装。而SubHookFunction的实现却是在/usr/lib/libsubstitute.0.dylib这里

/usr/lib/libsubstitute.0.dylib是一个软连接指向libsubstitute.dylib。这里的libsubstitute.dylib就是coolstar维护的版本。下面分析libsubstitute.dylib的inlinehook实现细节。

下面是我写的一个tweak插件代码(没错就是破解Filza的,不过只是部分代码),hook了_ZTL7624417887函数。

static BOOL (*original_ZTL7624417887)(int a1, int a2, int a3); 

BOOL new_ZTL7624417887(int a1, int a2, int a3){
    NSLog(@"====xxxx===hook ZTL7624417887--->%d", 0);
    return 0;
}

%ctor{    
    MSImageRef  image =  MSGetImageByName("/Applications/Filza.app/Filza");
    NSLog(@"===xxx===image:%p", image);
    void* ZTL7624417887 = (void*)MSFindSymbol(image, "_ZTL7624417887");
    NSLog(@"===xxx===ZTL7624417887:%p", ZTL7624417887);
    MSHookFunction((void*)ZTL7624417887, (void*)new_ZTL7624417887, (void**)&original_ZTL7624417887);
}

调试分析

MSHookFunction下断点,发现断在了我们预想的位置。

CydiaSubstrate`MSHookFunction:
->  0x10550fca0 <+0>:  cbz    x0, 0x10550fca8           ; <+8>
    0x10550fca4 <+4>:  b      0x10550fe80               ; symbol stub for: SubHookFunction
    0x10550fca8 <+8>:  ret
(lldb) re re 
General Purpose Registers:
        x0 = 0x000000010489a068  Filza`ZTL7624417887
        x1 = 0x00000001055bbbec  xkfilza.dylib`new_ZTL7624417887(int, int, int) at Tweak.xm:19
        x2 = 0x00000001055bc148  xkfilza.dylib`original_ZTL7624417887

* frame #0: 0x000000010550fca0 CydiaSubstrate`MSHookFunction
    frame #1: 0x00000001055bbcd0 xkfilza.dylib`_logosLocalCtor_9eb4d9ed(argc=1, argv=0x000000016b657b50, envp=0x000000016b657b60) at Tweak.xm:29
    frame #2: 0x00000001055df56c dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 424
    frame #3: 0x00000001055df7ac dyld`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 40

X0就是hook的函数地址,X1为替换的函数地址,X2为保存的原函数地址。

先看一下这三个地址的数据,如下所见,此时ZTL7624417887还没有hook,所以前几个指令没有变化。

// ZTL7624417887 函数指令
(lldb) x/5i 0x000000010489a068
    0x10489a068: 0xd2800008   mov    x8, #0x0
    0x10489a06c: 0xf0003489   adrp   x9, 1683
    0x10489a070: 0x911a4129   add    x9, x9, #0x690            ; =0x690 
    0x10489a074: 0xb868792a   ldr    w10, [x9, x8, lsl #2]
    0x10489a078: 0x6b00015f   cmp    w10, w0

// new_ZTL7624417887 函数指令
(lldb) x/5i 0x00000001055bbbec
    0x1055bbbec: 0xd503237f   pacibsp 
    0x1055bbbf0: 0xd100c3ff   sub    sp, sp, #0x30             ; =0x30 
    0x1055bbbf4: 0xa9027bfd   stp    x29, x30, [sp, #0x20]
    0x1055bbbf8: 0x910083fd   add    x29, sp, #0x20            ; =0x20 
    0x1055bbbfc: 0xb81fc3a0   stur   w0, [x29, #-0x4]

// original_ZTL7624417887 是一个函数指针
(lldb) x/5g 0x00000001055bc148
0x1055bc148: 0x0000000000000000 0x0000000000000000
0x1055bc158: 0x0000000000000000 0x0000000000000000
0x1055bc168: 0x0000000000000000

这里是我们单步执行两次,使其执行hook函数。这次再观察一下这三个地址的数据

// ZTL7624417887 函数指令
(lldb) x/5i 0x000000010489a068
    0x10489a068: 0xb0006911   adrp   x17, 3361
    0x10489a06c: 0x912fb231   add    x17, x17, #0xbec          ; =0xbec 
    0x10489a070: 0xd61f0220   br     x17
    0x10489a074: 0xb868792a   ldr    w10, [x9, x8, lsl #2]
    0x10489a078: 0x6b00015f   cmp    w10, w0

// new_ZTL7624417887 函数指令
(lldb) x/5i 0x00000001055bbbec
    0x1055bbbec: 0xd503237f   pacibsp 
    0x1055bbbf0: 0xd100c3ff   sub    sp, sp, #0x30             ; =0x30 
    0x1055bbbf4: 0xa9027bfd   stp    x29, x30, [sp, #0x20]
    0x1055bbbf8: 0x910083fd   add    x29, sp, #0x20            ; =0x20 
    0x1055bbbfc: 0xb81fc3a0   stur   w0, [x29, #-0x4]

// original_ZTL7624417887 是一个函数指针
(lldb) x/5g 0x00000001055bc148
0x1055bc148: 0x0000000106e38000 0x0000000000000000
0x1055bc158: 0x0000000000000000 0x0000000000000000
0x1055bc168: 0x0000000000000000

这里发现原函数前三个字节和original_ZTL7624417887这个函数指令数据都发生了变化。

0x10489a068: 0xb0006911   adrp   x17, 3361
0x10489a06c: 0x912fb231   add    x17, x17, #0xbec          ; =0xbec 
0x10489a070: 0xd61f0220   br     x17

这三条指令就是将原始执行流跳转到其他地址(这里也可以发现hook的函数至少大于3条指令,不然会覆盖其他函数)。这里简单计算就可以算出X17目标地址

(lldb) p/x (0x10489a068 & ~(0x1000-0x1))+ (3361<<12) + 0xbec
(long) $3 = 0x00000001055bbbec

所以会跳转到0x00000001055bbbec这个地址,等等!这个地址不就是new_ZTL7624417887我们hook代码的函数地址吗?所以函数hook就是通过修改前三条指令跳转到我们定义的函数来实现hook的。

这里还有个问题在于,如果我们在hook代码里面需要执行原函数,那么original_ZTL7624417887处保存的又是什么函数指针?所以这里跟一下0x0000000106e38000这个地址。

(lldb) x/12i 0x0000000106e38000
    0x106e38000: 0xd2800008   mov    x8, #0x0
    0x106e38004: 0xd29a0009   mov    x9, #0xd000
    0x106e38008: 0xf2a09e49   movk   x9, #0x4f2, lsl #16
    0x106e3800c: 0xf2c00029   movk   x9, #0x1, lsl #32
    0x106e38010: 0x911a4129   add    x9, x9, #0x690            ; =0x690 
    0x106e38014: 0xd0fed311   adrp   x17, -9630
    0x106e38018: 0x9101d231   add    x17, x17, #0x74           ; =0x74 
    0x106e3801c: 0xd61f0220   br     x17

这里可以看出也是一个跳转,可以计算出X17跳转后的地址

(lldb) p/x (0x106e38014 & ~(0x1000-0x1)) - (9630<<12) + 0x74
(long) $4 = 0x000000010489a074

再等等!这个地址不就是ZTL7624417887函数的第四条指令的地址吗,跳转到这里正好调用了原函数,但是有个问题在于,原函数的前三条指令去哪了?仔细观察上面的指令和原函数的前三条指令

//原函数前三条指令
0x10489a068: 0xd2800008   mov    x8, #0x0
0x10489a06c: 0xf0003489   adrp   x9, 1683
0x10489a070: 0x911a4129   add    x9, x9, #0x690            ; =0x690

// original_ZTL7624417887函数指针的指令
0x106e38000: 0xd2800008   mov    x8, #0x0
0x106e38004: 0xd29a0009   mov    x9, #0xd000
0x106e38008: 0xf2a09e49   movk   x9, #0x4f2, lsl #16
0x106e3800c: 0xf2c00029   movk   x9, #0x1, lsl #32
0x106e38010: 0x911a4129   add    x9, x9, #0x690            ; =0x690

稍加思索就知道,虽然指令不一样,但是结果却是一样的。为什么不直接写入原三条指令呢?这里涉及到adrp这个指令的相对寻址问题。由于adrp会根据当前pc值来计算,这样直接复制的话pc值已经变化,所以这里不得不重新计算X9的值。到这里,MSHookFunction的hook过程我们已经完全清楚了。

#iOS12 MSHookFunction分析(unc0ver越狱工具)

环境:iPhone6+ iOS12 jailbreak by unc0ver

由于saurik不给CoolStar的越狱工具提供substrate和cydia的支持,导致现在越狱工具出现了两种hook框架。以Coolstar团队基于开源代码substitute和pwn20wnd团队的substrate两种hook框架。上面分析了substitute的hook原理。下面分析substrate的hook相关细节。这里多说两句,关于整个事件,可以访问CoolStar的博客https://coolstarorg.tumblr.com/他介绍了整个事件以及自己开发移植substitute的完整过程。我个人来说,还是十分崇拜CoolStar那份创新和坚持。自己动手完成了最新越狱的substitute移植,tweak注入,以及Sileo的开发。在这中间的过程,正如他在博客里面提到的那样,十分曲折,令人佩服。

在unc0ver中有如下dylib和hook相关

/usr/lib/substrate/SubstrateInserter.dylib
/usr/lib/libsubstrate.dylib
/Library/MobileSubstrate/MobileSubstrate.dylib
/Library/Caches/cy-8lteBy.dylib

作为对比,这里同样以上面的tweak代码为例,hook了_ZTL7624417887函数。

static BOOL (*original_ZTL7624417887)(int a1, int a2, int a3); 

BOOL new_ZTL7624417887(int a1, int a2, int a3){
    NSLog(@"====xxxx===hook ZTL7624417887--->%d", 0);
    return 0;
}

%ctor{    
    MSImageRef  image =  MSGetImageByName("/Applications/Filza.app/Filza");
    NSLog(@"===xxx===image:%p", image);
    void* ZTL7624417887 = (void*)MSFindSymbol(image, "_ZTL7624417887");
    NSLog(@"===xxx===ZTL7624417887:%p", ZTL7624417887);
    MSHookFunction((void*)ZTL7624417887, (void*)new_ZTL7624417887, (void**)&original_ZTL7624417887);
}

调试分析

MSHookFunction下断点,发现断在了如下位置

// 调用栈
*libsubstrate.dylib`MSHookFunction
 SubstrateInserter.dylib`___lldb_unnamed_symbol6$$SubstrateInserter.dylib + 76
 cy-8lteBy.dylib`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 412
 cy-8lteBy.dylib`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 36

//下面可以看出来是hook了posix_spawn这个函数
x0 = 0x00000001be287310  libsystem_kernel.dylib`posix_spawn
x1 = 0x000000010194a4c0  SubstrateInserter.dylib`___lldb_unnamed_symbol2
x2 = 0x0000000101950258

这里可以暂时不用管,同样下面的hook函数都忽略先。

//================================ execve ========================================
//调用栈
*libsubstrate.dylib`MSHookFunction
 SubstrateInserter.dylib`___lldb_unnamed_symbol6$$SubstrateInserter.dylib + 100
 cy-8lteBy.dylib`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 412
 cy-8lteBy.dylib`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 36

//下面可以看出来是hook了execve这个函数
x0 = 0x00000001be290034  libsystem_kernel.dylib`execve
x1 = 0x000000010194a4fc  SubstrateInserter.dylib`___lldb_unnamed_symbol3
x2 = 0x0000000101950260  

//================================ __vfork ========================================
//调用栈
*libsubstrate.dylib`MSHookFunction
 cy-8lteBy.dylib`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 412
 cy-8lteBy.dylib`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 36

//下面可以看出来是hook了__vfork这个函数
x0 = 0x00000001be28fa80  libsystem_kernel.dylib`__vfork
x1 = 0x000000010194a5d4  SubstrateInserter.dylib`___lldb_unnamed_symbol4
x2 = 0x0000000101950268

通过上面可以看出,substrate会hook一些多进程启动相关的函数。这里我们都暂时不用分析,进行执行就到了我们自己写的hook点。

x0 = 0x0000000100f52068  Filza`ZTL7624417887
x1 = 0x0000000104a3fba4  xkfilza.dylib`new_ZTL7624417887(int, int, int) at Tweak.xm:19
x2 = 0x0000000104a40148  xkfilza.dylib`original_ZTL7624417887

libsubstrate.dylib`MSHookFunction:
->  0x101d244dc <+0>:   stp    x29, x30, [sp, #-0x10]!
    0x101d244e0 <+4>:   mov    x29, sp
    0x101d244e4 <+8>:   stp    x20, x19, [sp, #-0x10]!
    0x101d244e8 <+12>:  stp    x22, x21, [sp, #-0x10]!
    0x101d244ec <+16>:  sub    sp, sp, #0x20             ; =0x20 
    0x101d244f0 <+20>:  mov    x21, x2
    0x101d244f4 <+24>:  mov    x19, x1
    0x101d244f8 <+28>:  mov    x20, x0
    0x101d244fc <+32>:  cbz    x20, 0x101d24514          ; <+56>
    0x101d24500 <+36>:  mov    x1, #0x0
    0x101d24504 <+40>:  mov    x0, x19
    0x101d24508 <+44>:  bl     0x101d29150               ; symbol223$$libsubstrate.dylib
    0x101d2450c <+48>:  cmp    x0, #0x0                  ; =0x0 
    0x101d24510 <+52>:  csel   x19, x0, x19, ne
    0x101d24514 <+56>:  adrp   x8, 265
    0x101d24518 <+60>:  add    x8, x8, #0x498            ; =0x498 
    0x101d2451c <+64>:  ldrb   w8, [x8]
    0x101d24520 <+68>:  cbz    w8, 0x101d24538           ; <+92>
    0x101d24524 <+72>:  str    x19, [sp]
    0x101d24528 <+76>:  adr    x1, #0xc8d10              ; "  <=  %p"
    0x101d2452c <+80>:  nop    
    0x101d24530 <+84>:  orr    w0, wzr, #0x2
    0x101d24534 <+88>:  bl     0x101d10ad4               ; symbol80$$libsubstrate.dylib
    0x101d24538 <+92>:  adrp   x8, 240
    0x101d2453c <+96>:  add    x8, x8, #0xa80            ; =0xa80 
    0x101d24540 <+100>: add    x8, x8, #0x10             ; =0x10 
    0x101d24544 <+104>: stp    x21, x8, [sp, #0x8]
    0x101d24548 <+108>: cmp    x21, #0x0                 ; =0x0 
    0x101d2454c <+112>: add    x8, sp, #0x8              ; =0x8 
    0x101d24550 <+116>: csel   x8, xzr, x8, eq
    0x101d24554 <+120>: str    x8, [sp, #0x18]
    0x101d24558 <+124>: mov    x0, #0x0
    0x101d2455c <+128>: add    x4, sp, #0x10             ; =0x10 
    0x101d24560 <+132>: mov    x1, x20
    0x101d24564 <+136>: mov    x2, x20
    0x101d24568 <+140>: mov    x3, x19
    0x101d2456c <+144>: bl     0x101d23f3c                           ;<----------------hook实现函数
    0x101d24570 <+148>: sub    sp, x29, #0x20            ; =0x20 
    0x101d24574 <+152>: ldp    x22, x21, [sp], #0x10
    0x101d24578 <+156>: ldp    x20, x19, [sp], #0x10
    0x101d2457c <+160>: ldp    x29, x30, [sp], #0x10
    0x101d24580 <+164>: ret

从这里就可以看出和substitute的差别还是挺大的。先看下hook前三个地址的数据情况

// ZTL7624417887 函数指令
(lldb) x/5i 0x0000000100f52068
    0x100f52068: 0xd2800008   mov    x8, #0x0
    0x100f5206c: 0xf0003489   adrp   x9, 1683
    0x100f52070: 0x911a4129   add    x9, x9, #0x690            ; =0x690 
    0x100f52074: 0xb868792a   ldr    w10, [x9, x8, lsl #2]
    0x100f52078: 0x6b00015f   cmp    w10, w0

// new_ZTL7624417887 函数指令
(lldb) x/5i 0x0000000104a3fba4
    0x104a3fba4: 0xd100c3ff   sub    sp, sp, #0x30             ; =0x30 
    0x104a3fba8: 0xa9027bfd   stp    x29, x30, [sp, #0x20]
    0x104a3fbac: 0x910083fd   add    x29, sp, #0x20            ; =0x20 
    0x104a3fbb0: 0xb81fc3a0   stur   w0, [x29, #-0x4]
    0x104a3fbb4: 0xb81f83a1   stur   w1, [x29, #-0x8]

// original_ZTL7624417887 是一个函数指针
(lldb) x/5g 0x0000000104a40148
0x104a40148: 0x0000000000000000 0x0000000000000000
0x104a40158: 0x0000000000000000 0x0000000000000000
0x104a40168: 0x0000000000000000

下面我们执行完这个函数,再观察hook以后三个地址的数据情况

// ZTL7624417887 函数指令
(lldb) x/10i 0x0000000100f52068
    0x100f52068: 0x58000050   ldr    x16, #0x8                 ; <+8>
    0x100f5206c: 0xd61f0200   br     x16
    0x100f52070: 0x7ff00040   .long  0x7ff00040                ; unknown opcode
    0x100f52074: 0x00000001   .long  0x00000001                ; unknown opcode
    0x100f52078: 0x6b00015f   cmp    w10, w0
    0x100f5207c: 0x540000c0   b.eq   0x100f52094               ; <+44>
    0x100f52080: 0x91000508   add    x8, x8, #0x1              ; =0x1 
    0x100f52084: 0xf100311f   cmp    x8, #0xc                  ; =0xc 
    0x100f52088: 0x54ffff69   b.ls   0x100f52074               ; <+12>
    0x100f5208c: 0x52800008   mov    w8, #0x0

// new_ZTL7624417887 函数指令
(lldb)  x/5i 0x0000000104a3fba4
    0x104a3fba4: 0xd100c3ff   sub    sp, sp, #0x30             ; =0x30 
    0x104a3fba8: 0xa9027bfd   stp    x29, x30, [sp, #0x20]
    0x104a3fbac: 0x910083fd   add    x29, sp, #0x20            ; =0x20 
    0x104a3fbb0: 0xb81fc3a0   stur   w0, [x29, #-0x4]
    0x104a3fbb4: 0xb81f83a1   stur   w1, [x29, #-0x8]

// original_ZTL7624417887 是一个函数指针
(lldb) x/5g 0x0000000104a40148
0x104a40148: 0x0000000104a53fe8 0x0000000000000000
0x104a40158: 0x0000000000000000 0x0000000000000000
0x104a40168: 0x0000000000000000

这里可以发现,和substitute一样,原函数ZTL7624417887和original_ZTL7624417887函数都发生了变化,但是ZTL7624417887的改动却不一样。substrate这里首先占用了四条指令大小(这里也可以知道用substate进行hook的时候函数至少满足4个字节),其中后两条指令其实是存得一个地址占用8个字节。

(lldb) x/g 0x100f52070
0x100f52070: 0x000000017ff00040

按地址大小解析出来,目标跳转的地址为0x000000017ff00040现在去看下这个地址里面是什么

(lldb) x/12i 0x000000017ff00040
    0x17ff00040: 0x10020010   adr    x16, #0x4000
    0x17ff00044: 0xa9404610   ldp    x16, x17, [x16]
    0x17ff00048: 0xd61f0220   br     x17
    0x17ff0004c: 0xd503201f   nop    
    0x17ff00050: 0x10020010   adr    x16, #0x4000
    0x17ff00054: 0xa9404610   ldp    x16, x17, [x16]
    0x17ff00058: 0xd61f0220   br     x17
    0x17ff0005c: 0xd503201f   nop    
    0x17ff00060: 0x10020010   adr    x16, #0x4000
    0x17ff00064: 0xa9404610   ldp    x16, x17, [x16]
    0x17ff00068: 0xd61f0220   br     x17
    0x17ff0006c: 0xd503201f   nop

这里可以发现又会进行一些跳转

(lldb) p/x 0x17ff00040+0x4000
(long) $2 = 0x000000017ff04040

(lldb) x/5g 0x000000017ff04040
0x17ff04040: 0x0000000000000000 0x0000000104a3fba4

这里计算出来X16=0 X17=0x0000000104a3fba4所以这里会跳转到0x0000000104a3fba4这个地址。等下!这个地址不就是new_ZTL7624417887的地址吗,这样进过两次跳转就跳到了我们写的hook函数了,完成了对原函数的hook。下面再分析如何又执行原函数,分析original_ZTL7624417887函数数据

(lldb) x/12i 0x0000000104a53fe8
    0x104a53fe8: 0xd2800008   mov    x8, #0x0
    0x104a53fec: 0x580000e9   ldr    x9, #0x1c
    0x104a53ff0: 0x911a4129   add    x9, x9, #0x690            ; =0x690 
    0x104a53ff4: 0xb868792a   ldr    w10, [x9, x8, lsl #2]
    0x104a53ff8: 0x58000050   ldr    x16, #0x8
    0x104a53ffc: 0xd61f0200   br     x16
    0x104a54000: 0x00f52078   .long  0x00f52078                ; unknown opcode
    0x104a54004: 0x00000001   .long  0x00000001                ; unknown opcode

从上面可以发现前四条指令正是原函数new_ZTL7624417887的前四条指令等价指令,然后再进行跳转

0x104a53ff8: 0x58000050   ldr    x16, #0x8
0x104a53ffc: 0xd61f0200   br     x16
0x104a54000: 0x00f52078   .long  0x00f52078                ; unknown opcode
0x104a54004: 0x00000001   .long  0x00000001                ; unknown opcode

(lldb) x/g 0x104a54000
0x104a54000: 0x0000000100f52078

这里跳转的地址就是原函数new_ZTL7624417887的第五条指令地址,这样整个调用原函数的过程就结束了。

#vm_remap内存bug原因以及解决办法

这个bug困扰了我3周,内心相当难受,每天一有时间就会来尝试解决这个问题。frida、substitute、substrate都能够在iOS11/12上面进行代码段patch。为什么我写的代码就会有问题。

正如前面的那样,我尝试去分析substitute和substrate进行patch相关的细节,无论从闭源的substrate逆向分析,还是开源的substitute源码分析。最开始以为是代码签名问题,但在这两个框架中都没发现和代码签名相关的代码,于是转向frida,果然发现了很多和运行时内存页签名的代码。于是我以为我找到原因了,很可能就是代码签名的问题了,在这期间阅读了frida很多相关代码,也把iOS上的代码签名机制重新学习了一遍。就这样一直进入了代码前面的坑里面,甚至想去研究下remap对应的内核代码,到底是什么原因。

由于还是感觉还是没有找到问题的关键,于是我再从新回头过来思考iOS inlinehook本身,再次goolge搜索关键字,如果这是一个通用的问题那么理论上应该能搜到相关的资料。原本是想搜iOS inlinehook在各系统版本上面的差异变化。不巧搜到了一个别人抽离substitute的hook代码,由于直接抽离了出来,所以在Xcode中十分方便调试。于是抱着试一试的心态重新分析substitute的代码,结果我发现居然这个hook代码能够在iOS12上面进行代码patch。这就很有意思了,这说明CoolStar并不是进行了其他hack操作才能进行hook。就是原本substitute就能正常patch。这样就消除了我之前认为是越狱开发者从内核层面给hook框架提供的支持。接下来我决定一步步的跟下去,看代码patch那里到底和我写的代码差异在哪里。后面发现我的内存页大小居然和substitute里面的页大小不一致。我定义了页大小为4K也就是0x1000,而substitute为16K即0x4000。其实内存页大小这部分代码我也是参考别人写的代码,那代码是2019年作者能够正常运行,应该没问题的。因为目前iOS的设备32位基本淘汰了,然而那个代码定义的页大小就是32位设备上的4K,我手里的设备都是64位的,如果按照32位的4K去分配以及其他操作肯定会出问题。这和我之前remap后的内存错误也对应上来了,之前全部覆盖为0数据的大小正式4K的4倍,也就是一个64位上的16K内存页大小。最后我把内存页大小改为16K以后再次运行发现这次没有崩溃了,再检查一下patch的地址是否修改以及运行是否符合预期,发现一切都正常工作。

找到原因以后,我把xia0LLDB中的debugme的内存页大小改为16K以后再测试,发现在iOS12上就能够正常的反反调试了。到这里,困扰了我这么久的问题终于得到了解决,也给我以后分析bug有一定启示,很多时候我们先要对整个运行过程以及基本原理要足够了解,这里就因为我理所当然的认为那个代码在内存页大小这个问题上不会有问题,所以也没有仔细去查看是否正确,从而导走偏了方向。

#iOS unc0vers inlinehook失败原因分析(2019/09/19)

日志:

sub_1D124() call
sub_13B2C() call
__int64 MSServerPort()
{
  char *v0; // x0
  int v1; // w20

  v0 = **_NSGetArgv();
  if ( v0 && !strcmp(v0, "/usr/libexec/substrated") )
    return 0LL;
  if ( !dword_12D524 || (v1 = dword_12D528, v1 != getpid()) )
  {
    dword_12D524 = sub_1425C();
    dword_12D528 = getpid();
  }
  return (unsigned int)dword_12D524;
}
v3 = bootstrap_look_up(special_port, "cy:com.saurik.substrated", &sp);

mobilesubstrate deb包的目录结构

xia0 ~/xia0/iOSRE/research/iOS11-12-CodePatch-vm_remap-bug/Undecimus.app/apt $ dpkg -X mobilesubstrate_0.9.7033_iphoneos-arm.deb ./extract
./
./Library/
./Library/Frameworks/
./Library/Frameworks/CydiaSubstrate.framework/
./Library/Frameworks/CydiaSubstrate.framework/Headers/
./Library/Frameworks/CydiaSubstrate.framework/Info.plist
./Library/MobileSubstrate/
./Library/MobileSubstrate/DynamicLibraries/
./usr/
./usr/bin/
./usr/bin/cycc
./usr/bin/cynject
./usr/include/
./usr/include/substrate.h
./usr/lib/
./usr/lib/cycript0.9/
./usr/lib/cycript0.9/com/
./usr/lib/cycript0.9/com/saurik/
./usr/lib/cycript0.9/com/saurik/substrate/
./usr/lib/cycript0.9/com/saurik/substrate/MS.cy
./usr/lib/libsubstrate.dylib
./usr/lib/substrate/
./usr/lib/substrate/SubstrateBootstrap.dylib
./usr/lib/substrate/SubstrateInserter.dylib
./usr/lib/substrate/SubstrateLoader.dylib
./usr/libexec/
./usr/libexec/substrate
./usr/libexec/substrated
./Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate
./Library/Frameworks/CydiaSubstrate.framework/Headers/CydiaSubstrate.h
./Library/MobileSubstrate/MobileSubstrate.dylib

#参考