12、HOOK原理下

news2024/11/18 6:29:50

一、去符号和恢复符号

1.1 Stip和 Strip Type解释

  • strip在iOS中的作用是 剥掉目标文件中一些符号信息和调试信息,使文件变小。
  • dead code strip : 死代码剥离、然后再去链接。
  • 那么strip在哪些地方不能起作用呢?
    • 动态库 不能strip全局符号、因为全局符号要作为导出符号。
    • App中 间接符号表中的符号不能strip;那么App中 本地符号、全局符号都可以strip。
    • 静态库 = .o文件合集,存在重定位符号表,这个表中的数据也是不能strip的。所以 .o文件中能strip的是调试符号。
  • 因此我们在Build Settings中的Strip Style
    • Debugging Symbols(.o静态库/可执行文件 /动态库)调试符号
    • All Symbols     所有符号
    • Non-Global Symbols 不是全局符号
  • Strip Style: 

    .o/静态库 __DWARF(静态库没有签名) 

      • Mach-O        ----> 解析成模型Object              --->  遍历 LoadCommands                 ----> 找到 ‘Segname == __DWARF’的 ‘Load Command’  --->
      • 移除的‘Section’ ----> 从符号表中移除 ‘Symbol’ ---> 将修改后的模型Object重新写入 ----> Mach-O
    • Debugging Symbols(动态库、可执行文件)
      • 遍历符号表 ---> 删除调试符号的n_type包含 N_STAB(0xe0)  
    • All Symbols
      • markSymbols ----> 除了间接符号表中引用的符号 --->   都可以删除。
    • Non-Global Symbols
      • 遍历符号表 ---> 删除符号的n_type != N_EXT 
  • 那么就符号来说:我们的App在使用静态库体积会变小还是使用动态库体积会变小?
    • 答案是静态库;
    • 因为 App在链接静态库的时候,.o文件的合集会把.o中的所有符号、包括重定位的符号,都放到App的符号表中。因此可能变成了全局符号、本地符号、导出符号。那么根据strip的原理、在静态库中所有的符号都可以被剥离。
    • 而动态库中所有的符号都被放到App的间接符号表中、那么再去strip的时候、动态库中的死代码将不能被剥离。

1.2 Strip注意事项

  • strip脱符号,在Xcode中默认是在Archive的时候才会生效,移除对应符号.
  • 查看当前archive后脱去符号的MachO的代码段符号信息

$ objdump --macho -t symbolDemo
symbolDemo:
SYMBOL TABLE:
0000000005614542      d  *UND* radr://5614542
0000000100000000 g     F __TEXT,__text __mh_execute_header
0000000000000000         *UND* _NSLog
0000000000000000         *UND* _NSStringFromClass
0000000000000000         *UND* _OBJC_CLASS_$_UIResponder
0000000000000000  w      *UND* _OBJC_CLASS_$_UISceneConfiguration
0000000000000000         *UND* _OBJC_CLASS_$_UIViewController
0000000000000000         *UND* _OBJC_METACLASS_$_NSObject
0000000000000000         *UND* _OBJC_METACLASS_$_UIResponder
0000000000000000         *UND* _OBJC_METACLASS_$_UIViewController
...
0000000000000000         *UND* _objc_storeStrong
0000000000000000         *UND* dyld_stub_binder
  • 而正常运行时,符号信息还包括一些本地符号和全局符号
objdump --macho -t symbolDemo
symbolDemo:

SYMBOL TABLE:
0000000100005d8c l     F __TEXT,__text -[ViewController hanktest]
0000000100005da0 l     F __TEXT,__text -[ViewController viewDidLoad]
0000000100005df4 l     F __TEXT,__text -[ViewController test1]
0000000100005e20 l     F __TEXT,__text -[ViewController test]
....
  • 当符号被脱去后,想要还原原来的符号,可以通过restore-symbol 这个第三方库恢复
//restore-symbol可执行文件 + 要恢复的可执行文件路径 -0 输出文件名称
$ restore-symbol symbolDemo -o symbolRestores
=========== Start =============
Scan OC method in mach-o-file.
Scan OC method finish.
=========== Finish ============
// 查看代码段符号
$ objdump --macho -t symbolRestores
symbolRestores:

SYMBOL TABLE:
0000000005614542      d  *UND* radr://5614542
0000000100000000 g     F __TEXT,__text __mh_execute_header
0000000000000000         *UND* _NSLog
0000000000000000         *UND* _NSStringFromClass
0000000000000000         *UND* _OBJC_CLASS_$_UIResponder
0000000000000000  w      *UND* _OBJC_CLASS_$_UISceneConfiguration
0000000000000000         *UND* _OBJC_CLASS_$_UIViewController
0000000000000000         *UND* _OBJC_METACLASS_$_NSObject
0000000000000000         *UND* _OBJC_METACLASS_$_UIResponder
....
0000000000000000         *UND* _objc_storeStrong
0000000000000000         *UND* dyld_stub_binder
0000000100006250 l     F __TEXT,__text -[ViewController touchesBegan:withEvent:]
000000010000624c l     F __TEXT,__text -[ViewController test]
0000000100006230 l     F __TEXT,__text -[ViewController test1]
00000001000061f0 l     F __TEXT,__text -[ViewController viewDidLoad]
...
000000010000636c l     F __TEXT,__text -[SceneDelegate sceneDidEnterBackground:]
0000000100006368 l     F __TEXT,__text -[SceneDelegate sceneWillEnterForeground:]
0000000100006364 l     F __TEXT,__text -[SceneDelegate sceneWillResignActive:]
0000000100006360 l     F __TEXT,__text -[SceneDelegate sceneDidBecomeActive:]
000000010000635c l     F __TEXT,__text -[SceneDelegate sceneDidDisconnect:]

二、初探反HOOK防护

  • 2.1 如果要防护其他人

    • 需要保留自己的HOOK方法;如果要使用fishhook做防护,那么需要在framework里边去实现
      • 因为framework里边的load加载会比主工程的代码更快
      • 注入的HOOK代码在framework代码之后,主工程之前.所以要切入这个时机点去做防护
  • 2.2 反HOOK实战、

  • 1.假如我们防护 method_exchangeImplementations 方法、
    • 首先创建一个AntiHOOK项目、然后主界面设置两个按钮、接着增加一个HOOKManager的Framework、让主工程依赖它,在Framework中,我们在load方法中实现我们的反Hook逻辑
#import "AntiHOOKCode.h"
#import "fishhook.h"
#import <objc/message.h>
@implementation AntiHOOKCode
+ (void)load {
    //基本防护
    struct rebinding exchange;
    exchange.name  = "method_exchangeImplementations";
    exchange.replacement = my_exchange;
    exchange.replaced    = (void *)&exchangeP;
    struct rebinding bds[] = {exchange};
    rebind_symbols(bds, 1);
}
//指针,暴露给外界自己的工程使用
void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);
void my_exchange(Method _Nonnull m1, Method _Nonnull m2) {
    NSLog(@"检测到了HOOK");
}
    • 反HOOK部分已经完成、

    • 接下来、我们模拟HOOK方,对防护的Demo进行HOOK、
    • 新建一个HOOKDemo、根目录下创建一个App的文件夹、拿出史诗级脚本appSign.sh放入根目录下
    • 创建Payload文件夹、放入AntiHOOK包、APP目录下执行
$zip -ry AntiHOOK.ipa Payload/
adding: Payload/ (stored 0%)
....
adding: Payload/AntiHook.app/embedded.mobileprovision (deflated 36%)
adding: Payload/AntiHook.app/Info.plist (deflated 35%)
adding: Payload/AntiHook.app/PkgInfo (stored 0%)
    • 压缩完成后形成AntiHOOK.ipa.注释appSign脚本的yololib的执行方法, 运行HOOKDemo、将AntiHOOK.ipa跑进新的Demo中
    • 最后,开始注入操作、新建HolothurianHook的Framework、开始使用方法交换,HOOK项目中的btnClick1方法,
    • 此时打开yololib的动态注入方法.
#import "InjectHook.h"
#import <objc/message.h>
@implementation InjectHook
+ (void)load {
    IMP btnIMP = class_getInstanceMethod(objc_getClass("ViewController"), @selector(btnClick1:));
    IMP testIMP = class_getInstanceMethod(self, @selector(test));
    method_exchangeImplementations(btnIMP, testIMP);
}
- (void)test {
    NSLog(@"HOOK成功");
}
@end
    • 当运行项目时、我们的反HOOK起了作用.点击按钮时,只输出按钮1被点击的log、

  • 现在剩下的问题就是、当我们自己要使用exchange方法时,该怎么做?
    • 回到AntiHOOK的工程,在AntiHOOKCode.h文件中,将exchangeP方法暴露出来
CF_EXPORT void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);
    • 并且在HOOKManager.h文件中暴露出头文件
#import <HOOKManager/AntiHookCode.h>
    • 在ViewController中,实现我们自己的HOOK代码、结果如下

    • 这样我们就实现了反HOOK,及本工程自身的HOOK.
  • 此时我们将AntiHOOK的应用包,进行HOOKDemo的HOOK时,同理,按钮1可以响应,但是按钮2会依然执行本工程的HOOK成功log,这样更加验证了,反HOOK操作是成功的.

2.3 最后的问题

  • 1.这个时候我们的反HOOK依然存在问题,因为method_exchangeImplementations方法很容易在Framework的MachO文件中找到,我们从该字符串,可以定位到防护代码.
  • 2.执行反HOOK的操作是我们依靠运行时间间隔插入进去的防护,只要注入的动态库的HOOK库运行比反HOOK早,那么该反HOOK就失效了.

三、MonkeyDev

3.1 安装问题

  • theos安装的目录默认是在用户同级目录下
  • 安装教程、出现常见问题可以在issue里边找到答案.
  • 安装成功后可以在新建工程的时候看到逆向的部分

3.2 MonkeyDev应用

3.2.1 安装MonkeyDev后

  • 拿出我们的AntiHOOK工程.开启一个MonkeyApp类型工程,创建MonkeyTest的Demo
  • 这个时候,放入我们的破解版微信应用的ipa,放在指定目录下

  • 运行后随手解开两个报错

    • 这时候需要我们去 Build Settings中,搜索libstdc++,删掉弱链接即可

  • Xcode14.2 经常碰到找不到文件、

    • 到Drived Data中删除的缓存、重新Run即可. 这个时候我们跑出来了一个微信7.0.8版本的砸壳程序,可正常调试

3.3.2 运行AntiHook程序

  • 在MonkeyDev中如何做逆向防护?
    • 在MonkeyTestDylib的Logos文件夹下

    • 选中.xm文件、右侧选择Objective-C++ Preprocessed Source

    • 这个时候回到.xm文件,就可以看到其中的Logos代码. 删掉其中所有的示例代码、编写我们自己的代码
%hook ViewController - (void)btnClick1:(id)sender { NSLog(@"已HOOK ViewController 中 btnClick1代码~~~"); } %end
    • 这个时候我们运行Demo、已成功Hook了指定类下的指定方法.

3.3.3 再次防护

  • 这个时候、我们怀疑没有使用exchangeImp方法,而是使用了 getImp/setImp方法
  • 那么回到AntiHOOK工程、开始编写反HOOK代码
#import "AntiHOOKCode.h"
#import "fishhook.h"
@implementation AntiHOOKCode
+ (void)load {
    //基本防护
    struct rebinding exchange;
    exchange.name  = "method_exchangeImplementations";
    exchange.replacement = my_exchange;
    exchange.replaced    = (void *)&exchangeP;
    //method_setImplementation
    struct rebinding setIMP;
    setIMP.name    = "method_setImplementation";
    setIMP.replacement = my_setIMP;
    setIMP.replaced = (void *)&setIMP_P;
    //method_getImplementation
    struct rebinding getIMP;
    getIMP.name = "method_getImplementation";
    getIMP.replacement = my_getIMP;
    getIMP.replaced = (void *)&getIMP_P;
    struct rebinding bds[] = {exchange, setIMP, getIMP};
    rebind_symbols(bds, 3);
}
IMP _Nonnull (*setIMP_P)(Method _Nonnull m, IMP _Nonnull imp);
void my_setIMP(Method _Nonnull m, IMP _Nonnull imp) {
    NSLog(@"检测到my_setIMP");
}
IMP _Nonnull (*getIMP_P)(Method _Nonnull m);
void my_getIMP(Method _Nonnull m) {
    NSLog(@"检测到my_getIMP");
}

//指针,暴露给外界自己的工程使用
void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);
void my_exchange(Method _Nonnull m1, Method _Nonnull m2) {
    NSLog(@"检测到了HOOK");
}
@end
    • 编译运行、得到程序包,放入MonkeyTest的TargetApp目录下
    • 这个时候编译运行MonkeyTest工程、点击按钮1后,输出日志就没有Monkey的HOOK了、因此MonkeyDevHOOK的本质也就是利用 libsubstrate.dylib,HOOK set和get方法
    • MonkeyTest的程序包中包含了如下嵌入库.

    • 回到MonkeyTestDylib.m文件、可以看到实现部分,利用的是get/set

  • 回到AntiHOOK工程、我们去掉做的反HOOK防护,也就是恢复原来的系统函数调用方法
    IMP method1 = class_getInstanceMethod(self.class, @selector(btnClick2:));
    IMP method2 = class_getInstanceMethod(self.class, @selector(testHOOK));
    method_exchangeImplementations(method1, method2);
    //    rebind_symbols(bds, 3);

  • 再次替换MonkeyTest中的TargetApp、在Logos文件中,添加一个 %orig; 方法.表示原来的调用,相当于IMP,这个时候执行成功、HOOK到了目标程序方法

四、HOOK原理 总结

  • HOOK: 钩子,修改程序的执行流程的一种技术
    • MethodSwizzle
      • 利用OC的运行时(Runtime)特性修改SEL和IMP(函数指针)对应关系.达到HOOK OC方法的目的
      • method_exchangeIMP... 交换两个IMP
      • class_replaceMethod替换某个SEL的IMP(如果没有该方法,就添加.相当于替换掉这个方法)
      • method_getImplementation、method_setImplementation获取和设置某个方法的IMP(很多三方框架都使用)
    • fishhook
      • Facebook提供的一个工具,利用MachO文件的加载原理,动态修改懒加载和非懒加载两个符号表
    • Cydia Substrate
      • 一个强大的框架
  • fishhook
    • 可以HOOK系统的函数,但是无法HOOK自定义的函数
    • 原理:
      • 共享缓存
        • iOS系统有一块特殊的位置,存放公用动态库.动态库共享缓存(dyld shared cache)
      • PIC技术
        • 由于外部的函数调用,在我们编译时刻是没法确定其内存地址的
        • 苹果就采用了PIC技术(位置无关代码).在MachO文件Data段,建立两张表,懒加载和非懒加载表,里面存放执行外部函数的指针.
        • 首次调用懒加载函数,会去找桩执行代码.首次执行会执行binder函数.
    • 通过字符找到懒加载表
      • fishhook利用stringTable -> Symbols -> indirect Symbols --> 懒加载符号表之间的对应关系,通过重绑定修改指针的值达到HOOK的目的.
  • 反HOOK基本防护
    • 利用fishhook修改MethodSwizzle相关函数
    • 防护代码要最新被加载,否则先HOOK就修改完毕了,防护无效
    • 原始工程编写的Framework库会优先于注入库加载.所以适合写防护代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/438006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows下使用SSH密钥实现免密登陆Linux服务器

工具&#xff1a; win10、WinSCP 生成ssh密钥&#xff1a; 打开终端&#xff0c;使账号密码登录&#xff0c;输入命令 ssh-keygen -t rsa 会提示密钥存放路径&#xff0c;一般存放在默认路径&#xff0c;直接回车即可&#xff0c;中间会提示输入密码&#xff0c;这里需要注…

工作流自动化和RPA自动化,哪个更适合你?

2018年&#xff0c;一款名为《Overcooked!2》&#xff08;又名“胡闹厨房”、“分手厨房”&#xff09;的多人合作模拟类游戏风靡全球&#xff0c;在游戏中&#xff0c;玩家扮演厨师在充满各种障碍和危险的厨房里准备食材、烹饪、上菜和清理&#xff0c;需要在尽可能短的时间内…

window11开启wsl2

前言 以前玩linux&#xff0c;总是习惯装双系统&#xff0c;其实双系统特别麻烦。wsl现在的功能其实挺强大的&#xff0c;完全可以代替双系统&#xff0c;去完成一些在linux上的环境搭建。这篇文章记录下window11如何开启wsl2功能&#xff0c;并且安装ubuntu系统。 开启wsl2功…

2023自助洗车店系统解决方案共享洗车无人洗车风口

2021年中国汽车保有量预计超6.3亿辆,洗车市场需求巨大,传统洗车投资大、费用贵、成本高耗水大、占地面积大,而自助洗车机占据传统洗车耗水量1/4 ,占地面积1/70 ;节能环保得到政府的大力支持,且结合信息物联技术,实现智能化管理,高效能运营,灵活便捷服务,符合智慧城市发展原则,成…

开放式耳机有什么好处,列举几款性能高的开放式蓝牙耳机

骨传导耳机也称为“不入耳式”耳机&#xff0c;是一种通过颅骨、骨迷路、内耳淋巴液和听神经之间的信号传导&#xff0c;来达到听力保护目的的一种技术。由于它可以开放双耳&#xff0c;所以在跑步、骑行等运动时使用十分安全&#xff0c;可以避免外界的干扰。这种耳机在佩戴时…

AAAI 2023 | 基于Conductance的高效率和高质量的图聚类算法

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; ╱ 作者简介╱ 林隆龙 博士、副教授 目前任职于西南大学计算机与信息科学学院 软件学院。2022年6月于华中科技大学计算机科学与技术学院获博士学位。目前主要研究兴趣包括(时序)社区挖掘、局部聚类、Personaliz…

Altium Designer 20 导出 Gerber 制造文件流程及注意事项

一、导出 Gerber 流程 设置原点&#xff1a;在Edit菜单中选择Origin&#xff0d;Set &#xff08;快捷键E-O-S&#xff09;定好原点&#xff0c;一般放在左下角附近即可。 放置分孔图表&#xff1a;在Place菜单中选择String放置“.Legend”&#xff08;快捷键P-S&#xff09;…

C++多线程编程(一) thread类初窥

多线程编程使我们的程序能够同时执行多项任务。 在C11以前&#xff0c;C没有标准的多线程库&#xff0c;只能使用C语言中的pthread&#xff0c;在C11之后&#xff0c;C标准库中增加了thread类用于多线程编程。thread类其实是对pthread的封装&#xff0c;不过更加好用&#xff…

ThreadLocal的相关面试题

ThreadLocal的特点&#xff1a;实现线程间的资源隔离&#xff0c;实现线程内的资源共享 2.原理是&#xff0c;每个线程都有一个ThreadLocalMap类型的成员变量&#xff0c;用来储存资源对象 1.调用set方法&#xff0c;就是以ThreadLocal自己作为key&#xff0c;资源对象作为val…

《花雕学AI》比尔・盖茨:AI 和 ChatGPT 可以改善人类生活,但也要防止滥用和危害

3月21号&#xff0c;微软创始人比尔盖茨&#xff0c;发表最新AI文章《人工智能时代已经开始——人工智能与手机、互联网一样具有革命性》&#xff0c;文章中表示&#xff1a;「自1980年首次看到图形用户界面&#xff08;graphical user interface&#xff09;以来&#xff0c;O…

通过logstash实现mysql与es的双向数据同步

参考题目 一种基于MySQL和Elasticsearch的数据同步方法及系统基于MySQL和Elasticsearch的数据同步方法一种基于MySQL和Elasticsearch的数据同步系统基于MySQL和Elasticsearch的数据同步技术 目录 1【理论调研】 方案1&#xff1a;使用Logstash实现数据同步 方案2&#xff1a…

Spring MVC基本认识与操作

SpringMVC是隶属于Spring框架的一部分&#xff0c;主要是用来进行Web开发&#xff0c;是对Servlet进行了封装。 先来介绍三个概念&#xff1a; SpringMVC是处于Web层的框架&#xff0c;所以其主要的作用就是用来接收前端发过来的请求和数据然后经过处理并将处理的结果响应给前…

SpringCloud 微服务系列——【基础与服务注册中心详解】

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

文本批量翻译-批量翻译文件名

批量将英文翻译成中文的软件 批量将英文翻译成中文的软件的主要用途场景主要是在需要大量翻译英文文本到中文的场景下使用&#xff0c;例如&#xff1a; 商务文件翻译&#xff1a;许多企业需要将其商务文件&#xff0c;如合同、报告、信函等翻译成中文&#xff0c;以便其中文读…

HTML5 <p> 标签、HTML5 <pre> 标签

HTML5 <p> 标签 实例 HTML5 <p>标签用于定义一个段落。请参考下述示例&#xff1a; 以下代码标记了一个段落&#xff1a; <p>这是一个段落。</p>尝试一下 (在页面下部&#xff0c;您可以找到更多实例) 浏览器支持 目前大多数浏览器支持 <p>标…

java健身房会员签到,会员提醒,留言,消费,公告

1. 主页&#xff1a;即时登录,提供会员和管理员的登录。 2. 会员卡办理&#xff1a;登记健身会员的信息,设置卡到期时间。 3. 会员消费系统&#xff1a;对健身会员的日常消费进行添加。 4. 在线交流&#xff1a;健身会员之间的交流,管理员可以对其问题进行回复。 5.提醒功能&am…

一篇文章快速入门Spring AMQP

文章目录 一、AMQP二、Spring AMQP2.1 介绍2.2 SpringAMQP发送消息2.3 SpringAMQP接收消息2.4 WorkQueue模型2.4.1 概念2.4.2 示例 2.5 发布订阅模型2.5.1 介绍2.5.2 Fanout Exchange2.5.3 Direct Exchange2.5.4 Topic Exchange 2.6 消息转换器2.6.1 介绍2.6.2 切换消息转换器 …

重写equlas时为什么一定要重写hashcode方法?

equals方法和hashCode方法都是Object类中的两个基本方法&#xff0c;它们共同来判断两个对象是否相等。为什么要两个方法结合起来使用呢&#xff1f;原因是在 ‘性能’ 上面。 使用过 hashMap 我们知道&#xff0c;通过 hash 计算 &#xff0c;可以快速的在常量时间内找到某个…

webpack基本认知,它是什么,做什么的

一、基本概述 webpack本质是, 一个第三方模块包, 用于分析, 并打包代码 支持所有类型文件的打包支持less/sass > css支持ES6/7/8 > ES5压缩代码, 提高加载速度 二、安装 创建一个文件并运行以下命令&#xff1a; npm init -y npm i webpack webpack-cli -S 运行命令…

DNS域名解析服务

目录 一、DNS的简介 1&#xff09;DNS 数据结构分布 2&#xff09;服务器的类型 3&#xff09;DNS 域名解析方式 4&#xff09;DNS的查询方式 递归查询 迭代查询 二、DNS配置 1&#xff09;两台主从服务器进行配置操作 ​编辑 2&#xff09;DNS主域名服务器配置&am…