本来计划年后跑路的,不知道是我太菜,还是疫情原因,投简历都没人搭理我。现在又不能出门,只好自己找点事干了。
本文基于Android8.1分析。如果不想看分析过程,可以直接跳到最后的总结。
自己随便写个app,上传到百度开发者平台去加固。
加固后反编译看下。包名com.example.test下原来的类都没了,多了个com.baidu.protect,assets下面多了几个文件,lib下面多了一个so。猜测是通过libbaiduprotect.so将assets下的文件解密出dex,然后加载。
通过AndroidManifest.xml知道最先执行的class为com.baidu.protect.StubApplication
找到attachBaseContext方法,可以看到先通过Debug.isDebuggerConnected检测是否被调试,如果被调试就不会加载so,直接进行application替换,这样肯定是不行的,因为原来的class都没有被加载进来,程序直接就会崩溃,所以要调试的话需要把这里过掉。
然后看loadLibrary方法,可以看到直接System.loadLibrary(AppInfo.LIBNAME)加载so,AppInfo.LIBNAME就是baiduprotect。
将libbaiduprotect.so用ida打开。可以看到有.init_array,这个数组包含好几个函数,而其他很多函数,包括JNI_OnLoad都被加密了。
现在详细分析.init_array中的每一个函数。
先跳过第一个函数,看下后面的。进到函数sub_6FC4,看下c代码。没有被加密,也没有被混淆,但是其中调用的loc_3E73C被加密了。
现在只能回去分析第一个函数sub_88060了,把垃圾代码删除之后,分析出调用流程,发现全是一些字符操作,应该是在解密,没有发现有反调试的地方。
所以直接动态调试,当第一个函数sub_88060执行完后,dump解密后的so。将其用ida打开,可以看到函数都已经被解密了。
继续分析.init_array中的函数,通过分析,从sub_6FC4到sub_7578这8个函数都在做一件事情,就是向一个列表添加函数,每个函数添加的时候会指定一个数字(索引),将其通过索引排序插入列表。后面的过程中会按顺序调用列表中所有函数。
这8个函数这里就分析其中的sub_6FC4,其余的都类似,有兴趣的可以自己去看。
最后分析得到一个索引(即调用顺序)和函数的映射关系。
.init_array中最后两个函数sub_76BC和sub_7744是初始化tls和mutex相关的,就不看了。
将垃圾代码删除后,得到真实流程。开始我以为会通过时间来判断是否被调试,其实这里获取时间只是统计信息上报。
这里的函数sub_3E628就是调用队列中的所有函数,它的第2个参数会被作为参数传到函数中,判断函数是否该执行。
所以,首先用1作为参数调用队列中的所有函数,通过分析只有sub_B3B4会执行。该函数通过dlsym将libc中的符号获取保存下来,之后调用这些函数都通过指针调用。
继续回到JNI_OnLoad,执行完函数队列中的函数,就该执行函数sub_91E4了,该函数是注册com.baidu.protect.A中的部分本地函数,n001,n002,n003,分别对应的函数为sub_9318,sub_94E4,sub_9564
继续回到JNI_OnLoad,注册函数后,失败就直接返回了,成功则以2作为参数再次调用队列中的所有函数。通过分析,只有sub_3E29C会执行。可以看到,该函数可以接受2和3,现在我们只看参数为2的情况。
现在进入sub_3E36C,其主要就是调用sub_3E3F0,而sub_3E3F0就是通过读取/proc/self/maps文件,通过加载的虚拟机文件,判断虚拟机类型。
至此,libbaiduprotect.so的加载流程就执行完了。
sub_9318中将参数保存起来,然后最主要就是调用了sub_781C,
sub_781C也是被混淆的,但是代码很少,稍微看下,就知道只做了一件事,就是用3作为参数调用函数队列中的所有函数。
通过分析,会有sub_3E29C、sub_40CF8、sub_3DFC4、sub_11F5C、sub_45964这几个函数执行。
先看sub_3E29C,这个函数之前执行过参数为2的部分,现在来看参数为3的部分。先执行sub_13880,通过分析,该函数是获取apk包的签名,然后计算签名的MD5。然后sub_66064将签名的MD5值进行扩展,变为176字节。然后将签名的MD5和扩展后的内容存放在qword_BE690。
再看sub_40CF8,该函数可以接受3和4作为参数,现在先看3,
再看sub_3DFC4,这个函数最主要就是sub_3D6AC,通过解析apk中assets,生成各种路径,然后通过qword_BE2F0生成目录,qword_BE2F0就是之前从libc中获取的mkdir的指针。
再看sub_11F5C,该函数只是调用了sub_BC60,sub_BC60也被混淆了,删除垃圾代码后,流程如下。因为我用的手机是8.1的,所以只看了sdk大于26的,
先看sub_188AC,该函数也是被混淆的,删除垃圾代码后流程如下,
sub_4029C读取/proc/self/maps文件,查找对应的so,修改内存页属性
sub_3FF9C是对函数进行hook,通过动态节,找到重定位节和got,然后替换指定标签的地址。这里分别hook了__android_log_print和mmap,__android_log_print被替换为sub_1B044,这是个空函数,禁用log。mmap被替换为sub_1B070,在加载dex的时候有用,稍后分析。
再看sub_11AB0,最主要的是下面的这个循环,将assets下所有的jar解密为dex,然后通过InMemoryDexClassLoader加载,然后提取DexPathList$Element添加到源classloader中。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-3-3 20:21
被卧勒个槽编辑
,原因: 附件