前言
昨天又去测试了下数字公司的加固,顺便试了下脱壳。
按照以前的办法没搞定。
搜索现成的文章,
基本流程都是过反调试,找入口,找到加密后的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_
对应的源码在
a15K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3q4F1k6s2u0G2K9h3c8^5M7X3g2X3i4K6u0W2j5$3!0E0i4K6u0r3y4g2)9J5k6e0m8Q4x3X3f1H3i4K6g2X3M7U0u0Q4x3V1k6^5M7X3g2X3i4K6u0r3j5i4u0@1i4K6u0r3M7Y4g2F1N6r3W2E0k6g2)9J5c8X3#2A6M7Y4u0G2M7W2)9J5c8X3q4J5N6q4)9#2k6X3#2W2N6r3S2G2k6q4)9J5k6h3R3`.
注:与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)
代码改自5f1K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6J5j5i4N6Q4x3X3g2Y4K9i4c8Z5N6h3u0#2M7$3g2J5j5$3!0F1N6r3g2F1N6q4)9J5k6h3y4G2L8g2)9J5c8X3k6J5k6h3q4C8K9i4y4Z5k6X3!0^5i4K6u0r3P5p5q4F1f1$3!0Q4x3V1k6E0j5i4y4@1k6i4u0Q4x3V1k6u0c8p5q4e0j5%4u0A6M7s2c8Q4x3V1k6u0c8p5q4p5N6h3#2H3e0h3g2E0L8%4u0&6i4K6u0W2M7s2V1`.
另外一种办法是去/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)
代码改自5f1K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6J5j5i4N6Q4x3X3g2Y4K9i4c8Z5N6h3u0#2M7$3g2J5j5$3!0F1N6r3g2F1N6q4)9J5k6h3y4G2L8g2)9J5c8X3k6J5k6h3q4C8K9i4y4Z5k6X3!0^5i4K6u0r3P5p5q4F1f1$3!0Q4x3V1k6E0j5i4y4@1k6i4u0Q4x3V1k6u0c8p5q4e0j5%4u0A6M7s2c8Q4x3V1k6u0c8p5q4p5N6h3#2H3e0h3g2E0L8%4u0&6i4K6u0W2M7s2V1`.
另外一种办法是去/data/data/com.a360.reftest/.jiagu/classes.oat中去找,理论上是可以的。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课