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

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

2022-10-28 10:35
19759

前言

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

测试环境

雷电模拟器 Android 7.1.2/pixexl2 Android 8.1

抓包测试

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

 

请求报文如下

1
2
3
4
5
6
7
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请求中发现有传递以下参数

1
2
3
4
5
6
7
heybox_id      固定且唯一(对于每一个用户来说)
imei           移动通信国际识别码(每个移动设备具有唯一性)
os_type        系统类型
os_version     系统版本
version        apk的版本
_time          时间
hkey           时间key

以及cookie中的pkey

1
Cookie: pkey=???   固定且唯一(对于每一个用户登录后)

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

 

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

定位算法(v1.1.50)

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

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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());
    }
}

str是当前时间/1000

 

分析下str1是怎么赋值的

1
String str1 = d.h(((d.h("xiaoheihe/_time="+str)).replaceAll("a", "app")).replaceAll("0", "app"));

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

 

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

 

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

 

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

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 "";
       }
    }

发现就是个md5.

 

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

1
2
3
4
5
6
7
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

模拟算法(v1.1.50)

用脚本去验证下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#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是一致的
'''

定位算法(v.1.3.92)

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

 

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

1
2
3
4
5
6
7
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

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

 

我们先不逆向

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#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
'''

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

 

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

 

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

 

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

 

先看第一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 "";
       }
    }

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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());
    }
}

关键代码

1
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);

看下str2是怎么获得的

1
2
3
4
5
6
7
8
9
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);

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.max.xiaoheihe.utils.NDKTools;
import java.lang.System;
import java.lang.String;
import java.lang.Object;
 
public class NDKTools    // class@00138f
{
    static {
       System.loadLibrary("native-lib");
    }
    public void NDKTools(){
       super();
    }
    public static native int checkSignature(Object p0);
    public static native synchronized String encode(Object p0,String p1,String p2);
    public static native String getrsakey(Object p0,String p1);
}

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

hook&疑问

本地环境

1
2
frida --version
15.2.2

手机端运行frida的服务端

1
./frida-server-15.2.2-android-arm64 &

电脑端查看进程

1
Frida-ps -U

run.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#coding:utf8
import sys
import frida
process_name = 'com.max.xiaoheihe'
# 发送信息回调函数
def on_message(message, data):
    if message['type'] == 'send':
        print(f"[*] {message['payload']}")
    else:
        print(message)
if __name__ == '__main__':
    try:
        device = frida.get_usb_device(timeout=1000)
        print("* get usb device成功")
    except:
        device = frida.get_remote_device(timeout=1000)
        print("* get remote device成功")
    if not device:
        print("* 连接到Frida Server失败")
    else:
        process = device.attach(process_name)
        # 加载JS脚本
        js = open('hook.js', encoding='utf-8').read()
        print(js)
        script = process.create_script(js)
        script.on('message', on_message)
        script.load()
        # 读取返回输入
        input()
        script.unload()

hook.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
console.log("脚本载入成功");
Java.perform(function () {
    var encodeAddr = Module.findExportByName("libnative-lib.so", "encode");
    console.log(encodeAddr);
    if (encodeAddr != null) {
        Interceptor.attach(encodeAddr, {
            onEnter: function (args) {
                //args参数数组
                console.log('encode-Enter')
                console.log(args[0], Memory.readCString(args[0]));
                console.log(args[1], Memory.readCString(args[1]));
                console.log(args[2], Memory.readCString(args[2]));
                console.log(args[3], Memory.readCString(args[3]));
                console.log(args[4], Memory.readCString(args[4]));
            },
            onLeave: function (retval) {
                //retval函数返回值
                console.log('encode-Leave');
                console.log(retval.toString());
                console.log('======');
            }
        });
    }
})

发现可以成功运行起来

 

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

 

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

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
int __fastcall encode(_JNIEnv *env, int a2, int a3, int can_str2, int can_str1)
{
  const char *v5; // r10
  _JNIEnv *v6; // r4
  int v7; // r6
  int v8; // r8
  const char *str2; // r11
  int str1; // r0
  bool v11; // zf
  size_t v12; // r5
  char *v13; // r5
  char *v14; // r0
  size_t v15; // r0
  char *v16; // r0
  int v17; // r5
  int result; // r0
  int v19; // [sp+0h] [bp-30h]
  int *v20; // [sp+4h] [bp-2Ch]
  int v21; // [sp+8h] [bp-28h]
  int v22; // [sp+Ch] [bp-24h]
 
  v19 = can_str2;
  v6 = env;
  v7 = can_str2;
  if ( j_check_signature(env) == 1 )
  {
    v8 = 0;
    str2 = (const char *)((int (__fastcall *)(_JNIEnv *, int, _DWORD))v6->functions->GetStringUTFChars)(v6, v7, 0);
    str1 = ((int (__fastcall *)(_JNIEnv *, int, _DWORD))v6->functions->GetStringUTFChars)(v6, can_str1, 0);// 时间戳
    v11 = str2 == 0;
    if ( str2 )
    {
      v5 = (const char *)str1;
      v11 = str1 == 0;
    }
    if ( !v11 )                                 // str2不为空进入if
    {
      v21 = can_str1;
      v12 = strlen(str2);
      v20 = &v19;
      v13 = (char *)&v19 - ((strlen(v5) + v12 + 21) & 0xFFFFFFF8);
      v14 = strcpy(v13, str2);
      v15 = strlen(v14);
      _aeabi_memcpy(&v13[v15], "/bfhdkud_time=", 15);// v13为str2后面拼接上"/bfhdkud_time="
      v16 = strcat(v13, v5);                    // v16为v13后面拼接str1 即时间戳
      v17 = j_MDString(v16);                    // 对v16进行md5加密赋值给v17
      ((void (__fastcall *)(_JNIEnv *, int, const char *))v6->functions->ReleaseStringUTFChars)(v6, v7, str2);
      ((void (__fastcall *)(_JNIEnv *, int, const char *))v6->functions->ReleaseStringUTFChars)(v6, v21, v5);
      v8 = j_charToJstring(v6, v17);            // md5加密的结果赋值给v8
    }
    if ( _stack_chk_guard == v22 )
      return v8;                                // 返回
  }
  result = _stack_chk_guard - v22;
  if ( _stack_chk_guard == v22 )
    result = j_j_charToJstring(v6, UNSIGNATURE[0]);
  return result;
}

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

 

回到接口类中

1
2
String str3 = "app";
str2 = (Q.b(((NDKTools.encode(HeyBoxApplication.g(), str2, str1)).replaceAll("a", str3)).replaceAll("0", str3))).substring(i, 10);

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

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 "";
   }
}

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

模拟算法(v.1.3.92)

写成python实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#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():
    str1="1666285158"
    str1="1666259837"
    str2="/bbs/app/api/user/permission/"
    #str2="/account/get_ads_info/"
    if str2[-1]=="/":
        str2=str2[:-1]
    zuhe_str = str2+"/bfhdkud_time="+str1
    #print(zuhe_str)
    ret=md5(zuhe_str).replace("a","app").replace("0","app")
    hkey=md5(ret)[0:10]
    print(hkey)
 
if __name__ == '__main__':
    gethkey()
'''
MD5加密前为 :/bbs/app/api/user/permission/bfhdkud_time=1666259837
MD5加密后为 :5e3fa112b55e9b8a087a5a1196f4645f
MD5加密前为 :5e3fapp112b55e9b8appapp87app5app1196f4645f
MD5加密后为 :0cf9be6f884cbf25ffd97e9fa61778d4
0cf9be6f88
'''

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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: ???
Host: api.xiaoheihe.cn
Connection: Keep-Alive
Accept-Encoding: gzip
 
#####################################################
GET /account/get_ads_info/?heybox_id=???&imei=???&os_type=Android&os_version=8.1.0&version=1.3.92&_time=1666285158&hkey=d630c904c2 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: ????
Host: api.xiaoheihe.cn
Connection: Keep-Alive
Accept-Encoding: gzip

参考

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


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

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