From( 书旗小说过签名校验 【 使用 DDMS 分析方法调用流程 】 ):https://www.cnblogs.com/LuLuLuHao/p/12874468.html
签名校验一般步骤:
- 1. 先查有没有加壳,如果有壳,先脱壳
- 2. 如果没加壳,则 apk 在不做任何修改的情况下重新签名,然后安装,看能不能打开 app
书旗小说.apk 过签名校验
1、根据启动流程
:https://www.bilibili.com/video/BV1vE411c7Zj?p=62
2、签名三兄弟
( log 插桩方法 分析方法调用流程 ):https://www.bilibili.com/video/BV1vE411c7Zj?p=63
签名三兄弟:getPackageManager、getPackageInfo、getPackageName、( signature )
context.getPackageManager().getPackageinfo(context.getPackageName(), 64).signatures[0].hashCode()
视频中是通过搜索签名三兄弟,定位到 smali,然后 log 插桩,ddms 看 log 输出,分析流程。。。
3、根据 ddms 中 log 信息判断
1. 把书旗小说.apk( 下载地址:https://www.wandoujia.com/apps/288203/history_v175 )通过 AndroidKiller 重新签名,然后安装,安装发现闪退。
2. 打开 ddms 看看有什么信息 发现了一个 killProcess 方法
( 滑动到最后,从下往上看!!! 默认按时间先后顺序列出,最下面的是最新的 log )
3. 打开 jadx-gui 分析代码,搜索 "KillProcess" 根据 ddms 信息 发现它调用了 com.shuqi.app.ShuqiApplication 包里面的方法 我们跳转到里面去
4. 他这个逻辑就很清晰了
5. 让这个 handleToken 方法返回 true 即可 我们打开 Androidkiller 修改 smali
加这两行代码
6 .apk 完美运行
4、搜索 application 这个类
一个 APK 只有一个 Application。每个 Apk 运行时都需要有一个 Application对象,Application对象 执行 onCreate方法时APP就开始运行
一般做反调试或者签名校验都会在 入口点(即application),每个 Apk 运行时都需要有一个 Application对象,所以直接搜索 application 这个类。
点击进入 ,然后找到 onCreate 方法并查看,可以看到 一个 checkSigAsync 方法,
点击进入 checkSigAsync 方法,可以看到就是进行签名校验的。。。
2022.03.18 新版书旗小说
2022.03.18 最新版的书旗小说 签名校验已经不再 java 层,而是放到了 so 层,
jadx 反编译 书旗小说apk ,然后搜索 signature ,
Android 文档:https://developer.android.google.cn/reference/android/content/pm/Signature?hl=en
浦发银行 apk 过签名校验
哔哩哔哩( 浦发银行.apk 签名校验【so 文件修改】入口点 和 入口界面 ):
https://www.bilibili.com/video/BV1UE411A7rW?p=64
最新版本有加壳。。。。。。。。。。所以下载老版本 apk
浦发银行apk 下载地址(8.0 版本 ):https://www.wandoujia.com/apps/31675/history_v83
这个签名校验是在 so 层。。。
1. 查壳
下载好 8.0 版本的 apk,首先使用 AndroidKiller 查下有没有加壳
可以看到 8.0 版本的 apk 没有加壳。
2. 根据 入口点 或者 入口页面
入口点 优先于 入口页面 加载和执行。
图示:
定位到入口点 smali 代码,找到 onCreate 函数,查看对应逻辑,当不好分析时,可以转换成java 代码进行分析
提示:AndroidKiller 调用 jd-jui 查看 java 代码出现 "未找到对应的APK源码" 时,说明 jd-jui 无法把 smali 代码转换成 java 代码,这时需要换个工具,例如:jadx-gui、Jeb 等
转换成 java 代码进行分析( 这里使用 jadx-gui 转换 )
这里也看不出什么( 其实 YTSafe 就是要找的 关键点 ),打开 ddms 或者 monitor 看下 log 输出,
查看 Java_com_yitong_safe_YTSafe_native_1init 对应的 java 代码(静态注册)
可以看到就是在 libyt_safe.so 库里面进行的校验
到此,java 层分析结束,下面就是使用 IDA 分析这个 so 库了。。。
使用 IDA Pro 分析 so
使用 IDA Pro 打开提取到的 libyt_safe.so 文件。
拿到一个 so 库后,首先分析 so 的 "导出函数",
因为 init_array 比 JNI_onLoad 执行的时间更早,所以先看下 init_array 有没有坑。。。
Ctrl + s 打开 段选择 窗口,选择 init_array 点击进入 init_array 对应代码位置
发现 init_array 里面没有什么函数,然后搜索 JNI_onLoad ,发现没有 JNI_onLoad 这个函数,在搜索 java_ 开头的函数(即 静态注册的函数),发现有很多静态注册的函数
可以看到 有个函数带 init ,可以点进去看看。点击 ---> ARM 汇编代码 ---> F5 反编译 ,查看伪代码
双击 init_lib 函数,跳转到函数对应位置,可以看到 init_lib 函数调用了 check_app 函数
查看 check_app 代码,发现有个 get_sign 函数,字面意思理解就是 得到签名,
直接把这个函数去掉,或者 nop 掉,不调用这个签名函数。
修改 so 文件,并保存( 34' 45'' )。也可以使用 winhex 打开并修改对应位置。 35' 25''
修改后,替换原来的 so 文件,安装还是闪退,看下 check_app 代码 逻辑,是在 while 循环里面 ,
可以 使用 IDA 动态调试 so ,然后打断点进行分析,
int __fastcall check_app(int a1, int a2)
{int v2; // r5int v3; // r4int v4; // r0int v5; // r0int v6; // r5int v7; // r6unsigned __int8 *v8; // r5char *v9; // r5char *v10; // r6int i; // r3char v12; // r3int v13; // r5int v14; // r6int v15; // r3int v17; // [sp+Ch] [bp-44h]int v18; // [sp+10h] [bp-40h]unsigned __int8 *v19; // [sp+14h] [bp-3Ch]int v20; // [sp+18h] [bp-38h]_BYTE *v21; // [sp+1Ch] [bp-34h]int v22; // [sp+20h] [bp-30h]int v23; // [sp+24h] [bp-2Ch]int v24; // [sp+28h] [bp-28h]unsigned __int8 *v25; // [sp+30h] [bp-20h]v2 = a2;v3 = a1;v4 = (*(int (**)(void))(*(_DWORD *)a1 + 668))();v5 = get_sign(v3, v2, v4);v6 = cert_encode(v3, v5);v7 = message_digest(v3, "MD5", v6);v22 = message_digest(v3, "SHA1", v6);v20 = (*(int (__fastcall **)(int, int))(*(_DWORD *)v3 + 684))(v3, v22);v23 = j_malloc(v20);(*(void (__fastcall **)(int, int, _DWORD, int, int))(*(_DWORD *)v3 + 800))(v3, v22, 0, v20, v23);v8 = (unsigned __int8 *)(*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)v3 + 736))(v3, v7, 0);v24 = (*(int (__fastcall **)(int, int))(*(_DWORD *)v3 + 684))(v3, v7);inv_mix_key(v8, v24);v25 = (unsigned __int8 *)get_key(v8, v24);(*(void (__fastcall **)(int, int, unsigned __int8 *, _DWORD))(*(_DWORD *)v3 + 768))(v3, v7, v8, 0);v18 = 0;while ( !CHECK_APP ){if ( v18 >= ENC_COUNT )j_exit(0);v9 = &enc_sha1[65 * v18];v17 = j_strlen(v9) / 2;v19 = (unsigned __int8 *)j_malloc(v17);v10 = (char *)j_malloc(3);v10[2] = 0;for ( i = (int)v19; ; i = (int)(v21 + 1) ){v21 = (_BYTE *)i;if ( i - (signed int)v19 >= v17 )break;*v10 = *v9;v12 = v9[1];v9 += 2;v10[1] = v12;*v21 = hex2dec(v10);}j_free(v10);v13 = invCipherAll(v19, v17, v25, v24);j_free(v19);while ( !*(_BYTE *)(v13 + v17 - 1) )--v17;v14 = j_malloc(v17);j_memcpy();v15 = 0;if ( v17 == v20 ){while ( 1 ){if ( v15 >= v20 ){LOBYTE(v15) = 1;goto LABEL_16;}if ( *(unsigned __int8 *)(v14 + v15) != *(unsigned __int8 *)(v23 + v15) )break;++v15;}LOBYTE(v15) = 0;}
LABEL_16:CHECK_APP = v15;++v18;}j___android_log_print(6, "YT_SAFE", &unk_695E);return (*(int (__fastcall **)(int, int, int, _DWORD))(*(_DWORD *)v3 + 768))(v3, v22, v23, 0);
}
在看下 get_sign 函数
点击
函数进入,可以看到和签名相关的函数
方法 2( 搜索字符串 ):
在打开的 Strings window中搜索 getPackageManager、getPackageInfo、signatures。这里以搜索 getPackageManager 为例:
查看 getPackageManager 的调用:
可以看到只在 get_sign 里面调用了 getPackageManager,所以可以判定 get_sign 是关键函数。。。
或者 直接把 check_app 给去掉 。 40' 30''
按教程 上搞到这没搞出来,换思路在搞。。。so 分析流程,ida 修改 so 文件
方法 2:
删除 smali 代码中的
发现 apk 可以打开显示界面
这里不在截图。。。