乾为天
要不要写这篇文章我是想了很久的,本来不想再写;写文章看似简单,实际上合理的组织语言写一篇即有点深度又易懂的文章是很难的;但自己许下的愿就这样半途而废有悖天地法则,所谓天圆地方,圆圆满满,做事需有头有尾,乃为规律。
我同样秉着和上篇文章一样的态度,尽量用浅显的语言让更多的人了解它。
地水师
想研究无线保镖中的安全特性,你就不得不弄懂litevm;如avmp、安全对抗、数据收集等,很多核心安全的实现被内置在这个litevm中,sgmain6.3.80对应sgavmp6.3.29中还没有litevm,由此可以看出litevm和avmp是独立的,两者并不存在直接关系。avmp的时间早于litevm,litevm是一个较新版本的安全组件。
其实义如其名litevm就是一个小的轻量的vm,下面是我给它的一个定义:
火天大有
说什么都没有直接拨开它更具说服力,我们先看看它的sdk中暴露的组件包结构形式:
在看看sdk中接口形式:
看看sdk中litevm包装类:
我们在看看最接近sgmain的部分:
看了这么多可以反过来证实一下我上面说的话了吧,他们预期将来对外提供一系列的安全方法,这些暴露给上层调用的方法是基于dex的方法(至于它将来内部想通过什么方式提供,如dex vmp、 jni反射、或者elf vmp、直接字节码,这都不重要);不过它可不仅仅提供dex方式的方法,它内部是个虚拟机,它可以提供任何方式的方法,并且保镖内部调用lvm完全和上层没有关系,vm执行的是字节码,vm还可以vmp化。sgavmp的字节码加载、签名计算都调用了lvm。或许在不久的将来你将无法在无线保镖中找到sgavmp的踪影。
山天大畜
就我研究的版面目前还未能提供它上层暴露的所有功能,上层也没有显著调用lvm的地方,应该是目前版本还未实现那些功能。目前只提供内部调用,在无线保镖内部其他组件通过lvm command方式调用lvm相关逻辑,这个后面再说。
想研究lvm首先需要了解它的创建过程,我们大致看一下它的创建过程。
初九:有厉、利己
我们就以从上到下的次序来看它的创建过程,首先通过代理调用创建lvm实例:
九二:舆说輹
在通过doCommand调用底层sgmain的command方法:
而0x30d5=12501,对应native层的command是1,0x19,1,这也恰好是创建lvm的地方。
不过从下层看你会发现更多,你会发现1,0x19,x是一系列和lvm相关的命令:
九三:良马遂,利艰贞。日闲舆卫,利有攸往
创建过程比较复杂,会生成很多的数据结构,如外层litevm,实例lvm_inst、lvm context等、同时初始化这些结构,如计数、索引、实例方法等。
注册lvm方法,这些方法包含系统方法,jni方法,和sgmain内部方法。
总之为lvm准备先决条件。
风火家人
初九:闲在家,悔亡
在执行command时,sgmain优先在lvm_command中查找command,找不到在去普通的command中查找。lvm command查找主要存在两个主链; 分别由0x2261、0x2622作为表头,没找到返回0, 外层返回0x52。找到后即跳转到指定的command处。
但lvm字节码最终的执行入口都是command1,0x19,2; 执行过程是调用lvm获取lvm_runtime、打开runtime,拷贝外部参数到lvm栈,进入lvm执行字节码,关闭lvm_runtime开关,得到返回结果。
六四:富家,大吉
真正的程序逻辑影射的是lvm对应的字节码,字节码的解释执行就对应着程序逻辑的前进。lvm执行字节码工作大致如下:
九五:王假有家,勿恤,吉
这里有一个比较有意思的地方,在执行字节码前先解码,这个解码不是解密,而是把外部的字节码转换为lvm内部能够解释执行的code,我把这种code称之为lvm_vcode;每条vcode都对应一个handler,vcode的handler可以相同,也可以不同;它还可以是lvm_method。lvm是基于栈的。
如这里列举一条字节码的解密过程(字节码好像也是32位):
上九:有孚威如。终吉
每个vcode对应的handler都很短,handler的主要责任就是执行vcode,vcode中标明了该执行的操作,如完成类似寄存器移动呀、两个数的累加呀、调用外部函数等。vcode运算都是基于lvm栈进行的,你认为它有寄存器也可以,认为没有也可以。下面是一个短小的handler的图示:
坎为水
我们以第一条vcode的执行过程为例,字节码执行的第一步就是找到第一个vcode的handler(第一个handler一般都是保存栈信息):
然后更新vm的pc:
保存栈信息(第一vcode的handler):
进入下一个vcode:
雷泽归妹
就像jvm虚拟机一样,java字节码中可以调用java方法(自己实现的)、java库方法、native方法,lvm也提供了类似的方法调用,调用lvm自实现方法,调用外部方法(库函数如libc的方法、JNI方法)、调用sgmain方法。大致如下图:
bridge列表,有我单独标识的:
如调用lvm方法入口:
根据解析vcode对应调用外部方法的类型调用真正的外部方法:
外部方法部分截图:
火水未济
好,虽然写的有些急促和不再状态,但我感觉我应该描述清楚了,最后赠上几个数据结构(不保证完全准确性):
lvm_method:
lvm_vcode:
lvm_runtime:
好,手工,累坏我了。
本人该项目github地址: https://github.com/ylcangel/crack_litevm
该文档仅仅用来学习交流,用来提高安全门槛,不能用来做恶意事情,否则后果自付!转载需标明出处,否则发现必究!!!
[培训]内核驱动高级班,冲击BAT一流互联网大厂工
作,每周日13:00-18:00直播授课