[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fneSrj_wusiH7RnmXSV59g3HPclqYLo9tH51ouwakFek":3},{"code":4,"message":5,"data":6},200,"成功",{"id":7,"createdAt":8,"title":9,"content":10,"summary":11,"image":12,"uid":13,"user":14,"categoryId":21,"category":22,"subCategoryId":24,"subCategory":25,"comments":27,"status":17,"reason":12,"notice":12,"visitCount":28,"commentCount":29,"keywords":30},57,"2024-01-31T02:44:48.503Z","iOS的hook介绍，fishhook的调试理解","# HOOK\n## Method Swizzle\n利用OC的runtime特性，动态改变`SEL`（方法编号）和`IMP`（方法实现）的对应关系，达到OC方法调用流程改变的目的。主要用于OC方法。\n\n## fishhook\n它是facebook提供的一个动态修改链接`mach-O`文件的工具。利用`MachO`文件加载原理，通过修改懒加载和非懒加载两个表的指针达到C函数HOOK的目的。\n### hook C函数\n> 引入`facebook`的`fishhook.h`和`fishhook.c`\n```\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    \n    // HOOK 交换\n    /**\n     struct rebinding {\n     const char *name; // 需要HOOK的函数名称，C字符串\n     void *replacement; // 新函数的地址\n     void **replaced; // 用来保存原始函数地址的指针\n     };\n     */\n    struct rebinding nslog;\n    nslog.name = \"NSLog\";\n    nslog.replaced = (void *) &sys_nslog; // 保存系统函数的地址的指针的指针\n    nslog.replacement = myNSlog; // 新函数的地址\n    \n    struct rebinding rebs[1] = {nslog};\n    /**\n     用于重新绑定符号\n     一次性交换多个函数，\n     arg1:存放rebinding结构体的数组\n     arg2:数组的长度\n     */\n    rebind_symbols(rebs, 1);\n}\n\n// ----更改系统的NSLog函数调用\n// 函数指针，用来保存原始的函数地址!\nstatic void(*sys_nslog)(NSString *str, ...);\n\n\n// 定义一个新的函数\nvoid myNSlog(NSString *str, ...) {\n    str = [str stringByAppendingString:@\"\\n钩上了！\"];\n    // 由于系统的内部实现不知道\n    sys_nslog(str);\n}\n\n- (void)touchesBegan:(NSSet\u003CUITouch *> *)touches withEvent:(UIEvent *)event {\n    NSLog(@\"点击了屏幕!\");\n}\n```\n\nhook 自定义的C函数 （勾不住）\n```\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    \n    [self funcDemo];\n}\n\n// 交换自定义函数\n- (void)funcDemo {\n    rebind_symbols((struct rebinding[1]){{\"func\", newFunc, (void *)&funcP}}, 1);\n}\n// 保存原始函数的指针\nstatic void(*funcP)(const char *);\n\n// 新函数\nvoid newFunc(const char * str) {\n    NSLog(@\"勾住了\");\n    funcP(str);\n}\n// 自定义的函数\nvoid func(const char * str) {\n    NSLog(@\"%s\", str);\n}\n\n- (void)touchesBegan:(NSSet\u003CUITouch *> *)touches withEvent:(UIEvent *)event {\n    func(\"点击了屏幕\");\n}\n```\n\n### 底层汇编解释\n- C函数是静态的\n- PIC 位置独立代码\n- DYLD 将可执行文件加载到内存中，将NSLog的地址绑定到符号symbol，一开始符号symbol都是0x0，当APP被DYLD加载到内存中运行的时候，DYLD会把symbol中的指针指向内存中的UIKit, UIFoundation中的函数地址。\n\n在NSLog函数的hook代码中，在rebind操作时打一个断点，然后在xCode终端看底层汇编的内容:\n\n1.  命令`image list`可以查看fishhook.app的exec可执行文件在内存中的地址：\n```\nimage list\n[  0] DC3F7324-1654-3F1B-8A0A-2E8E9B228968 0x0000000108bf5000 /Users/hanweixing/Library/Developer/Xcode/DerivedData/FishHook-egipaudxwxzvacdyvhhoisbqvjio/Build/Products/Debug-iphonesimulator/FishHook.app/FishHook \n[  1] CE635DB2-D47E-3C05-A0A3-6BD982E7E750 0x000000010bbd1000 /usr/lib/dyld \n[  2] 528E1F55-F655-3533-99B9-7EAE1DAE5D07 0x0000000108c01000 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/dyld_sim \n...\n```\n得到可执行文件的内存地址：`0x0000000108bf5000`\n\n2\\. 通过MachOView软件，打开fishhook.app的可执行文件exec，在`__la_symbol_ptr`的 `Lazy Symbol Pointers`中可以看到`NSLog`的内存偏移：`00004028`\n- 在Xcode中读取`NSLog`对应的`symbol`地址：\n```\n(lldb) x 0x0000000108bf5000+0x4028\n0x108bf9028: a0 79 bf 08 01 00 00 00 89 b4 f7 08 01 00 00 00  .y..............\n0x108bf9038: 36 0f d8 0c 01 00 00 00 e6 79 bf 08 01 00 00 00  6........y......\n```\n- 取前面的8个字节，然后倒序拼接，就可以将`symbol`中的值转换成汇编代码：（可以看到这是系统Foundation中的NSLog）\n```\n(lldb) dis -s 0x0108bf79a0\nFoundation`NSLog`:\n    0x108bf79a0: pushq  $0x0\n    0x108bf79a5: jmp    0x108bf7990\n    0x108bf79aa: pushq  $0xd\n    0x108bf79af: jmp    0x108bf7990\n    0x108bf79b4: pushq  $0x118                    ; imm = 0x118 \n    0x108bf79b9: jmp    0x108bf7990\n```\n- 将断点跳一步，继续在Xcode中进行调试，读取最新的`symbol`中的值，可以发现被替换成了我们替换的函数实现。\n```\n(lldb) x 0x0000000108bf5000+0x4028\n0x108bf9028: e0 6d bf 08 01 00 00 00 89 b4 f7 08 01 00 00 00  .m..............\n0x108bf9038: 36 0f d8 0c 01 00 00 00 31 71 91 0b 01 00 00 00  6.......1q......\n(lldb) dis -s 0x0108bf6de0\nFishHook`myNSlog:\n    0x108bf6de0 \u003C+0>:  pushq  %rbp\n    0x108bf6de1 \u003C+1>:  movq   %rsp, %rbp\n    0x108bf6de4 \u003C+4>:  subq   $0x30, %rsp\n    0x108bf6de8 \u003C+8>:  movq   $0x0, -0x8(%rbp)\n    0x108bf6df0 \u003C+16>: leaq   -0x8(%rbp), %rax\n    0x108bf6df4 \u003C+20>: movq   %rdi, -0x10(%rbp)\n    0x108bf6df8 \u003C+24>: movq   %rax, %rdi\n    0x108bf6dfb \u003C+27>: movq   -0x10(%rbp), %rsi\n(lldb)\n```\n\n## Cydia Substrate （主要用在逆向）\nCydia Substrate原名为Mobile Substrate,它的主要作用是针对OC方法、C函数以及函数地址进行HOOK操作。当然它不仅仅是针对iOS而设计的，安卓一样可以用。\n官方地址：\u003Chttp://www.cydiasubstrate.com/>\n\n","iOS中的hook操作有3种主流的方式，主要介绍fishhook的调试步骤，用于理解hook的原理。","",499668042977349,{"phone":15,"userId":13,"nickName":16,"vipType":17,"avatar":18,"sign":19,"createdAt":20},"13121171998","全栈老韩",1,"https://image.xinwei.ltd/images/IMG_5430.JPG","全栈工程师，擅长iOS App开发、前端（vue、react、nuxt、小程序&Taro）开发、Flutter、React Native、后端（midwayjs、golang、express、koa）开发、docker容器、seo优化等。","2024-01-01T16:14:30.305Z",2,{"id":21,"name":23},"IT技术",3,{"id":24,"name":26,"parentId":21},"iOS",[],86,0,"ios,ios hook,ios fishhook,ios开发"]