从零开始逆向分析APP系列

文章正文
发布时间:2025-10-29 21:33

从零开始逆向分析APP系列----微博APP协议分析

在抓包尝试调用微博极速版APP相关接口的时候,发现修改参数并不能通过服务端的校验,会提示如下:

{"errmsg":"客户端身份校验失败","errno":-105,"errtype":"DEFAULT_ERROR","isblock":false}

登录的数据包如下:

POST https://api.weibo.cn/2/account/login HTTP/1.1 X-Sessionid: 1ecc1f6e-3e64-46ff-9e3a-bc401f199b75 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Content-Length: 353 Host: api.weibo.cn Connection: Keep-Alive Accept-Encoding: gzip User-Agent: okhttp/3.12.1 c=weibofastios&i=1234567&s=00000000&u=13123232321&p=lXtrKeNaL48e0vosKaz%2F9nVIBo%2BfWPEZ2l8t%2FUe9h50V5gIpXVjcpkscP4257e2LqXZlv70u4y1h2QKvF7BsoSycfq%2BfAk6dE9%2FYnMfVpTGSmGyDi4re2xnz5WxVoqcpPjP%2BuFl5e0El87ZeYCXn05oG8yNPzetkEOrIjzsVqy4%3D&getuser=1&getoauth=1&getcookie=1&lang=zh_CN&aid=01A1H_TanahcG58Oq1snTGp9kL_6PttMMsBzCuqVCH1HGFBEs.&from=2599295010

通过一番分析,我们发现主要的校验是在s字段,s字段并不像一般哈希算法的加密长度,那么s是如何生成的呢,这就是本文探究的对象。

准备工具:JADX、Frida、IDA Pro

[i]注:本文主要目的是以探究s字段算法为目的进行学习和研究,若有侵权,请联系删除。

定位加密算法

将我们的安装包用jadx打开

点击搜索,我们搜索字符串”s”看看:

1.png (112.75 KB, 下载次数: 0)

下载附件

2021-2-13 21:55 上传

2.png (51.69 KB, 下载次数: 0)

下载附件

2021-2-13 21:55 上传

3.png (70.59 KB, 下载次数: 0)

下载附件

2021-2-13 21:55 上传

出来了很多,注意到这个calculateS函数,calculate是计算的意思

接下来我们需要使用frida去hook这个函数,看看他有哪些传参,返回了什么传参

Frida工具hook java函数

启动frida-server、动态转发

4.png (76.04 KB, 下载次数: 1)

下载附件

2021-2-13 21:55 上传

编写hook脚本如下:

function hookJava(){     Java.perform(function(){         var WeicoSecurityUtils = Java.use("com.sina.weibo.security.WeicoSecurityUtils");         WeicoSecurityUtils.generateS.implementation = function(a,b,c,d,e){         var result = this.generateS(a,b,c,d,e);         console.log("WeicoSecurityUtils",b,c,d,e,"\nresult",result);         return result;     };     }); } function main(){     hookJava(); } setImmediate(main);

启动脚本

frida -U -f com.sina.weibolite -l js/hookWeibo.js

WeicoSecurityUtils 13123232323123123 g4c8CKKdwh3LE1mRX7uxyx7AafXUkJsh 2599295010 902784192 result 00000000

5.png (418.1 KB, 下载次数: 0)

下载附件

2021-2-13 21:55 上传

6.png (117.41 KB, 下载次数: 0)

下载附件

2021-2-13 21:56 上传

可以看到13123232323123123是我们的账号+密码,别的一些参数呢都能在提交参数中找到,或是固定值,就不过多分析。接下来我们再编写一个主动调用的脚本,方便我们去调试,完善代码如下:

function hookJava(){     Java.perform(function(){         var WeicoSecurityUtils = Java.use("com.sina.weibo.security.WeicoSecurityUtils");         WeicoSecurityUtils.generateS.implementation = function(a,b,c,d,e){         var result = this.generateS(a,b,c,d,e);         console.log("WeicoSecurityUtils",b,c,d,e,"\nresult",result);         return result;     };     }); } function callGenerateS(){     Java.perform(function(){         var WeicoSecurityUtils = Java.use("com.sina.weibo.security.WeicoSecurityUtils");         //得到context         var currentApplication = Java.use('android.app.ActivityThread').currentApplication();         var context = currentApplication.getApplicationContext();         var result = WeicoSecurityUtils.generateS(context,"13123232323123123","g4c8CKKdwh3LE1mRX7uxyx7AafXUkJsh","2599295010","902784192");         console.log("WeicoSecurityUtils-result",result);         return result;     }); } function main(){     //hookJava(); } setImmediate(main);

再调用一下看看

7.png (48.08 KB, 下载次数: 0)

下载附件

2021-2-13 21:56 上传

Ida Pro分析so代码

将apk改后缀为zip拿到lib目录下面的libnative-lib.so,使用ida打开

8.png (77.36 KB, 下载次数: 0)

下载附件

2021-2-13 21:56 上传

具体分析如下

int __fastcall Java_com_sina_weibo_security_WeicoSecurityUtils_generateS(_JNIEnv *a1, int a2, int a3, int a4, int a5, int a6, int a7) {   _JNIEnv *v7; // r4   void *v8; // r6   int context; // r5   const char *str4; // r9   const char *str3; // r11   jclass AboutActivity; // r0   void *AboutActivity_; // r6   jmethodID forVerify; // r0   void *v15; // r8   const char *forVerifyResult; // r10   int v17; // r5   int str3_; // r6   bool v19; // zf   jclass WeicoSecurityUtils; // r0   void *v21; // r6   jmethodID v22; // r0   int v23; // r8   int result; // r0   size_t v25; // r5   size_t v26; // r0   char *v27; // r5   jclass v28; // r0   void *v29; // r6   jmethodID v30; // r0   int v31; // r5   int v32; // [sp+Ch] [bp-1Ch]   char *str; // [sp+10h] [bp-18h]   char *str2; // [sp+14h] [bp-14h]   void *str_; // [sp+18h] [bp-10h]   v7 = a1;   v8 = (void *)a4;   context = a3;   str_ = (void *)a4;   str4 = a1->functions->GetStringUTFChars(&a1->functions, (jstring)a7, 0);// 得到第四个传参字符串 902784192   v32 = verify((int)v7, context, (int)str4);   _android_log_print(4);   str = (char *)v7->functions->GetStringUTFChars(&v7->functions, v8, 0);// 得到第一个传参字符串 13123232323123123   str2 = (char *)v7->functions->GetStringUTFChars(&v7->functions, (jstring)a5, 0);// 得到第二个传参字符串 g4c8CKKdwh3LE1mRX7uxyx7AafXUkJsh   str3 = v7->functions->GetStringUTFChars(&v7->functions, (jstring)a6, 0);// 得到第三个传参字符串 2599295010   _android_log_print(4);   AboutActivity = v7->functions->FindClass(&v7->functions, "com/weico/international/mvp/v2/AboutActivity");// 获取AboutActivity类   AboutActivity_ = AboutActivity;   forVerify = v7->functions->GetStaticMethodID(&v7->functions, AboutActivity, "forVerify", "()Ljava/lang/String;");// 获取AboutActivity类方法forVerify   v15 = (void *)_JNIEnv::CallStaticObjectMethod(v7, AboutActivity_, forVerify);// 调用此方法得到一个字符串   forVerifyResult = v7->functions->GetStringUTFChars(&v7->functions, v15, 0);   v17 = strcmp(forVerifyResult, "#*123321");    // 比较字符串是否为#*123321   v7->functions->DeleteLocalRef(&v7->functions, AboutActivity_);   v7->functions->ReleaseStringUTFChars(&v7->functions, v15, forVerifyResult);   v7->functions->ReleaseStringUTFChars(&v7->functions, (jstring)a7, str4);   str3_ = *(unsigned __int8 *)str3;   _android_log_print(4);   v19 = v17 == 0;                               // 判断v17是否为0,并赋值给v19   if ( !v17 )                                   // 如果v17不为零     v19 = v32 == 1;                             // 判断v32是否为一,结果赋值给v19   if ( v19 && str3_ )                           // 一系列的判断应该是为了检测是否为客户端,防止别人打包调用这个so   {     WeicoSecurityUtils = v7->functions->FindClass(&v7->functions, "com/sina/weibo/security/WeicoSecurityUtils");     v21 = WeicoSecurityUtils;     v22 = v7->functions->GetStaticMethodID(             &v7->functions,             WeicoSecurityUtils,             "aa4",             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");// 到头来又调用了java层的算法aa4     v23 = _JNIEnv::CallStaticObjectMethod(v7, v21, v22);     v7->functions->ReleaseStringUTFChars(&v7->functions, str_, str);     v7->functions->ReleaseStringUTFChars(&v7->functions, (jstring)a5, str2);     v7->functions->ReleaseStringUTFChars(&v7->functions, (jstring)a6, str3);     v7->functions->DeleteLocalRef(&v7->functions, v21);     result = v23;   }   else   {     v25 = strlen(str);     v26 = strlen(str2);     v27 = (char *)malloc(v26 + v25 + 1);     sprintf(v27, "%s%s", str, str2);     v7->functions->NewStringUTF(&v7->functions, v27);     v28 = v7->functions->FindClass(&v7->functions, "com/sina/weibo/security/WeicoSecurityUtils");     v29 = v28;     v30 = v7->functions->GetStaticMethodID(&v7->functions, v28, "aa3", "(Ljava/lang/String;)Ljava/lang/String;");// 如果检测结果为假,则调用这个方法     v31 = _JNIEnv::CallStaticObjectMethod(v7, v29, v30);     v7->functions->ReleaseStringUTFChars(&v7->functions, str_, str);     v7->functions->ReleaseStringUTFChars(&v7->functions, (jstring)a5, str2);     v7->functions->ReleaseStringUTFChars(&v7->functions, (jstring)a6, str3);     v7->functions->DeleteLocalRef(&v7->functions, v29);     result = v31;   }   return result; }

我们又看到java这边的aa4算法

我们写个hook,看看两次sha512的传参值分别是什么

脚本补充如下

function hookJava(){     Java.perform(function(){         var KotlinUtilKt = Java.use("com.weico.international.utility.KotlinUtilKt");         KotlinUtilKt.sha512.implementation = function(a){         var result = this.sha512(a);         console.log("sha512",a,result);         return result;     };     }); } function callGenerateS(){     Java.perform(function(){         var WeicoSecurityUtils = Java.use("com.sina.weibo.security.WeicoSecurityUtils");         //得到context         var currentApplication = Java.use('android.app.ActivityThread').currentApplication();         var context = currentApplication.getApplicationContext();         var result = WeicoSecurityUtils.generateS(context,"13123232323123121","g4c8CKKdwh3LE1mRX7uxyx7AafXUkJsh","2599295010","902784192");         console.log("WeicoSecurityUtils-result",result);         return result;     }); } function main(){     hookJava(); } setImmediate(main);

call一下

第一个sha512结果

eff01f442d0d8d5969660681bcf72240b9a016f083f657b39b2e8e5fa6680d0e6b70b0bfc785be38e87cb41f14209cfb39de42168575ca0dcfff1c313a9b8e61

第二个sha512结果

a50e5c2a080ecadb54bf1f7dfbba9b63ff2fac02a049593604af2144ac2070358fda4a613b93bcd4b3eafa020031262c418de65b8d2156fb919e2e2875ea0377

首先取第二个sha512的第0个字符a,得到a在字符串0123456789abcdef的对应位置11

取第一个sha512的第11位得到字符0

然后再取第二个sha512的第0+11个字符0,得到a在字符串0123456789abcdef的对应位置0
取第一个sha512的第0+11位得到字符0,一直循环下去,因为取到的第二个sha512的值为0,因此后面的字符串不会发生变化,算法基本就是这样子,不知道大家能不能听懂,哈哈,反正大家对照着java代码看一遍应该能知道我说的是什么意思了。

本来想做微博APP的,后面看了极速版比较小,就拿了这个来分析,没想到极速版的缩水了,核心代码放在了java里面,反正咱也不懂为什么要这么写代码,很迷惑,不过可能这就是加密艺术吧(手动狗头)。

新的一年祝大家新年快乐、身体健康,我看见什么比较有意思的加密还会给大家带来教程的,会继续把这个系列完善,当然只是针对新手,因为本人技术也只是刚入门的菜鸟,共勉。



 

 

9.png (10.72 KB, 下载次数: 2)

下载附件

2021-2-13 21:56 上传

9.png

 
 

10.png (23.81 KB, 下载次数: 1)

下载附件

2021-2-13 21:56 上传

10.png

 
 

11.png (284.94 KB, 下载次数: 5)

下载附件

2021-2-13 21:56 上传

11.png

 

免费评分 参与人数 11威望 +3 吾爱币 +66 热心值 +11 理由

j582992806
    + 1   + 1   谢谢@Thanks!  

错过的恨
    + 1   + 1   用心讨论,共获提升!  

夜泉
    + 1   + 1   好帖  

htpsky
    + 1   + 1   过来支持下  

海盗小K
    + 3   + 1   大佬,能分析一下aid是怎么生成的吗,非常感谢!  

qtfreet00
  + 3   + 52   + 1   感谢发布原创作品,吾爱破解论坛因你更精彩!  

poca
    + 1   + 1   用心讨论,共获提升!  

嘛哩嘛哩轰
      + 1   感谢发布原创作品,吾爱破解论坛因你更精彩!  

cxfqy
    + 1   + 1   用心讨论,共获提升!  

yanxunchan
    + 1   + 1   谢谢@Thanks!  

兜兜风f
    + 4   + 1   用心讨论,共获提升!  

查看全部评分

首页
评论
分享
Top