一、前言

在前文中我们介绍了如何使用 Xposed框架修改地理位置信息来进行自身的隐藏功能,本文将继续介绍Xposed框架的另外一个功能就是实现应用的简单脱壳,其实说是Xposed的作用其实也不是,主要是模块编写的好就可以了,主要是利用Xposed的牛逼Hook技术实现的,下面就先来介绍一下这个脱壳模块工具ZjDroid的原理,因为他是开源的,所以咋们直接分析源码即可,源码的下载地址:https://github.com/halfkiss/ZjDroid 不过可惜的时候他只公开了Java层的代码,而native层的代码并没有公开,但是分析源码之后会发现最重要的功能就在native层,不过也没关系,等分析到那里的时候我在给大家讲解底层的大致实现方案即可。


二、ZjDroid原理分析

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


android printservice 使用_sed


android printservice 使用_sed_02

我们直接进入到这个类即可:


android printservice 使用_sed_03

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


android printservice 使用_数据_04

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


android printservice 使用_数据_05

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


android printservice 使用_数据_06

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

一个是进程id:这个作用主要是为了过滤其他应用,只处理本应用的逻辑,因为这个广播发送之后所有的应用都能接收到,但是我们脱壳有时候肯定只是针对于某一个应用,那么只需要在这个应用的广播接收中做处理即可。

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

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


android printservice 使用_sed_07

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

第一个命令:dump_dexinfo

DumpDexInfoCommandHandler


android printservice 使用_sed_08

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


android printservice 使用_应用程序_09

命令用法:

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

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

第二个命令:dump_dexfile

DumpDexFileCommandHandler


android printservice 使用_数据_10

/data/data/xxx/files/dexdump.odex


android printservice 使用_应用程序_11

命令用法:

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

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

第三个命令:backsmali

命令用法:

am broadcast -a com.zjdroid.invoke --ei target pid --es cmd '{"action":"backsmali","dexpath":"*****"}'

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

第四个命令:dump_mem

DumpMemCommandHandler

android printservice 使用_应用程序_12

/proc/[pid]/maps


android printservice 使用_数据_13

命令用法:

am broadcast -a com.zjdroid.invoke --ei target [pid] --es cmd '{"action":"dump_mem","start":111,"length":23}'

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

第五个命令:dump_heap

命令用法:

am broadcast -a com.zjdroid.invoke --ei target [pid] --es cmd '{"action":"dump_heap"}'

第六个命令:dump_class

getClassNameList


android printservice 使用_应用程序_14

命令用法:

am broadcast -a com.zjdroid.invoke --ei target pid --es cmd '{"action":"dump_class","dexpath":"*****"}'

这里的dexpath是需要得到所有类信息的dex文件路径,也就是应用的apk文件路径。

第七个命令:invoke

命令用法:

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进行拦截然后添加监控代码即可。


三、命令总结

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

1、获取APK当前加载DEX文件信息
am broadcast -a com.zjdroid.invoke --ei target pid --es cmd '{"action":"dump_dexinfo"}'

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

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

4、Dump指定DEX内存中的数据并保存到文件
am broadcast -a com.zjdroid.invoke --ei target pid --es cmd '{"action":"dump_dex","dexpath":"*****"}'

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

6、Dump Dalvik堆栈信息到文件,文件可以通过java heap分析工具分析处理
am broadcast -a com.zjdroid.invoke --ei target pid --es cmd '{"action":"dump_heap"}'

7、运行时动态调用Lua脚本
am broadcast -a com.zjdroid.invoke --ei target pid --es cmd '{"action":"invoke","filepath":"****"}'

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


四、模块使用及案例分析

下面咋们就要用一个案例来看看这个工具到底如何使用,有哪些功效,咋们就用一个应用做案例,就是 捕鱼达人游戏,具体的apk文件可以自行去网上搜索哈。我们安装游戏之后,然后顺便把上面的ZjDroid模块工具也安装上,然后进行重启生效。

我们最好是单独开一个CMD窗口用来查看打印结果,但是从上面的命令可以看到,我们应该需要这游戏的包名和进程id,那么这两个数据怎么获取呢?其实我在前面的文章已经介绍了很多次了,用一个命令即可:

adb shell dumpsys activity top

但是这时候需要运行起来捕鱼达人游戏:


android printservice 使用_数据_15

这里看到了,就非常简单的获取到了游戏的包名:org.cocos2d.fishingjoy3和进程id=25304,这两个数据非常重要可以这里先进行保管,进而后面可以使用。

下面首先来看一下这个应用用了哪些敏感的api数据,使用上面查看日志的命令即可:

adb shell logcat -s zjdroid-apimonitor-org.cocos2d.fishingjoy3


android printservice 使用_sed_16

看到了,这里又网络请求信息,网络切换的广播等数据的,感觉还是蛮有用的这个工具。

下面在来看一下这个应用的dex文件信息,可以使用下面命令即可:

am broadcast -a com.zjdroid.invoke --ei target 25304 --es cmd '{action:dump_dexinfo}'

这里运行之后的结果:


android printservice 使用_数据_17

这时候会发现,运行没有看到实际效果,原因是因为我们需要通过日志才能可以看到数据的,因为上面命令运行的结果都是需要通过这个日志才可以看到的:

adb logcat -s zjdroid-shell-org.cocos2d.fishingjoy3


android printservice 使用_应用程序_18

这里就可以看到了具体的信息了,看到了有一个filepath这个就是我们后续有些命令需要用到的dex路径,所以一定要记下来,后面的命令会使用到的。

接下来在看一个关于dump出游戏中所有的类名的命令:

am broadcast -a com.zjdroid.invoke --ei target 25304 --es cmd '{"action":"dump_class","dexpath":"/data/app/org.cocos2d.fishingjoy3-1.apk"}'

这里的路径就是上面获取到的apk路径,结果咋们还是需要通过上面的日志命令才可以看到:


android printservice 使用_数据_19

看到了吧,这里就导出来了游戏包含的所有类名了。

最后在来一发,这个是最关键的,也是本文的重点也是这个工具最实用的一个功能,就是进行应用的脱壳处理了,而本文的游戏也是进行加固处理的,我们可以反编译看看这个游戏:


android printservice 使用_数据_20

你会发现没几个类,而且有一个Application类,那么可以认定了这个游戏被加固了,本文不介绍是使用哪家的加固平台操作了,也不再使用IDA等工具去动态调试脱壳了,这里直接使用这个工具进行操作即可。咋们为了后续代码阅读方便可以直接获取他的smali代码,也就是使用这个命令:

am broadcast -a com.zjdroid.invoke --ei target 25304 --es cmd '{action:backsmali, "dexpath":"/data/app/org.cocos2d.fishingjoy3-1.apk"}'

这个命令的运行结果咋们通过日志查看:


android printservice 使用_数据_21

而这个smali文件夹是存放在应用的 

/data/app/org.cocos2d.fishingjoy3/smali

中的,咋们可以把他拷贝出来即可:


android printservice 使用_sed_22

这里可以看到咋们就成功的脱壳了,生成了游戏的所有smali文件代码了。其实这个脱壳操作和我们之前介绍使用IDA工具进行脱壳原理都差不多,因为应用程序不管怎么加固,最终都会使用一个系统函数将dex文件加载到内存中,而加载之前肯定要进行解密操作,我们只要在加载之前解密之后进行拦截即可。


五、总结

好了,到这里我们就讲解完了基于Xposed框架的脱壳神器ZjDroid的实现原理以及具体用法。而这里也感受到了Xposed框架的强大之处,当然这也只是一部分,后面还可以利用这个框架编写游戏外挂等操作。所以好好膜拜这个框架,也好好拜读这个框架的源码吧,学不完的东东呢!