源码分析 脱壳神器ZjDroid工做原理

0. 神器ZjDroid

Xposed框架的另一个功能就是实现应用的简单脱壳,其实说是Xposed的做用其实也不是,主要是模块编写的好就能够了,主要是利用Xposed的牛逼Hook技术实现的,下面就先来介绍一下这个脱壳模块工具ZjDroid的原理,由于他是开源的,因此咋们直接分析源码便可,源码的下载地址:https://github.com/halfkiss/ZjDroid 不过惋惜的时候他只公开了Java层的代码,而native层的代码并无公开,可是分析源码以后会发现最重要的功能就在native层,不过也不要紧,等分析到那里的时候我在给你们讲解底层的大体实现方案便可。java


1. 源码分析ZjDroid原理(

下面就来详细的分析一下ZjDroid工具的源码吧,他是一个Eclipse工程导入很简单,基于以前的Xposed模块编写的经验,咱们知道找到入口代码也很简单,在assets目录下有一个xposed_init文件中就记录了模块的入口类:git

而后咱们直接进入到这个类查看便可:github

看到了,遵循统一规则,实现了IXposedHookLoadPackage接口,实现handleLoadPackage回调方法便可,下面继续分析入口方法ModuleContext的initModuleContextshell

 

发现这开始拦截Application的onCreate方法了,而这个方法通常是每一个应用程序的启动方法,在这里作拦截操做也是合情合理的,在看看拦截以后作了什么,也就是ApplicationOnCreateHook类的实现:设计模式

  在这里开始了真正的拦截操做了,主要是添加了一个广播,也就是说设备中每一个应用在启动的时候都回去注册这个广播,而若是后续发送一个这样对应Action的广播的话,每一个应用程序都会收到。因此这里能够看到,核心工做就在这个广播的接受以后作了,接下来继续去看这个广播的定义:

  果真在这里,能够看到了首先会经过发送广播的intent中携带一些数据过来,主要是两个数据:

一个是进程id:api

这个做用主要是为了过滤其余应用,只处理本应用的逻辑,由于这个广播发送以后全部的应用都能接收到,可是咱们脱壳有时候确定只是针对于某一个应用,那么只须要在这个应用的广播接收中作处理便可。cookie

一个是命令字符串:这个是为了发送广播能够支持多种功能,后面分析也能够看到的确有不少功能的。app


而后这里获得命令以后就开始构造一个命令执行器类,这里用到了设计模式中的命令模式。下面继续看看有哪几种命令执行器类:框架

 

在这个方法中就开始分析了这里支持的哪几种命令类,下面来一一分析一下:函数

第一个命令:dump_dexinfo

获取应用运行时内存中dex的信息:DumpDexInfoCommandHandler

 

进入方法在详细查看一下:

 

看到了,这里的实现逻辑仍是比较简单的,所有经过反射机制获取每一个应用的dex文件对应的DexFile类型对象,这里的工做和咱们以前介绍了Android中插件化开发已经很熟悉了,经过应用的默认类加载PathClassLoader类获得DexPathList类,而后在获得具体的DexFile对象便可。这里要说的就是这个dex文件对应的cookie值,这个值很是重要,是后续命令操做的基本信息,他表明的含义就是底层中每一个应用的dex文件对应的惟一id值,系统会维护一个map结构来保存这些数据的,系统而后经过这个cookie值来找到对应的dex文件信息的。

命令用法:am broadcast -a com.zjdroid.invoke –ei target [pid] –es cmd '{"action":"dump_dexinfo"}'

这里使用的是命令方式发送一个广播,经过–ei携带目标进程id是一个int类型,经过–es携带命令字符串



第二个命令:dump_dexfile

这个命令也是后续脱壳的重要命令,就是dump出应用内存中的dex文件:DumpDexFileCommandHandler

这里能够看到dump出应用的内存数据,首先得须要传入源应用的dex数据也就是apk文件,这个通常都是存放在/data/app/xxx.apk目录下的,而后就是这里本身构建了一个dump以后的dex文件路径,经过源码查看是在/data/data/xxx/files/dexdump.odex中。接下来继续查看dump的核心代码:

  看到这里有一个核心的方法,可是惋惜的是这个方法是native的,而这个工具并无把native层的代码公开,可是经过这里传递的参数能够了解到
 

命令用法:am broadcast -a com.zjdroid.invoke –ei target [pid] –es cmd '{"action":"dump_dexfile","dexpath":"*****"}'

注意这里的dexpath参数是表明须要脱壳的dex文件,也就是应用程序文件。


第三个命令:backsmali

这个命令实际上是和上面的命令差很少功能,只是这里的命令多了一层操做就是把dex文件转化成smali文件,因此这里再也不详细说明了,咋们能够先获得dex文件,而后在经过工具获得smali文件也是能够的。

命令用法:am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”backsmali”,”dexpath”:”*****”}’

注意这里的dexpath参数是表明须要脱壳的dex文件,也就是应用程序文件。而最终生成的smali文件夹是放在/data/data/xxx/smali下面的。


第四个命令:dump_mem

这个命令是用来dump出应用程序运行时内存中指定开始位置和长度的内存块数据的:DumpMemCommandHandler

惋惜这个方法也是native层的,可是这个操做就比较简单了,咱们知道每一个应用运行时的内存地址都在 /proc/[pid]/maps 文件中:

那么查找内存地址,而后在使用memcpy进行内存数据拷贝也是很是简单的。

命令用法:am broadcast -a com.zjdroid.invoke –ei target [pid] –es cmd ‘{“action”:”dump_mem”,”start”:111,”length”:23}’

注意这里的start和length都是十进制的,而不是十六进制的数据格式。


第五个命令:dump_heap

这个命令是能够dump出虚拟机的堆内存信息的,文件可使用java heap工具进行分析,而对于这个命令咱们想一下应该也知道实现逻辑应该是也是在native层的,并且这个代码逻辑应该和上面的那个命令差很少的,可是对于这个命令我尚未想到具体的思路,悲哀呀,若是有了解的同窗就告知一下哈!

命令用法:am broadcast -a com.zjdroid.invoke –ei target [pid] –es cmd ‘{“action”:”dump_heap”}’

第六个命令:dump_class

这个命令主要是用于dump出dex文件中的类信息,这个操做也是很是简单的,由于在DexFile对象中有一个隐藏的方法能够把dex文件中的全部类名获取到:getClassNameList

这里能够看到这个方法的传入参数为一个dex文件对应的cookie值。

命令用法:am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_class”,”dexpath”:”*****”}’

这里的dexpath是须要获得全部类信息的dex文件路径,也就是应用的apk文件路径。


第七个命令:invoke

这个命令是用于运行时动态调用Lua脚本,本人并无看懂这个命令的做用,该功能能够经过Lua脚本动态调用java代码。使用场景:能够动态调用解密函数,完成解密。能够动态触发特定逻辑。代码就不进行分析了,由于我以为这个命令应该不怎么会使用

命令用法:am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”invoke”,”filepath”:”****”}’

这里的filepath是lua脚本文件的存放路径。


到这里就所有介绍完了ZjDroid的全部命令了,下面还有两个很是重要的打印日志的tag:

第一个:adb logcat -s zjdroid-shell-{package name}

这个tag能够查看上面每一个命令执行的结果,便于查看命令执行的状态。

第二个:adb logcat -s zjdroid-apimonitor-{package name}

这个tag能够监听对应包名应用调用的哪些api信息,这个做用有点相似于运行时权限请求的做用。这个作起来就很是简单了,能够直接经过Xposed提供的方法进行系统的一些敏感api进行拦截而后添加监控代码便可。


3、命令总结

上面就从源码的角度彻底分析完了ZjDroid工具的功能了,下面就来总结一下:

一、获取APK当前加载DEX文件信息
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_dexinfo”}’

二、获取指定DEX文件包含可加载类名
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_class”,”dexpath”:”*****”}’

三、根据Dalvik相关内存指针动态反编译指定DEX,并以文件形式保存
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”backsmali”,”dexpath”:”*****”}’

四、Dump指定DEX内存中的数据并保存到文件(数据为odex格式,可在pc上反编译)
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_dexfile”,”dexpath”:”*****”}’

五、Dump指定内存空间区域数据到文件
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_mem”,”start”:1234567,”length”:123}’

六、Dump Dalvik堆栈信息到文件,文件能够经过java heap分析工具分析处理
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”dump_heap”}’

七、运行时动态调用Lua脚本
该功能能够经过Lua脚本动态调用java代码。使用场景:能够动态调用解密函数,完成解密。能够动态触发特定逻辑。
am broadcast -a com.zjdroid.invoke –ei target pid –es cmd ‘{“action”:”invoke”,”filepath”:”****”}’

八、相关命令执行结果查看
一、命令执行结果
adb shell logcat -s zjdroid-shell-{package name}
二、敏感API调用监控输出结果
adb shell logcat -s zjdroid-apimonitor-{package name}


三、总结

好了,到这里咱们就讲解完了基于Xposed框架的脱壳神器ZjDroid的实现原理以及具体用法。而这里也感觉到了Xposed框架的强大之处,固然这也只是一部分,后面还能够利用这个框架编写游戏外挂等操做。


四、源码







附件列表

相关文章
相关标签/搜索