计划是写一个android中so文件反混淆的系列文章,目前这是第三篇。 第一篇:android so文件攻防实战-百度加固免费版libbaiduprotect.so反混淆 第二篇:android so文件攻防实战-某团libmtguard.so反混淆 今天分析的是企业版64位,我用LibChecker查了一下手机上的APP找到的,时间也还比较新。根据其他人的分析可知,libDexHelper.so是指令抽取的实现,libdexjni.so是VMP的实现。
首先因为加密过,肯定是不能直接反编译的,可以在libart.so下断点,进入JNI_onLoad以后就可以dump下来。 不过此时也不能直接F5,还存在以下混淆方式: 1.垃圾指令 这些垃圾指令是在switch的一个永远不会被执行到的分支里面,可以直接将IDA不能MakeCode的地方patch成NOP再MakeCode。 2.字符串加密 有好几个解密字符串的函数,0x186C4,0x7783C,0x95B9C。在android so文件攻防实战-百度加固免费版libbaiduprotect.so反混淆 中我们是交叉引用拿到加密后的字符串和它对应的解密函数的表然后frida主动调用得到的解密后的字符串,但是在这里这个方法就不太好用了。因为这里加密后的字符串是在栈上一个byte一个byte拼起来的,和最后调用解密函数之间可能隔了很多条指令,甚至都不在一个block。 我最后用的是下面这种方案:以0x40110处调用0x186C4处的解密函数为例,这里面字符串解密的逻辑比较简单,需要三个参数。我们可以自己实现也可以用unicorn,我就用unicorn了。
总共有几百处调用,不可能全部人工去这样解出来,我写了另外以一个脚本去调用decstr.py。首先通过交叉引用找到所有调用解密函数的地方,然后把起始地址设为该block的起始地址,结束地址设为调用解密函数的地址,通过unicorn跑出decstr.py需要的三个参数之后调用decstr.py。遇到unicorn.unicorn.UcError也有两个处理策略,一个是跳过该地址( loop_call_prepare_arg1),起始地址不变;一个是将起始地址设为下一条地址(loop_call_prepare_arg2)。当然这套方案还有优化的空间,比如生成调用解密函数需要的参数的代码和最后调用解密函数的代码不在一个block,就处理不了。
更恶心的是还有很多字符串是自己在函数内解密的,这种情况我也没想到有什么好的方法。 3.控制流混淆 第一种是把正常顺序执行的指令打乱成switch的形式,这个影响倒不是太大: 第二种是动态计算跳转地址,基本上类似于在android so文件攻防实战-某团libmtguard.so反混淆 见过的那种,但是要更复杂。 比如这里的指令,在0x1DA0C处给X2赋值,X2此时为.data段中的一个地址,W0为偏移,取出值后在0x1DA18处乘4加上0x1DA20,最后的值就是0x1DA1C处X0的值。那么需要解决这么几个问题: 如何确定0x1DA0C处给X2赋的值 将0x1DA00处的指令改成跳转指令,0x1DA00这个地址又该如何确定 找到所有会跳转到0x1DA1C的指令,将跳转地址改成计算出来的X0的值 第一个问题,其实和字符串解密面临的情况是类似的,比如这里需要找到和"LDR X2, [X29,#0x190+var_118]"对应的"STR XX, [X29,#0x190+var_118]"这条指令,然后再找给XX寄存器赋值的指令,然而这两条指令很可能和BR X0隔了好几个block。我的解决方法是通过IDA提供的idaapi.FlowChar功能,递归前面的block查找。不足之处在于前提条件是IDA正确识别了函数的起始地址,否则会出现我们需要的指令和BR X0不在同一个函数的情况,这样就处理不了。 第二个问题,在递归前面的block的时候就先找到0x1D9D4处这条给W0赋值的指令,然后从0x1D9D4处开始直到0x1DA1C,找到第一个存在交叉引用的地址,也就是0x1DA04。它的前一条指令0x1DA00就是需要改成跳转指令的地方。 第三个问题,确定了0x1DA00之后,那么从0x1DA00到0x1DA1C所有存在交叉引用的地址都要去交叉引用的地方修改跳转地址。不过这里有很多细节。 (1)如果W0是由CSEL,CSET,CSINC这些指令赋值的,像下面这种情况,那么需要把0x1DE80和0x1DE84修改成 B.GE和B.LT。 patch前: patch后: (2)0x1DE80处的CSEL W0, WZR, W8, LT
,这里W8的值是在0x1D9DC MOV W8, #5
赋值的,所以我的代码中有一个register_value_dict,在改掉0x1DA00处的指令之后会读取0x1DA00所在的block到0x1DA1C所在的block的所有指令,找到给寄存器赋值的指令然后把值存起来。 (3)有些地方还会有一条sub指令,这个也要考虑进去,比如下面这种情况0x33394处跳转的地址就应该按照W8为4计算。 最后的脚本放附件了。当然还有一些脚本处理不了的地方,不过问题已经不算太大了,需要的话可以动态调试确定。 4.函数地址动态计算 这个在IDA里面是能看清楚的,v35其实就是off_12EB80[0],即调用0x80FE0处的p329AAB59961F6410ABA963EF972FE303。 接下来我们就来分析libDexHelper.so,来看看它都干了些什么。精力有限,很多地方没能很详细去分析。有些地方分析的可能也不一定对,将就看吧。
JNI_OnLoad(0x3EA68)的分析在最后。
读/proc/self/maps,特征字符串:
获取系统属性,读/proc/%d/cmdline,特征字符串:
off_12EF10:为2表示yunos,art模式;为1表示yunos,dalvik模式;为0表示非yunos。
md5。
字符串解密函数。
返回字符串rw。
返回字符串su。
返回字符串mount。
写classes.dve文件。
读取目录中的文件。
创建String类型的数组,第一个参数是String列表,第二个参数是数组长度。
调用0x19E08创建数组:
调用0x19E08创建数组:
调用0x19E08创建数组:
调用0x19E08创建数组:
system_property_get ro.product.cpu.abi和读/system/lib/libc.so判断是不是x86架构。
查看classes.dve是否存在。
调用0x19E08创建数组:
初始化一些路径,特征字符串:
将libc中的一些函数的地址放到.DATA。
读/proc/self/cmdline,判断是否含有com.miui.packageinstaller从而判断是否由小米应用包管理组件启动。
先system_property_get ro.product.manufacturer和system_property_get ro.product.model判断是否是samsung,然后system_property_get ro.build.characteristics是否为emulator。
注册如下native函数:
system_property_get ro.build.version.release/ro.build.version.sdk/ro.build.version.codename,最终返回sdkversion。
创建一些目录:
模拟器检测,特征字符串:
读proc/pid/cmdline找字符串":bbs",没搞懂这是什么意思。这个函数名是is_magisk_check_process。
调用setOuterContext。
system_property_get ro.product.brand,针对华为/荣耀机型,调用startLoadFromDisk。
getDeclaredFields获取field对象数组之后调用equals,返回查找的指定的field对象。
修改mInitialApplication和mClassLoader。
修改mAllApplications(remove和add)。
模拟器检测,特征字符串:
通过FLAG_DEBUGGABLE判断是debug还是release。
通过android.content.pm.Signature获取签名的md5。
通过access以下文件判断是否被root:
读/proc/self/cmdline,调用java层的com.secneo.apkwrapper.H.j,调用bindService,获取android_id,调用android.app.Application.attach,如果包名是com.huawei.irportalapp.uat调用setOuterContext。
调用java层的com.secneo.apkwrapper.H.f(ff)加载v1filter.jar和原始dex。 查看/proc/self/maps: anon:dalvik-classes.dex extracted in memory from v1filter.jar anon:dalvik-DEX data 把多出来这样的段dump下来。 原始dex: 指令虚拟化是调用JniLib.cV解析执行的,最后一个参数是一个函数code索引,用来查找被虚拟化后的指令,其它是方法参数: v1filter.jar:
hook libcutils.so/liblog.so中的android_log_write和android_log_buf_write,使其返回0。
currentActivityThread-mPackages-LoadedApk-mResources-getAssets。
调用android.content.res.Resources.getAssets,失败再调用0x339FC。
读取assets文件。
对传入参数调用makeInMemoryDexElements,修改dalvik.system.DexFile.mFileName。
初始化下列字符串:
调用0x80458计算包名hash,调用0x75AA8 调用AAssetManager_open读取assets/resthird.data写入v1filter.jar,调用0x31474 (看别人的分析应该读assets下面两个文件:classes0.jar是被加密的dex,classes.dgc是被加密的抽取后的指令。不过我分析的这个样本中没有classes0.jar和classes.dgc,可能是名字变了)
检测dexhunter,dumpclass好像是dexhunter里面的吧。特征字符串:
参数是文件名,返回文件是否存在。
模拟器检测,特征字符串:
system_property_get ro.debuggable,调用检测模拟器的函数。
通过android.hardware.usb.action.USB_STATE监听USB状态。
md5。
hook下列函数(反调试):
system_property_get ro.yunos.version。
hook下列函数(指令抽取还原):
md5。
读/proc/self/maps找到含有包名的段。
调用java层的com.secneo.apkwrapper.H1.find_dexfile。
调用java.lang.StackTraceElement.getMethodName和java.lang.StackTraceElement.getClassName。
加载assets中的classes.dgg。
读/proc/self/maps找到libDexHelper.so。
设置dex2oat的参数,--zip-fd/--oat-fd/--zip-location/--oat-location/--oat-file/--instruction-set。
hook libdvm.so中的函数(类似于0x67544),具体没仔细看,0x5BAA8-0x5BEF8都是被hook后的实现。
hook libc中的下列函数:
根据不同SDK版本返回Name Mangling之后的art::DexFileLoader::open。
根据不同SDK版本返回Name Mangling之后的art::OatFileManager::OpenDexFilesFromOat。
hook下列函数:
patch掉art::Runtime::IsVerificationEnabled。
hook art::DexFileVerifier::Verify(hook后:0x6D38C/0x6D394,直接返回1)。
hook art::DexFileLoader::open(hook后:0x6D39C/0x6D3E8)。
hook下列函数:
hook libdvm.so中的函数,具体没仔细看,0x6EB1C/0x74DEC/0x6FFBC都是被hook后的实现。
读java.lang.DexCache.dexfile(这个dexfile就是解压apk之后根目录的那个classes.dex)。
参数是so文件路径,打开该so文件。
参数是libart.so中的一个函数,返回该函数地址。
第一个参数是so中的函数名,第二个参数是so的相对路径,返回该函数在so中的地址。
参数是libdexfile.so中的一个函数,返回该函数地址。
参数是libjdwp.so中的一个函数,返回该函数地址。
md5。
字符串解密函数。
计算传入字符串的hash(不完全是md5)。
热补丁检测,特征字符串:
调用0x79270。
hook libc中的下列函数:
hook libdvm.so中的函数(类似于0x44708),具体没仔细看,0x856C0/0x87F00/0x87F4C都是被hook后的实现。
patch掉art::Runtime::UseJitCompilation。
hook函数实现。
读/proc/sys/fs/inotify/max_queued_watches。
读/proc/sys/fs/inotify/max_user_instances。
读/proc/sys/fs/inotify/max_user_watches。
看起来好像是通过判断时间实现的反调试。
字符串查找函数。
字符串解密函数。
socket连接。
frida检测,读/proc/self/task,特征字符串:gum-js-loop;读/proc/self/fd,特征字符串linjector。
xposed检测,特征字符串:
hook框架检测,特征字符串:
调用0x96398检测frida,system_property_get ro.product.model,调用0x9FD88检测xposed和自动脱壳机,hook dlopen(hook后:0x9B89C)和ptrace(hook后:0x95BF8)。
通过读取/proc/%d/status判断TracerPid等实现反调试。
通过读取/proc/%d/wchan判断是不是ptrace_stop实现反调试。
通过读取/proc/%ld/task/%ld/status判断TracerPid等实现反调试。
通过java.lang.StackTraceElement.getClassName打印函数调用栈进行xposed检测。
通过java.lang.ClassLoader.getSystemClassLoader.loadClass打印类加载器进行xposed检测。
调用0x9ED44和0x9F770,通过判断ServiceManager里是否有user.xposed.system进行xposed检测,然后检测自动脱壳机: fart(https://github.com/hanbinglengyue/FART) FUPK3(https://github.com/F8LEFT/FUPK3) Youpk(https://github.com/Youlor/Youpk) 检测方法是判断下列类或者方法是否存在:
getInstalledApplications获取系统中安装的APP信息。
解密出字符串Java和JNI_OnLoad,hook了几个函数,被hook的原地址未知,新地址:0xA43A0/0xA485C/0xA48F4/0xA54B0;hook dlsym(hook后:0xA4554)和dlopen(hook后:0xA4D30)。
hook libc中的下列函数:
system_property_get debug.atrace.tags.enableflags,hook bionic_trace_begin和bionic_trace_end(hook后:0xA8EF4和0xA8EF8,直接返回),没有找到则hook g_trace_marker_fd(hook后:0xA8EFC,返回-1)。 这些hook是为了透明加密,具体没仔细看,之前论坛也有人分析过,估计应该没有太大的变化:梆梆加固之透明加密分析 。
sha1。
md5init。
base64。
base64。
APK签名相关。
sha1。
sha1init。
md5。
调用0xD75A0。
读/proc/self/cmdline。
hook libdvm.so中的函数(hook后:0xD6988)。
根据off_12EF10处的值判断调用0xD6484还是0xD6578。
hook libaoc.so中的函数(hook后:0xD69BC)。
JNI_OnLoad。分析环境pixel4 android10,动态分析过程中一些没有被调用的函数不再分析。 1.初始化cpuabi字符串(arm64)于0x12E7C8 2.初始化so名字符串(libDexHelper)于0x12EC38 3.初始化字符串com/secneo/apkwrapper/H于0x137B10 4.调用0x1E520 5.
6.将包名存于0x138040 7.
8.调用0x218A8 9.
10.读/proc/pid/fd,匹配包名+base.apk,0x12EA38存放指向base.apk完整路径的指针的指针 11.
12.将得到的结果和###MPAAS###比较,0x12E7F8指向0x137D9C,0x137D9C存放比较结果 13.调用0x22068 14.调用0x23568 15.调用0x1F250 16.将字符串lib/libart.so存放于0x1378A8 17.读/proc/self/maps,找权限为"r-xp"的lib/libart.so 18.初始化下列字符串:
19.fstat /data/app/cn.missfresh.application-xxx/oat/arm64/base.odex 20.计算md5(不太清楚具体算的什么),0x12EC98指向0x130080,0x130080存放计算结果 21.access /data/user/0/cn.missfresh.application/.cache/classes.dve,不存在则把之前算的md5写入该文件;存在则读取其中的值和之前算的比较,不相等则写入新计算的值 22.调用0x3371C(根据标记位决定是否调用) 23.调用0x1FDC8 24.初始化下列字符串:
25.调用0x3766C 26.调用0xB4B94 27.调用0x9C0BC 28.调用0xD5CDC 29.调用0x24C08 30.调用0x1C40C 31.调用0xA7D3C 32.结束
梆梆APP加固产品方案浅析:https://www.cnblogs.com/2014asm/p/14547218.html 某加固详细分析总结,另附该加固脱壳机: https://bbs.pediy.com/thread-252828.htm
样本混淆强度还是比较大的,比前两篇文章中的样本要复杂很多。不过分析过程中也是有一些技巧:比如位置相邻的函数之前其实是有联系的,和另外某些壳的代码有类似的地方(估计也是抄来抄去),可以网上搜一下旧版本的分析博客,有一些函数名和字符串没有被抹去,等等。
import
sys
import
unicorn
import
binascii
import
threading
import
subprocess
from
capstone
import
*
from
capstone.arm64
import
*
with
open
(
"C:\\Users\\hjy\\Downloads\\out1.fix.so"
,
"rb"
) as f:
sodata
=
f.read()
uc
=
unicorn.Uc(unicorn.UC_ARCH_ARM64, unicorn.UC_MODE_ARM)
code_addr
=
0x0
code_size
=
8
*
0x1000
*
0x1000
uc.mem_map(code_addr, code_size)
stack_addr
=
code_addr
+
code_size
stack_size
=
0x1000000
stack_top
=
stack_addr
+
stack_size
-
0x8
uc.mem_map(stack_addr, stack_size)
uc.mem_write(code_addr, sodata)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X29, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X28, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X27, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X26, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X25, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X24, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X23, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X22, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X21, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X20, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X19, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X18, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X17, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X16, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X15, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X14, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X13, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X12, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X11, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X10, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X9, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X8, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X7, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X6, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X5, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X4, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X3, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X2, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X1, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X0, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_SP, stack_top)
X0
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X0)
uc.mem_write(X0, bytes.fromhex(sys.argv[
1
]))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X1,
int
(sys.argv[
2
],
16
))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X2,
int
(sys.argv[
3
],
16
))
uc.emu_start(
0x1777C
,
0x17780
)
X0
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X0)
decstr
=
uc.mem_read(X0,
80
)
print
(
"decstr:"
, decstr)
uc.mem_unmap(stack_addr, stack_size)
uc.mem_unmap(code_addr, code_size)
import
sys
import
unicorn
import
binascii
import
threading
import
subprocess
from
capstone
import
*
from
capstone.arm64
import
*
with
open
(
"C:\\Users\\hjy\\Downloads\\out1.fix.so"
,
"rb"
) as f:
sodata
=
f.read()
uc
=
unicorn.Uc(unicorn.UC_ARCH_ARM64, unicorn.UC_MODE_ARM)
code_addr
=
0x0
code_size
=
8
*
0x1000
*
0x1000
uc.mem_map(code_addr, code_size)
stack_addr
=
code_addr
+
code_size
stack_size
=
0x1000000
stack_top
=
stack_addr
+
stack_size
-
0x8
uc.mem_map(stack_addr, stack_size)
uc.mem_write(code_addr, sodata)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X29, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X28, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X27, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X26, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X25, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X24, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X23, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X22, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X21, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X20, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X19, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X18, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X17, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X16, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X15, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X14, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X13, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X12, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X11, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X10, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X9, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X8, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X7, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X6, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X5, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X4, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X3, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X2, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X1, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X0, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_SP, stack_top)
X0
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X0)
uc.mem_write(X0, bytes.fromhex(sys.argv[
1
]))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X1,
int
(sys.argv[
2
],
16
))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X2,
int
(sys.argv[
3
],
16
))
uc.emu_start(
0x1777C
,
0x17780
)
X0
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X0)
decstr
=
uc.mem_read(X0,
80
)
print
(
"decstr:"
, decstr)
uc.mem_unmap(stack_addr, stack_size)
uc.mem_unmap(code_addr, code_size)
import
unicorn
import
binascii
import
threading
import
subprocess
from
capstone
import
*
from
capstone.arm64
import
*
inscnt
=
0
start_addr
=
0
end_addr
=
0
stop_addr
=
0
stop_addr_list
=
[]
def
hook_code(uc, address, size, user_data):
global
inscnt
global
end_addr
global
stop_addr
global
stop_addr_list
md
=
Cs(CS_ARCH_ARM64, CS_MODE_ARM)
for
ins
in
md.disasm(sodata[address:address
+
size], address):
stop_addr
=
ins.address
if
ins.address
in
stop_addr_list:
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address
+
size)
return
inscnt
=
inscnt
+
1
if
(inscnt >
500
):
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC,
0xffffffff
)
return
if
ins.mnemonic.find(
"b."
) !
=
-
1
:
print
(
"will pass 0x%x:\t%s\t%s"
%
(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address
+
size)
return
if
ins.mnemonic.find(
"bl"
) !
=
-
1
:
print
(
"will pass 0x%x:\t%s\t%s"
%
(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address
+
size)
return
if
ins.op_str
in
[
"x0"
,
"x1"
,
"x2"
,
"x3"
]:
X1
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X1)
if
X1 >
0x105A88
:
print
(
"will pass 0x%x:\t%s\t%s"
%
(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address
+
size)
return
if
ins.op_str.startswith(
"#0x"
):
addr
=
int
(ins.op_str[
3
:],
16
)
if
(addr >
0x14E50
and
addr <
0x15820
) \
or
addr
=
=
0x186C4
\
or
addr >
0x105A88
:
print
(
"will pass 0x%x:\t%s\t%s"
%
(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address
+
size)
return
def
call_prepare_arg():
global
inscnt
global
start_addr
global
end_addr
global
stop_addr
global
stop_addr_list
inscnt
=
0
uc
=
unicorn.Uc(unicorn.UC_ARCH_ARM64, unicorn.UC_MODE_ARM)
code_addr
=
0x0
code_size
=
8
*
0x1000
*
0x1000
uc.mem_map(code_addr, code_size)
stack_addr
=
code_addr
+
code_size
stack_size
=
0x1000000
stack_top
=
stack_addr
+
stack_size
-
0x8
uc.mem_map(stack_addr, stack_size)
uc.hook_add(unicorn.UC_HOOK_CODE, hook_code)
uc.mem_write(code_addr, sodata)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X29, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X28, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X27, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X26, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X25, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X24, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X23, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X22, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X21, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X20, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X19, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X18, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X17, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X16, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X15, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X14, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X13, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X12, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X11, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X10, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X9, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X8, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X7, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X6, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X5, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X4, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X3, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X2, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X1, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X0, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_SP, stack_top)
uc.emu_start(start_addr, end_addr)
X0
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X0)
decstr
=
uc.mem_read(X0,
80
)
end_index
=
decstr.find(bytearray(b
'\x00'
),
1
)
decstr
=
decstr[:end_index]
decstr
=
binascii.b2a_hex(decstr)
decstr
=
decstr.decode(
'utf-8'
)
X1
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X1)
X2
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X2)
pi
=
subprocess.Popen([
'C:\\Python38\\python.exe'
,
'decstr.py'
, decstr,
hex
(X1),
hex
(X2)], stdout
=
subprocess.PIPE)
output
=
pi.stdout.read()
print
(output)
def
loop_call_prepare_arg1():
global
inscnt
global
end_addr
global
stop_addr
global
stop_addr_list
loopcnt
=
0
stop_addr_list
=
[]
while
True
:
try
:
loopcnt
=
loopcnt
+
1
if
(loopcnt >
200
):
break
call_prepare_arg()
except
unicorn.unicorn.UcError:
print
(
"adding...."
)
print
(
hex
(stop_addr))
stop_addr_list.append(stop_addr)
else
:
break
def
loop_call_prepare_arg2():
global
inscnt
global
end_addr
global
stop_addr
global
stop_addr_list
global
start_addr
loopcnt
=
0
stop_addr_list
=
[]
while
True
:
try
:
loopcnt
=
loopcnt
+
1
if
(loopcnt >
200
):
break
call_prepare_arg()
except
unicorn.unicorn.UcError:
start_addr
=
stop_addr
+
4
else
:
break
with
open
(
"C:\\Users\\hjy\\Downloads\\out1.fix.so"
,
"rb"
) as f:
sodata
=
f.read()
all_addr
=
[]
with
open
(
'xref_decstr.txt'
,
'r'
, encoding
=
'utf-8'
) as f:
for
line
in
f:
addr
=
"0x"
+
line[
2
:]
addr
=
int
(addr,
16
)
all_addr.append(addr)
for
i
in
all_addr:
print
(
"i:"
)
print
(
hex
(i))
end_addr
=
i
CODE
=
sodata[i
-
4
:i]
md
=
Cs(CS_ARCH_ARM64, CS_MODE_ARM)
for
x
in
md.disasm(CODE, i
-
4
):
mnemonic
=
x.mnemonic
while
mnemonic !
=
"ret"
\
and
mnemonic !
=
"b"
\
and
mnemonic !
=
"br"
\
and
mnemonic !
=
"cbz"
\
and
mnemonic !
=
"cbnz"
:
i
=
i
-
4
CODE
=
sodata[i
-
4
:i]
for
x
in
md.disasm(CODE, i
-
4
):
mnemonic
=
x.mnemonic
start_addr
=
i
print
(
"start_addr:"
)
print
(
hex
(start_addr))
print
(
"end_addr:"
)
print
(
hex
(end_addr))
loop_call_prepare_arg1()
loop_call_prepare_arg2()
import
unicorn
import
binascii
import
threading
import
subprocess
from
capstone
import
*
from
capstone.arm64
import
*
inscnt
=
0
start_addr
=
0
end_addr
=
0
stop_addr
=
0
stop_addr_list
=
[]
def
hook_code(uc, address, size, user_data):
global
inscnt
global
end_addr
global
stop_addr
global
stop_addr_list
md
=
Cs(CS_ARCH_ARM64, CS_MODE_ARM)
for
ins
in
md.disasm(sodata[address:address
+
size], address):
stop_addr
=
ins.address
if
ins.address
in
stop_addr_list:
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address
+
size)
return
inscnt
=
inscnt
+
1
if
(inscnt >
500
):
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC,
0xffffffff
)
return
if
ins.mnemonic.find(
"b."
) !
=
-
1
:
print
(
"will pass 0x%x:\t%s\t%s"
%
(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address
+
size)
return
if
ins.mnemonic.find(
"bl"
) !
=
-
1
:
print
(
"will pass 0x%x:\t%s\t%s"
%
(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address
+
size)
return
if
ins.op_str
in
[
"x0"
,
"x1"
,
"x2"
,
"x3"
]:
X1
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X1)
if
X1 >
0x105A88
:
print
(
"will pass 0x%x:\t%s\t%s"
%
(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address
+
size)
return
if
ins.op_str.startswith(
"#0x"
):
addr
=
int
(ins.op_str[
3
:],
16
)
if
(addr >
0x14E50
and
addr <
0x15820
) \
or
addr
=
=
0x186C4
\
or
addr >
0x105A88
:
print
(
"will pass 0x%x:\t%s\t%s"
%
(ins.address, ins.mnemonic, ins.op_str))
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_PC, address
+
size)
return
def
call_prepare_arg():
global
inscnt
global
start_addr
global
end_addr
global
stop_addr
global
stop_addr_list
inscnt
=
0
uc
=
unicorn.Uc(unicorn.UC_ARCH_ARM64, unicorn.UC_MODE_ARM)
code_addr
=
0x0
code_size
=
8
*
0x1000
*
0x1000
uc.mem_map(code_addr, code_size)
stack_addr
=
code_addr
+
code_size
stack_size
=
0x1000000
stack_top
=
stack_addr
+
stack_size
-
0x8
uc.mem_map(stack_addr, stack_size)
uc.hook_add(unicorn.UC_HOOK_CODE, hook_code)
uc.mem_write(code_addr, sodata)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X29, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X28, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X27, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X26, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X25, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X24, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X23, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X22, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X21, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X20, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X19, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X18, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X17, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X16, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X15, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X14, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X13, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X12, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X11, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X10, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X9, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X8, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X7, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X6, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X5, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X4, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X3, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X2, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X1, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_X0, stack_addr)
uc.reg_write(unicorn.arm64_const.UC_ARM64_REG_SP, stack_top)
uc.emu_start(start_addr, end_addr)
X0
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X0)
decstr
=
uc.mem_read(X0,
80
)
end_index
=
decstr.find(bytearray(b
'\x00'
),
1
)
decstr
=
decstr[:end_index]
decstr
=
binascii.b2a_hex(decstr)
decstr
=
decstr.decode(
'utf-8'
)
X1
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X1)
X2
=
uc.reg_read(unicorn.arm64_const.UC_ARM64_REG_X2)
pi
=
subprocess.Popen([
'C:\\Python38\\python.exe'
,
'decstr.py'
, decstr,
hex
(X1),
hex
(X2)], stdout
=
subprocess.PIPE)
output
=
pi.stdout.read()
print
(output)
def
loop_call_prepare_arg1():
global
inscnt
global
end_addr
global
stop_addr
global
stop_addr_list
loopcnt
=
0
stop_addr_list
=
[]
while
True
:
try
:
loopcnt
=
loopcnt
+
1
if
(loopcnt >
200
):
break
call_prepare_arg()
except
unicorn.unicorn.UcError:
print
(
"adding...."
)
print
(
hex
(stop_addr))
stop_addr_list.append(stop_addr)
else
:
break
def
loop_call_prepare_arg2():
global
inscnt
global
end_addr
global
stop_addr
global
stop_addr_list
global
start_addr
loopcnt
=
0
stop_addr_list
=
[]
while
True
:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2022-7-20 14:14
被houjingyi编辑
,原因:
上传的附件: