|
本帖最后由 怜渠客 于 2022-5-28 21:19 编辑
不少人都搞过笔趣阁app,之前的版本(2021年以来)都是一层腾讯御安全,常规脱修后pmshook(mt去签普通版)即可过掉签名验证。
不过新版本(2022年5月),增强了签名校验,使得普通版不再有效。
一天,某耗发了个新版本让我试试。于是,就有了以下的分析。

- mt管理器
- 任意崩溃日志记录器
- IDA Pro
- Android studio
- 笔趣阁新版本
壳常规脱修。签名,运行。
闪退,看崩溃日志。
日志如下:
- FATAL EXCEPTION: main
- Process: com.biquge.ebook.app, PID: 3741
- java.lang.NoSuchMethodError: no non-static method "Lcom/jni/crypt/project/CryptDesManager;.<init>(Ljava/lang/String;)V"
- at com.jni.crypt.project.CryptDesManager.cVerify(Native Method)
- at com.jni.crypt.project.CryptDesManager.init(CryptDesManager.java:1)
- at com.biquge.ebook.app.app.AppContext.onCreate(AppContext.java:5)
- at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1193)
- at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6991)
- at android.app.ActivityThread.access$1500(ActivityThread.java:257)
- at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1982)
- at android.os.Handler.dispatchMessage(Handler.java:106)
- at android.os.Looper.loop(Looper.java:236)
- at android.app.ActivityThread.main(ActivityThread.java:8056)
- at java.lang.reflect.Method.invoke(Native Method)
- at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656)
- at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967)
复制代码
看样子是说,com.jni.crypt.project.CryptDesManager.cVerify里调用了一个不存在的非静态方法Lcom/jni/crypt/project/CryptDesManager;.<init>(Ljava/lang/String;)V
该方法在libCryptDesManager.so中
打开IDA,看看这个so。
输出表里的四个Java_xxx并没有CryptDesManager.cVerify方法。
说明该方法为动态注册(我不确定,请大佬纠正)。
代开string窗口
一眼看到了好几个老朋友。
getApplicationInfo
getPackageInfo
signatures
这都是调用的安卓API获取的安装包信息,包括签名。

众所周知,signatures获取的签名,是能被pms过掉的。但是为何依旧闪退?
so里的代码没有混淆,十分清晰。
我们不得不怀疑,Java层有其他校验。

此时,安装包已用pms(mt去签普通版)处理过。
这里用的是mt自带的日志注入功能。
如图
我选择了全局注入,打印string类型的返回值

安装,授予存储权限,运行,看日志。
在发生闪退的前几行,获取了apk安装路径?
我们有充分的理由怀疑这里是校验apk是否未修改。
合理推测:
- so层signatures校验
- Java层安装包校验
后续验证,此推测正确。

进入获取apk路径的代码看一看。
进入a方法。
smali指令看的不清晰,转Java代码。
看到这里就明白了,通过applicationinfo的sourceDir获取apk路径。
- 各大过签工具,不用多强,支持Java重定向即可;
- pms(mt)过so层校验,书写一点代码,实现局部重定向;
- 获取apk后如何校验?能不能改一些东西,伪装原包?
- 将libCryptDesManager.so中的有效代码还原成Java,校验代码删除。还原后libCryptDesManager.so就可以删了;
- 爆破改so,过掉so层,Java层同2或3。
以上五种方法我全试了,都能搞定。最难的是方法4,还原Java代码,不再演示,各位可以自己尝试。
我演示一下方法2和方法3
方法2:
首先,mt过签普通版。
接着,在获取apk路径的地方,换成原包路径。
我选择的是将原包放到lib/arm64-v8a目录下,重命名为libshell.so,然后,将路径指向此文件即可。
Java代码:
- public static String getApk(Context context) {
- StringBuilder stringBuilder = new StringBuilder();
- String lib = context.getApplicationInfo().nativeLibraryDir;
- String result = "/libshell.so";
- return stringBuilder.append(lib).append(result).toString();
- }
复制代码
推荐用Java2smali插件
smali:
- .method public static getApk(Landroid/content/Context;)Ljava/lang/String;
- .registers 5
- .param p0, "context" # Landroid/content/Context;
- .prologue
- .line 8
- new-instance v2, Ljava/lang/StringBuilder;
- invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V
- .line 9
- .local v2, "stringBuilder":Ljava/lang/StringBuilder;
- invoke-virtual {p0}, Landroid/content/Context;->getApplicationInfo()Landroid/content/pm/ApplicationInfo;
- move-result-object v3
- iget-object v0, v3, Landroid/content/pm/ApplicationInfo;->nativeLibraryDir:Ljava/lang/String;
- .line 10
- .local v0, "lib":Ljava/lang/String;
- const-string v1, "/libshell.so"
- .line 11
- .local v1, "result":Ljava/lang/String;
- invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
- move-result-object v3
- invoke-virtual {v3, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
- move-result-object v3
- invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
- move-result-object v3
- return-object v3
- .end method
复制代码
将此方法替代原来的获取apk路径的代码即可。并且将“原包”重命名为libshell.so放进lib/arm64-v8a里
这就实现了手动局部重定向。
类:d.m.a.a.g
代码截图:
其实和Java原包重定向差不多了,那个只是反射弄了个总代理。
方法3:
写了快一小时了,主要是中间刷新了一次,数据都丢了,重写了一半。有点累了。
思路:查找 获取apk路径方法 的调用,看看获取后干了什么。
拿着获取到的apk文件,去初获取了一个类对象。
看到channel,结合以往经验,我们可以猜测是channel校验。
接着往下看,拿着两个参数(String和Map)去初始化了一个类对象作为返回值。
我们打印一下,这几个相关的类,看看参数值、返回值是什么。
这里我不再操作,用一个过签成功的包去打印。
总之,正确的应该是channel为“gw2022_5”,将channel对应的value赋值为“gw2022_5”即可。
类:d.m.a.a.c
类:d.b.a.a.k.a
提示一下方法4,可以用simplehook对那几个native函数的参数和返回值进行hook。
再结合ida分析,重写成java就容易一些了。
没有成品,思路更重要。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
-
查看全部评分
总评分:好评 +16
金币 +18
|