分析工具: dex2jar + jd-gui + ida 6.1 + ExamDiff Pro
加壳选择的 1 个类:
Lcn/com/fmsh/cube/a/a;
用dex2jar后在jd-gui中看到该类只有两个函数调用 a 和 b
然后是上传网站加密后将apk包下载回来,我们先看看最主要的 classes.dex 文件变了没有
加密前 classes.dex 文件大小 : 2,925,772 字节
加密后 classes.dex 文件大小 : 2,926,676 字节
接下来就开始动手分析代码了:
首先,我们使用ida逆向加密后的 dex 文件
以 "cn.com.fmsh.cube.a.a.a(" 字符串在IDA中查找到函数入口,看看我们选择的类的名为a的函数字节码有变化没有
加密前
加密后
加密后的代码IDA无法完整逆向,如此我们可以确定,该壳确实加密了classes.dex 中的字节码。
然后,让我们看看加密后的包多了什么,使用 ExamDiff 对加密后apk解压出来目录和未加密apk解压出来的目录进行匹配,发现只多了libapkprotect.so 的库文件。
接着,让我们用 ida 对 libapkprotect.so 库进行分析,发现只有 5 个 jni 层入口函数, JNI_OnLoad 、_d、_a、Java_com_apkprotect_Init、Java_com_apkprotect_Version, 通过查看jni层函数代码的汇编码,可以确信该库是加过壳的,so的壳以前尚未见过,脱壳方法也有待探寻,所以我只能暂时先绕道,但是通过这个库,我们可以做如下猜测:
如果Java层要调用这个库,那么必然会存在 System.loadLibrary 的函数调用,于是我使用IDA对加密后的 dex 文件分析查找,发现了名为 apkprotect 的 Java 类,而这个类的代码只有 <clinit> 与 <init> 函数,不存在其它函数,如此我们就可以确定该类的代码应该是这样的
public class apkprotect
{
static
{
System.loadLibrary("apkprotect");
}
public native int Init();
public native int Version();
}
从以上代码的函数名,我们又可以猜测出最大的可能调用的函数应该是 Init ,因此我们使用"apkprotect.Init("字符串来搜索dex代码,
共搜索到以下几处调用点
1. com.lakala.android.bll.receiver.AlarmReceiver.onReceive 函数
2. com.lakala.android.bll.receiver.BroadcastReceiver.onReceive 函数
3. com.lakala.android.bll.receiver.LoginoutReceiver.onReceive 函数
4. com.lakala.android.bll.receiver.StatisticReceiver.onReceive 函数
5. com.lakala.android.common.ApplicationExtension.<clinit> 函数
6. com.lakala.android.common.service.DownloadAppService.onCreate 函数
7. com.lakala.android.common.service.DownloadFileService.onCreate 函数
8. com.zch.safelottery.broadcast.SafelotteryBroadcastReceiver.onReceive 函数
个人猜测如下:
要使程序正常执行,那么必然需要将加密的字节码在运行前就解密回来或者是接管系统的执行接口在执行加密类的时候使用自己的方法去执行,这个壳可能偏向于前者,因为它附带的libapkprotect.so 库文件并不是很大,要自己解密执行,肯定不止这么一点代码才是。
以下是我的测试用例的下载地址:
http://pan.baidu.com/share/link?shareid=1355314020&uk=3157398793
分析深度尚浅,望高手绕道!
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)