apk加固工具探究系列——advmp | 宜武汇-ag真人国际厅网站

前言

分析了obfuscapk,这一篇文章继续分析另一个apk加固工具advmp。
作者说明:
github地址:
简单来说,advmp参考dalvik虚拟机的解释器对字节码进行解释执行。代码结构如下。

  • advmptest:测试用的项目。
  • base:java写的工具代码。
  • control-centre:java写的控制加固流程的代码。
  • separator:java写的抽离方法指令,然后将抽离的指令按照自定义格式输出,并同时输出c文件的代码。
  • template/jni:c写的解释器的代码。
  • ycformat:java写的用于保存抽取出的指令等数据的自定义的文件格式代码。

我们来写一个demo,看看加固前后的效果:

代码中默认对separatortest方法进行加固。可以看到加固后separatortest方法已经变成一个native方法,并且加载了advmp.so。

dalvik虚拟机的解释器

首先参考infoq上几篇文章回顾下dalvik虚拟机的解释器。我们知道可以通过registernatives函数注册native方法,最后调用到dvmsetnativefunc函数中将method的nativefunc指向dvmcalljnimethod函数。

在dvmcallmethodv函数中将ins指向第一个参数,如果不是静态方法将this指针放入ins,根据后面参数的类型依次将后面的参数放入ins。

如果调用的是native方法就会进入method的nativefunc指向的dvmcalljnimethod函数;如果调用的是java方法就会进入dvminterpret函数。

下面我们来分析dvminterpret函数。dvminterpret函数选择解释器(这里以portable解释器为例),调用dvminterpretportable函数。dvminterpretportable函数通过define_goto_table定义了一个 handlertable[knumpackedopcodes]数组。数组元素通过h宏定义,比如h(op_return_void)展开后得到&&op_op_return_void,表示op_op_return_void的位置。op_op_return_void通过handle_opcode宏定义。

之后dvminterpretportable函数中调用了finish(0)取第一条指令并执行。移动pc,然后获取对应指令的操作码到inst。根据inst获取该指令的操作码(一条指令包含操作码和操作数),然后goto到该操作码对应的label处理处。在对应label处理处从指令中提取参数,比如inst_a或inst_b。处理后再次调整pc,使得能处理下一条指令。

advmp原理

了解了dalvik虚拟机的解释器原理之后我们就可以理解advmp加壳的过程了。
插入system.loadlibrary指令加载advmp.so:

抽取separatortest方法的代码写到classes.yc文件中,生成新的separatortest方法(native)。yc文件为自定义格式,保存了抽取出来的方法指令/访问标志/参数个数等等信息:

将separatortest方法对应的c代码和注册该方法的c代码写到advmp_separator.cpp文件中,然后将该文件中的代码合并到定义了jni_onload方法的avmp.cpp文件中,如下所示为生成的advmp_separator.cpp文件:

jni_onload中首先调用registerfunctions函数然后释放并解析yc文件:

在separatortest方法对应的c代码中调用了bwdvminterpretportable函数,第一个参数为从yc文件中得到的data,bwdvminterpretportable函数首先要做类似于dvmcallmethodv函数的工作,然后就可以像dvminterpretportable函数一样对字节码进行解释执行了。

参考资料

1.

原文链接:https://xz.aliyun.com/t/6536

网络摘文,本文作者:15h,如若转载,请注明出处:https://www.15cov.cn/2023/08/27/apk加固工具探究系列-advmp/

发表评论

邮箱地址不会被公开。 必填项已用*标注

网站地图