小紅書shield算法破解分析參數(shù)

交流: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”秧了。

圖片.png

然后找啊找,會發(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ù)晶通。

圖片.png

可以看到璃氢,在so中,注冊了initializeNative狮辽、intercept一也、initialize這幾個(gè)函數(shù)。
然后在java層找下喉脖,可以找到在“com.xingin.shield.http.XhsHttpInterceptor”這個(gè)類下椰苟,如下圖:

圖片.png

二、尋找Native函數(shù)的偏移位置
方法一:
上文有使用Frida hook了so的RegisterNatives函數(shù)树叽,hook到的同時(shí)舆蝴,也打印出了函數(shù)的offset偏移位置。

圖片.png

initializeNative函數(shù)的偏移位為:0x6c11d
intercept函數(shù)的偏移位為:0x6b9e9
initialize函數(shù)的偏移位為:0x6b801
方法二:
首先使用ida打開libshield.so文件菱皆,使用shift+F12打開String window窗口须误。
在窗口中直接搜索剛剛找到的Native函數(shù),如intercept:

圖片.png

然后點(diǎn)進(jìn)去仇轻,就能找到這里

圖片.png

intercept函數(shù)的偏移位就是0x6b9e9京痢。
方法三:
同樣使用ida打開libshield.so文件,在Exports窗口中找到JNI_OnLoad(動態(tài)注冊的函數(shù)都會在JNI_OnLoad中進(jìn)行注冊)篷店,然后進(jìn)去F5反匯編下祭椰。


圖片.png

然后可以看到sub_9FA0這個(gè)函數(shù),點(diǎn)進(jìn)去疲陕。

圖片.png

這邊有很多函數(shù)方淤,逐個(gè)進(jìn)行查看,最終找到sub_6B360這個(gè)地方蹄殃,點(diǎn)進(jìn)去携茂。

圖片.png

可以看到j(luò)ava層的“com.xingin.shield.http.XhsHttpInterceptor”這個(gè)類,在點(diǎn)進(jìn)去诅岩,就到了剛剛方法二中的這個(gè)位置讳苦,偏移位直接復(fù)制下就好。

圖片.png

三吩谦、搭建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ù)

圖片.png

我們分析下這塊代碼:

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ò)了醇疼。

圖片.png

這個(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ò)了

圖片.png

這次是缺少一個(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:

圖片.png

這里是缺少一個(gè)sDeviceId參數(shù),我這里是通過IDA分析這塊代碼怪得,然后打印GetStringUTFChars函數(shù)結(jié)果找到的卑硫。


圖片.png
圖片.png

ps:

這里分析IDA代碼有個(gè)技巧,像這塊代碼欢伏,v1大概率就是env入挣,可以在v1上右鍵“set lvar type”颜懊,把類型改為JNIEnv*,然后確定匠璧,會發(fā)現(xiàn)很多函數(shù)能顯示出來了咸这,看起來會直觀很多。

圖片.png

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

}

六杂彭、最終效果

圖片.png

七吓揪、最終還原源碼

"""
生成小紅書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)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末间螟,一起剝皮案震驚了整個(gè)濱河市损肛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌治拿,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哎榴,死亡現(xiàn)場離奇詭異拂玻,居然都是意外死亡荞驴,警方通過查閱死者的電腦和手機(jī)贯城,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鲫骗,“玉大人踩晶,你說我怎么就攤上這事执泰《沈撸” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵顿苇,是天一觀的道長。 經(jīng)常有香客問我纪岁,道長,這世上最難降的妖魔是什么幔翰? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮叫惊,結(jié)果婚禮上做修,老公的妹妹穿的比我還像新娘。我一直安慰自己饰及,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布宾濒。 她就那樣靜靜地躺著,像睡著了一般绘梦。 火紅的嫁衣襯著肌膚如雪赴魁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天尚粘,我揣著相機(jī)與錄音,去河邊找鬼郎嫁。 笑死,一個(gè)胖子當(dāng)著我的面吹牛尚辑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播杠茬,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼瓢喉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起决左,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤走贪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后坠狡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡逃沿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年感挥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缩搅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片触幼。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡究飞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出媒峡,到底是詐尸還是另有隱情,我是刑警寧澤谅阿,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布酬滤,位于F島的核電站,受9級特大地震影響盯串,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜体捏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一糯崎、第九天 我趴在偏房一處隱蔽的房頂上張望河泳。 院中可真熱鬧拆挥,春花似錦、人聲如沸黄锤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽负甸。三九已至,卻和暖如春呻待,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奏篙。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工迫淹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留秘通,地道東北人敛熬。 一個(gè)月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像话原,于是被迫代替她去往敵國和親诲锹。 傳聞我的和親對象是個(gè)殘疾皇子繁仁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容