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; // r5
int v3; // r4
int v4; // r0
int v5; // r0
int v6; // r5
int v7; // r6
unsigned __int8 *v8; // r5
char *v9; // r5
char *v10; // r6
int i; // r3
char v12; // r3
int v13; // r5
int v14; // r6
int v15; // r3
int 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 可以打开显示界面
这里不在截图。。。