要不要写这篇文章我是想了很久的,本来不想再写;写文章看似简单,实际上合理的组织语言写一篇即有点深度又易懂的文章是很难的;但自己许下的愿就这样半途而废有悖天地法则,所谓天圆地方,圆圆满满,做事需有头有尾,乃为规律。
我同样秉着和上篇文章一样的态度,尽量用浅显的语言让更多的人了解它。
想研究无线保镖中的安全特性,你就不得不弄懂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执行字节码工作大致如下:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)