文章目录
- 前言
- 一、抓包确定目标
- 二、反编译定位加密位置
- 三、反编译定位加密位置
- 四、frida hook验证
- 五、进一步分析so
- 六、算法还原
- 结束语
- ------------------------------------------------END--------------------------------------------
前言
工欲善其事必先利其器 准备工具
- Fiddler 或任意一款抓包工具
- 真机或者模拟器
- VSCode
- Frida
- Jadx\Jeb\GDA 任选一款
- IDA
一、抓包确定目标
分析加密第一步 先抓包确定参数 所以老规矩 打开FD先抓包
其中 zzReqSign 便是我们需要还原的算法 我们查课发现没有加固 直接丢进jadx进行反编译
二、反编译定位加密位置
通过jadx反编译后搜索初步定位到这里 发现是个native 方法 那么加密在so层 上面 System.loadLibrary(“signLib”); 就是加载so的指令 其中 signLib就是so名字
三、反编译定位加密位置
解压apk 去lib目录寻找是否有这个文件
发现确实有这个so 拖入IDA 导出函数 搜索 getSign
定位如下位置:
代码如下:
int __fastcall Java_com_zhuanzhuan_sign_SignUtil_getSign(JNIEnv_ *a1, int a2, int a3, int a4)
{
const char *app_sign_sha1; // r0
struct _jobject *v9; // r8
signed int v10; // r5
int DevID; // r0
struct _jobject *v12; // r8
int v13; // r9
jbyte *v14; // r6
jsize v15; // r10
_BYTE *v16; // r8
signed int i; // r11
jbyte v18; // r4
int v19; // r1
JNIEnv_ *v20; // r4
int v21; // r9
int MD5; // r10
int v24; // [sp+8h] [bp-30h]
struct _jobject *v25; // [sp+Ch] [bp-2Ch]
struct _jobject *v26; // [sp+10h] [bp-28h]
JNIEnv_ *v27; // [sp+14h] [bp-24h]
jbyte *v28; // [sp+18h] [bp-20h]
if ( !a3 )
return 0;
app_sign_sha1 = get_app_sign_sha1(a1, a4);
if ( !app_sign_sha1 )
return 0;
if ( strcmp(app_sign_sha1, app_sing_str) )
return 0;
v9 = toBytes(a1, a3);
v10 = a1->functions->GetArrayLength(a1, v9);
v28 = a1->functions->GetByteArrayElements(a1, v9, 0);
DevID = getDevID(a1, a2);
if ( !DevID )
return 0;
v26 = v9;
v24 = DevID;
v12 = toBytes(a1, DevID);
v13 = 0;
v14 = a1->functions->GetByteArrayElements(a1, v12, 0);
v27 = a1;
v25 = v12;
v15 = a1->functions->GetArrayLength(a1, v12);
v16 = malloc(v10);
for ( i = 0; i < v10; ++i )
{
v18 = v28[v13 % v10];
v19 = (v13 + 1) % v15;
v13 += 2;
v16[i] = v14[v19] ^ v18;
}
v20 = v27;
v21 = v27->functions->NewByteArray(&v27->functions, v10 + 9);
(v20->functions->SetByteArrayRegion)(v20, v21, 0, v10, v16, a3);
v20->functions->SetByteArrayRegion(&v20->functions, v21, v10, 9, "smiletozz");
MD5 = getMD5(v27, v21);
v20->functions->DeleteLocalRef(&v20->functions, v21);
free(v16);
v20->functions->DeleteLocalRef(&v20->functions, v24);
v20->functions->ReleaseByteArrayElements(&v20->functions, v25, v14, 0);
v20->functions->ReleaseByteArrayElements(&v20->functions, v26, v28, 0);
v20->functions->DeleteLocalRef(&v20->functions, v25);
v20->functions->DeleteLocalRef(&v20->functions, v26);
return MD5;
这段函数最终返回了MD5 MD5是由 MD5 = getMD5(v27, v21);而来的 我们姑且认为他是一个md5算法 点进去看看
代码如下:
int __fastcall getDigestedBytes(_JNIEnv *a1, int a2)
{
struct _jobject *v4; // r6
jmethodID v5; // r5
jstring v6; // r0
_jobject *v7; // r9
_jmethodID *v8; // r0
int v9; // r8
v4 = a1->functions->FindClass(a1, "java/security/MessageDigest");
v5 = a1->functions->GetStaticMethodID(a1, v4, "getInstance", "(Ljava/lang/String;)Ljava/security/MessageDigest;");
v6 = a1->functions->NewStringUTF(a1, "MD5");
v7 = _JNIEnv::CallStaticObjectMethod(a1, v4, v5, v6);
v8 = a1->functions->GetMethodID(a1, v4, "digest", "([B)[B");
v9 = _JNIEnv::CallObjectMethod(a1, v7, v8, a2);
a1->functions->DeleteLocalRef(a1, v4);
a1->functions->DeleteLocalRef(a1, v7);
return v9;
插播一条广子 yzm平台 有需要的朋友们可以看看
点我直达
新用户注册加群即送10000点余额
四、frida hook验证
这段就比较简单了 反射java调用md5算法 到这里好像已经分析完毕 貌似就是个md5算法而已 是不是这样呢?我们试验一下
rida hook java层 getSign方法
代码如下:
let SignUtil = Java.use("com.zhuanzhuan.sign.SignUtil");
SignUtil["getSign"].overload('java.lang.String', 'android.content.Context').implementation = function (str, context) {
console.log(`SignUtil.getSign is called: str=${str}, context=${context}`);
let result = this["getSign"](str, context);
console.log(`SignUtil.getSign result=${result}`);
return result;
};
抓包结果为:zzReqSign: 47383db507e87badc5bc9ce348a6193e
我们去hook结果搜索
下面为结果 上面是明文 我们md5一下
五、进一步分析so
发现结果并不对 那么肯定是在md5之前还有其他操作 我们返回so继续分析
我们看到有个getDevID 方法
getDevID 代码如下:
int __fastcall getDevID(int a1, int a2)
{
int v4; // r2
v4 = (*(*a1 + 452))(a1, a2, "getDeviceId", "()Ljava/lang/String;");
return j__JNIEnv::CallStaticObjectMethod(a1, a2, v4);
}
也是反射的java 这里对应的好像就是java 层
我们hook一下此方法 拿到值
let SignUtil = Java.use("com.zhuanzhuan.sign.SignUtil");
SignUtil["getDeviceId"].implementation = function () {
console.log(`SignUtil.getDeviceId is called`);
let result = this["getDeviceId"]();
console.log(`SignUtil.getDeviceId result=${result}`);
return result;
};
值=SignUtil.getDeviceId result=BE304BAE68E9C99571DEE26718102680
六、算法还原
这个md5加密前经过了一段简单处理 代码就不放出来了 有兴趣的自己去研究研究 很简单
结束语
- 云在青天水在瓶
- 你以前的选择成为了现在的你,无法改变,而你现在的选择将造就未来的你。