首页
社区
课程
招聘
[原创]某黑盒某请求参数分析
发表于: 2022-10-28 10:35 21377

[原创]某黑盒某请求参数分析

2022-10-28 10:35
21377

业余时间写的,纯兴趣更新! 做个记录。

雷电模拟器 Android 7.1.2/pixexl2 Android 8.1

首先在apk中进行登录账户的时候进行抓包,获取登录凭证。

请求报文如下

在get请求中发现有传递以下参数

以及cookie中的pkey

以上参数我们需要知道hkey是怎么来的

因为是请求报文,所以算法肯定在apk内部实现的。要么在应用层要么在so层

将apk拖入到GDA中进字符串搜索"hkey"

发现在intercept方法中有存在这个字符串。双击进入

str是当前时间/1000

分析下str1是怎么赋值的

首先调用类d的h方法,参数为特定字符串"xiaoheihe/_time="和当前时间str进行拼接的结果

然后再次调用类d的h方法,参数为 将第一次调用的的返回值中的“a”和"0"给替换为"app"的结果

最后就是对str1进行赋值了,将第二次调用d的h方法的返回值.

后面其实就是一个拼接请求头的操作,不需要关注。

所以这里我们看下类d的h方法的怎么实现的

发现就是个md5.

我们可以得知请求报文中的_time和hkey字段是关联的。

用脚本去验证下

下载了小黑盒 v.1.3.92版本。

同样在登录的时候进行抓包。

这里imei变化了是因为换了台手机。

我们先不逆向

用上面的gethkey.py跑一下看看hkey和请求报文中的是否一致。如果不一致就说明,加密算法变化了。

发现不一致,所以这个版本的getkey的算法发生了变化。

额,脑子坏掉了,请求报文中的hkey的长度只有10位的长度,肯定加密算法变了。

同样的操作定位到hkey的位置

发现新版本有三处地址含有该字符串。

先看第一个

类Q下的b方法,就是md5加密

第二个是就是这个版本使用的接口

关键代码

看下str2是怎么获得的

发现调用了类NDKTools下的encode方法

encode方法在native-lib的so中进行实现的。

本地环境

手机端运行frida的服务端

电脑端查看进程

run.py

hook.js

发现可以成功运行起来

0xc9e90b01是encode函数的地址,当打开app后,这个地址是不变的。

这里我运行这个脚本只输出这些内容,但并没有打印出来参数和返回地址。

先静态分析吧。解包获得libnative-lib.so并拖入ida中

分析得知encode函数是将(str2+"/bfhdkud_time="+str1)进行md5加密,将加密的结果吗作为返回值

回到接口类中

发现只取md5返回值然后将其中的"a"和"0"都替换成str3即"app"

然后又调用了Q类下的b(String)方法,发现同样是md5算法

然后再将其返回值取前10位赋值给str2,即后面的hkey

写成python实现

对比下请求报文,发现key值是一样的。

小黑盒逆向分析笔记(二) - Chr_小屋 (chrxw.com)

 
GET /store/has_unfinished_game/?heybox_id=???&imei=???&os_type=Android&os_version=7.1.2&version=1.1.50&_time=1666165262&hkey=5656c95245635812219460113c5a14eb HTTP/1.1
Referer: http://api.maxjia.com/
User-Agent: Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36 ApiMaxJia/1.0
Cookie: pkey=???
Host: api.xiaoheihe.cn
Connection: Keep-Alive
Accept-Encoding: gzip
GET /store/has_unfinished_game/?heybox_id=???&imei=???&os_type=Android&os_version=7.1.2&version=1.1.50&_time=1666165262&hkey=5656c95245635812219460113c5a14eb HTTP/1.1
Referer: http://api.maxjia.com/
User-Agent: Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36 ApiMaxJia/1.0
Cookie: pkey=???
Host: api.xiaoheihe.cn
Connection: Keep-Alive
Accept-Encoding: gzip
heybox_id      固定且唯一(对于每一个用户来说)
imei           移动通信国际识别码(每个移动设备具有唯一性)
os_type        系统类型
os_version     系统版本
version        apk的版本
_time          时间
hkey           时间key
heybox_id      固定且唯一(对于每一个用户来说)
imei           移动通信国际识别码(每个移动设备具有唯一性)
os_type        系统类型
os_version     系统版本
version        apk的版本
_time          时间
hkey           时间key
Cookie: pkey=???   固定且唯一(对于每一个用户登录后)
Cookie: pkey=???   固定且唯一(对于每一个用户登录后)
 
 
package com.max.xiaoheihe.network.b$1;
import okhttp3.w;
import com.max.xiaoheihe.network.b;
import java.lang.Object;
import okhttp3.w$a;
import okhttp3.ad;
import okhttp3.ab;
import com.max.xiaoheihe.app.HeyBoxApplication;
import com.max.xiaoheihe.bean.account.User;
import okhttp3.v;
import okhttp3.v$a;
import java.lang.StringBuilder;
import java.lang.System;
import java.lang.String;
import com.max.xiaoheihe.b.d;
import com.max.xiaoheihe.b.af;
import com.max.xiaoheihe.b.c;
import com.max.xiaoheihe.bean.account.AccountDetailObj;
import android.os.Build$VERSION;
import okhttp3.ab$a;
 
class b$1 implements w    // class@000e5c
{
    final b a;
 
    void b$1(b p0){
       this.a = p0;
       super();
    }
    public ad intercept(w$a p0){
       ab uoab = p0.request();
       User user = HeyBoxApplication.b();
       v$a uoa = uoab.a().v();
       StringBuilder str = (System.currentTimeMillis() / 1000)+""; //获取当前时间/1000
       String str1 = d.h(((d.h("xiaoheihe/_time="+str)).replaceAll("a", "app")).replaceAll("0", "app"));  //这里是关键代码
       if (c.b(af.b(uoab.a().toString(), "heybox_id"))) {
          String str2 = "heybox_id";
          String userid = (user.isLoginFlag())? user.getAccount_detail().getUserid(): "-1";
          uoa.b(str2, userid);
       }
       uoa.b("imei", d.g()).b("os_type", "Android").b("os_version", (Build$VERSION.RELEASE).trim()).b("version", d.h()).b("_time", str).b("hkey", str1);
       if (!c.b("")) {
          uoa.b("game_type", "");
       }
       v ov = uoa.c();
       str = "";
       String str3 = (c.b(user.getPkey()))? "": "pkey="+user.getPkey();
       str = str+str3;
       str3 = (c.b(uoab.a("Cookie")))? "": ";"+uoab.a("Cookie");
       return p0.proceed(uoab.f().b("Referer", "http://api.maxjia.com/").b("User-Agent", "Mozilla/5.0 AppleWebKit/537.36 \(KHTML, like Gecko\) Chrome/41.0.2272.118 Safari/537.36 ApiMaxJia/1.0").a("Cookie", str+str3).a(ov).d());
    }
}
package com.max.xiaoheihe.network.b$1;
import okhttp3.w;
import com.max.xiaoheihe.network.b;
import java.lang.Object;
import okhttp3.w$a;
import okhttp3.ad;
import okhttp3.ab;
import com.max.xiaoheihe.app.HeyBoxApplication;
import com.max.xiaoheihe.bean.account.User;
import okhttp3.v;
import okhttp3.v$a;
import java.lang.StringBuilder;
import java.lang.System;
import java.lang.String;
import com.max.xiaoheihe.b.d;
import com.max.xiaoheihe.b.af;
import com.max.xiaoheihe.b.c;
import com.max.xiaoheihe.bean.account.AccountDetailObj;
import android.os.Build$VERSION;
import okhttp3.ab$a;
 
class b$1 implements w    // class@000e5c
{
    final b a;
 
    void b$1(b p0){
       this.a = p0;
       super();
    }
    public ad intercept(w$a p0){
       ab uoab = p0.request();
       User user = HeyBoxApplication.b();
       v$a uoa = uoab.a().v();
       StringBuilder str = (System.currentTimeMillis() / 1000)+""; //获取当前时间/1000
       String str1 = d.h(((d.h("xiaoheihe/_time="+str)).replaceAll("a", "app")).replaceAll("0", "app"));  //这里是关键代码
       if (c.b(af.b(uoab.a().toString(), "heybox_id"))) {
          String str2 = "heybox_id";
          String userid = (user.isLoginFlag())? user.getAccount_detail().getUserid(): "-1";
          uoa.b(str2, userid);
       }
       uoa.b("imei", d.g()).b("os_type", "Android").b("os_version", (Build$VERSION.RELEASE).trim()).b("version", d.h()).b("_time", str).b("hkey", str1);
       if (!c.b("")) {
          uoa.b("game_type", "");
       }
       v ov = uoa.c();
       str = "";
       String str3 = (c.b(user.getPkey()))? "": "pkey="+user.getPkey();
       str = str+str3;
       str3 = (c.b(uoab.a("Cookie")))? "": ";"+uoab.a("Cookie");
       return p0.proceed(uoab.f().b("Referer", "http://api.maxjia.com/").b("User-Agent", "Mozilla/5.0 AppleWebKit/537.36 \(KHTML, like Gecko\) Chrome/41.0.2272.118 Safari/537.36 ApiMaxJia/1.0").a("Cookie", str+str3).a(ov).d());
    }
}
 
String str1 = d.h(((d.h("xiaoheihe/_time="+str)).replaceAll("a", "app")).replaceAll("0", "app"));
String str1 = d.h(((d.h("xiaoheihe/_time="+str)).replaceAll("a", "app")).replaceAll("0", "app"));
 
 
 
 
public static String h(String p0){
       if (TextUtils.isEmpty(p0)) {
          return "";
       }
       try{
          byte[] uobyteArray = MessageDigest.getInstance("MD5").digest(p0.getBytes());
          String str = "";
          int len = uobyteArray.length;
          for (int i = 0; i < len; i = i + 1) {
             int i1 = uobyteArray[i] & 0x00ff;
             String str1 = Integer.toHexString(i1);
             if (str1.length() == 1) {
                str1 = "0"+str1;
             }
             str = str+str1;
          }
          return str;
       }catch(java.security.NoSuchAlgorithmException e6){
          e6.printStackTrace();
          return "";
       }
    }
public static String h(String p0){
       if (TextUtils.isEmpty(p0)) {
          return "";
       }
       try{
          byte[] uobyteArray = MessageDigest.getInstance("MD5").digest(p0.getBytes());
          String str = "";
          int len = uobyteArray.length;
          for (int i = 0; i < len; i = i + 1) {
             int i1 = uobyteArray[i] & 0x00ff;
             String str1 = Integer.toHexString(i1);
             if (str1.length() == 1) {
                str1 = "0"+str1;
             }
             str = str+str1;
          }
          return str;
       }catch(java.security.NoSuchAlgorithmException e6){
          e6.printStackTrace();
          return "";
       }
    }
 
GET /store/has_unfinished_game/?heybox_id=46447531&imei=863342023667829&os_type=Android&os_version=7.1.2&version=1.1.50&_time=1666165262&hkey=5656c95245635812219460113c5a14eb HTTP/1.1
Referer: http://api.maxjia.com/
User-Agent: Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36 ApiMaxJia/1.0
Cookie: pkey=MTY2NjE2NTIyNC45M180NjQ0NzUzMWhyd2JubG9ud2NndHFubmI__
Host: api.xiaoheihe.cn
Connection: Keep-Alive
Accept-Encoding: gzip
GET /store/has_unfinished_game/?heybox_id=46447531&imei=863342023667829&os_type=Android&os_version=7.1.2&version=1.1.50&_time=1666165262&hkey=5656c95245635812219460113c5a14eb HTTP/1.1
Referer: http://api.maxjia.com/
User-Agent: Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36 ApiMaxJia/1.0
Cookie: pkey=MTY2NjE2NTIyNC45M180NjQ0NzUzMWhyd2JubG9ud2NndHFubmI__
Host: api.xiaoheihe.cn
Connection: Keep-Alive
Accept-Encoding: gzip
#coding:utf8
import hashlib
import datetime
 
def md5(test_str: str, key=None):
    print('MD5加密前为 :' + test_str)
 
    if key is None:
        m = hashlib.md5()
    else:
        m = hashlib.md5(key.encode('utf-8'))
 
    m.update(test_str.encode())
    res = m.hexdigest()
    print('MD5加密后为 :' + res)
    return res
 
 
def gethkey():
    _time = "1666165262"
    str=md5(_time)
    str1=md5(str.replace("a","app").replace("0","app"))
 
 
if __name__ == '__main__':
    gethkey()
 
'''
MD5加密前为 :xiaoheihe/_time=1666165262
MD5加密后为 :49d640ad07515bc4c9ec4a9f893c24a7
MD5加密前为 :49d64appappdapp7515bc4c9ec4app9f893c24app7
MD5加密后为 :5656c95245635812219460113c5a14eb            和请求报文中的hkey是一致的
'''
#coding:utf8
import hashlib
import datetime
 
def md5(test_str: str, key=None):
    print('MD5加密前为 :' + test_str)
 
    if key is None:
        m = hashlib.md5()
    else:
        m = hashlib.md5(key.encode('utf-8'))
 
    m.update(test_str.encode())
    res = m.hexdigest()
    print('MD5加密后为 :' + res)
    return res
 
 
def gethkey():
    _time = "1666165262"
    str=md5(_time)
    str1=md5(str.replace("a","app").replace("0","app"))
 
 
if __name__ == '__main__':
    gethkey()
 
'''
MD5加密前为 :xiaoheihe/_time=1666165262
MD5加密后为 :49d640ad07515bc4c9ec4a9f893c24a7
MD5加密前为 :49d64appappdapp7515bc4c9ec4app9f893c24app7
MD5加密后为 :5656c95245635812219460113c5a14eb            和请求报文中的hkey是一致的
'''
 
GET /bbs/app/api/user/permission?heybox_id=???&imei=???&os_type=Android&os_version=8.1.0&version=1.3.92&_time=1666259837&hkey=0cf9be6f88 HTTP/1.1
Referer: http://api.maxjia.com/
User-Agent: Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36 ApiMaxJia/1.0
Cookie: pkey=???
Host: api.xiaoheihe.cn
Connection: Keep-Alive
Accept-Encoding: gzip
GET /bbs/app/api/user/permission?heybox_id=???&imei=???&os_type=Android&os_version=8.1.0&version=1.3.92&_time=1666259837&hkey=0cf9be6f88 HTTP/1.1
Referer: http://api.maxjia.com/
User-Agent: Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36 ApiMaxJia/1.0
Cookie: pkey=???
Host: api.xiaoheihe.cn
Connection: Keep-Alive
Accept-Encoding: gzip
 
 
#coding:utf8
import hashlib
import datetime
 
def md5(test_str: str, key=None):
    print('MD5加密前为 :' + test_str)
 
    if key is None:
        m = hashlib.md5()
    else:
        m = hashlib.md5(key.encode('utf-8'))
 
    m.update(test_str.encode())
    res = m.hexdigest()
    print('MD5加密后为 :' + res)
    return res
 
def gethkey():
    _time = "xiaoheihe/_time="+"1666165262"    #v1.1.50
    _time = "xiaoheihe/_time="+"1666259837"    #v.1.3.92
    str=md5(_time)
    str1=md5(str.replace("a","app").replace("0","app"))
 
if __name__ == '__main__':
    gethkey()
 
'''
MD5加密前为 :xiaoheihe/_time=1666259837
MD5加密后为 :5ff217a9966ad4c64a17fd4df122f03b
MD5加密前为 :5ff217app9966appd4c64app17fd4df122fapp3b
MD5加密后为 :2ba491715784e9606d289bde1f7890b0
'''
#coding:utf8
import hashlib
import datetime
 
def md5(test_str: str, key=None):
    print('MD5加密前为 :' + test_str)
 
    if key is None:
        m = hashlib.md5()
    else:
        m = hashlib.md5(key.encode('utf-8'))
 
    m.update(test_str.encode())
    res = m.hexdigest()
    print('MD5加密后为 :' + res)
    return res
 
def gethkey():
    _time = "xiaoheihe/_time="+"1666165262"    #v1.1.50
    _time = "xiaoheihe/_time="+"1666259837"    #v.1.3.92
    str=md5(_time)
    str1=md5(str.replace("a","app").replace("0","app"))
 
if __name__ == '__main__':
    gethkey()
 
'''
MD5加密前为 :xiaoheihe/_time=1666259837
MD5加密后为 :5ff217a9966ad4c64a17fd4df122f03b
MD5加密前为 :5ff217app9966appd4c64app17fd4df122fapp3b
MD5加密后为 :2ba491715784e9606d289bde1f7890b0
'''
 
 
 
 
private void i(){
   L l = new L$a().c(0, TimeUnit.MILLISECONDS).b(0, TimeUnit.MILLISECONDS).a();
   String str = this.h();
   T.a("zzzzconntest", "url=="+str);
   HashMap hashMap = new HashMap(16);
   User user = HeyBoxApplication.k();
   String userid = (user.isLoginFlag())? user.getAccount_detail().getUserid(): "-1";
   hashMap.put("userid", userid);
   hashMap.put("appid", "heybox");
   hashMap.put("pkey", user.getPkey());
   hashMap.put("imei", Q.d());
   hashMap.put("os_type", "Android");
   hashMap.put("os_version", (Build$VERSION.RELEASE).trim());
   hashMap.put("version", Q.g());
   hashMap.put("hkey", Q.b(((Q.b("xiaoheihe/_time="+(System.currentTimeMillis() / 1000)+"")).replaceAll("a", "app")).replaceAll("0", "app")));//这里其实就是v1.1.50版本gethkey是一样的
   l.a(new N$a().b(Ab.a(str, hashMap)).a(), new l$c(this));
   l.h().b().shutdown();
   return;
}
private void i(){
   L l = new L$a().c(0, TimeUnit.MILLISECONDS).b(0, TimeUnit.MILLISECONDS).a();
   String str = this.h();
   T.a("zzzzconntest", "url=="+str);
   HashMap hashMap = new HashMap(16);
   User user = HeyBoxApplication.k();
   String userid = (user.isLoginFlag())? user.getAccount_detail().getUserid(): "-1";
   hashMap.put("userid", userid);
   hashMap.put("appid", "heybox");
   hashMap.put("pkey", user.getPkey());
   hashMap.put("imei", Q.d());
   hashMap.put("os_type", "Android");
   hashMap.put("os_version", (Build$VERSION.RELEASE).trim());
   hashMap.put("version", Q.g());
   hashMap.put("hkey", Q.b(((Q.b("xiaoheihe/_time="+(System.currentTimeMillis() / 1000)+"")).replaceAll("a", "app")).replaceAll("0", "app")));//这里其实就是v1.1.50版本gethkey是一样的
   l.a(new N$a().b(Ab.a(str, hashMap)).a(), new l$c(this));
   l.h().b().shutdown();
   return;
}
public static String b(String p0){
       if (TextUtils.isEmpty(p0)) {
          return "";
       }
       try{
          byte[] uobyteArray = MessageDigest.getInstance("MD5").digest(p0.getBytes());
          int len = uobyteArray.length;
          String str = "";
          for (int i = 0; i < len; i = i + 1) {
             int i1 = uobyteArray[i] & 0x00ff;
             String str1 = Integer.toHexString(i1);
             if (str1.length() == 1) {
                str1 = "0"+str1;
             }
             str = str+str1;
          }
          return str;
       }catch(java.security.NoSuchAlgorithmException e7){
          e7.printStackTrace();
          return "";
       }
    }
public static String b(String p0){
       if (TextUtils.isEmpty(p0)) {
          return "";
       }
       try{
          byte[] uobyteArray = MessageDigest.getInstance("MD5").digest(p0.getBytes());
          int len = uobyteArray.length;
          String str = "";
          for (int i = 0; i < len; i = i + 1) {
             int i1 = uobyteArray[i] & 0x00ff;
             String str1 = Integer.toHexString(i1);
             if (str1.length() == 1) {
                str1 = "0"+str1;
             }
             str = str+str1;
          }
          return str;
       }catch(java.security.NoSuchAlgorithmException e7){
          e7.printStackTrace();
          return "";
       }
    }
package com.max.xiaoheihe.network.c;
import okhttp3.H;
import com.max.xiaoheihe.network.d;
import java.lang.Object;
import okhttp3.H$a;
import okhttp3.T;
import okhttp3.N;
import com.max.xiaoheihe.app.HeyBoxApplication;
import com.max.xiaoheihe.bean.account.User;
import okhttp3.G;
import okhttp3.G$a;
import java.lang.StringBuilder;
import java.lang.System;
import java.lang.String;
import com.max.xiaoheihe.utils.NDKTools;
import com.max.xiaoheihe.utils.Q;
import com.max.xiaoheihe.utils.Ab;
import com.max.xiaoheihe.utils.M;
import com.max.xiaoheihe.bean.account.AccountDetailObj;
import android.os.Build$VERSION;
import okhttp3.N$a;
 
class c implements H    // class@00135d
{
    final d a;
 
    void c(d p0){
       this.a = p0;
       super();
    }
    public T intercept(H$a p0){
       N n = p0.request();
       User user = HeyBoxApplication.k();
       G$a uoa = n.h().j();
       String str = "";
       StringBuilder str1 = (System.currentTimeMillis() / 1000)+str;
       String str2 = n.h().c();
       int i = 0;
       if (str2.endsWith("/")) {
          str2 = str2.substring(i, (str2.length() - 1));
       }
       String str3 = "app";
       str2 = (Q.b(((NDKTools.encode(HeyBoxApplication.g(), str2, str1)).replaceAll("a", str3)).replaceAll("0", str3))).substring(i, 10);
       String str4 = "heybox_id";
       if (M.d(Ab.b(n.h().toString(), str4))) {
          String userid = (user.isLoginFlag())? user.getAccount_detail().getUserid(): "-1";
          uoa.a(str4, userid);
       }
       uoa.a("imei", Q.d()).a("os_type", "Android").a("os_version", (Build$VERSION.RELEASE).trim()).a("version", Q.g()).a("_time", str1).a("hkey", str2);
       if (Q.h()) {
          uoa.a(str3, "concept");
       }
       G g = uoa.a();
       str1 = "";
       String str5 = (M.d(user.getPkey()))? str: "pkey="+user.getPkey();
       str1 = str1+str5;
       if (!M.d(n.a("Cookie"))) {
          str = ";"+n.a("Cookie");
       }
       return p0.proceed(n.f().a("Referer", "http://api.maxjia.com/").a("User-Agent", "Mozilla/5.0 AppleWebKit/537.36 \(KHTML, like Gecko\) Chrome/41.0.2272.118 Safari/537.36 ApiMaxJia/1.0").b("Cookie", str1+str).a(g).a());
    }
}
package com.max.xiaoheihe.network.c;
import okhttp3.H;
import com.max.xiaoheihe.network.d;
import java.lang.Object;
import okhttp3.H$a;
import okhttp3.T;
import okhttp3.N;
import com.max.xiaoheihe.app.HeyBoxApplication;
import com.max.xiaoheihe.bean.account.User;
import okhttp3.G;
import okhttp3.G$a;
import java.lang.StringBuilder;
import java.lang.System;
import java.lang.String;
import com.max.xiaoheihe.utils.NDKTools;
import com.max.xiaoheihe.utils.Q;
import com.max.xiaoheihe.utils.Ab;
import com.max.xiaoheihe.utils.M;

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 4
支持
分享
最新回复 (1)
雪    币: 310
活跃值: (960)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
本人菜鸡一枚,欢迎大佬们陆续加入到QQ群 801022487 一起交流学习
2022-10-29 15:24
0
游客
登录 | 注册 方可回帖
返回
//