首页
社区
课程
招聘
[原创]还原数字公司dex加固opcode映射关系
发表于: 2018-3-9 18:20 9973

[原创]还原数字公司dex加固opcode映射关系

2018-3-9 18:20
9973
前言
昨天又去测试了下数字公司的加固,顺便试了下脱壳。
按照以前的办法没搞定。
搜索现成的文章,
基本流程都是过反调试,找入口,找到加密后的code_item,解密code_item,
然后找到opcode的映射关系,还原出原始的opcode。

我对这种加固的理解是:类似cpu的多核执行的方式。也想过不用分析,
直接的通用的还原办法,不过目前没想到,似乎也没法,因为这个的确是在
自己实现的代码中执行dalvik opcode。除非能跟到dex_pc,

一、找入口
1.构造demo
按照官方文档写了一段这样的代码

对应的code_item是

android手机目前是andorid 5所以基于5的art来弄,

enter的值就是注册jni函数的入口了,没加固的时候是0x00
注:不同rom偏移偏移不一定是10*4,具体参考源码
原理是art_method jni 的入口entry_point_from_jni_
对应的源码在
http://androidxref.com/5.0.0_r2/xref/art/runtime/mirror/art_method.h
注:与dvm dvmUseJNIBridge 方法类似只是不用去hook
上传加固后得到的入口是0xa369415f
2.调试
目的是找opcode对照表,所以采用白盒的方式,不用启动的时候附加,
所以不过反调试。
打开app直接AS附加成功,br s -a 0xa369415e 设置断点后触发,
结果直接挂了,这里折腾半天,以为遇到了什么反调试,结果是lldb
在识别arm,thumb有问题。所以放弃AS还是用ida来调。
ida调试的时候需要先启动应用,再启动android_server
附加后成功下段到


二、找 code_item
这个地方本来不想dump so的,结果还是需要dump下方便分析
也根据前人的文章有个内存加载的so
1.dump so
找到debug006的开头,加载这个是1k对齐的,所以直接找很快。

找到这个内存加载文件的头了,直接可以肉眼解密,与或0x52
dump脚本,大小是猜就行了。
import idautils
import idc
import idaapi
import struct


def main(ea_start, ea_end, save_file):    
    print '[*]begin to dump segment'

    count = 0
    
    handle_f = open(save_file, 'wb')
    for byte_addr in range(ea_start, ea_end):
        count += 1
        byte_value = idaapi.get_byte(byte_addr)
        if count <= 340 :
            handle_f.write(struct.pack('B',byte_value ^ 0x52))
        else :
            handle_f.write(struct.pack('B',byte_value))
    
    handle_f.close()
    hooks = idaapi.DBG_Hooks()
    hooks.hook()
          
    print '[*]script by freakish, enjoy~~'       
    print '[*]script finish'


ea_start = 0xA3687000
ea_end = 0xa3729408
save_file = 'd:/text.so'

main(ea_start, ea_end, save_file)
代码改自https://raw.githubusercontent.com/freakishfox/xAnSo/master/IDAScript/IDADumpMemory.py
另外一种办法是去/data/data/com.a360.reftest/.jiagu/classes.oat中去找,理论上是可以的。
3.找虚拟机入口
根据参数和返回值,sub_D930动态调试的时候的unk_A3694930就是这个虚拟机的入口了

这个函数有点大,折腾许久,根据调试和参考之前那三篇文章定位到sub_3FE74应该就是解释器入口

看到这个函数不管前面在干嘛,直接定位sub_3FF66函数了。
import idautils
import idc
import idaapi
import struct


def main(ea_start, ea_end, save_file):    
    print '[*]begin to dump segment'

    count = 0
    
    handle_f = open(save_file, 'wb')
    for byte_addr in range(ea_start, ea_end):
        count += 1
        byte_value = idaapi.get_byte(byte_addr)
        if count <= 340 :
            handle_f.write(struct.pack('B',byte_value ^ 0x52))
        else :
            handle_f.write(struct.pack('B',byte_value))
    
    handle_f.close()
    hooks = idaapi.DBG_Hooks()
    hooks.hook()
          
    print '[*]script by freakish, enjoy~~'       
    print '[*]script finish'


ea_start = 0xA3687000
ea_end = 0xa3729408
save_file = 'd:/text.so'

main(ea_start, ea_end, save_file)
代码改自https://raw.githubusercontent.com/freakishfox/xAnSo/master/IDAScript/IDADumpMemory.py
另外一种办法是去/data/data/com.a360.reftest/.jiagu/classes.oat中去找,理论上是可以的。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 1
支持
分享
最新回复 (12)
雪    币: 303
活跃值: (179)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
2
思路很不错,但现在vmp最大问题不是分析,而是怎么批量解决,当然找到了映射关系,或者可以对这种置换表批量,但像DX那种,连数据都是CPP  ollvm后,硬编码搞的,手工还原起来不适合业务需求
2018-3-9 19:04
0
雪    币: 1535
活跃值: (695)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢楼主分享!厉害
2018-3-10 11:11
0
雪    币: 7
活跃值: (263)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
数字的壳,兼容性确实不错
2018-3-10 11:16
0
雪    币: 131
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
学习一下  感谢分享!
2018-3-10 14:41
0
雪    币: 203
活跃值: (1756)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学习一下    感谢分享!
2018-3-11 12:46
0
雪    币: 446
活跃值: (145)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2018-3-12 08:43
0
雪    币: 33
活跃值: (779)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
学习一下        感谢分享!
2018-3-12 10:34
0
雪    币: 237
活跃值: (3183)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
9
问下mid+10*4这个10*4是怎么得来的。谢谢。代码完全看不出偏移
2018-3-15 16:37
0
雪    币: 116
活跃值: (290)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
10
gtict 问下mid+10*4这个10*4是怎么得来的。谢谢。代码完全看不出偏移
class  Box
{
      public:
            double  length;      //  盒子的长度
            double  breadth;    //  盒子的宽度
            double  height;      //  盒子的高度
};
~=
struct  Box
{
    double  length;      //  盒子的长度
            double  breadth;    //  盒子的宽度
            double  height;      //  盒子的高度
};
2018-3-15 16:56
0
雪    币: 237
活跃值: (3183)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
11
lpcdma class Box { public: double length; // 盒子的长度 double breadth; // 盒子的宽度 do ...
我意思是entry_point_from_jni_入口地址跟add地址在代码里面没有体现出来,,不是具体计算。
2018-3-15 17:24
0
雪    币: 237
活跃值: (3183)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
12
2018-3-15 17:30
0
雪    币: 84
活跃值: (95)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
13
厉害,收藏
2018-3-20 19:44
0
游客
登录 | 注册 方可回帖
返回
//