小红书shield算法破解分析参数

交流:base64解码(UVEyODkxNTkwNTc4)

shield是小红书请求header中的一个加密参数,具体算法是在so中计算的,so文件是libshield.so。我这边主要就讲一下如何利用unidbg调用so生成shield参数。因篇幅可能较长,这篇文章就讲下如何找到Native函数和函数所对应的偏移位置。

一、寻找Native函数
老规矩,首先反编译apk后用JD-GUI工具打开(也可使用jadx等工具),直接搜索shield,结果意料之中,在java层没搜到什么有用的信息,算法大概率放在了so层。
那我们只能在so层中寻找突破口,这里推荐一位大佬开发的工具frida_hook_libart(项目地址:https://github.com/lasting-yang/frida_hook_libart),它是把在libart.so中的常用函数都进行了hook。
总共有三个hook文件hook_RegisterNatives.js、hook_art.js、hook_artmethod.js,我们先使用这个hook_art。
首先在手机上打开frida-server服务,电脑终端运行命令:“frida -U –no-pause -f com.xingin.xhs -l hook_art.js”。

图片.png

然后找啊找,会发现在NewStringUTF这个函数中,出现了shield结果。这里所对应的so文件是libshield.so 。
然后运行命令:“frida -U –no-pause -f com.xingin.xhs -l hook_RegisterNatives.js”,看一下在libshield里动态注册了哪些Native函数。

图片.png

可以看到,在so中,注册了initializeNative、intercept、initialize这几个函数。
然后在java层找下,可以找到在“com.xingin.shield.http.XhsHttpInterceptor”这个类下,如下图:

图片.png

二、寻找Native函数的偏移位置
方法一:
上文有使用Frida hook了so的RegisterNatives函数,hook到的同时,也打印出了函数的offset偏移位置。

图片.png

initializeNative函数的偏移位为:0x6c11d
intercept函数的偏移位为:0x6b9e9
initialize函数的偏移位为:0x6b801
方法二:
首先使用ida打开libshield.so文件,使用shift+F12打开String window窗口。
在窗口中直接搜索刚刚找到的Native函数,如intercept:

图片.png

然后点进去,就能找到这里

图片.png

intercept函数的偏移位就是0x6b9e9。
方法三:
同样使用ida打开libshield.so文件,在Exports窗口中找到JNI_OnLoad(动态注册的函数都会在JNI_OnLoad中进行注册),然后进去F5反汇编下。


图片.png

然后可以看到sub_9FA0这个函数,点进去。

图片.png

这边有很多函数,逐个进行查看,最终找到sub_6B360这个地方,点进去。

图片.png

可以看到java层的“com.xingin.shield.http.XhsHttpInterceptor”这个类,在点进去,就到了刚刚方法二中的这个位置,偏移位直接复制下就好。

图片.png

三、搭建unidbg环境

首先把unidbg项目拉下来(项目地址:https://github.com/zhkl0228/unidbg)。

在test中新建一个类,然后把小红书apk和对应的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() {
        // 创建模拟器实例
        emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.xhs").build();
        Memory memory = emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));

        // 创建Android虚拟机
        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函数

图片.png

我们分析下这块代码:

1 首先需要调initializeNative这个初始化函数;

2 第二步调initialize函数,获取cPtr;

3 最终生成shield是调用intercept函数,需传入一个“okhttp3/Interceptor$Chain”,paramLong就是第二步获取的cPtr值。

五、补缺失环境

先把初始化函数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();

}

直接运行下,会发现报错了。

图片.png

这个报错一般就说明要补环境了。

这里先解释下这个:“java/nio/charset/Charset->defaultCharset()Ljava/nio/charset/Charset;”

这句话的意思是调用java/nio/charset/Charset这个类下的defaultCharset函数,返回值是Ljava/nio/charset/Charset,unidbg缺少这一块的处理逻辑,我们需要手动补上。

我们可以直接点“com.github.unidbg.linux.android.dvm.AbstractJni.callStaticObjectMethodV(AbstractJni.java:388)”这个位置,进去后会看到一个方法,我们需要重写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);

}

继续运行,发现又报错了

图片.png

这次是缺少一个versionCode参数,这个参数可以在AndroidManifest.xml文件中找到,我这个版本是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);

}

然后继续运行,报错了就补环境,我就不把所有的都写出来了,比较多,挑几个讲一下。

sDeviceId:

图片.png

这里是缺少一个sDeviceId参数,我这里是通过IDA分析这块代码,然后打印GetStringUTFChars函数结果找到的。


图片.png
图片.png

ps:

这里分析IDA代码有个技巧,像这块代码,v1大概率就是env,可以在v1上右键“set lvar type”,把类型改为JNIEnv*,然后确定,会发现很多函数能显示出来了,看起来会直观很多。

图片.png

main_hmac:

这个参数可以直接adb连上去,在s.xml文件下找到。

然后依次把三个函数的所有环境补完,就可以运行生成shield了。

下面是三个Native函数的代码逻辑:

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接口参数中的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 "关键代码找我拿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 "关键代码找我拿,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=''):
    """
    生成签名  根据main_hmac device_id解密出一个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)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容