交流:base64解碼(UVEyODkxNTkwNTc4)
shield是小紅書請求header中的一個(gè)加密參數(shù)双仍,具體算法是在so中計(jì)算的,so文件是libshield.so朽基。我這邊主要就講一下如何利用unidbg調(diào)用so生成shield參數(shù)削彬。因篇幅可能較長叶圃,這篇文章就講下如何找到Native函數(shù)和函數(shù)所對應(yīng)的偏移位置。
一布轿、尋找Native函數(shù)
老規(guī)矩,首先反編譯apk后用JD-GUI工具打開(也可使用jadx等工具)来颤,直接搜索shield汰扭,結(jié)果意料之中,在java層沒搜到什么有用的信息脚曾,算法大概率放在了so層东且。
那我們只能在so層中尋找突破口,這里推薦一位大佬開發(fā)的工具frida_hook_libart(項(xiàng)目地址:https://github.com/lasting-yang/frida_hook_libart)本讥,它是把在libart.so中的常用函數(shù)都進(jìn)行了hook珊泳。
總共有三個(gè)hook文件hook_RegisterNatives.js、hook_art.js拷沸、hook_artmethod.js色查,我們先使用這個(gè)hook_art。
首先在手機(jī)上打開frida-server服務(wù)撞芍,電腦終端運(yùn)行命令:“frida -U –no-pause -f com.xingin.xhs -l hook_art.js”秧了。
然后找啊找,會發(fā)現(xiàn)在NewStringUTF這個(gè)函數(shù)中序无,出現(xiàn)了shield結(jié)果验毡。這里所對應(yīng)的so文件是libshield.so 衡创。
然后運(yùn)行命令:“frida -U –no-pause -f com.xingin.xhs -l hook_RegisterNatives.js”,看一下在libshield里動態(tài)注冊了哪些Native函數(shù)晶通。
可以看到璃氢,在so中,注冊了initializeNative狮辽、intercept一也、initialize這幾個(gè)函數(shù)。
然后在java層找下喉脖,可以找到在“com.xingin.shield.http.XhsHttpInterceptor”這個(gè)類下椰苟,如下圖:
二、尋找Native函數(shù)的偏移位置
方法一:
上文有使用Frida hook了so的RegisterNatives函數(shù)树叽,hook到的同時(shí)舆蝴,也打印出了函數(shù)的offset偏移位置。
initializeNative函數(shù)的偏移位為:0x6c11d
intercept函數(shù)的偏移位為:0x6b9e9
initialize函數(shù)的偏移位為:0x6b801
方法二:
首先使用ida打開libshield.so文件菱皆,使用shift+F12打開String window窗口须误。
在窗口中直接搜索剛剛找到的Native函數(shù),如intercept:
然后點(diǎn)進(jìn)去仇轻,就能找到這里
intercept函數(shù)的偏移位就是0x6b9e9京痢。
方法三:
同樣使用ida打開libshield.so文件,在Exports窗口中找到JNI_OnLoad(動態(tài)注冊的函數(shù)都會在JNI_OnLoad中進(jìn)行注冊)篷店,然后進(jìn)去F5反匯編下祭椰。
然后可以看到sub_9FA0這個(gè)函數(shù),點(diǎn)進(jìn)去疲陕。
這邊有很多函數(shù)方淤,逐個(gè)進(jìn)行查看,最終找到sub_6B360這個(gè)地方蹄殃,點(diǎn)進(jìn)去携茂。
可以看到j(luò)ava層的“com.xingin.shield.http.XhsHttpInterceptor”這個(gè)類,在點(diǎn)進(jìn)去诅岩,就到了剛剛方法二中的這個(gè)位置讳苦,偏移位直接復(fù)制下就好。
三吩谦、搭建unidbg環(huán)境
首先把unidbg項(xiàng)目拉下來(項(xiàng)目地址:https://github.com/zhkl0228/unidbg)。
在test中新建一個(gè)類式廷,然后把小紅書apk和對應(yīng)的libshiled.so文件放到resources資源目錄下。
然后把最基本的unidbg框架搭下,代碼如下:
public class ShieldTest extends AbstractJni {
//ARM模擬器
private final AndroidEmulator emulator;
//vm
private final VM vm;
//載入的模塊
private final Module module;
public ShieldTest() {
// 創(chuàng)建模擬器實(shí)例
emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.xhs").build();
Memory memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
// 創(chuàng)建Android虛擬機(jī)
vm = emulator.createDalvikVM(new File("unidbg-android/src/test/resources/xhs/xhs_v6.97.0.apk"));
vm.setJni(this);
vm.setVerbose(true);
//加載so
DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/xhs/libshield_v6.97.0.so"), true);
dm.callJNI_OnLoad(emulator);
module = dm.getModule();
}
}
四袜爪、分析Native函數(shù)
我們分析下這塊代碼:
1 首先需要調(diào)initializeNative這個(gè)初始化函數(shù);
2 第二步調(diào)initialize函數(shù)穗慕,獲取cPtr饿敲;
3 最終生成shield是調(diào)用intercept函數(shù)逛绵,需傳入一個(gè)“okhttp3/Interceptor$Chain”倔韭,paramLong就是第二步獲取的cPtr值术浪。
五、補(bǔ)缺失環(huán)境
先把初始化函數(shù)initializeNative的代碼邏輯寫上(偏移位置怎么找可以看我的上篇文章)寿酌。
public void initializeNative() {
List<Object> params = new ArrayList<>();
params.add(vm.getJNIEnv());
params.add(0);
module.callFunction(emulator, 0x6c11d, params.toArray());
}
public static void main(String[] args) {
ShieldTest shieldTest = new ShieldTest();
shieldTest.initializeNative();
}
直接運(yùn)行下胰苏,會發(fā)現(xiàn)報(bào)錯(cuò)了醇疼。
這個(gè)報(bào)錯(cuò)一般就說明要補(bǔ)環(huán)境了。
這里先解釋下這個(gè):“java/nio/charset/Charset->defaultCharset()Ljava/nio/charset/Charset;”
這句話的意思是調(diào)用java/nio/charset/Charset這個(gè)類下的defaultCharset函數(shù)秧荆,返回值是Ljava/nio/charset/Charset,unidbg缺少這一塊的處理邏輯陕赃,我們需要手動補(bǔ)上颁股。
我們可以直接點(diǎn)“com.github.unidbg.linux.android.dvm.AbstractJni.callStaticObjectMethodV(AbstractJni.java:388)”這個(gè)位置么库,進(jìn)去后會看到一個(gè)方法甘有,我們需要重寫callStaticObjectMethodV方法,然后把Charset對象return回去就好忱反。
@Override
public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
switch (signature) {
case "java/nio/charset/Charset->defaultCharset()Ljava/nio/charset/Charset;":
return vm.resolveClass("java/nio/charset/Charset").newObject(Charset.defaultCharset());
}
throw new UnsupportedOperationException(signature);
}
繼續(xù)運(yùn)行幌氮,發(fā)現(xiàn)又報(bào)錯(cuò)了
這次是缺少一個(gè)versionCode參數(shù),這個(gè)參數(shù)可以在AndroidManifest.xml文件中找到该互,我這個(gè)版本是6970181,直接返回即可蔓搞。
@Override
public int getIntField(BaseVM vm, DvmObject<?> dvmObject, String signature) {
switch (signature) {
case "android/content/pm/PackageInfo->versionCode:I": {
return 6970181;
}
}
return super.getIntField(vm, dvmObject, signature);
}
然后繼續(xù)運(yùn)行,報(bào)錯(cuò)了就補(bǔ)環(huán)境喂分,我就不把所有的都寫出來了,比較多甘萧,挑幾個(gè)講一下梆掸。
sDeviceId:
這里是缺少一個(gè)sDeviceId參數(shù),我這里是通過IDA分析這塊代碼怪得,然后打印GetStringUTFChars函數(shù)結(jié)果找到的卑硫。
ps:
這里分析IDA代碼有個(gè)技巧,像這塊代碼欢伏,v1大概率就是env入挣,可以在v1上右鍵“set lvar type”颜懊,把類型改為JNIEnv*,然后確定匠璧,會發(fā)現(xiàn)很多函數(shù)能顯示出來了咸这,看起來會直觀很多。
main_hmac:
這個(gè)參數(shù)可以直接adb連上去媳维,在s.xml文件下找到。
然后依次把三個(gè)函數(shù)的所有環(huán)境補(bǔ)完指黎,就可以運(yùn)行生成shield了州丹。
下面是三個(gè)Native函數(shù)的代碼邏輯:
public void initializeNative() {
List<Object> params = new ArrayList<>();
params.add(vm.getJNIEnv());
params.add(0);
module.callFunction(emulator, 0x6c11d, params.toArray());
}
public long initialize() {
List<Object> params = new ArrayList<>();
params.add(vm.getJNIEnv());
params.add(0);
params.add(vm.addLocalObject(new StringObject(vm, "main")));
Number number = module.callFunction(emulator, 0x6b801, params.toArray());
return number.longValue();
}
public void intercept(long cPtr) {
List<Object> params = new ArrayList<>();
params.add(vm.getJNIEnv());
params.add(0);
DvmObject<?> chain = vm.resolveClass("okhttp3/Interceptor$Chain").newObject(null);
params.add(vm.addLocalObject(chain));
params.add(cPtr);
Number number = module.callFunction(emulator, 0x6b9e9, params.toArray());
Object result = vm.getObject(number.intValue()).getValue();
}
public static void main(String[] args) {
ShieldTest shieldTest = new ShieldTest();
shieldTest.initializeNative();
long cPtr = shieldTest.initialize();
System.out.println(cPtr);
shieldTest.intercept(cPtr);
}
六杂彭、最終效果
七吓揪、最終還原源碼
"""
生成小紅書app接口參數(shù)中的shield
"""
import base64
from functools import reduce
from operator import add, or_, xor
import base64
def bytes_to_int32(t):
return [int.from_bytes(t[i * 4:(i + 1) * 4], byteorder='little') for i in range(len(t) // 4)]
def int32_to_bytes(t):
return reduce(add, [bytearray((t % 2 ** 32).to_bytes(4, byteorder='little')) for t in t])
def byte_n(t, n):
return bytearray(t.to_bytes(4, byteorder='little'))[n]
def read_int16(t):
return int.from_bytes(t[:2], byteorder='little')
def read_int32(t):
return int.from_bytes(t[:4], byteorder='little')
def b_swap32(t):
return bytes_to_int32(int32_to_bytes([t])[::-1])[0]
data_a798 = bytearray('0123456789abcdef', encoding='utf-8')
AES_T3 = ["種子找我拿qq2891590578"]
AES_T4 = ["種子找我拿qq2891590578"]
AES_T1 = ["種子找我拿qq2891590578"]
AES_SBOX = ["種子找我拿qq2891590578"]
AES_RCON = ["種子找我拿qq2891590578"]
AES_T5 = ["種子找我拿qq2891590578"]
AES_T6 = ["種子找我拿qq2891590578"]
AES_T7 = ["種子找我拿qq2891590578"]
AES_T8 = bytes_to_int32( ["種子找我拿qq2891590578"])
AES_SIBOX = ["種子找我拿qq2891590578"]
def sub_2af14(a1, a3):
a1 = bytes_to_int32(a1)
a3 = bytes_to_int32(a3)
a3[60] = 10
a3[0] = b_swap32(a1[0]) ^ 0xF1892131
a3[1] = b_swap32(a1[1]) ^ 0xFF001123
a3[2] = b_swap32(a1[2]) ^ 0xF1001356
a3[3] = b_swap32(a1[3]) ^ 0xF1234890
v1 = 0
v8 = 0
while True:
v3 = a3[v1 + 3]
a3[v1 + 4] = reduce(xor, [
a3[v1 + 0],
AES_T3[(v3 >> 16) & 0xFF] & 0xFF000000,
AES_T4[(v3 % 2 ** 16) >> 8] & 0xFF0000,
AES_T1[v3 % 2 ** 8] & 0xFF00,
AES_SBOX[4 * (v3 >> 24)],
AES_RCON[v8]
])
a3[v1 + 5] = a3[v1 + 1] ^ a3[v1 + 4]
a3[v1 + 6] = a3[v1 + 2] ^ a3[v1 + 5]
a3[v1 + 7] = a3[v1 + 3] ^ a3[v1 + 6]
v8 += 1
if v8 == 10:
break
v1 += 4
return int32_to_bytes(a3)
def sub_2b2d0(a3):
a3 = bytes_to_int32(a3)
v13 = 0
i = 4 * a3[60]
while v13 < i:
for j in range(4):
v3 = a3[v13 + j]
a3[v13 + j] = a3[i + j]
a3[i + j] = v3
v13 += 4
i -= 4
v15 = 0
i = 1
while i < a3[60]:
v15 += 4
a3[v15] = reduce(xor, [
AES_T8[AES_SBOX[4 * (a3[v15] % 2 ** 8)]],
AES_T5[AES_SBOX[4 * (a3[v15] >> 24)]],
AES_T6[AES_SBOX[4 * ((a3[v15] >> 16) & 0xFF)]],
AES_T7[AES_SBOX[4 * (a3[v15] % (2 ** 16) >> 8)]]
])
a3[v15 + 1] = reduce(xor, [
AES_T8[AES_SBOX[4 * (a3[v15 + 1] % 2 ** 8)]],
AES_T5[AES_SBOX[4 * (a3[v15 + 1] >> 24)]],
AES_T6[AES_SBOX[4 * ((a3[v15 + 1] >> 16) & 0xFF)]],
AES_T7[AES_SBOX[4 * (a3[v15 + 1] % (2 ** 16) >> 8)]]
])
a3[v15 + 2] = reduce(xor, [
AES_T8[AES_SBOX[4 * (a3[v15 + 2] % 2 ** 8)]],
AES_T5[AES_SBOX[4 * (a3[v15 + 2] >> 24)]],
AES_T6[AES_SBOX[4 * ((a3[v15 + 2] >> 16) & 0xFF)]],
AES_T7[AES_SBOX[4 * (a3[v15 + 2] % (2 ** 16) >> 8)]]
])
a3[v15 + 3] = reduce(xor, [
AES_T8[AES_SBOX[4 * (a3[v15 + 3] % 2 ** 8)]],
AES_T5[AES_SBOX[4 * (a3[v15 + 3] >> 24)]],
AES_T6[AES_SBOX[4 * ((a3[v15 + 3] >> 16) & 0xFF)]],
AES_T7[AES_SBOX[4 * (a3[v15 + 3] % (2 ** 16) >> 8)]]
])
i += 1
return int32_to_bytes(a3)
def sub_2b954(a1, a2, a3):
a1 = bytes_to_int32(a1)
a3 = bytes_to_int32(a3)
v17 = 0
v16 = b_swap32(a1[0]) ^ a3[0]
v15 = b_swap32(a1[1]) ^ a3[1]
v14 = b_swap32(a1[2]) ^ a3[2]
v13 = b_swap32(a1[3]) ^ a3[3]
v8 = a3[60] >> 1
while True:
raise "關(guān)鍵代碼找我拿qq2891590578"
v3 = reduce(or_, [
AES_SIBOX[byte_n(v12, 3)] << 24,
AES_SIBOX[byte_n(v9, 2)] << 16,
AES_SIBOX[(v10 % 2 ** 16) >> 8] << 8,
AES_SIBOX[(v11 % 2 ** 8)]
]) ^ a3[v17]
a2[0] = byte_n(v3, 3)
a2[1] = byte_n(v3, 2)
a2[2] = byte_n(v3, 1)
a2[3] = byte_n(v3, 0)
v4 = reduce(or_, [
AES_SIBOX[byte_n(v11, 3)] << 24,
AES_SIBOX[byte_n(v12, 2)] << 16,
AES_SIBOX[(v9 % 2 ** 16) >> 8] << 8,
AES_SIBOX[(v10 % 2 ** 8)]
]) ^ a3[v17 + 1]
a2[4] = byte_n(v4, 3)
a2[5] = byte_n(v4, 2)
a2[6] = byte_n(v4, 1)
a2[7] = byte_n(v4, 0)
v5 = reduce(or_, [
AES_SIBOX[byte_n(v10, 3)] << 24,
AES_SIBOX[byte_n(v11, 2)] << 16,
AES_SIBOX[(v12 % 2 ** 16) >> 8] << 8,
AES_SIBOX[(v9 % 2 ** 8)]
]) ^ a3[v17 + 2]
a2[8] = byte_n(v5, 3)
a2[9] = byte_n(v5, 2)
a2[10] = byte_n(v5, 1)
a2[11] = byte_n(v5, 0)
v6 = reduce(or_, [
AES_SIBOX[byte_n(v9, 3)] << 24,
AES_SIBOX[byte_n(v10, 2)] << 16,
AES_SIBOX[(v11 % 2 ** 16) >> 8] << 8,
AES_SIBOX[(v12 % 2 ** 8)]
]) ^ a3[v17 + 3]
a2[12] = byte_n(v6, 3)
a2[13] = byte_n(v6, 2)
a2[14] = byte_n(v6, 1)
a2[15] = byte_n(v6, 0)
return a2
def sub_2be2c(a1, a2, a3, a4, a7):
# a1, v3, len(a1), v2, bytearray(256)
a1 = bytes_to_int32(a1)
a2 = bytes_to_int32(a2)
a4 = bytes_to_int32(a4)
v1 = 0
v2 = 0
v16 = bytearray(16)
while a3:
v16 = sub_2b954(int32_to_bytes(a1[v1:]), v16, int32_to_bytes(a4))
i = 0
while True:
v10 = 0
if i <= 0xF:
v8 = 0
if i < a3:
v8 = 1
v10 = v8
if not (v10 << 31):
break
a2[v2 + i] = v16[i] ^ a7[i]
a7[i] = byte_n(bytes_to_int32(int32_to_bytes(a1)[i:])[v1], 0)
i += 1
a3 -= 16
v1 += 4
v2 += 16
if a3 <= 0x10:
while i <= 0xF:
a7[i] = byte_n(bytes_to_int32(int32_to_bytes(a1)[i:])[v1], 0)
i += 1
break
return a2
def sub_aaac(a1, a2):
a1 = base64.b64decode(a1)
v1 = [ord(t) for i, t in enumerate(a2) if i < 16]
v2 = [0 for _ in range(256)]
v2 = sub_2af14(v1, v2) # aes
v2 = sub_2b2d0(v2) # 可能是aes解密 初始化密鑰
v3 = bytearray(512)
v3 = sub_2be2c(a1, v3, len(a1), v2, bytearray(256)) # aes解密
return v3[16:80]
def make_ctx(a1, a2):
v2 = sub_aaac(a1, a2)
# print([hex(i) for i in v2])
# v2 = [0x31, 0xa3, 0xf5, 0x5, 0x52, 0x8b, 0x45, 0xce, 0xf7, 0x96, 0xd1, 0x7d, 0x70, 0xa9, 0xa1, 0x3a, 0xde, 0xc, 0x37, 0xe1, 0x40, 0xe5, 0xe, 0x92, 0xfe, 0x9c, 0x38, 0xfa, 0x51, 0x5, 0x3d, 0x33, 0x35, 0x4a, 0x4, 0xbc, 0x96, 0x6f, 0x3c, 0xe9, 0xe8, 0x84, 0x27, 0xdb, 0x0, 0x4a, 0xd4, 0xe9, 0xcf, 0xfc, 0x95, 0x13, 0xc7, 0xa5, 0x1a, 0x64, 0xe1, 0x64, 0x93, 0x2a, 0xbe, 0x86, 0x11, 0x38]
# 1, 35, 69, 103,137, 171, 205, 239,254, 220, 186, 152,118, 84, 50, 16
# 118, 84, 50, 16, 254, 220, 186, 152, 137, 171, 205, 239, 1, 35, 69, 103
v1 = [118, 84, 50, 16, 254, 220, 186, 152, 137, 171, 205, 239, 1, 35, 69, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 183, 201, 233, 121, 164,
27, 215, 219, 129, 16, 36, 217, 136, 16, 104, 175, 247, 20, 155, 177, 91, 31, 255, 190, 215, 28, 136, 34, 97,
102, 102, 147, 97, 102, 246, 158, 99, 25, 166, 33, 9, 20, 73, 238, 206, 29, 193, 175, 15, 28, 245, 42, 198,
23, 71, 19, 70, 16, 169, 1, 149, 22, 253, 98, 37, 30, 246, 83, 20, 116, 2, 145, 230, 33, 210, 201, 251, 19,
226, 230, 205, 97, 34, 151, 13, 213, 242, 237, 20, 90, 66, 5, 233, 119, 162, 249, 163, 119, 242, 217, 18, 111,
98, 154, 76, 42, 146, 64, 179, 64, 192, 81, 90, 94, 38, 170, 199, 246, 233, 93, 16, 63, 214, 214, 7, 87, 195,
66, 57, 252, 255, 145, 214, 124, 151, 68, 234, 188, 164, 169, 207, 220, 75, 112, 188, 188, 190, 198, 126, 140,
40, 96, 75, 204, 246, 250, 39, 172, 234, 149, 16, 236, 212, 57, 208, 220, 217, 229, 136, 220, 230, 5, 29, 140,
4, 249, 124, 162, 31, 34, 97, 157, 109, 101, 86, 172, 196, 28, 57, 229, 253, 68, 34, 41, 244, 167, 35, 148,
171, 57, 160, 147, 245, 195, 89, 91, 101, 151, 255, 42, 69, 125, 36, 239, 245, 209, 93, 132, 133, 146, 204,
12, 133, 224, 38, 153, 249, 79, 126, 153, 249, 20, 67, 153, 169, 130, 126, 83, 197, 161, 17, 8, 69, 166, 17,
8, 69, 53, 242, 58, 189, 145, 211, 134, 235, 0, 0, 0, 0]
backup = [86, 183, 201, 233, 121, 164, 27, 215, 219, 129, 16, 36, 217, 136, 16, 104, 175, 247, 20, 155, 177, 91, 31,
255, 190, 215, 28, 136, 34, 97, 102, 102, 147, 97, 102, 246, 158, 99, 25, 166, 33, 9, 20, 73, 238, 206,
29, 193, 175, 15, 28, 245, 42, 198, 23, 71, 19, 70, 16, 169, 1, 149, 22, 253, 98, 37, 30, 246, 83, 20,
116, 2, 145, 230, 33, 210, 201, 251, 19, 226, 230, 205, 97, 34, 151, 13, 213, 242, 237, 20, 90, 66, 5,
233, 119, 162, 249, 163, 119, 242, 217, 18, 111, 98, 154, 76, 42, 146, 64, 179, 64, 192, 81, 90, 94, 38,
170, 199, 246, 233, 93, 16, 63, 214, 214, 7, 87, 195, 66, 57, 252, 255, 145, 214, 124, 151, 68, 234, 188,
164, 169, 207, 220, 75, 112, 188, 188, 190, 198, 126, 140, 40, 96, 75, 204, 246, 250, 39, 172, 234, 149,
16, 236, 212, 57, 208, 220, 217, 229, 136, 220, 230, 5, 29, 140, 4, 249, 124, 162, 31, 34, 97, 157, 109,
101, 86, 172, 196, 28, 57, 229, 253, 68, 34, 41, 244, 167, 35, 148, 171, 57, 160, 147, 245, 195, 89, 91,
101, 151, 255, 42, 69, 125, 36, 239, 245, 209, 93, 132, 133, 146, 204, 12, 133, 224, 38, 153, 249, 79,
126, 153, 249, 20, 67, 153, 169, 130, 126, 83, 197, 161, 17, 8, 69, 166, 17, 8, 69, 53, 242, 58, 189, 145,
211, 134, 235]
ctx = [bytearray(v1), bytearray(v1), bytearray(v1)]
ctx[0] = sub_md5(ctx[0], [t ^ 0x36 for t in v2], 0x40)
ctx[1] = sub_md5(ctx[1], [t ^ 0x36 for t in v2], 0x40)
ctx[2] = sub_md5(ctx[2], [t ^ 0x5C for t in v2], 0x40)
return ctx
def sub_604db(a1):
for i in range(4):
a1[8 + i] = 0xFF
def sub_a6e8(a1, a2, a3):
v3, v5, v6, v8 = a1, a2, 0, 0
while True:
v8 = v5[v6]
if int.from_bytes(v3[8:12], 'little', signed=False) > 0:
sub_604db(a1)
v3[12 + 2 * v6] = data_a798[v8 >> 4]
v10 = v5[v6]
if int.from_bytes(v3[8:12], 'little', signed=False) > 0:
sub_604db(a1)
v3[12 + 2 * v6 + 1] = data_a798[v10 & 0xF]
v6 += 1
if v6 >= a3:
break
def sub_abb8():
v15 = bytearray(45)
v17 = bytearray([187, 197, 152, 57, 144, 47, 56, 83, 99, 121, 252, 203, 124, 139, 35, 19])
v15[0] = 0x20
v15[4] = 0x20
v15[8] = 0x00
for i in range(32):
v15[12 + i] = 0x20
v15[44] = 0x00
sub_a6e8(v15, v17, 0x10)
return v15
def __ror4__(value, count):
nbits = 32
value %= 2 ** nbits
low = value << (nbits - count)
value >>= count
value |= low
return value
# 類似md5的update
def sub_2cda0(a1, a2, a3):
a1 = bytes_to_int32(a1)
v205 = a1
v204 = a3
v203 = 0
v202 = a1[0]
v201 = a1[1]
v200 = a1[2]
i = a1[3]
while True:
r = v204
v204 -= 1
if not r:
break
raise "關(guān)鍵代碼找我拿叭首,base64解碼UVEyODkxNTkwNTc4"
return int32_to_bytes(a1)
# 類似md5的init
def sub_md5(a1, a2, a3):
a1 = bytes_to_int32(a1)
v8 = a1[4] + 8 * a3
if v8 < a1[4]:
a1[5] += 1
a1[5] += a3 >> 29
a1[4] = v8
v6 = a1[22]
if v6:
v9 = 6
a1 = int32_to_bytes(a1)
for i in range(64 - v6):
a1[v9 * 4 + v6 + i] = a2[i]
a1 = sub_2cda0(a1, a1[v9 * 4:], 1) # md5
a1 = bytes_to_int32(a1)
v3 = 64 - v6
a2 = a2[v3:]
a3 -= v3
a1[22] = 0
for i in range(64):
a1[v9 + i] = 0
v7 = a3 >> 6
if v7:
a1 = int32_to_bytes(a1)
a1 = sub_2cda0(a1, a2, v7)
a1 = bytes_to_int32(a1)
v4 = v7 << 6
a2 = a2[v4:]
a3 -= v4
if a3:
a1[22] = a3
a1 = int32_to_bytes(a1)
for i in range(a3):
a1[24 + i] = a2[i]
a1 = bytes_to_int32(a1)
return int32_to_bytes(a1)
def sub_2dd88(a1, a2):
v32 = 0
v31 = 0
v30 = 24
a2 = bytes_to_int32(a2)
v2 = a2[22]
a2 = int32_to_bytes(a2)
a2[v30 + v2] = 128
v29 = v2 + 1
if v29 >= 0x39:
for i in range(64 - v29):
a2[v30 + v29 + i] = 0
v29 = 0
a2 = sub_2cda0(a2, a2[24:], 1)
for i in range(56 - v29):
a2[v30 + v29 + i] = 0
v3 = v30 + 56
v4 = v3
v3 += 1
a2[v4] = read_int32(a2[v31 + 16:]) % 2 ** 8
v5 = v3
v3 += 1
a2[v5] = (read_int16(a2[v31 + 16:]) >> 8) % 2 ** 8
v6 = v3
v3 += 1
a2[v6] = read_int16(a2[v31 + 18:]) % 2 ** 8
v7 = v3
v3 += 1
a2[v7] = a2[v31 + 19]
v8 = v3
v3 += 1
a2[v8] = read_int32(a2[v31 + 20:]) % 2 ** 8
v9 = v3
v3 += 1
a2[v9] = (read_int16(a2[v31 + 20:]) >> 8) % 2 ** 8
v10 = v3
v3 += 1
a2[v10] = read_int16(a2[v31 + 22:]) % 2 ** 8
a2[v3] = a2[v31 + 23]
v3 -= 63
a2 = sub_2cda0(a2[v31:], a2[v3:], 1)
a2 = bytes_to_int32(a2)
a2[(v31 + 88) // 4] = 0
a2 = int32_to_bytes(a2)
for i in range(64):
a2[v3 + i] = 0
v11 = read_int32(a2[v31:])
v12 = v32
v13 = v32 + 1
a1[v12] = read_int32(a2[v31:]) % 2 ** 8
v14 = v13
v13 += 1
a1[v14] = byte_n(v11, 1)
v15 = v13
v13 += 1
a1[v15] = byte_n(v11, 2)
v16 = v13
v13 += 1
a1[v16] = byte_n(v11, -1)
v17 = read_int32(a2[v31 + 4:])
v18 = v13
v13 += 1
a1[v18] = v17 % 2 ** 8
v19 = v13
v13 += 1
a1[v19] = byte_n(v17, 1)
v20 = v13
v13 += 1
a1[v20] = byte_n(v17, 2)
v21 = v13
v13 += 1
a1[v21] = byte_n(v17, -1)
v22 = read_int32(a2[v31 + 8:])
v23 = v13
v13 += 1
a1[v23] = v22 % 2 ** 8
v24 = v13
v13 += 1
a1[v24] = byte_n(v22, 1)
v25 = v13
v13 += 1
a1[v25] = byte_n(v22, 2)
a1[v13] = byte_n(v22, -1)
v26 = read_int32(a2[v31 + 12:])
a1[v13 + 1] = v26 % 2 ** 8
a1[v13 + 2] = byte_n(v26, 1)
a1[v13 + 3] = byte_n(v26, -2)
a1[v13 + 4] = byte_n(v26, -1)
return a1, a2
def get_oldsign(path='', params='', xy_common_params='', xy_platform_info='', data='', content='',
main_hmac='', device_id=''):
"""
生成簽名 根據(jù)main_hmac device_id解密出一個(gè)key放棒。
"""
ctx = make_ctx(main_hmac, device_id)
content = bytearray(content, encoding='utf-8') or bytearray(
''.join([path, params, xy_common_params, xy_platform_info, data]), encoding='utf-8')
# content = "/api/sns/v4/search/recommendkeyword=nnss&source=search_result_notes&word_request_id=&geo=eyJsYXRpdHVkZSI6MC4wMDAwMDAsImxvbmdpdHVkZSI6MC4wMDAwMDB9%0Afid=162925699210bf9c0d3447ec1a57edbfc9b9f44f9625&device_fingerprint=20210810140918508c2ccd6e986960ec8432e9c2edd16b01265a5749ac3489&device_fingerprint1=20210810140918508c2ccd6e986960ec8432e9c2edd16b01265a5749ac3489&launch_id=1629277029&tz=Asia%2FShanghai&channel=YingYongBao&versionName=7.1.0&deviceId=879246a0-b385-3400-b59d-76f63fa5baff&platform=android&sid=session.1629264087421090169948&identifier_flag=4&t=1629280763&project_id=ECFAAF&build=7010138&x_trace_page_current=search_entry&lang=zh-Hans&app_id=ECFAAF01&uis=lightplatform=android&build=7010138&deviceId=879246a0-b385-3400-b59d-76f63fa5baff".encode()
# print(content)
t1 = bytearray(16)
ctx[0] = sub_md5(ctx[0], content, len(content))
t1, ctx[0] = sub_2dd88(t1, ctx[0])
ctx[0] = ctx[2].copy()
ctx[0] = sub_md5(ctx[0], t1, 16)
t1, ctx[0] = sub_2dd88(t1, ctx[0])
# print(t1.hex())
return t1.hex()
# oldsign = get_oldsign(
# main_hmac="mXtwWNLkY+tzqBSiMdzc89grN5pkqeSWKe9mayVcsnTdvJBpgLv4CZpN9vGdOm9TITM8m1BwGVYdZAicMfrQ8gaQcY8JZ7Q2WK79Foi0093WoffnaDzet9I+rvtM8PDg",
# device_id="98fd23e2-8b96-3fdd-92ca-a5d191250cd6", path="/api/sns/v1/system_service/check_code",
# params="zone=86&phone=15270065469&code=123456",
# xy_common_params="fid=161728778310debbddf17fc6716ba47ffbd57b170ffb&device_fingerprint=20210317164618c676e8334dd11e5066095451d7ac31a101a234c9b78b1cdb&device_fingerprint1=20210317164618c676e8334dd11e5066095451d7ac31a101a234c9b78b1cdb&launch_id=1617288292&tz=GMT&channel=Lite&versionName=6.86.0.1&deviceId=98fd23e2-8b96-3fdd-92ca-a5d191250cd6&platform=android&sid=session.1617259043556226191363&identifier_flag=0&t=1617272131&project_id=ECFAAF&build=6860179&x_trace_page_current=login_full_screen_sms_page&lang=zh-Hans&app_id=ECFAAF01&uis=light",
# xy_platform_info="platform=android&build=6860179&deviceId=98fd23e2-8b96-3fdd-92ca-a5d191250cd6")
# print(oldsign)