原版APK内的classes.dex 只负责加载libDexHelper.so,在这个so的JNI_OnLoad() 函数中,通过跟踪代码,发现在第一运行时向

/data/data/com.chaozh.iReaderFree/.cache

这个目录下面写了3个文件:

这个是在调试过程中截的图,因此 dex 文件还大小是0。

DVE文件不知道是干什么的,JAR文件就是 apk 里的 asset/class0.jar ,但用ZIP无法解压,说明也是经过处理的。

跟踪了一下,处理的方法如下:

1. 初始化一个长度为256的byte(unsigned char)数组,每个元素的值与其索引相等,即:

for (i = 0; i < 0x100; i++)
    a[i] = i;

2. 用到另外一个数组

unsigned char b[16] = {
    0x66, 0x97, 0x6C, 0xE8, 0x6D, 0x46, 0x38, 0xB0, 
    0x09, 0x5A, 0xA5, 0xD7, 0x0F, 0xCB, 0x9A, 0xA0,
};

3. 累加数组a中的元素和b中的元素,因为b只有16个元素,如果到末尾,就从头再开始,将“和”表示的索引的值与当前元素的值互换

int sum = 0, temp;

for (i = 0, j = 0; i < 0x100; i++, j++)
{
    if (j > 15)
            j = 0;
    sum = (sum + a[i] + b[j]) & 0XFF;
    temp = a[sum];
    a[sum] = a[i];
    a[i] = temp;
}

4. 文件的前0x20000个字节,使用下面的算法解密:

unsigned int R1, R6, R7;
size_t i, j;

R1 = 0;

for (i = 0, j = 0; i < len; i++)
{
        j = (j+1) & 0xFF;
        R7 = a[j];
        R1 += R7;
        R1 = R1 & 0xFF; 

        R6 = a[R1];
        a[j] = R6;
        a[R1] = R7;
        //R6 = (R6 + R7) & 0xFF; 
        R6 = (a[j] + a[R1]) & 0xFF;

        R7 = src[i] ^ a[R6];
        dest[i] = R7;
}

5. 从0x20000以后的字节,简单的与0xAC异或。

 

这样处理之后,class0.jar 就变成了一个zip文件:

并且里面只有一个 classes.dex,用ZIP解压出来就是原始的dex了。但在手机上,.cache 文件夹下面的 classes.dex 并不是直接解压出来的,而是在解压出来后对文件进行了处理,过程与上面处理 class0.jar 的完全一样。

 

IREADER APK同时做了加壳、DEX混淆、资源混淆,但脱壳之后,其他的就无关紧要了。用未加固的classes.dex,可以删除lib/armeabi下面的libDexHelper.so了。

但是这样打包后,运行APK会发生错误:

05-12 09:34:48.064 W/dalvikvm(30980): JNI_OnLoad returned bad version (2147483647) in /data/app-lib/com.chaozh.iReaderFree1-1/libUiControl.so 0x41150990

05-12 09:34:48.064 W/dalvikvm(30980): Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing Lcom/zhangyue/iReader/JNI/Common;

05-12 09:34:48.064 D/dalvikvm(30980): threadid=13: exiting

 

在APP运行时,会对签名进行验证,很多APP会验证签名,但验证的方式不尽相同,大部分是在JAVA里做的,干掉比较简单,但IREADER的验证是在libUiControl.so里面做的,而且这个SO使用的是THUMB指令集,分析起来稍微有点难度。验证是在 sub_5F038FAE 函数中做的,我们改过签名,肯定不能通过,函数返回 0x7FFFFFFF,然后把这个值放到了R6寄存器里。

 

JNI_OnLoad() 会返回JAVA版本,这个SO里的做法有点奇怪,大致是这样的:

double d1 = (double) 0x7FFFFFFF; // R6 
double d2 = 10000, d3 = 65542, d4 = 2;
double d_result;
int result;

d_result = pow(d2, d1) * d3 - d4;
result = (int) d_result;

也就是将签名验证的结果放到 R6 中,计算 10000 的 R6 次方,然后乘以 65545,再减去2. 如果签名验证通过,R6里为0,那么结果是 0x10004,也就是 JNI_VERSION_1_4。

看到最后的签名结果是从R6中取的,那么我们只需将R6的值清0:。在调用sub_5F038FAE函数之后,会把返回值R0保存到R6中:

OPCODE是0x1C06,在这里清R6,改为 EOR R6, R6. OPCODE为0x4076:

写回到文件中

IREADER就可以运行起来了。修改 AndroidMenifest.xml ,把 LAUNCH Activity 改成 com.zhangyue.iReader.bookshelf.ui.ActivityBookShelf,删除 WelcomeActivity,这样就可以跳过欢迎界面直接进书架。

 

但是还遇到一个问题,在书架界面第一次按返回键,进入到“书城”界面,返回后再按返回键才能退出。看来 ActivityBookShelf 对返回键也做了处理,打开 smali 文件,找到 onKeyDown() 函数,观察到应该调用 this.s() 函数(这里面有调用了this.j())是退出,前面有一些判断,不必管它是干什么,直接干掉:

.line 1135
:cond_8

invoke-direct {p0}, Lcom/zhangyue/iReader/bookshelf/ui/ActivityBookShelf;->s()V

goto/16 :goto_0

.line 1159

在 this.j() 里面也有this.h的判断,同样干掉即可。用apktool重新打包,就搞定了。

 

重新生成APK放到了百度网盘,链接: http://pan.baidu.com/s/1i5wFTgp 密码: vxxt

 

posted @ 2016-05-13 15:49 西北望长安 阅读(4742) 评论(4) 推荐(1) 编辑
摘要: 一、原理 腾讯乐固(http://legu.qcloud.com/)提供APK加壳技术,分析了一下,做了个简单的脱壳程序。 以某新华字典APP为例,APK下载地址:https://apkpure.com/%E6%96%B0%E5%8D%8E%E5%AD%97%E5%85%B8/com.qiushui 阅读全文
posted @ 2016-04-29 15:24 西北望长安 阅读(3183) 评论(0) 推荐(0) 编辑
摘要: 在 com.baidu.bus.offline 下面有一个 CAPI.smali 文件,里面定义了几个JNI的接口:public class CAPI { static { System.loadLibrary("busoffline"); } public native int clo... 阅读全文
posted @ 2016-01-19 12:48 西北望长安 阅读(696) 评论(0) 推荐(0) 编辑
摘要: 还有两个问题没有解决。(1) prov_city_list.json 下载后,如果变为 com.baidu.bus.f.b 的对象的?在3.加载城市列表 的第 14 步中,hObject 的成员 c 被赋了一个值,类型就是 com.baidu.bus.f.a,向上找这个对象是如何生成的:invoke... 阅读全文
posted @ 2016-01-19 11:53 西北望长安 阅读(501) 评论(0) 推荐(0) 编辑
摘要: 1. 在进入OfflineDataManageActivity时,找到 onCreate() 方法,在最后几行:new-instance v0, Lcom/baidu/bus/d/i;iget-object v1, p0, Lcom/baidu/bus/activity/OfflineDataMan... 阅读全文
posted @ 2016-01-19 11:42 西北望长安 阅读(433) 评论(0) 推荐(0) 编辑
摘要: 首先找到离线下载的界面(Activity),使用Apktool将APK包decode一下(Apktool的使用方法请参考官方文档)。这样decode之后生成的是源文件是.smali格式的,在这里也可以使用其他工具(如dex2jar+Java Decompiler或者Procyon)直接输出可读性更好... 阅读全文
posted @ 2016-01-19 11:17 西北望长安 阅读(503) 评论(0) 推荐(0) 编辑
摘要: 声明:仅作为个人学习交流,不得用于任何商业用途。本文将分析百度公交离线文件的下载过程以及数据格式,只为记录分析的过程以为日后工作可能之参考。准备工作:1. 软件包(APK): 当前版本为1.4,下载地址:http://wuxian.baidu.com/map/application.html2. 工... 阅读全文
posted @ 2016-01-19 10:48 西北望长安 阅读(242) 评论(0) 推荐(0) 编辑
摘要: 1. 登陆迅雷离线下载的第一步需要使用账号登陆,网页的登陆页面是:http://lixian.xunlei.com/login.html首先,迅雷服务器验证账号和密码的地址为:https://login.xunlei.com/sec2loginhttps://login2.xunlei.com/se... 阅读全文
posted @ 2015-09-08 19:06 西北望长安 阅读(7049) 评论(0) 推荐(0) 编辑
摘要: 一、简介Opkg 是一个基于 ipkg 的轻量级的软件包管理系统,主要用于嵌入式系统,目前应用opkg的有Open WRT 和 Open Embedded。1Opkg的详细使用方法可以参考Open WRT的 WIKI页面2,不再赘述,本文将重点解释opkg的工作原理。Opkg 的源代码可以在Goog... 阅读全文
posted @ 2015-09-08 18:52 西北望长安 阅读(15776) 评论(0) 推荐(1) 编辑
摘要: 1. Python 2 None 对象无 __eq__ 方法的原因分析Python2.7: typeobject.c 里面 PyBaseObject_Type 结构体 tp_richcompare 成员为 0 而在 Python 3.x 的代码里面这个成员的值是 object_richcompar... 阅读全文
posted @ 2015-09-08 13:40 西北望长安 阅读(201) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示