先看看设备注册的包:
POST https://log-lq.snssdk.com/service/2/device_register/?device_id=56581003169&
is_activated=1&aid=1128&tt_data=a&version_code=12.4.0&app_name=aweme&app_version=12.4.0&vid=84185501-88C0-4E38-BA3D-F3656A073020&device_id=56581003169&channel=App%20Store&mcc_mnc=46001&aid=1128&screen_width=1125&openudid=690af6a89ae78c69306c8a07bca241b840sd156&cdid=AD072FE4-41B7-4890-BEBC-2D57A4F3F253&os_api=18&ac=4G&os_version=12.4&build_number=123011&device_platform=android&iid=3125112636576938&device_type=Huawei%C8600&is_vcd=1 HTTP/1.1
Host: log-lq.snssdk.com
Connection: keep-alive
Content-Length: 856
Accept: application/json
Cookie: odin_tt=458f8eb0d95b7b9adb4b6fc6591918bfb996096967a7aa4305bd81b5150a8199d2e29ed21883cdd7709c5beaa2be3baa; sessionid=66e5128a179ef5f03f5187bae265bf9c; sessionid_ss=ff5128a179ef5f03f5187baecss22; sid_guard=d2da128a179ef5f03f5187bae265bf9c%7C1598662639%7C5183349%7CWed%2C+28-Oct-2020+00%3A46%3A28+GMT; sid_tt=66e5128a179ef5f03f5187bae265bf9c; uid_tt=fsffdc1fa00bb0ddddd400f58d5795df3; uid_tt_ss=232ec1fa00bb0ddddd400f58d5795321; install_id=3125112636576938; ttreq=1$432133fb80de2e267dd1a8478e5394cdd0cd23d1
Content-Type: application/octet-stream;tt-data=a
X-SS-Cookie: install_id=3125112636576938; ttreq=432133fb80de2e267dd1a8478e5394cdd0cd23d1; sessionid=ff5128a179ef5f03f5187baecss22; sessionid_ss=ff5128a179ef5f03f5187baecss22; sid_guard=ff5128a179ef5f03f5187baecss22%7C1598662639%7C5183349%7CWed%2C+28-Oct-2020+00%3A46%3A28+GMT; sid_tt=ff5128a179ef5f03f5187baecss22; uid_tt=d36ec1fa00bb0ddddd400f58d5795df3; uid_tt_ss=d36ec1fa00bb0ddddd400f58d5795df3; odin_tt=a09d8eb0d95b7b9adb4b6fc6591918bfb996096967a7aa4305bd81b5150a8199d2e29ed21883cdd7709c5beaa2be3baa
tt-request-time: 15994653422123
User-Agent: Aweme 12.3.0 rv:123015 (iPhone; iOS 12.2; zh_CN) Cronet
aid: 1128
x-Tt-Token: 00632e5128a179ef5f03f5187bae265bf9cdded28ab77be5f36e4259d59aa924b6c7f5284cdd07bf788188bb5185d61c32145
sdk-version: 2
passport-sdk-version: 5.12.1
X-SS-STUB: 34C32EDE4A3C45F55403E5EBD44A321B
X-SS-DP: 1128
x-tt-trace-id: 00-6123a32f7a09f80897b9fe6e7cc5490468-62a08f7a09f32457-01
Accept-Encoding: gzip, deflate, br
X-Khronos: 1599465342
X-Gorgon: 040802f0000e09020319e1d6be6194bfbd32024c25831c86bce
在新版设备注册的url中你会发现多了一部分参数,但是有一个参数比较耀眼那就是is_activated=1。明白人一眼就能看出来是什么含义,关于设备注册里面的参数在这里不方便分析,需要详细了解的可以联系我!评论区有联系方式!
首先我们要知道抖音封禁设备靠判断什么
然后我们就可以针对它来解。
抖音判断一台设备无非就是根据手机的IMEI,IMSI,MAC,系统版本
型号之类的来判断时候同一台设备
我们利用JADX来逆向,关键函数在ttEncrypt方法
func IIDEncrypt(plainStr []byte) []byte {
CplainStr := C.CString(string(plainStr))
defer C.free(unsafe.Pointer(CplainStr))
plainlength := len(plainStr)
libPathC := C.CString(EXTENSION_DIR + OIDB_API)
defer C.free(unsafe.Pointer(libPathC))
encryptedLength := plainlength + 4 + (16 - plainlength%16)
CKeyStr := C.CString("!*ss!_defaul%t54K&EY")
defer C.free(unsafe.Pointer(CKeyStr))
CEncryptedStr := C.encode(libPathC, CplainStr, C.int(encryptedLength), CKeyStr, C.int(20))
defer C.free(unsafe.Pointer(CEncryptedStr))
encryptedStr := C.GoBytes(unsafe.Pointer(CEncryptedStr), C.int(encryptedLength))
//encryptedHexStr := hex.EncodeToString(encryptedStr)
return encryptedStr
}
char* Encode(char* plain, int plainlength, char* key, int keylength)
{
//string plain = hexToStr(hexplain);
char *xkey;
char *xplain;
//int keylength = key.length();
//int plainlength = plain.length();
xkey = (char*) malloc(keylength);
xplain = (char*) malloc(plainlength);
memcpy(xkey, key, keylength);
memcpy(xplain, plain, plainlength);
unsigned char *out = (unsigned char*) malloc(plainlength + 100);
aweme_aes((__int64)xplain, plainlength, (__int64)xkey, keylength, (__int64)out);
free(xkey);
free(xplain);
xkey = NULL;
xplain = NULL;
// int cryptedStr_length = plainlength + 4 + (16 - plainlength%16);
// std::string hexStr = charsToHex(out, cryptedStr_length);
// free(out);
//out = NULL;
return (char*)out;
}
#include "subs.h"
uint32 bswap32(uint32 x)
{
return ((x << 24) & 0xff000000) |
((x << 8) & 0x00ff0000) |
((x >> 8) & 0x0000ff00) |
((x >> 24) & 0x000000ff);
}
unsigned char InvSbox[256] = { // inverse s-box
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
unsigned char Sbox[256] = { // forward s-box
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };
__int64 aweme_aes(__int64 plainStr, __int64 plainStr_length, __int64 key, __int64 key_length, __int64 strOut)
{
return sub_1005D099C((const void *)plainStr, plainStr_length, (void *)key, key_length, (_BYTE *)strOut, 2);
}
signed __int64 sub_1005D099C(const void *plainStr, signed int plainStr_length, void *keyStr, signed int keyStr_Length, _BYTE *strOut, char value_2)
{
char v6; // w21
_BYTE *strOut2; // x19
signed int v8; // w20
const void *v9; // x22
signed __int64 result; // x0
int v11; // w8
unsigned int v12; // w8
int v13; // w9
int v14; // w8
unsigned int v15; // w24
int v16; // w25
_BYTE *v17; // x23
signed __int64 v18; // x8
signed __int64 v19; // x8
int v20; // w10
int w11; // w11
int w12; // w12
int w14; // w14
unsigned int *v24; // x13
unsigned int v25; // w16
unsigned int *v26; // [xsp+8h] [xbp-58h]
int v27; // [xsp+Ch] [xbp-54h]
int v28; // [xsp+10h] [xbp-50h]
int v29; // [xsp+14h] [xbp-4Ch]
v26 = (unsigned int*) malloc(1000);
v6 = value_2;
strOut2 = strOut;
v8 = plainStr_length;
v9 = plainStr;
result = 0xFFFFFFFFLL;
if (keyStr_Length >= 1 && keyStr && plainStr_length >= 1 && strOut)
{
sub_1005D0B50(keyStr, keyStr_Length, (unsigned int *)v26);
//sub_1005D0B50(a3, a4, (unsigned int *)&v26);
v11 = v8 + 15;
if (v8 >= 0)
v11 = v8;
v12 = v8 - (v11 & 0xFFFFFFF0);
v13 = 16 - v12;
v14 = 31 - v12;
if (v13 >= 0)
v14 = v13;
v15 = v13 - (v14 & 0xFFFFFFF0);
v16 = v8 + v15 + 4;
v17 = strOut2 + 4;
memmove(strOut2 + 4, v9, v8);
*strOut2 = 116;
strOut2[1] = 99;
strOut2[2] = v6;
strOut2[3] = v15;
if (v16 >= 5) //plainStr_length
{
v18 = (unsigned int)v16 - 4LL;
do
{
*v17 = Sbox[(unsigned __int8)*v17];
++v17;
--v18;
} while (v18);
}
if ((signed int)(v15 + v8) >= 16)
{
v19 = 0LL;
// v20 = v26; //0x25
//
// w11 = (int)((&v26)[1]);
// w12 = (int)((&v26)[2]);
// w14 = (int)((&v26)[3]);
v20 = *v26; //0x25
//int * tmp1 = (int*)v20;
w11 = v26[1];
// int * tmp2 = (int*)w11;
w12 = v26[2];
//int * tmp3 = (int*)w12;
w14 = v26[3];
//int * tmp4 = (int*)w14;
v24 = (unsigned int *)(strOut2 + 16);
do
{
v25 = *(v24 - 2);
*(v24 - 3) = bswap32(bswap32(*(v24 - 3)) ^ v20);
*(v24 - 2) = bswap32(w11 ^ __ROR4__(bswap32(v25), 24));
*(v24 - 1) = bswap32(w12 ^ __ROR4__(bswap32(*(v24 - 1)), 16));
*v24 = bswap32(w14 ^ __ROR4__(bswap32(*v24), 8));
v24 += 4;
++v19;
} while (v19 < (v15 + v8) >> 4);
}
result = 0LL;
}
free(v26);
v26 = NULL;
return result;
}
void * sub_1005D0B50(void *keyStr, signed int keyStr_length, unsigned int *out)
{
unsigned int *out2; // x19
signed int keyStr_length2; // w20
signed int v5; // w21
void *result; // x0
__int64 v7; // x8
bool v8; // nf
unsigned __int8 v9; // vf
__int64 v10; // x8
unsigned int v11; // w9
unsigned int v12; // w9
out2 = out;
keyStr_length2 = keyStr_length;
if (keyStr_length >= 16)
v5 = 16;
else
v5 = keyStr_length;
result = memcpy(out, keyStr, v5);
if (keyStr_length2 <= 15)
{
v7 = v5 + 1;
do
{
*((_BYTE *)out2 + v7 - 1) = InvSbox[*((unsigned __int8 *)out2 + v7 - 2)];
v9 = __OFSUB__(v7, 16LL);
v8 = v7++ - 16 < 0;
} while (v8 ^ v9);
}
v10 = 0LL;
do
{
*((_BYTE *)out2 + v10) = Sbox[*((unsigned __int8 *)out2 + v10)];
++v10;
} while (v10 != 16);
v11 = out2[1];
*out2 = bswap32(*out2); //w10
out2[1] = bswap32(v11); //w11
v12 = out2[3];
out2[2] = bswap32(out2[2]); //w12
out2[3] = bswap32(v12); //w14
//printf("");
return result;
}
通过上面device_register的url我们可以知道,设备注册其实是向抖音提交当前设备的一些信息,例如MAC、SSID、UUID、IMEI、IMSI、WIFIMAC、device_brand、device_model、device_board、device_type、openudid、clientudid、build_serial等等来注册得到 device_id和install_id。
其实抖音的验签机制很野,即使你的x-gorgon算法生成稍微和它APP本身计算的有些出入(说白了就是抖音检测到你是独立计算到),它照样会开放一些功能给你,比如获取feed接口(热门视频),但是你会发现没法点赞,评论,私信。后来经过frida进行一个hook验证,发现确有此事,很多x-gorgon算法都是使用hook或者直接调用so到方式实现到,根本没去真正解刨它里面到运算过程。再一次测试到过程中,我把url以及x-khrons和cookie,xttsub固定起来,使用hook或者调用so的方式去计算x-gorgon结果,发现不管你执行多少次,结果都是一样的。但是,我使用frida来拦截抖音它自己的签名过程,并把参数改成和上面的一样,那么它每次计算的结果都不一样。由此可见,抖音在计算过程中肯定获取了某些全局参数,比如它签名后会把一些值存入到
一个全局变量,下次计算到时候读取,也或者它在某些功能动作到时候,会记录一些值,影响签名到计算算法。这个事情到确实得到多次证实,用hook或者so调用方式其实抖音是知道的
如果是直接把SO拿出来调用,得到的跟APP里面得出的是不一致的。
进一步验证,我把cms的接口都HOOK住。然后看顺序。
输出结果如下
decode:0404001000018b386ff8b154ff4fc10cf79d74bca55d75398ee0
decode:5dfc13b6e9b1a8131ec9fe3546ce6e4900000000000000000000000000000000435be92aa3259d3fdbed7d341f16d2da00000000000000000000000000000000
decode:040400100001d956086cf8e14b01c10cf79d74bca55d75394ea6
decode:153a6e2fbe986c0472603ddb349fd95d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
decode:0404001000019bde7af5f8e14bc33736dad874bca55d75395665
decode:f3e0258d2bb713f718dd8a335109228a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
decode:040400100001b6b912a1f8e14bc33736dad874bca55d753956d1
decode:00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
decode:0404001000014d6de9baf8e14bc33736dad874bca55d7539560e
decode:153a6e2fbe986c0472603ddb349fd95d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
decode:0404001000019bde7af5f8e14bc33736dad874bca55d7539d66d
decode:153a6e2fbe986c0472603ddb349fd95d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
decode:0404001000019bde7af5f8e14bc33736dad874bca55d7539d66d
decode:18cb57ab5a5e6c4e281a59e850958c6614e1e5f771c631bc1195c3725673279c435be92aa3259d3fdbed7d341f16d2da00000000000000000000000000000000
调用了META接口之后,XG有明显的变化。在经过234编号后就无明显变化。
XG的计算不单纯是简单的几个参数串在一起调用SO就完事的。
我为了严谨再次确认,从软件启动的时候每隔3秒调用一次。输出如下。
‘ * “0404d07100019a0e1440e23f320ce4a518a2316455f6681c77ff|1595258812”
‘ * “0404d07100019a0e1440e23f320ce4a518a2316455f6681cb7f3|1595258815”
‘ * “0404d07100019a0e1440e23f320ce4a518a2316455f6681c0918|1595258818”
‘ * “0404f871000116414c1cb5ff90d058381eac0ff8b86f5b6cf841|1595258821”
‘ * “0404c0fa0001b283c4aa6d8371ce4786276f68d39bbfbe3ff76b|1595258824”
‘ * “04047847000199e497dc87cc722beb6b04bec1dc480ba39ce3b6|1595258827”
‘ * “04040000000116faf9c9565f3c17c9e2a8d723bfb55edbb34c29|1595258830”
‘ * “04040000000116faf9c9565f3c17c9e2a8d723bfb55edbb3b4a6|1595258833”
‘ * “04040000000116faf9c9565f3c17c9e2a8d723bfb55edbb314ac|1595258836”
‘ * “04040000000116faf9c9565f3c17c9e2a8d723bfb55edbb324af|1595258840”
‘ * “04040000000116faf9c9565f3c17c9e2a8d723bfb55edbb3e4a3|1595258843”
‘ * “04040000000116faf9c9565f3c17c9e2a8d723bfb55edbb344a9|1595258846”
‘ * “04040000000116faf9c9565f3c17c9e2a8d723bfb55edbb3b866|1595258849”
‘ * “04040000000116faf9c9565f3c17c9e2a8d723bfb55edbb3186c|1595258852”
‘ * “04040000000116faf9c9565f3c17c9e2a8d723bfb55edbb3d860|1595258855”
‘ * “04040000000116faf9c9565f3c17c9e2a8d723bfb55edbb3686b|1595258858”