首页
论坛
课程
招聘
[原创]拼夕夕anti-token分析
2022-5-12 21:13 15602

[原创]拼夕夕anti-token分析

2022-5-12 21:13
15602

前言:拼夕夕charles抓包分析发现跟商品相关的请求头里都带了一个anti-token的字段且每次都不一样,那么下面的操作就从分析anti-token开始了


1.jadx反编译直接搜索

选中跟http相关的类对这个方法进行打印堆栈

结合堆栈方法调用的情况找到具体anti-token是由拦截器类f.a方法调用的,在http.a.c()方法中生成并且http.p.e()方法中加入请求头

在http.a.c()方法中有个一个判断条件如果为true则走d.a().e()方法生成anti-token

如果为false则走j()方法生成anti-token

hook这个i()方法返回值可知获取商品详情接口返回值为false所以走的是j()方法进行计算anti-token。

SecureNative.deviceInfo3()方法生成,传入的str为pdd生成的固定id 一个字符串.

根据hook_libart 得到info3()方法是在libodd_secure.so中,那么ida打开看看这个so包



2.这部分我们采用unidbg+jnitrace+frida相结合的方式

unidbg前期准备的代码这里就不发了直接调用这个info3方法



这里提示调用gad()方法返回一个字符串那么frida hook这个方法拿到这个值 如下图 一个固定的字符串

16位长度看着像AES的密钥

继续补环境 这里简单补环境就不发了

补完简单的环境代码后,再次运行报这个错误 看错误应该是缺少文件 ,那么看看日志需要补那个文件

继续运行,没有返回值报空指针。execve()函数执行的时候程序exit了这里我们返回对象本身.


execve()函数执行的时候程序exit了

execve filename=/system/bin/sh, args=[sh, -c, cat /proc/sys/kernel/random/boot_id]

这个函数相当于查看 boot_id这个文件信息

捋顺下逻辑应该就是先fork进程 然后在子进程中读取这个文件 然后把他写入pip中

那么自定义syscallhandler后 再次运行成功拿到结果

全部代码如下:

package pdd;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.file.linux.AndroidFileIO;
import com.github.unidbg.linux.android.AndroidARMEmulator;
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.file.ByteArrayFileIO;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.memory.SvcMemory;
import com.github.unidbg.spi.SyscallHandler;
import com.github.unidbg.unix.UnixSyscallHandler;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class Pddmain extends AbstractJni implements IOResolver<AndroidFileIO> {

    private AndroidEmulator androidEmulator;
    private static final String APK_PATH = "/Users/Downloads/com.xunmeng.pinduoduo_6.7.0_60700.apk";
    private static final String SO_PATH = "/Users/Downloads/com.xunmeng.pinduoduo_6.7.0_60700/lib/armeabi-v7a/libpdd_secure.so";
    private Module moduleModule;
    private VM dalvikVM;

    public static void main(String[] args) {
        Pddmain main = new Pddmain();
        main.create();
    }

    private void create() {
        AndroidEmulatorBuilder androidEmulatorBuilder = new AndroidEmulatorBuilder(false) {
            @Override
            public AndroidEmulator build() {
                return new AndroidARMEmulator("com.xunmeng.pinduoduo",rootDir,backendFactories) {
                    @Override
                    protected UnixSyscallHandler<AndroidFileIO> createSyscallHandler(SvcMemory svcMemory) {
                        return new PddArmSysCallHand(svcMemory);
                    }
                };
            }
        };
        androidEmulator = androidEmulatorBuilder.setProcessName("").build();
        androidEmulator.getSyscallHandler().addIOResolver(this);
        Memory androidEmulatorMemory = androidEmulator.getMemory();
        androidEmulatorMemory.setLibraryResolver(new AndroidResolver(23));
        dalvikVM = androidEmulator.createDalvikVM(new File(APK_PATH));
        DalvikModule module = dalvikVM.loadLibrary(new File(SO_PATH), true);
        moduleModule = module.getModule();
        dalvikVM.setJni(this);
        dalvikVM.setVerbose(true);
        dalvikVM.callJNI_OnLoad(androidEmulator, moduleModule);
        callInfo3();
    }

    @Override
    public void callStaticVoidMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        if ("com/tencent/mars/xlog/PLog->i(Ljava/lang/String;Ljava/lang/String;)V".equals(signature)) {
            return;
        }
        super.callStaticVoidMethodV(vm, dvmClass, signature, vaList);
    }

    private void callInfo3() {
        List<Object> argList = new ArrayList<>();
        argList.add(dalvikVM.getJNIEnv());
        argList.add(0);
        DvmObject<?> context = dalvikVM.resolveClass("android/content/Context").newObject(null);
        argList.add(dalvikVM.addLocalObject(context));
        argList.add(dalvikVM.addLocalObject(new StringObject(dalvikVM, "api/oak/integration/render")));
        argList.add(dalvikVM.addLocalObject(new StringObject(dalvikVM, "dIrjGpkC")));
        Number number = moduleModule.callFunction(androidEmulator, 0xb6f9, argList.toArray())[0];
        String toString = dalvikVM.getObject(number.intValue()).getValue().toString();
        System.out.println(toString);
    }

    @Override
    public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        if ("com/xunmeng/pinduoduo/secure/EU->gad()Ljava/lang/String;".equals(signature)) {
            return new StringObject(vm, "cb14a9e76b72a627");
        } else if ("java/util/UUID->randomUUID()Ljava/util/UUID;".equals(signature)) {
            UUID uuid = UUID.randomUUID();
            DvmObject<?> dvmObject = vm.resolveClass("java/util/UUID").newObject(uuid);
            return dvmObject;
        }
        return super.callStaticObjectMethodV(vm, dvmClass, signature, vaList);
    }

    @Override
    public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        if ("java/util/UUID->toString()Ljava/lang/String;".equals(signature)) {
            UUID uuid = (UUID) dvmObject.getValue();
            return new StringObject(vm, uuid.toString());
        } else if ("java/lang/String->replaceAll(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;".equals(signature)) {
            String obj = dvmObject.getValue().toString();
            String arg0 = vaList.getObjectArg(0).toString();
            String arg1 = vaList.getObjectArg(1).toString();
            String replaceAll = obj.replaceAll(arg0, arg1);
            return new StringObject(vm, replaceAll);

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

    @Override
    public int callIntMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        if ("java/lang/String->hashCode()I".equals(signature)) {
            return dvmObject.getValue().toString().hashCode();
        }
        return super.callIntMethodV(vm, dvmObject, signature, vaList);
    }

    @Override
    public FileResult<AndroidFileIO> resolve(Emulator<AndroidFileIO> emulator, String pathname, int oflags) {
        if ("/proc/stat".equals(pathname)) {
            String info = "cpu  15884810 499865 12934024 24971554 59427 3231204 945931 0 0 0\n" +
                    "cpu0 6702550 170428 5497985 19277857 45380 1821584 529454 0 0 0\n" +
                    "cpu1 4438333 121907 3285784 1799772 3702 504395 255852 0 0 0\n" +
                    "cpu2 2735453 133666 2450712 1812564 4626 538114 93763 0 0 0\n" +
                    "cpu3 2008473 73862 1699542 2081360 5716 367109 66860 0 0 0\n" +
                    "intr 1022419954 0 0 0 159719900 0 16265892 4846825 5 5 5 6 0 0 497 24817167 17 176595 1352 0 28375276 0 0 0 0 5239 698 0 0 0 0 0 0 3212852 0 12195284 0 0 0 0 0 43 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 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 12513 2743129 375 12477726 0 0 0 0 37 1351794 0 36 8 0 0 0 0 0 0 5846 0 0 0 0 0 0 0 0 0 141 32 0 55 0 0 0 0 0 0 0 0 18 0 18 0 0 0 0 0 0 66 0 0 0 0 0 0 0 77 0 166 0 0 0 0 0 394 0 0 0 0 0 1339137 0 0 0 0 0 0 313 0 0 0 55759 7 7 7 0 0 0 0 0 0 0 0 3066136 0 47 0 0 0 2 2 0 0 0 6 8 0 0 0 2 0 462 2952327 35420 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 495589 0 0 0 0 3 27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 37662 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 4760 0 0 97 0 0 0 0 0 0 0 0 0 243 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 4649 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 22355451 0 0 0 14 0 24449357 96 49415 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17067 780222 3211 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 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 2 1 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 1 1 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 1 1 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 649346 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\n" +
                    "ctxt 1572087931\n" +
                    "btime 1649910663\n" +
                    "processes 230673\n" +
                    "procs_running 6\n" +
                    "procs_blocked 0\n" +
                    "softirq 374327567 12481657 139161248 204829 7276312 2275183 26796 12851725 80988196 1422751 117638870";
            return FileResult.success(new ByteArrayFileIO(oflags, pathname, info.getBytes(StandardCharsets.UTF_8)));
        }
        return null;
    }
}



看雪招聘平台创建简历并且简历完整度达到90%及以上可获得500看雪币~

最后于 2022-5-18 13:23 被那年没下雪编辑 ,原因:
收藏
点赞2
打赏
分享
打赏 + 80.00雪花
打赏次数 1 雪花 + 80.00
 
赞赏  Editor   +80.00 2022/06/13 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (15)
雪    币: 297
活跃值: 活跃值 (1688)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Zard_ 活跃值 2022-5-14 16:35
2
0
nb 就完事了 
雪    币: 2701
活跃值: 活跃值 (1855)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 活跃值 2022-5-14 17:07
3
0
厉害
雪    币: 10128
活跃值: 活跃值 (12154)
能力值: ( LV12,RANK:460 )
在线值:
发帖
回帖
粉丝
随风而行aa 活跃值 9 2022-5-15 21:04
4
0
很强
雪    币: 1287
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Y6blNU1L 活跃值 2022-5-15 22:19
5
0
强!向大佬学习
雪    币: 12
活跃值: 活跃值 (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hmlyn 活跃值 2022-5-17 14:56
6
0
强,主要拼多多日志流风控太难过了,有anti算法也没有用,必须模拟日志流才行,不然账号直接异常。
雪    币: 21
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
foryaoyaoho 活跃值 2022-5-17 19:21
7
1
PddArmSysCallHand这个类去哪了呢
雪    币: 35
活跃值: 活跃值 (69)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
大肥猪 活跃值 2022-5-18 13:56
8
0
hmlyn 强,主要拼多多日志流风控太难过了,有anti算法也没有用,必须模拟日志流才行,不然账号直接异常。
这个也很好解决的花点时间就出来了  选择这种电商事件流实时日志系统 基本上电商平台都有
雪    币: 12
活跃值: 活跃值 (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hmlyn 活跃值 2022-6-5 23:29
9
0
t.gif的rctk参数怎么加密出来的,楼主能分析一下吗?
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
机械皇帝 活跃值 2022-6-6 14:02
10
0
hmlyn t.gif的rctk参数怎么加密出来的,楼主能分析一下吗?
aes
雪    币: 35
活跃值: 活跃值 (69)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
大肥猪 活跃值 2022-6-7 11:25
11
0
hmlyn t.gif的rctk参数怎么加密出来的,楼主能分析一下吗?
我前面分析过
雪    币: 52
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
北辰清影 活跃值 2022-6-16 17:29
12
0
大佬能否详细讲下fork进程以及syscallhandler自定义
雪    币: 200
活跃值: 活跃值 (68)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
荧光之夏 活跃值 2022-6-20 14:43
13
0
...
雪    币: 0
活跃值: 活跃值 (404)
能力值: ( LV5,RANK:63 )
在线值:
发帖
回帖
粉丝
falconnnn 活跃值 2022-6-21 10:10
14
0
foryaoyaoho PddArmSysCallHand这个类去哪了呢

我试了一下应该是这样的
```java
package com.pdd;
import com.github.unidbg.Emulator;
import com.github.unidbg.arm.context.EditableArm32RegisterContext;
import com.github.unidbg.linux.file.ByteArrayFileIO;
import com.github.unidbg.linux.file.DumpFileIO;

import com.github.unidbg.memory.SvcMemory;
import com.sun.jna.Pointer;

import java.util.concurrent.ThreadLocalRandom;

public class PddArmSysCallHand extends com.github.unidbg.linux.ARM32SyscallHandler {
    public PddArmSysCallHand(SvcMemory svcMemory) {
        super(svcMemory);
    }
    @Override
    protected boolean handleUnknownSyscall(Emulator emulator, int NR) {
        switch (NR) {
            case 190:
                vfork(emulator);
                return true;
            case 359:
                pipe2(emulator);
                return true;
        }

        return super.handleUnknownSyscall(emulator, NR);
    }
    private void vfork(Emulator<?> emulator) {
        EditableArm32RegisterContext context = (EditableArm32RegisterContext) emulator.getContext();
        int childPid = emulator.getPid() + ThreadLocalRandom.current().nextInt(256);
        int r0 = 0;
        r0 = childPid;
        System.out.println("vfork pid=" + r0);
        context.setR0(r0);
    }


    @Override
    protected int pipe2(Emulator<?> emulator) {
        EditableArm32RegisterContext context = (EditableArm32RegisterContext) emulator.getContext();
        Pointer pipefd = context.getPointerArg(0);
        int flags = context.getIntArg(1);
        int write = getMinFd();
        this.fdMap.put(write, new DumpFileIO(write));
        int read = getMinFd();
        String stdout = "d29d36c7-df12-461f-96d7-c0804cb9686e\n";
        this.fdMap.put(read, new ByteArrayFileIO(0, "pipe2_read_side", stdout.getBytes()));
        pipefd.setInt(0, read);
        pipefd.setInt(4, write);
        System.out.println("pipe2 pipefd=" + pipefd + ", flags=0x" + flags + ", read=" + read + ", write=" + write + ", stdout=" + stdout);
        context.setR0(0);
        return 0;
    }

}

```

最后于 2022-6-21 10:12 被falconnnn编辑 ,原因:
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_sttngdoi 活跃值 2022-6-22 14:22
15
0
大佬666
雪    币: 101
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
limozhu 活跃值 4天前
16
0
666666
游客
登录 | 注册 方可回帖
返回