最新版xhs_9_20_0

补环境

网上教程挺多,我直接丢个成品

package com.ruhua.study.xhs;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.Backend;
import com.github.unidbg.arm.backend.Unicorn2Factory;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.debugger.BreakPointCallback;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.array.ArrayObject;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.pointer.UnidbgPointer;
import com.github.unidbg.utils.Inspector;
import com.github.unidbg.virtualmodule.android.AndroidModule;
import com.github.unidbg.virtualmodule.android.JniGraphics;
import com.github.unidbg.virtualmodule.android.MediaNdkModule;
import com.github.unidbg.virtualmodule.android.SystemProperties;
import com.sun.jna.Pointer;
import okhttp3.*;
import okio.Buffer;
import okio.BufferedSink;
import org.apache.commons.codec.binary.Base64;
import unicorn.Arm64Const;


import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

public class demo1 extends AbstractJni implements IOResolver {
    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;

    public long num;

    public DvmClass XhsHttpInterceptor;//静态
    public DvmObject<?> xhshttpinterceptorObject; //实例



    static Request request1;

    public FileResult resolve(Emulator emulator, String pathname, int oflags) {
        System.out.println("open file:" + pathname);
        return null;
    }


    demo1(){
        // 创建模拟器实例
        emulator = AndroidEmulatorBuilder.for64Bit().setProcessName("").addBackendFactory(new Unicorn2Factory(false)).build();
        // 添加IO接口要加这句
        emulator.getSyscallHandler().addIOResolver(this);
        // 获取模拟器的内存操作接口
        final Memory memory = emulator.getMemory();
        // 设置系统类库解析
        memory.setLibraryResolver(new AndroidResolver(23));
        // 创建Android虚拟机,传入APK,Unidbg可以替我们做部分签名校验的工作
        vm = emulator.createDalvikVM(new File("E:\\F\\ud\\unidbg-master\\unidbg-master\\unidbg-android\\src\\test\\java\\com\\ruhua\\study\\xhs\\file\\小红书_9.20.0.apk"));
        // 4个虚拟模块
//        new AndroidModule(emulator,vm);
//        new MediaNdkModule(emulator,vm);
//        new JniGraphics(emulator,vm);
//        new SystemProperties(emulator,null);
        // 设置JNI
        vm.setJni(this);
        // 打印日志
        vm.setVerbose(true);
        // 加载目标SO
        DalvikModule dm = vm.loadLibrary("xyass", true);
        // DalvikModule dm = vm.loadLibrary(new File("unidbg-android/apks/xx/lib.so"), true);
        //获取本SO模块的句柄,后续需要用它
        module = dm.getModule();
        // 调用JNI OnLoad
        dm.callJNI_OnLoad(emulator);

        XhsHttpInterceptor = vm.resolveClass("com/xingin/shield/http/Native");

//        url = "https://edith.xiaohongshu.com/api/nike/v3/update/check/plugin?";
//        String jsonBody = "{\"abi\":\"X64\",\"appVersion\":\"8.70.0\",\"appVersionCode\":8700313,\"application\":\"xhs\",\"baseType\":1,\"isTest\":1,\"plugins\":[{\"pluginName\":\"face_recognition\",\"pluginVersion\":\"8700.105.1\"},{\"pluginName\":\"davinci\",\"pluginVersion\":\"8700.108.1\"},{\"pluginName\":\"dev_tool_plugin\",\"pluginVersion\":\"8700.105.1\"},{\"pluginName\":\"animation_widgets\",\"pluginVersion\":\"8700.69.1\"},{\"pluginName\":\"document_preview\",\"pluginVersion\":\"8700.105.1\"},{\"pluginName\":\"sku_poi\",\"pluginVersion\":\"8700.107.1\"},{\"pluginName\":\"ai_engine\",\"pluginVersion\":\"8700.108.1\"},{\"pluginName\":\"xymap\",\"pluginVersion\":\"8700.108.1\"},{\"pluginName\":\"redscanner\",\"pluginVersion\":\"8700.105.1\"},{\"pluginName\":\"hey\",\"pluginVersion\":\"8700.107.1\"}]}";
//        RequestBody body = RequestBody.create(
//                MediaType.parse("application/json"), // 这里指定了请求体的类型为JSON
//                jsonBody
//        );
//        request = new Request.Builder()
//                .url(url)
//                .addHeader("xy-direction","52")
//                .addHeader("xy-scene","fs=1&point=-1")
//                .addHeader("xy-common-params","fid=173889177110c91957adf78217727d0f5e60134f77f8&device_fingerprint1=20250217190846119f418d25f88d13283009703738ffa201c8be0b1852911d&gid=7c3e8c648188540b9d2809bd725d935cbd15932947359e6577830067&device_model=phone&tz=Asia%2FShanghai&channel=Vivo&versionName=8.70.0&deviceId=b2e8e75b-d18d-35dc-87c3-490cf0bb7f30&platform=android&sid=session.1739842095180283261761&identifier_flag=4&project_id=ECFAAF&x_trace_page_current=&lang=zh-Hans&app_id=ECFAAF01&uis=light&teenager=0&device_fingerprint=20250217190846119f418d25f88d13283009703738ffa201c8be0b1852911d&cpu_name=Qualcomm+Technologies%2C+Inc+SM8150&dlang=zh&launch_id=1738893890&overseas_channel=0&folder_type=none&t=1739844213&build=8700313")
//                .post(body)
//                .build();

    };
    public void callByAddress(){
        // args list
        List<Object> list = new ArrayList<>(10);
        // jnienv
        list.add(vm.getJNIEnv());
        // jclazz
        list.add(0);
        // str1
        list.add(vm.addLocalObject(new StringObject(vm, "str1")));



        // strArr 假设字符串包含两个字符串
        // str6_1
        StringObject str6_1 = new StringObject(vm, "str6_1");
        vm.addLocalObject(str6_1);
        // str6_2
        StringObject str6_2 = new StringObject(vm, "str6_2");
        vm.addLocalObject(str6_2);

        ArrayObject arrayObject = new ArrayObject(str6_1,str6_2);
        list.add(vm.addLocalObject(arrayObject));

        // 最后的int
        list.add(1);

        Number number = module.callFunction(emulator, 0x2301, list.toArray());
        ArrayObject resultArr = vm.getObject(number.intValue());
        System.out.println("result:"+resultArr);
    };

    public void callByAPI(){
        DvmClass RequestCryptUtils = vm.resolveClass("com/meituan/android/payguard/RequestCryptUtils");

        StringObject str6_1 = new StringObject(vm, "str6_1");
        vm.addLocalObject(str6_1);
        StringObject str6_2 = new StringObject(vm, "str6_2");
        vm.addLocalObject(str6_2);
        ArrayObject arrayObject = new ArrayObject(str6_1,str6_2);

        ArrayObject result = RequestCryptUtils.callStaticJniMethodObject(emulator, "encryptRequestWithRandom()", "str1","str2", "str3","str4","str5",arrayObject,1);
        System.out.println(result);
    };


    public Response callfun(){
        DvmObject<?> chain = vm.resolveClass("okhttp3/Interceptor$Chain").newObject(null);

        DvmObject<?> result = xhshttpinterceptorObject.callJniMethodObject(emulator, "intercept(Lokhttp3/Interceptor$Chain;J)Lokhttp3/Response;", chain, num);

        return result != null ? (Response)result.getValue() : null;
    }


    public void callinitializeNative(){
        XhsHttpInterceptor.callStaticJniMethod(emulator, "initializeNative()V");
        //V要大写
    }

    public void callinitialize(){
        xhshttpinterceptorObject = XhsHttpInterceptor.newObject("xhs");
        num = xhshttpinterceptorObject.callJniMethodLong(emulator,"initialize(Ljava/lang/String;)J","main");
        System.out.println("num:>>>>>>>>>>>>>>>>"+num);

    }
    public static void main(String[] args) {
        demo1 demo = new demo1();
        demo.callinitializeNative();
        demo.callinitialize();
        demo.callfun();
        System.out.println("result:"+request1.headers());
    }

    @Override
    public void callStaticVoidMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        switch (signature) {
            case "com/xingin/shield/http/ContextHolder->writeLog(I)V":
            {
                System.out.println("writeLog:"+vaList.getIntArg(0));
                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()); //这个地方补成null出一个问题
//                return DvmClass
            }
            case "com/xingin/shield/http/Base64Helper->decode(Ljava/lang/String;)[B":
            {
                String input = vaList.getObjectArg(0).toString();
                System.out.println("----------------------- :" + input);
                System.out.println("----------------------- :" + Arrays.toString(Base64.decodeBase64(input)));
                return new ByteArray(vm, Base64.decodeBase64(input));
            }
        }
        return super.callStaticObjectMethodV(vm, dvmClass, signature, vaList);
    }

    @Override
    public DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {

        switch (signature) {
//            case "com/xingin/shield/http/ContextHolder->sLogger:Lcom/xingin/shield/http/ShieldLogger;":{
//                return vm.resolveClass("com/xingin/shield/http/ShieldLogger").newObject(null);
//            }
            case "com/xingin/shield/http/ContextHolder->sDeviceId:Ljava/lang/String;":{
//                return vm.resolveClass("java/lang/String").newObject(null);
                return new StringObject(vm, "057edeb4-300d-3c49-84e2-5b84e81dd105");
            }
        }
        return super.getStaticObjectField(vm, dvmClass, signature);
    }

    @Override
    public int getStaticIntField(BaseVM vm, DvmClass dvmClass, String signature) {
        switch (signature){
            case "com/xingin/shield/http/ContextHolder->sAppId:I":{
                return -319115519;
            }
        }
        return super.getStaticIntField(vm, dvmClass, signature);
    }
    @Override
    public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        switch (signature) {
            case "android/content/Context->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;":
            {
                return vm.resolveClass("android/content/SharedPreferences").newObject(vaList.getObjectArg(0).getValue().toString());
            }
            case "android/content/SharedPreferences->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;":
            {
                String fileName = dvmObject.getValue().toString();
                System.out.println("fileName:"+fileName);
                switch (fileName) {
                    case "s": {
                        String key = vaList.getObjectArg(0).getValue().toString();
                        System.out.println("key:" + key);
                        switch (key) {
                            case "main": {
                                return new StringObject(vm, "");
                            }
                            case "main_hmac": {
                                return new StringObject(vm, "AsD3t9V+UHn+VjkBRkjPwCDCBpEP8AjGV/SBhMnn/teJhcLp8JN/YhIEeuUxZa/oLjb1V18PVw0cmbL98OXrHhM+//5OFY/sYGQY637GT4ZnmDCJxyNGR3aNpugeVXpA");
                            }
                        }
                    }
                }

            }
            case "okhttp3/Interceptor$Chain->request()Lokhttp3/Request;":{
                String url ="https://mediacloud.xiaohongshu.com/api/httpdns/prefetch";
                Request request = new Request.Builder()
                        .url(url)
                        .addHeader("accept", "*/*")
                        .addHeader("host","mediacloud.xiaohongshu.com")
                        .build();
                return vm.resolveClass("okhttp3/Request").newObject(request);
            }
            case "okhttp3/Request->url()Lokhttp3/HttpUrl;":{
                return vm.resolveClass("okhttp3/HttpUrl").newObject(((Request)dvmObject.getValue()).url());
            }
            case "okhttp3/HttpUrl->encodedPath()Ljava/lang/String;":{
                HttpUrl httpUrl = (HttpUrl) dvmObject.getValue();
                return new StringObject(vm, httpUrl.encodedPath());
            }
            case "okhttp3/HttpUrl->encodedQuery()Ljava/lang/String;":{
                HttpUrl httpUrl = (HttpUrl) dvmObject.getValue();
                String query = httpUrl.encodedQuery();
                return new StringObject(vm, query == null ? "" : query);
            }
            case "okhttp3/Request->body()Lokhttp3/RequestBody;":{
                return vm.resolveClass("okhttp3/RequestBody").newObject(((Request)dvmObject.getValue()).body());
            }
            case "okhttp3/Request->headers()Lokhttp3/Headers;":{
                return vm.resolveClass("okhttp3/Headers").newObject(((Request)dvmObject.getValue()).headers());
            }
            case "okio/Buffer->writeString(Ljava/lang/String;Ljava/nio/charset/Charset;)Lokio/Buffer;":{
                Buffer buffer = (Buffer) dvmObject.getValue();
                String arg0 = vaList.getObjectArg(0).toString();
                Charset arg1 = (Charset) vaList.getObjectArg(1).getValue();
                buffer.writeString(arg0,arg1);
                return dvmObject;
            }
            case "okhttp3/Headers->name(I)Ljava/lang/String;":{
                Headers buffer = (Headers) dvmObject.getValue();
                int index = vaList.getIntArg(0);
                System.out.println("index:"+index);
                String name = buffer.name(index);
                System.out.println("name:"+name);
                return new StringObject(vm, name);
            }
            case "okio/Buffer->clone()Lokio/Buffer;":{
                Buffer buffer = (Buffer) dvmObject.getValue();
                return vm.resolveClass("okio/Buffer").newObject(buffer.clone());
            }
            case "okhttp3/Request->newBuilder()Lokhttp3/Request$Builder;":{
                Request req = (Request) dvmObject.getValue();
                return vm.resolveClass("okhttp3/Request$Builder").newObject(req.newBuilder());
            }
            case "okhttp3/Request$Builder->header(Ljava/lang/String;Ljava/lang/String;)Lokhttp3/Request$Builder;": {
                Request.Builder builder = (Request.Builder) dvmObject.getValue();
                String arg0 = vaList.getObjectArg(0).toString();
                String arg1 = vaList.getObjectArg(1).toString();
                builder.header(arg0,arg1);
                return vm.resolveClass("okhttp3/Request$Builder").newObject(builder);
            }
            case "okhttp3/Request$Builder->build()Lokhttp3/Request;":{
                Request.Builder builder = (Request.Builder) dvmObject.getValue();
                request1 = builder.build();
                return vm.resolveClass("okhttp3/Request").newObject(request1);
            }
            case "okhttp3/Interceptor$Chain->proceed(Lokhttp3/Request;)Lokhttp3/Response;":{
//                try {
//                    Interceptor.Chain chain = (Interceptor.Chain) dvmObject.getValue();
//                    Request request = (Request) vaList.getObjectArg(0).getValue();
//                    Response response = chain.proceed(request);
//                    return vm.resolveClass("okhttp3/Response").newObject(response);
//                } catch (Exception e) {
//                    System.out.println(e.getMessage());
//                }
                return vm.resolveClass("okhttp3/Response").newObject(null);

            }
        }
        return super.callObjectMethodV(vm, dvmObject, signature, vaList);
    }

    @Override
    public void callVoidMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        switch (signature){
            case "okhttp3/RequestBody->writeTo(Lokio/BufferedSink;)V":{
                RequestBody requestBody = (RequestBody) dvmObject.getValue();
                BufferedSink bufferedSink = (BufferedSink) vaList.getObjectArg(0).getValue();

                if(requestBody == null){
                    return;
                }

                try {
                    requestBody.writeTo(bufferedSink);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                return;
            }
        }
    }

    @Override
    public int callIntMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        switch (signature) {
            case "okhttp3/Headers->size()I":{
                Headers buffer = (Headers) dvmObject.getValue();
                return buffer.size();
            }
            case "okio/Buffer->read([B)I":{
                byte[] arg0 = (byte[]) vaList.getObjectArg(0).getValue();
                Buffer buffer = (Buffer) dvmObject.getValue();
                return buffer.read(arg0);
            }
            case "okhttp3/Response->code()I":{
                return 200;
            }
        }
        return super.callIntMethodV(vm, dvmObject, signature, vaList);
    }
    @Override
    public DvmObject<?> newObjectV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        switch (signature) {
            case "okio/Buffer-><init>()V":{
                return dvmClass.newObject(new Buffer());
            }
        }
        return super.newObjectV(vm, dvmClass, signature, vaList);
    }
}

探索纯算

首先要看见字符串的最后赋值出现位置,我们可以直接hook memcpy

去追踪地址123d8140

emulator.traceWrite(0x123d8140L, 0x123d8140L + 132);

去看看0x4bd60 这就是base64

无魔改base64

就是这两部分拼起来base64,先去追第一段,读写0x123e3070

继续去0x1c18c在libc,去0x1dbf8看看

几个memcpy的拼接

hook一下这个函数(),看看入参

在第三次断下后x0为前半部分,x7为后半部分

雀食来自a1+1

追下调用栈,是函数1dd34

继续看眼参数,第四次断下后,x0x1是两个参数

这里前16字节的栈为0xe4ffefb8,继续读写,这里发现0x20这个字节是单独的,所以我们先看下面的

发现是位于函数sub_4B3D0内的,这里已经初见端倪了,我们来分析一下

所以我们不能直接看出来的是第二三个字节以及最后四个字节,目前我们能确认单格式是这样的,前面两个比价困难,我们先看最后四个

20 ?? ?? 00 04 00 00 00 01 53 00 00 00 ?? ?? ?? ??

这里可以很明显的看出,v35来自v34,而此处为我们重命名的这个字符串拼接函数的返回值,在这个大函数中,一共调用了四次,这是第三次

分析这个函数可以得知返回值是一个指向std::string对象的指针,所以了解一下,这个对象的结构体

首先  
第一个字节
0x51 = 0b01010001  最后一位是1,说明要使用__long(堆模式)

第一段:0x51
去掉标志位:81 & ~1 = 80
减去 \0 占位:80 - 1 = 79
堆缓冲区分配了 80 字节,可存 79 个字符

第二段:0x43
当前字符串长度为 67 个字符

第三段:0x12411000 地址
存放了当前字符串

所以这里实际上是总字符串长度,刚好为0x53,所以最后两部分实际上都是在获取字符串长度

所以现在只剩下第二三个字节了

交叉引用发现是跟入参相关

a3 = 4 雀食符合我们 2 3字节是00 04的事实,但是从哪里来的呢

继续往上追是sub_467DC,先别急,继续看看入参,这里a3应该还是4

然后继续找调用,向0xe4fff630下一个读写断点

这里追踪到地址是0x4ae64

w8是0x4,w8是上面x29-oxa8来的,继续在0xe4fff458下断点追

追到是0x4a5dc,这里x9就是0x4,看眼代码是从x22来的

继续在0x123e00c0追,看到是libc的地址,应该是memcpy写入,去看眼lr

应该追x22也就是0x123e0060

​这俩xor,然后0x4往x27(0x123e0060)中写,x22和x19只差第一个字节,看看这俩16字节哪里来的,分别下断点0xe4fff130 0xe4fff088

这里看到是0x80a58,这里x8是目标信息,指向的是so中目标偏移0x15c50的地址,是一段硬编码

再去看看另一个,赋值地址每个都不一样,貌似涉及了某种算法,先看简单的

回顾下前面,这个字符串最后经过了base64,然后就是我们的16字节和后面的字节进行一个拼接,所以我们现在要对后面的字节是怎么来的进行探讨,也就是0x35及之后

这是第三次调用append函数(偏移1DD30)

第四次发现就被加密了

说明是在这中间,而很明显,在两个append之间,雀食有一坨看起来像加密的函数,不急慢慢看,先hook函数看眼入参

(x0)a1 = 1。(疑似固定值)

image-20250606130046944

(x1)a2是个字符数组,代表build,如下。

0xE表示sso存储,占用了7个字节。

image-20250606121335072
image-20250606132842937
image-20250606122006533

(x2)a3来自于AppId。

image-20250606130146772
image-20250606130210235

(x3)a4为0x4;——之前q1、q2异或的0x4。

(x4)a5是个string类型;

image-20250606121826620

存放了device_id。

image-20250606121842021

(x5)a6=0xe4fff521,似乎存放了16个字节。

image-20250606130901638

(x6)a7 = 0x10,似乎代表a6的大小。

image-20250606130328066

(x7)a8=0x38663439662d3038,存放了8个字符“80-f94f8”也就是deviceid的一部分

image-20250606131755330

我这里已经提前给参数命名了()

改一下参数继续分析

这里清空数据开始正常加密

这里有一个循环不知道在干什么,hook看眼x10

这里123456...的很像rc4的sbox

这里看这个v49也很像rc4的初始化,像key

奇奇怪怪的

没绷住,字符串欺骗可还行

至此0x53个字节分析完了,现在还剩那个q0和最后16个字节,这16字节就是那个包含了四个append和rc4的大参数的sub_4B3D0的a6

然后去对0xe4fff501下读写断点

继续追0x46fb8

这里数据来源为x29-0x18,继续追

继续读写断点跟踪

很明显,追踪到这里的a2,a2由v2赋值

这里的w8就是v2

这里下断点,第二次才是目标数据

下断点

看起来像md5而且经对比,这个算法像是II算法,也就是md5最后一轮

发现了神秘md5常数,但是按理来说这都最后了,应该被变化了才对

搜索sub_84020,发现被调用了五次,从第一次开始追,x11是目标,x8只是魔数而已

追踪x29-0x30也就是x11

这里0xb0a457a3是由之前的魔数+0x7xxxx得到的,所以去追踪0x7xxxx,感觉签名就是md5的魔改

回到sub_8277C函数,看看入参和返回



1\
0000: 76 54 32 10 FE DC BA 98 89 AB CD EF 01 23 45 67    vT2..........#Eg

0000: 5E CB CD 0D 32 96 C8 95 16 B3 BD 04 D2 24 DE 96    ^...2........$..
0010: B6 91 50 F9 57 F8 95 1D 60 66 EA E8 EA 8D 5C 5E    ..P.W...`f....\^
0020: CF A0 3C 52 4B B3 46 80 71 C6 64 71 0A 23 13 59    ..<RK.F.q.dq.#.Y
0030: 42 58 89 2F 90 5A C8 59 4A 54 F2 03 2A 23 6B 5E    BX./.Z.YJT..*#k^

0000: 5C C2 05 46 7C 46 DE 18 4A 5B A7 5D 91 56 F9 F9    \..F|F..J[.].V..

-----------------------------------------------------------------------------------------

2\
0000: 76 54 32 10 FE DC BA 98 89 AB CD EF 01 23 45 67    vT2..........#Eg

0000: 34 A1 A7 67 58 FC A2 FF 7C D9 D7 6E B8 4E B4 FC    4..gX...|..n.N..
0010: DC FB 3A 93 3D 92 FF 77 0A 0C 80 82 80 E7 36 34    ..:.=..w......64
0020: A5 CA 56 38 21 D9 2C EA 1B AC 0E 1B 60 49 79 33    ..V8!.,.....`Iy3
0030: 28 32 E3 45 FA 30 A2 33 20 3E 98 69 40 49 01 34    (2.E.0.3 >.i@I.4

0000: EE 7E F0 3E 0E C3 7C 74 57 C4 47 58 4D A8 EC 20    .~.>..|tW.GXM.. 

-----------------------------------------------------------------------------------------
3\
0000: 5C C2 05 46 7C 46 DE 18 4A 5B A7 5D 91 56 F9 F9    \..F|F..J[.].V..

0000: 22 2F 61 70 69 2F 68 74 74 70 64 6E 73 2F 70 72    "/api/httpdns/pr
0010: 65 66 65 74 63 68 22 22 22 22 70 6C 61 74 66 6F    efetch""""platfo
0020: 72 6D 3D 61 6E 64 72 6F 69 64 26 62 75 69 6C 64    rm=android&build
0030: 3D 39 32 30 30 38 30 35 26 64 65 76 69 63 65 49    =9200805&deviceI
0040: 64 3D 30 35 37 65 64 65 62 34 2D 33 30 30 64 2D    d=057edeb4-300d-
0050: 33 63 34 39 2D 38 34 65 32 2D 35 62 38 34 65 38    3c49-84e2-5b84e8
0060: 31 64 64 31 30 35 22 00 00 00 00 00 00 00 00 00    1dd105".........

0000: D4 66 7B 62 C0 37 8B 29 E4 D6 CA 4F 8D DF FE E0    .f{b.7.)...O....

-----------------------------------------------------------------------------------------
4\
0000: D4 66 7B 62 C0 37 8B 29 E4 D6 CA 4F 8D DF FE E0    .f{b.7.)...O....

0000: 64 3D 30 35 37 65 64 65 62 34 2D 33 30 30 64 2D    d=057edeb4-300d-
0010: 33 63 34 39 2D 38 34 65 32 2D 35 62 38 34 65 38    3c49-84e2-5b84e8
0020: 31 64 64 31 30 35 22 80 00 00 00 00 00 00 00 00    1dd105".........
0030: 00 00 00 00 00 00 00 00 38 05 00 00 00 00 00 00    ........8.......

0000: D9 5F A1 45 38 EA C7 98 3D 03 FF F9 8D 39 82 F5    ._.E8...=....9..
-----------------------------------------------------------------------------------------
5\
0000: EE 7E F0 3E 0E C3 7C 74 57 C4 47 58 4D A8 EC 20    .~.>..|tW.GXM..

0000: D9 5F A1 45 38 EA C7 98 3D 03 FF F9 8D 39 82 F5    ._.E8...=....9..
0010: 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0030: 00 00 00 00 00 00 00 00 80 02 00 00 00 00 00 00    ................

0000: A3 57 A4 B0 8E CE 26 B8 F8 12 CE F0 41 01 0F 09    .W....&.....A...




第1次调用的返回值,是第3次加密的魔数值——0x36与key异或作为输入,魔数是标准md5魔数;
第2次调用的返回值,是第5次加密的魔数值——0x5C与key异或作为输入,魔数是标准md5魔数;
第3次调用的返回值,是第4次加密的魔数值——明文url + xy-common-params + xy-direction + platform + build + deviceId + xy-scene作为输入,魔数是第1次调用的返回值;
第4次调用的返回值,是第5次加密的输入——第4次调用的输入是第3次加密中,末尾不足64字节的部分;如果第3次调用刚好满足每组都是64字节,第4次调用的输入将是0x80开头,然后在最后的8个字节中,会描述前面的所有块的大小。
第5次加密就是将第4次的16字节进行了填充得到最终的16字节。