《九阴真经: iOS黑客攻防秘籍》新书发布,干货满满,快来看看吧!

iOS 安全论坛 - 专注于研究 iOS 安全

 找回密码
 立即注册
查看: 14108|回复: 17

【Frida 实战】Hook 大法,拦截器的使用

[复制链接]

119

主题

582

帖子

2626

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2626
发表于 2020-5-10 20:53:07 | 显示全部楼层 |阅读模式
本文是 Frida 实战系列教程的第二篇。第一篇请查看 https://www.ioshacker.net/thread-360-1-1.html
拦截器(Interceptor)是 Frida 很重要的一个功能,它能够帮助我们 Hook C 函数、Objective-C 方法,在第一篇使用 frida-trace 跟踪 CCCrypt 函数的实例中,frida-trace 实际上也用到了拦截器。

Objective-C 数据类型的处理
在学习使用拦截器(Interceptor)之前,有必要了解在 frida 脚本里如何对 Objective-C 的数据类型进行处理,比如像 NSString、NSData、NSArray、NSDictionary 都是很常见的类型,我们必须要知道这些类型在 frida 脚本中该怎么读取内容。下面通过一个实例来看看 NSString 如何读取内容并输出。
应用在发送 HTTP 请求时,通常都会调用 [NSURL URLWithString:] 这个方法来初始化 URL 地址,我们对这个方法进行跟踪,执行下面的命令,xxx 代表目标进程的名称。


  1. frida-trace -U -m "+[NSURL URLWithString:]" xxx
复制代码
然后在 handlers 找到 NSURL_URLWithString.js 文件,可以看到 UTF8String 这个函数是 NSString,我们调用 UTF8String 即可得到字符串。
  1. onEnter: function (log, args, state) {
  2.     log("+[NSURL URLWithString:" + args[2] + "]");
  3.     var objcHttpUrl = ObjC.Object(args[2]);  //获取 Objective-C 对象 NSString
  4.     var strHttpUrl = objcHttpUrl.UTF8String();
  5.     log("httpURL: " + strHttpUrl);   

  6.   },
复制代码

然后我们来做第二个实例,了解如何获取 NSData 的字符串。应用发送 HTTP 请求,通常会调用 [NSURLRequest setHTTPBody:] 设置 HTTPBody,需要注意的是除了 NSURLRequest,可能还会有一个 NSMutableURLRequest,对这两个方法进行跟踪。

  1. frida-trace -U -m "-[NSURLRequest setHTTPBody:]" -m "-[NSMutableURLRequest setHTTPBody:]" xxx
复制代码
找到 NSMutableURLRequest_setHTTPBody.js 修改成如下代码,可以看到调用 NSData 的 bytes 函数得到内存地址,然后再调用 readUtf8String 读取内存中的数据,即可得到字符串。
  1. onEnter: function (log, args, state) {
  2.     log("-[NSMutableURLRequest setHTTPBody:" + args[2] + "]");

  3.     var objcData = ObjC.Object(args[2]);  //NSData
  4.     var strBody = objcData.bytes().readUtf8String(objcData.length()); //NSData 转换成 string
  5.     log("HTTPBody: " + strBody);
  6.    
  7.   },
复制代码

遍历 NSDictionary 的代码如下:
  1. var dict = new ObjC.Object(args[2]);
  2. var enumerator = dict.keyEnumerator();
  3. var key;
  4. while ((key = enumerator.nextObject()) !== null) {
  5.   var value = dict.objectForKey_(key);
  6. }
复制代码
遍历 NSArray 的代码如下:

  1. var array = new ObjC.Object(args[2]);
  2. var count = array.count().valueOf();
  3. for (var i = 0; i !== count; i++) {
  4.   var element = array.objectAtIndex_(i);
  5. }
复制代码

拦截 C 函数

下面我们学习如何使用拦截器编写一个 Hook fopen 的功能。了解一下 fopen 函数的原型和功能,原型如下:
  1. FILE *fopen(const char *filename, const char *mode)
复制代码
其功能是使用给定的模式 mode 打开 filename 所指向的文件。文件如果打开成功,会返回一个指针,相当于句柄。如果文件打开失败则返回 0。新建一个文件 fopen.js,添加下面的代码,其中 Interceptor.attach() 是我们添加的拦截器,拦截 fopen 函数,onEnter 是进入 fopen 函数时要执行的代码,打印出 fopen 的第一个参数,也就是 fopen 准备操作的文件路径,onLeave 是离开 fopen 函数时要执行的代码,打印返回值,并将返回值替换成 0, 这样 fopen 打开文件就会失败
  1. Interceptor.attach(Module.findExportByName(null, "fopen"), {
  2.    
  3.         onEnter: function(args) {
  4.             if (args[0].isNull()) return;
  5.             var path = args[0].readUtf8String();
  6.             console.log("fopen " + path);
  7.    
  8.         },
  9.             onLeave: function(retval) {
  10.                     console.log("\t[-] Type of return value: " + typeof retval);
  11.                     console.log("\t[-] Original Return Value: " + retval);
  12.                     retval.replace(0);  //将返回值替换成0
  13.                     console.log("\t[-] New Return Value: " + retval);
  14.             },
  15.     })
复制代码
然后在计算机上执行命令 frida -U -l /Users/exchen/frida/fopen.js xxx,-l 参数表示加载指定的脚本文件,xxx 是你要操作的应用名称。此时我们看到原本 fopen 能操作的文件,使用拦截器修改返回值之后,就不能则会打开失败。还有一种加载脚本的方法,是先进入交互模式,比如执行 frida -U xxx,注入 xxx 应用的进程,再调用 %load 命令加载脚本。如果想退出frida,保持应用在前台,然后在计算机上按 control+D 即可。
  1. [iPhone::iDevice]-> %load /Users/exchen/frida/fopen.js
复制代码
除了系统库自带的函数,我们还可以拦截自定义的函数,比如我们自定义一个 getStr 函数,返回的参数是一个字符串指针,我们在 onLeave 函数中添加下面的代码,新建一个变量 string,分配内存并填充字符串 4567789, 然后将返回值替换变量 string。
  1. Interceptor.attach(Module.findExportByName(null, "getStr"), {

  2.     onEnter: function(args) {
  3.         console.log("getStr");

  4.     },
  5.         onLeave: function(retval) {
  6.                 console.log("\t[-] Type of return value: " + typeof retval);
  7.                 console.log("\t[-] Original Return Value: " + retval.readUtf8String());

  8.                 var string = Memory.allocUtf8String("456789");  //分配内存
  9.                 retval.replace(string); //替换

  10.                 console.log("\t[-] New Return Value: " + retval.readUtf8String());
  11.         },
  12. })
复制代码

拦截 Objective-C 方法

frida 不仅可以拦截 C 函数,还可以拦截 Objective-C 方法,比如我们编写脚本对 +[NSURL URLWithString:] 进行拦截,代码如下,其中 onEnter 调用 ObjC.classes.NSString.stringWithString_ 给 NSString 传递新的值,这样相当于替换原本的 URL。
  1. var className = "NSURL";
  2. var funcName = "+ URLWithString:";
  3. var hook = eval('ObjC.classes.' + className + '["' + funcName + '"]');
  4. Interceptor.attach(hook.implementation, {
  5.         onLeave: function(retval) {

  6.                 console.log("[*] Class Name: " + className);
  7.                 console.log("[*] Method Name: " + funcName);
  8.                 console.log("\t[-] Type of return value: " + typeof retval);
  9.                 console.log("\t[-] Original Return Value: " + retval);
  10.         },

  11.         onEnter: function(args){

  12.                 var className = ObjC.Object(args[0]);
  13.                 var methodName = args[1];
  14.                 var urlString = ObjC.Object(args[2]);

  15.                 console.log("className: " + className.toString());
  16.                 console.log("methodName: " + methodName.readUtf8String());
  17.                 console.log("urlString: " + urlString.toString());
  18.                 console.log("-----------------------------------------");

  19.                 urlString = ObjC.classes.NSString.stringWithString_("http://www.baidu.com")
  20.                 console.log("newUrlString: " + urlString.toString());
  21.                 console.log("-----------------------------------------");

  22.         }
  23. });
复制代码
有时候被拦截的函数调用的次数较多,打印的信息也会较多,我们需要保存成文件,方便以后慢慢查看,可以使用下面的代码将有用的信息保存成文件。
  1. var file = new File("/var/mobile/log.txt","a+");//a+表示追加内容,和c语言的fopen函数模式类似
  2. file.write("logInfo");
  3. file.flush();
  4. file.close();
复制代码

想了解最新的iOS安全资讯、技术干货请关注 iOS安全论坛(ioshacker.net)微信公众号



回复

使用道具 举报

6

主题

29

帖子

234

积分

中级会员

Rank: 3Rank: 3

积分
234
发表于 2020-5-11 13:06:48 | 显示全部楼层
期待下一篇! 数组和字典的位置需要调换一下
回复

使用道具 举报

119

主题

582

帖子

2626

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2626
 楼主| 发表于 2020-5-12 02:32:17 | 显示全部楼层
init 发表于 2020-5-11 13:06
期待下一篇! 数组和字典的位置需要调换一下

看到了,已经修改。
回复

使用道具 举报

0

主题

2

帖子

123

积分

注册会员

Rank: 2

积分
123
发表于 2020-5-13 21:51:38 | 显示全部楼层
有个疑惑,hook oc方法的时候,onEnter函数里,方法传递的数据是从args[2]开始的,那前边的args[0] args[1] 传递的类名和方法名又什么作用呢。
回复

使用道具 举报

119

主题

582

帖子

2626

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2626
 楼主| 发表于 2020-5-14 12:18:39 | 显示全部楼层
Cola 发表于 2020-5-13 21:51
有个疑惑,hook oc方法的时候,onEnter函数里,方法传递的数据是从args[2]开始的,那前边的args[0] args[1] ...

args[0] args[1] 分别是类名和方法名,objc_msgSend 会用到它们,通过类名和方法名才能找到地址并调用。
回复

使用道具 举报

0

主题

1

帖子

22

积分

新手上路

Rank: 1

积分
22
发表于 2020-5-25 10:23:02 | 显示全部楼层
不知道作者是否遇到过这种情况 frida-trace附加进程报错
方便留个v咨询大佬问题吗 书写的不错 期待后续更多作品

  1. YoudeMacBook-Pro:~ youfuck$ frida-trace -U -m "+[NSURL URLWithString:]" 微博
  2. Failed to start tracing: Error: missing argument
  3.     at includeObjCMethod (/profile-resolver.js:148)
  4.     at /profile-resolver.js:31
  5.     at reduce (native)
  6.     at [anon] (/profile-resolver.js:41)
  7.     at frida/runtime/message-dispatcher.js:45
  8.     at o (frida/runtime/message-dispatcher.js:27)
复制代码
回复

使用道具 举报

119

主题

582

帖子

2626

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2626
 楼主| 发表于 2020-5-25 20:21:45 | 显示全部楼层
hkxj 发表于 2020-5-25 10:23
不知道作者是否遇到过这种情况 frida-trace附加进程报错
方便留个v咨询大佬问题吗 书写的不错 期待后续更多 ...

命令是对的,刚才试了下,我这边是可以的。你是附加所有进程都这样吗?还是只有微博这样?另外就是看一下电脑上的版本和手机上 frida 的版本, frida --version,两端的版本最好保持一致。
回复

使用道具 举报

4

主题

40

帖子

472

积分

中级会员

Rank: 3Rank: 3

积分
472
发表于 2020-5-26 09:37:26 | 显示全部楼层
请问大神,6s有9.3.2的shsh可以降回9.3.2系统吗?,感谢
回复

使用道具 举报

4

主题

40

帖子

472

积分

中级会员

Rank: 3Rank: 3

积分
472
发表于 2020-5-26 09:42:14 | 显示全部楼层
请大神看看这是6s 9.3.2的shsh文件,不知是否是完整的

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

0

主题

2

帖子

84

积分

注册会员

Rank: 2

积分
84
发表于 2020-5-26 10:05:30 | 显示全部楼层
并不能,shsh在64bit时代已经失效,都是用shsh2了,而且还要SEP兼容
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|iOSHacker

GMT+8, 2022-8-15 15:42 , Processed in 0.023728 second(s), 20 queries .

iOS安全论坛

© 2017-2020 iOS Hacker Inc. 京ICP备17074153号-2

快速回复 返回顶部 返回列表