首页
社区
课程
招聘
[原创]一例简单的frida反调试绕过
发表于: 2022-8-25 14:45 16446

[原创]一例简单的frida反调试绕过

2022-8-25 14:45
16446

一例简单的frida反调试绕过

前言

最近在分析一款app时遇见了frida反调试,花了时间简单学习了一下,有不少收获,记录下学习的过程。

抛出问题

frida是一个很强大的hook框架,用的人多了,自然而然就出现了很多检测方案,这次碰到的app就检测了frida,可以正常打开,但是当你用frida -f启动或者attach进程,不久后就会闪退。

常见frida检测

1.检测frida-server文件名
2.检测27042默认端口
3.检测D-Bus
4.检测/proc/pid/maps映射文件
5.检测/proc/pid/tast/tid/stat或/proc/pid/tast/tid/status
6.双进程保护

 

前两种可以通过修改frida-server文件名,改默认端口绕过。双进程可以通过-f spawn模式启动绕过。其他的需要去hook修改。

定位

先针对简单的几个可能检测的方式,我修改了文件名,改了端口,也尝试了spawn启动,均会在启动后不久闪退。
这时考虑到其他几种检测。
首先用frida去看看载入了哪些so,看看是哪里检测了,看了个寂寞。

1
2
3
4
5
6
7
8
9
10
  function fridaProcess(){
    Java.perform(function () {
      var enumMoudle = Process.enumerateModules();
      for (var i = 0; i < enumMoudle.length; i++){
        console.log("", enumMoudle[i].name)
      }
    });
  }
 
setImmediate(fridaProcess,0)


因为so载入的时候,底层最后open去打开的。
所以再用frida去hook应用中的open函数,看看读取了哪些so或者文件,可以看到最后断在了/proc/self/maps。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var pth = Module.findExportByName(null,"open");
    Interceptor.attach(ptr(pth),{
        onEnter:function(args){
            this.filename = args[0];
            console.log("",this.filename.readCString())
            if (this.filename.readCString().indexOf(".so") != -1){
                args[0] = ptr(0)
 
            }
 
        },onLeave:function(retval){
            return retval;
        }
    })

稍稍深入

这里当挂上frida后对应的maps文件中会出现re.frida.server之类的特征,这是在使用frida server的时候自动创建的,其中存放着frida的功能模块,可以在载入so的hook脚本输出中能看到最后也是断在frida-agent.so。

 

这里要绕过这个检测,我是通过备份一个正常启动时的maps文件(这里前面也讲到app不使用frida是能正常启动不闪退的)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function main() {
  const openPtr = Module.getExportByName('libc.so', 'open');
  const open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
  var readPtr = Module.findExportByName("libc.so", "read");
  var read = new NativeFunction(readPtr, 'int', ['int', 'pointer', "int"]);
  var fakePath = "/data/data/com.app/maps";
  var file = new File(fakePath, "w");
  var buffer = Memory.alloc(512);
  Interceptor.replace(openPtr, new NativeCallback(function (pathnameptr, flag) {
      var pathname = Memory.readUtf8String(pathnameptr);
      var realFd = open(pathnameptr, flag);
      if (pathname.indexOf("maps") >= 0) {
          while (parseInt(read(realFd, buffer, 512)) !== 0) {
              var oneLine = Memory.readCString(buffer);
              if (oneLine.indexOf("tmp") === -1) {
                  file.write(oneLine);
              }
          }
          var filename = Memory.allocUtf8String(fakePath);
          return open(filename, flag);
      }
      var fd = open(pathnameptr, flag);
      return fd;
  }, 'int', ['pointer', 'int']));
}
setImmediate(main)


然后就可以继续调试了。

总结

这只是一个简单的例子,但是确实在这个bypass的过程中学到了东西,只要花时间是去分析,总能找到对应的突破口。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 4
支持
分享
最新回复 (6)
雪    币: 348
活跃值: (1583)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
直接用这个就行了
https://github.com/hzzheyang/strongR-frida-android
2022-8-25 15:36
0
雪    币: 0
活跃值: (107)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
5.检测/proc/pid/tast/tid/stat或/proc/pid/tast/tid/status  

这个frida 检测哪里?
2022-8-30 17:22
0
雪    币: 340
活跃值: (107)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
学到了,不过一楼工具感觉也不错
2022-8-30 20:18
0
雪    币: 537
活跃值: (1497)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
双进程保护,是什么意思 ?
2022-8-31 23:38
0
雪    币: 216
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
lipengzhu 直接用这个就行了 https://github.com/hzzheyang/strongR-frida-android
用了这个依旧闪退  请问是怎么回事
2022-9-13 11:33
0
雪    币: 158
活跃值: (1101)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
请问fakePath在/data/data目录下就提示【Error: failed to open file (No such file or directory)】,但是在/data/local/tmp却正常。但是maps文件在此会不会对后续有所影响?
2023-3-6 09:12
0
游客
登录 | 注册 方可回帖
返回
//