android脱壳:一种使用native进行抽取壳脱壳的方法,native版本的frida-fart

前言

写rxposed的时候,搞了很多模块,其中有一个远程调用脱壳的,但是当时使用的是rmi远程调用,因为一些问题无法使用,可能是对抗问题,也有可能是技术问题,所以我又换了一种远程调用方式。

概述

android的dex加固,有整体dex加固,抽取加固,dex vmp,java2c,虽然有这么多,但是其实就脱壳主要是两个方面,第一个是整体dex脱壳,第二个就是在整体dex脱壳的基础上进行dex加密函数还原。抽取加固,dex vmp,java2c这些加固方式都以函数为粒度,进行函数代码的保护。

整体加固脱壳

这个比较简单,有一些dex的文件是不进行加固的,直接解压apk就行,有些dex是加固过的,常用的dex不落地的内存加载,对于这种dex的脱壳都有个通用的方案,就是内存dump。dex在运行时总是要加载到内存中的,所以选择合适的时机是可以dump下来完整的dex的。

抽取壳脱壳

dexvmp,java2c,dex抽取,这些加固方案,在我看来其实都是函数方法抽取,dex抽取是代码抽取了以后,在运行时还原,dexvmp,java2c这些方案是抽取了以后将抽取的代码转变成了另一种代码,导致了无法自动还原,code_item消失。

dex抽取还原与防护的问题

如上所属,整体加固的脱壳,在运行时dump下来,而dex抽取,我也说了,在运行时还原,那么可以不可以将dex整体dump和dex抽取还原放到一起那

可以,这种可执行文件加固,本质上就是一种静态加密,动态运行时解密,理论上只要在动态运行解密后dump下来就可以了。

为什么fart和frida-fart都是先脱dex然后在修复code_item的方案

因为直接在内存dump整体dex,然后在获取解密的code_item的修复到dex的方案,对于某些有针对性对抗的安全方案是无效的,对于比较简答的dex抽取确实没有问题

为什么对于某些有针对性对抗的安全方案,内存直接修复dex无效(没有完全分析完成)

因为内存中dump下来的dex在修复code_item的时候,都是将dump下来的code_item,写到dex中code_item被抽取出来的位置,但是内存中dump出来的dex中,可能没有code_item的位置,可能是dex文件进行了重新编译的时候抽出来,也可能是定制了dex重编译,将特定的code_item抽出来,也有可能是修改了偏移位置等等

fart和frida-fart异同

fart和frida-fart都是基于主动加载脱壳,但是fart是基于函数级别的主动加载,会在dex方法执行前夕进行dump,frida-fart是基于类加载的主动加载,颗粒度没有fart细,但是他们有同属于dex内存加密函数自动还原方式的脱壳,如果frida-fart不行,可能是有一些别的问题,如果fart,那么可能就是真的不行,这种方案就本身不行了。甚至可能不是dex抽取壳。

frida-fart 能不能做到和fart一样

理论上可以,hook一些fart中dex函数主动调用需要用到的函数,确实可以,但是目前没有实践

修复问题

fart和frida-fart具体怎么修复的我没有去了解,但是如果内存位置不够的话,先反编译dex,将code_item的字节码反编译然后写入到dex中(可能需要用smail写),然后在回编译,可能就可以了。当然,如果可以做到dex内存重组,也可以。

dex抽取壳的强度好像有点低,有没有更高强度的方案

dex抽取相比于dex内存不落地加载,实现的难度高很多,但是在保护方面,强度确实好像并没有很高,有些确实有修复问题,但是实际上内存中都解密了。

网上说fart是主动调用,但是我觉得不太准确,far和frida-fart其实都像是主动加载,博客里说的这些函数需要真正执行一次在dump,更像是主动调用

借鉴一段他的代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

.method public constructor <init>()V

    .registers 2

    goto :goto_c

    :goto_1

    nop

    nop

    nop

    nop

    nop

    nop

    nop

    nop

    nop

    nop

    return-void

    :goto_c

    const v0, 0x1669

    invoke-static {v0}, Ls/h/e/l/l/H;->i(I)V

    goto :goto_1

.end method

函数本身就是壳代码,需要先执行一次,对本身进行解密。

还有一些强度更高的,被加密的函数执行以后,会先调用壳代码解密,然后调用执行原函数,然后在加密回去。甚至可以将dex指令揭秘一条,执行一条,循环解密,这些可能会需要一些技巧,但是都是fart或者说自动脱壳所无法做到的。

抽取方案的问题

确实可能存在更高强度的抽取,我在研究的时候也一堆纠结,但是转换思路想写,抽取壳本身的兼容问题,写的强队越高,越复杂,兼容问题越严重,而且还有性能问题,一般越复杂的加密和解密,都意味着性能成倍的损耗。另外方案价值的问题,如果抽壳的方案写的如此复杂,就像我前面说的,解密要好几层,那么为什么不用dex vmp。

学到了点东西

安全对抗中技术确实是一个问题,但是一个安全产品不是技术的高低问题,而是他是否能符合客户要求,在符合用户要求和最大化利益的情况下,提高技术上线。毕竟要吃饭,这也是对抗中防守方的弱势问题。

native版本的frida-fart

我在上一次写博客推荐我的rxposed的工具的时候,埋了个脱壳的坑,但是有些事没搞完。

讲个笑话:

当时我觉得fart这类工具确实是可以做到内存自动修复的,然后我屁颠屁颠的去找肉丝说我给你修一下,然后肉丝说你去搞搞银行app,然后我去了,我才发现这种code_item偏移位置有问题的dex,理论上确实能做,但是工程里估计很大,只能说,真是尴尬。

网上说fart是主动调用,但是我觉得不太准确,far和frida-fart其实都像是主动加载,博客里说的这些函数需要真正执行一次在dump,更像是主动调用

借鉴一段他的代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

.method public constructor <init>()V

    .registers 2

    goto :goto_c

    :goto_1

    nop

    nop

    nop

    nop

    nop

    nop

    nop

    nop

    nop

    nop

    return-void

    :goto_c

    const v0, 0x1669

    invoke-static {v0}, Ls/h/e/l/l/H;->i(I)V

    goto :goto_1

.end method

函数本身就是壳代码,需要先执行一次,对本身进行解密。

还有一些强度更高的,被加密的函数执行以后,会先调用壳代码解密,然后调用执行原函数,然后在加密回去。甚至可以将dex指令揭秘一条,执行一条,循环解密,这些可能会需要一些技巧,但是都是fart或者说自动脱壳所无法做到的。

抽取方案的问题

确实可能存在更高强度的抽取,我在研究的时候也一堆纠结,但是转换思路想写,抽取壳本身的兼容问题,写的强队越高,越复杂,兼容问题越严重,而且还有性能问题,一般越复杂的加密和解密,都意味着性能成倍的损耗。另外方案价值的问题,如果抽壳的方案写的如此复杂,就像我前面说的,解密要好几层,那么为什么不用dex vmp。

学到了点东西

安全对抗中技术确实是一个问题,但是一个安全产品不是技术的高低问题,而是他是否能符合客户要求,在符合用户要求和最大化利益的情况下,提高技术上线。毕竟要吃饭,这也是对抗中防守方的弱势问题。

native版本的frida-fart

我在上一次写博客推荐我的rxposed的工具的时候,埋了个脱壳的坑,但是有些事没搞完。

讲个笑话:

当时我觉得fart这类工具确实是可以做到内存自动修复的,然后我屁颠屁颠的去找肉丝说我给你修一下,然后肉丝说你去搞搞银行app,然后我去了,我才发现这种code_item偏移位置有问题的dex,理论上确实能做,但是工程里估计很大,只能说,真是尴尬。

  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Frida是一款强大的动态分析工具,可以用于脱壳测试。下面是使用Frida进行脱壳测试的详细教程: 1. 安装Frida 首先需要在电脑上安装Frida,可以从Frida官网下载安装包进行安装。安装完成后,可以在终端中输入以下命令来检查Frida是否安装成功: ``` frida-ps -U ``` 如果输出了设备中运行的进程信息,则Frida安装成功。 2. 查找目标应用程序 使用以下命令来查看设备上所有运行的应用程序: ``` frida-ps -U ``` 找到目标应用程序的进程ID或名称。 3. 编写Frida脚本 编写Frida脚本来实现脱壳功能。以下是一个简单的脚本示例: ``` function dump_memory(address, size, file_path) { var buffer = Memory.readByteArray(ptr(address), size); var file = new File(file_path, 'wb'); file.write(buffer); file.flush(); file.close(); console.log('Dumped memory to ' + file_path); } Interceptor.attach(Module.findExportByName(null, 'memcpy'), { onEnter: function(args) { if (args[0].toInt32() == 0x12345678) { dump_memory(args[1], args[2], '/sdcard/dump.bin'); } } }); ``` 这个脚本会在应用程序调用memcpy函数时,判断目标内存地址是否为0x12345678,如果是则将内存内容保存到指定的文件中。 4. 运行Frida脚本 使用以下命令来运行Frida脚本: ``` frida -U -l script.js -f com.example.app ``` 其中,-U表示连接USB设备,-l指定脚本文件,-f指定目标应用程序。 5. 测试脚本 运行目标应用程序,触发脚本中的条件,查看指定的文件是否成功保存了内存内容。 注意:脚本中的条件和保存路径需要根据实际情况进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值