Null_Null 发表于 2021-2-13 21:58

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

本帖最后由 Null_Null 于 2021-2-13 22:00 编辑

### 从零开始逆向分析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

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

#### 定位加密算法

将我们的安装包用jadx打开

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







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

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

#### Frida工具hook java函数

启动frida-server、动态转发



编写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
```




可以看到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);
```

再调用一下看看



#### Ida Pro分析so代码

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



具体分析如下

```
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; //
char *str; //
char *str2; //
void *str_; //

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里面,反正咱也不懂为什么要这么写代码,很迷惑,不过可能这就是加密艺术吧(手动狗头)。

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

Null_Null 发表于 2021-2-16 19:28

o10pwno 发表于 2021-2-16 17:27
终于更新了,之前关闭的帖子还会重发吗

之前关闭的帖子侵权了 不会再发出来了

h591166533 发表于 2023-3-16 11:47

你好请问你会写微博刷量转评赞协议吗?用APP协议接口,如果有意向可以添加我的QQ 2211962041

闷骚小贱男 发表于 2021-2-13 22:05

本帖最后由 闷骚小贱男 于 2021-2-13 22:10 编辑

{:301_997:}看到这个我好像想到了Android 中级题

嗯,,好像又不一样..

syrmb 发表于 2021-2-13 22:22

前段时间刚搞了微博APP v11

Airey 发表于 2021-2-13 22:29

{:1_918:}nice

8585859 发表于 2021-2-13 22:36

前段时间刚搞了微博APP v11

丨紫陌流年丶 发表于 2021-2-13 23:04

楼主能帮忙看一下这个吗?谢谢
https://www.52pojie.cn/thread-1370392-1-1.html

13169456869 发表于 2021-2-14 00:09

没看懂,但是还是要膜拜大佬

xixicoco 发表于 2021-2-14 00:51

顶你一下

雨中独撑伞 发表于 2021-2-14 10:21

感谢楼主的无私奉献

vosdbk 发表于 2021-2-14 10:52

密码学大佬...
页: [1] 2 3
查看完整版本: 从零开始逆向分析APP系列----微博APP协议分析