2023 腾讯游戏安全 mobile 决赛 wp

拿flag的思路和初赛一样,这里主要讲解算法的还原。

相关混淆的处理

变量 + 具体值的间接跳转混淆

全局变量 + 具体值

image-20250228193030431

该一下变量类型即可:

image-20250228193310976

image-20250228193321647

由于间接跳转过多这里写了个批量处理的ida python脚本

# 1、修改变量的参数类型
import idc
import idaapi
import idautils
def change_var_type(ea, new_type):
    # current_type = idc.get_type(ea)
    idc.SetType(ea, new_type)


begin = 0X0000000001270D0
end = 0x00000000013D9A0
for i in range(begin,end,8):
    var_address = i
    new_type = "const unsigned __int64"
    change_var_type(var_address, new_type)

处理完之后大致是这样:

image-20250228193524452

传参 + 具体值

image-20250228193715434

类似于这种的,通过传入固定的参数与具体值相加后进行函数调用。

去混淆方法: patch,把 blr跳转寄存器,patch成跳转具体地址。

由于在本题中这种混淆出现的敌方不是很多,因此笔者未做处理,只在调试的时候打注释标记了一下目的地址。

br混淆

存在两种br混淆,不建议去混淆,太麻烦,很难去,会浪费大量时间还不一定有成功。

这里我更推荐手动patch,调试的时候知道基本块执行流程,就可以尝试patch br混淆,来连接两个基本块。

类似于这样:

image-20250228194825622 image-20250228194831252

不过显然这样只能解决br混淆程度比较低的函数,不过已经够了。

我只写了其中一种br混淆的去混淆脚本(而且去的不是很完美):

image-20250301220439196

首先是混淆函数的筛选:

1、读取所有伪代码,根据伪代码筛选出存在混淆的函数段
import idaapi
import idautils

fun_start = []
def Ida_Decode(begin,end):
    global fun_start
    All_Fun = list(idautils.Functions(begin,end))            #idautils.Functions([st],[ed])	#st与ed参数不存在时,获取所有函数的首地址,返回一个list ,st与ed参数存在时,获取该范围内所有函数的首地址
    for i in range(len(All_Fun)):
        func = idaapi.get_func(All_Fun[i])  # 获取函数
        cfunc = str(idaapi.decompile(func.start_ea))  
        
        if "__asm { BR" in cfunc and "_ReadStatusReg" in cfunc:
            fun_start.append(func.start_ea)


begin = 0x00000000004F1D0
end = 0x00000000010526C
Ida_Decode(begin,end)

print(len(fun_start))
for i in fun_start:
    print(hex(i))


2、根据首地址筛选出尾地址
fun_start = [0x73654,0x73928,0x73c68,0x74b68,0x76108,0x7645c,0x76730,0x76c84,0x77290,0x77e9c,0x783a4,0x78bdc,0x78d74,0x78f88,0x791b8,0x793f0,0x79700,0x79c90,0x7ad84,0x7b8d0,0x7d7f8,0x7d9a0,0x7e25c,0x7e690,0x7e8b0,0x7eae4,0x7f138,0x7f40c,0x7f620,0x7f7f4,0x7ffc0,0x80270,0x80b20,0x80ce0,0x80f00,0x8111c,0x81338,0x8151c,0x81844,0x81e04,0x83644,0x84174,0x8486c,0x85000,0x85e84,0x86168,0x86458,0x8676c,0x86964,0x8b418,0x8b928,0x8c244,0x8c664,0x8cde0,0x8d508,0x8de88,0x8e738,0x8ed88,0x8f4b8,0x8f878,0x8fe5c,0x9006c,0x90284,0x90410,0x906e4,0x90904,0x92ec0,0x9389c,0x93bac,0x93ebc,0x94040,0x94368,0x94a50,0x9558c,0x95970,0x95b48,0x96318,0x980c4,0x98898,0x98e50,0x997cc,0x99a98,0x99ef4,0x9a498,0x9a74c,0x9acc0,0x9afe4,0x9b618,0x9bbc8,0x9c218,0x9ca34,0x9d2e4,0x9d668,0x9d94c,0x9dc44,0x9df60,0x9e154,0x9e374,0x9e598,0x9e7b4,0x9eaf4,0x9f360,0x9f50c,0x9f704,0x9fed8,0xa00bc,0xa0264,0xa040c,0xa08b4,0xa0b18,0xa1314,0xa1488,0xa17a4,0xa194c,0xa1ae0,0xa1d74,0xa1efc,0xa236c,0xa27c4,0xa2d4c,0xa2ec8,0xa3050,0xa3424,0xa38d4,0xa3e6c,0xa460c,0xa5178,0xa56e4,0xa61f8,0xa672c,0xa7410,0xa7ccc,0xa85a8,0xa8d18,0xa8f38,0xa9150,0xa9388,0xa9f5c,0xaa83c,0xaa9e4,0xaaec4,0xab754,0xac0c8,0xac754,0xac974,0xacb84,0xacef8,0xad1c0,0xad504,0xad90c,0xadd0c,0xaf798,0xb0154,0xb5054,0xb5bbc,0xb6024,0xb8464,0xb9270,0xb9e60,0xba1c0,0xba94c,0xbae90,0xbb758,0xbbad8,0xbbdd0,0xbc0d0,0xbc430,0xbd0ec,0xbf3f0,0xc697c,0xc6cc4,0xc6eb8,0xc75a4,0xc7758,0xc81b0,0xc8420,0xca794,0xcb4ec,0xcb840,0xcc5f8,0xccc24,0xcce64,0xccfc0,0xcd3c0,0xcd634,0xcdd10,0xce680,0xcf004,0xcfac4,0xcfde8,0xd0664,0xd0b2c,0xd10a4,0xd13bc,0xd1724,0xd1ae8,0xd1cc0,0xd2420,0xd27c0,0xd2ad0,0xd32d8,0xd3708,0xd3b80,0xd3fc4,0xd4418,0xd4864,0xd4c80,0xd50c8,0xd5518,0xd5a78,0xd5d98,0xd6158,0xd6e00,0xd7ac8,0xd7f4c,0xd8b64,0xd8e5c,0xd9a7c,0xdc308,0xdd8dc,0xde4ec,0xde7cc,0xdec20,0xdeed4,0xdf19c,0xdf458,0xdf75c,0xdfa6c,0xdfd9c,0xe00a8,0xe028c,0xe05b0,0xe08e8,0xe0be8,0xe1148,0xe14e4,0xe17ec,0xe1bcc,0xe227c,0xe2db4,0xe3a00,0xe3e18,0xe4980,0xe4c50,0xe58ac,0xe5d48,0xe5fdc,0xe6270,0xe6bf4,0xe76dc,0xe7a14,0xe8054,0xe8858,0xe8bd4,0xe9080,0xe9564,0xe98b4,0xea1f0,0xea428,0xea5fc,0xea9fc,0xeae20,0xeb11c,0xeb408,0xeb8c0,0xebdf4,0xec868]
fun_end = []
for i in range(len(fun_start)):
    Asm_data = ""
    ea = fun_start[i]
    while True:
        asm_code = str(hex(ea)) + ":    " + idc.generate_disasm_line(ea, 0) + "\n"
        now_ea = ea
        ea = idc.next_head(ea)

        if "RET" in asm_code:
            asm_next_code = str(hex(ea)) + ":    " + idc.generate_disasm_line(ea, 0) + "\n"
            if ".__stack_chk_fail" in asm_next_code:
                fun_end.append(ea)
            else:
                fun_end.append(now_ea)
            break

print(len(fun_end))
for i in fun_end:
    print(hex(i),end = ",")

之后把筛选出来的函数收尾地址copy到下面的br_addr变量中。

这里的思路其实就是unidbg模拟执行完序言,之后纯静态计算各个基本块的 CMP W8, W11 运算,之后根据运行结果与CSEL指令,把基本块之间patch成类似于

B.EQ xxx
B yyy

这样的条件分支形式。

image-20250301222017191

->

image-20250301222248521

package com.Tencent_game;

import capstone.Capstone;
import capstone.api.Instruction;
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.CodeHook;
import com.github.unidbg.arm.backend.UnHook;
import com.github.unidbg.debugger.BreakPointCallback;
import com.github.unidbg.debugger.DebuggerType;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.virtualmodule.android.AndroidModule;
import keystone.Keystone;
import keystone.KeystoneArchitecture;
import keystone.KeystoneEncoded;
import keystone.KeystoneMode;
import unicorn.Arm64Const;

import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

public class fin_2023 {
    public final AndroidEmulator emulator;
    public final VM vm;
    public final Memory memory;
    public final Module module;
    DvmClass cNative;
    public fin_2023(){
        emulator = AndroidEmulatorBuilder.for64Bit().build();
        memory =  emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));
        emulator.getSyscallHandler().setEnableThreadDispatcher(true);
        vm = emulator.createDalvikVM();
        new AndroidModule(emulator,vm).register(memory);

        DalvikModule dalvikModule = vm.loadLibrary(new File("C:\\Users\\27236\\Desktop\\2023_tencent_game\\mobile\\final\\libsec2023.so"), true);
        module = dalvikModule.getModule();
        vm.callJNI_OnLoad(emulator,module);
    }


    public  static  void main(String[] args){
        fin_2023 mainActivity = new fin_2023();
        mainActivity.anti_confuse();
    }

    public static void padding_reg2val(HashMap<String, Integer> reg2val) {
        reg2val.put("x0",Arm64Const.UC_ARM64_REG_X0);
        reg2val.put("x1",Arm64Const.UC_ARM64_REG_X1);
        reg2val.put("x2",Arm64Const.UC_ARM64_REG_X2);
        reg2val.put("x3",Arm64Const.UC_ARM64_REG_X3);
        reg2val.put("x4",Arm64Const.UC_ARM64_REG_X4);
        reg2val.put("x5",Arm64Const.UC_ARM64_REG_X5);
        reg2val.put("x6",Arm64Const.UC_ARM64_REG_X6);
        reg2val.put("x7",Arm64Const.UC_ARM64_REG_X7);
        reg2val.put("x8",Arm64Const.UC_ARM64_REG_X8);
        reg2val.put("x9",Arm64Const.UC_ARM64_REG_X9);
        reg2val.put("x10",Arm64Const.UC_ARM64_REG_X10);
        reg2val.put("x11",Arm64Const.UC_ARM64_REG_X11);
        reg2val.put("x12",Arm64Const.UC_ARM64_REG_X12);
        reg2val.put("x13",Arm64Const.UC_ARM64_REG_X13);
        reg2val.put("x14",Arm64Const.UC_ARM64_REG_X14);
        reg2val.put("x15",Arm64Const.UC_ARM64_REG_X15);
        reg2val.put("x16",Arm64Const.UC_ARM64_REG_X16);
        reg2val.put("x17",Arm64Const.UC_ARM64_REG_X17);
        reg2val.put("x18",Arm64Const.UC_ARM64_REG_X18);
        reg2val.put("x19",Arm64Const.UC_ARM64_REG_X19);
        reg2val.put("x20",Arm64Const.UC_ARM64_REG_X20);
        reg2val.put("x21",Arm64Const.UC_ARM64_REG_X21);
        reg2val.put("x22",Arm64Const.UC_ARM64_REG_X22);
        reg2val.put("x23",Arm64Const.UC_ARM64_REG_X23);
        reg2val.put("x24",Arm64Const.UC_ARM64_REG_X24);
        reg2val.put("x25",Arm64Const.UC_ARM64_REG_X25);
        reg2val.put("x26",Arm64Const.UC_ARM64_REG_X26);
        reg2val.put("x27",Arm64Const.UC_ARM64_REG_X27);
        reg2val.put("x28",Arm64Const.UC_ARM64_REG_X28);

        reg2val.put("x29",Arm64Const.UC_ARM64_REG_FP);
        reg2val.put("x30",Arm64Const.UC_ARM64_REG_LR);

        reg2val.put("sp",Arm64Const.UC_ARM64_REG_SP);
        reg2val.put("pc",Arm64Const.UC_ARM64_REG_PC);



    }

    public static long byteArrayToLong(byte[] byteArray) {
        ByteBuffer buffer = ByteBuffer.wrap(byteArray);
        buffer.order(ByteOrder.LITTLE_ENDIAN);  // 设置字节顺序为小端
        return buffer.getLong();

    }
    public long read_reg_by_str(Backend backend,String reg){
        long true_reg_val = -1;
        if(reg2val.containsKey(reg)){
            true_reg_val = backend.reg_read(reg2val.get(reg)).longValue();
        }else if(reg.equals("xzr")){
            true_reg_val = 0;
        }else{
            assert false;
        }
        return true_reg_val;
    }

    public Set<Long> patch_addr_Set = new HashSet<>();
    public HashMap<Long, byte[]> patch_addr2bytes = new HashMap<>();
    public HashMap<String, Integer> reg2val = new HashMap<>();


    public void anti_br_by_static(Backend backend,long begin,long end){

        try{
            // 先获取区域所有汇编指令
            Capstone capstone = new Capstone(Capstone.CS_ARCH_ARM64,Capstone.CS_MODE_LITTLE_ENDIAN);
            byte[] bytes = backend.mem_read(begin + module.base, end - begin);
            Instruction[] disasm = capstone.disasm(bytes, 0);

            HashMap<Long, byte[]> reg2val = new HashMap<>();
            for(int i=0;i<disasm.length;i+=1){


                if ("csel".equals(disasm[i].getMnemonic()) && "ldr".equals(disasm[i+1].getMnemonic()) && "add".equals(disasm[i+2].getMnemonic()) && "br".equals(disasm[i+3].getMnemonic()) ){
                    String ins1_regs[] = disasm[i].getOpStr().split(",");
                    String ins1_reg1_name = ins1_regs[0].trim();
                    String ins1_reg2_name = ins1_regs[1].trim();
                    String ins1_reg3_name = ins1_regs[2].trim();
                    String ins1_op_name = ins1_regs[3].trim();

                    String ins2_regs[] = disasm[i+1].getOpStr().split(",");
                    String ins3_regs[] = disasm[i+2].getOpStr().split(",");

                    String ins2_reg1_name = ins2_regs[0].replaceAll("[\\s\\[]","");
                    String ins2_reg2_name = ins2_regs[1].replaceAll("[\\s\\[]","");
                    String ins2_reg3_name = ins2_regs[2].replaceAll("[\\s\\[]","");

                    String ins3_reg1_name = ins3_regs[0].replaceAll("[\\s\\[]","");
                    String ins3_reg2_name = ins3_regs[1].replaceAll("[\\s\\[]","");
                    String ins3_reg3_name = ins3_regs[2].replaceAll("[\\s\\[]","");



                    long true_op_reg_val = -1;
                    long fals_op_reg_val = -1;


                    Boolean ture_tag = false;
                    Boolean false_tag = false;
                    try{
                        for(int j=i-1;j>=i-4;j--){
                            String spl_regs[] = disasm[j].getOpStr().split(",");
                            String src_reg  = spl_regs[0].replace('w','x').trim();
                            if( (disasm[j].getMnemonic().contains("mov") &&  disasm[j].getMnemonic().contains("movk") == false )  && (src_reg.contains(ins1_reg2_name) || src_reg.contains(ins1_reg3_name)  ) ){
                                String ins_regs[] = disasm[j].getOpStr().split(",");

                                if(src_reg.contains(ins1_reg2_name)){
                                    if (ture_tag){
                                        continue;
                                    }
                                    String true_op_reg_val_str = ins_regs[1].replaceAll("[\\s\\[#]","");
                                    true_op_reg_val = Long.parseLong(true_op_reg_val_str.substring(2),16);
                                    ture_tag = true;
                                }else if(src_reg.contains(ins1_reg3_name)) {
                                    if(false_tag){
                                        continue;
                                    }
                                    String fals_op_reg_val_str = ins_regs[1].replaceAll("[\\s\\[#]","");
                                    fals_op_reg_val = Long.parseLong(fals_op_reg_val_str.substring(2),16);
                                    false_tag = true;
                                }
                            }
                        }
                    }catch (Exception  e){
                        System.out.printf("%s\n",e);
                    }


                    if(ins1_reg2_name.contains("xzr") || ins1_reg2_name.contains("wzr")){
                        true_op_reg_val = 0;
                    }
                    if(ins1_reg3_name.contains("xzr") || ins1_reg3_name.contains("wzr")){
                        fals_op_reg_val = 0;
                    }

                    if(true_op_reg_val == -1){
                        true_op_reg_val = read_reg_by_str(backend,ins1_reg2_name);
                    }
                    if(fals_op_reg_val == -1){
                        fals_op_reg_val  = read_reg_by_str(backend,ins1_reg3_name);
                    }

                    long base_reg_val = read_reg_by_str(backend,ins2_reg2_name);
                    long add_reg_val = read_reg_by_str(backend,ins3_reg3_name);

                    byte[] true_jmp_addr_byte = backend.mem_read(base_reg_val + true_op_reg_val, 8);
                    long true_jmp_addr = byteArrayToLong(true_jmp_addr_byte);

//                    System.out.printf("0x%x - 0x%x - 0x%x\n",begin + 4 * i,base_reg_val + true_op_reg_val,base_reg_val + fals_op_reg_val);
                    byte[] fals_jmp_addr_byte = backend.mem_read(base_reg_val + fals_op_reg_val, 8);
                    long fals_jmp_addr = byteArrayToLong(fals_jmp_addr_byte);

                    long true_fin_jmp = true_jmp_addr +add_reg_val;
                    long fals_fin_jmp = fals_jmp_addr + add_reg_val;



                    String new_asm1 =String.format("B.%s\t0x%x",ins1_op_name ,true_fin_jmp );
                    String new_asm2 =String.format("B\t0x%x" ,fals_fin_jmp );
                    Keystone keystone = new Keystone(KeystoneArchitecture.Arm64, KeystoneMode.LittleEndian);

                    KeystoneEncoded assemble1 = keystone.assemble(new_asm1, (int) begin + 4 * i);
                    byte[] machineCode1 = assemble1.getMachineCode();

                    KeystoneEncoded assemble2= keystone.assemble(new_asm2,(int)begin + 4 * i +4 );
                    byte[] machineCode2 = assemble2.getMachineCode();

                    KeystoneEncoded assemble3 = keystone.assemble("nop" );
                    byte[] machineCode3 = assemble3.getMachineCode();

                    byte[] final_patch = new byte[16];
                    System.arraycopy(machineCode1, 0, final_patch, 0, 4);
                    System.arraycopy(machineCode2, 0, final_patch, 4, 4);
                    System.arraycopy(machineCode3, 0, final_patch, 8, 4);
                    System.arraycopy(machineCode3, 0, final_patch, 12, 4);
                    reg2val.put(begin + 4 * i,final_patch);
                }


            }


            System.out.printf("begin,end = 0x%x,0x%x\n",begin,end);
            System.out.printf("patcher = {} \n");

            for (Long address : reg2val.keySet()) {
                byte[] patch_bytes = reg2val.get(address);
                System.out.printf("patcher[0x%x]  = %s\n", address , Arrays.toString(patch_bytes));
            }
            System.out.printf("patcherr()\n");
            System.out.printf("\n\n");

        }catch (Exception ee){
            System.out.printf("=> %s\n",ee);
        }


    }
    public void hook_and_anti(long begin_addr,long end_addr){

        int arr[] = {0};
        emulator.getBackend().hook_add_new(new CodeHook() {
            @Override
            public void hook(Backend backend, long address, int size, Object user) {
                int[] newArr = (int[]) user;
                if(newArr[0] == 1){
                    return;
                }
                Capstone capstone = new Capstone(Capstone.CS_ARCH_ARM64,Capstone.CS_MODE_ARM);
                byte[] bytes = emulator.getBackend().mem_read(address, 4);
                Instruction[] disasm = capstone.disasm(bytes, 0);
                if("csel".equals(disasm[0].getMnemonic())) {
                    anti_br_by_static(backend,begin_addr,end_addr);
                    newArr[0] = 1;
                }
            }

            @Override
            public void onAttach(UnHook unHook) {
            }

            @Override
            public void detach() {
            }
        },module.base + begin_addr,module.base + end_addr,arr);

    }

    public class res_two_regs{
        public String reg1_name;            // true
        public String reg2_name;            // false

        public String if_op;                // 条件分支的条件
        public long reg1_val;
        public long reg2_val;
        public res_two_regs(String reg1_name, String reg2_name, long reg1_val,long reg2_val,String if_op) {
            this.reg1_name = reg1_name;
            this.reg2_name = reg2_name;
            this.reg1_val = reg1_val;
            this.reg2_val = reg2_val;
            this.if_op =if_op;
        }

    }

    public void set_hook(){
        emulator.getBackend().hook_add_new(new CodeHook() {
            @Override
            public void hook(Backend backend, long address, int size, Object user) {
                if (address == 0x000000000094440 + module.base){
                    backend.reg_write(Arm64Const.UC_ARM64_REG_X0,0);
                }
            }

            @Override
            public void onAttach(UnHook unHook) {}

            @Override
            public void detach() {}
        },0x00000000009443C + module.base,0x000000000094444 + module.base,null);

    }
    public void anti_confuse(){
        padding_reg2val(reg2val);

        // 这里记录了要去混淆的函数收尾地址,需要注意,这个尾地址,用func.end_ea,idapython得到的可能不对
        long br_addr[][] = {
            {0xe2db4,0x0000000000E39FC},
            {0xe227c,0x0000000000E2DB0},
            {0xcf004,0x0000000000CFAC0},
            {0xd2ad0,0x0000000000D31D0},
            {0xd6158,0x0000000000D6DF4},
            {0xd6e00,0x0000000000D7AC4},
            {0xd1cc0,0x0000000000D241C},
            {0xe6bf4,0x0000000000E76D8},
            {0xe3e18,0x0000000000E497C},
            {0xe4c50,0x0000000000E58A4},
            {0xe0be8,0x0000000000E1144},
            {0xd0b2c,0x0000000000D10A0},
            {0xe8054,0x0000000000E8854},
            {0xd7f4c,0x0000000000D8B60},
            {0xd5518,0x0000000000D5A74},
                {0x00000000000EB408,0x0000000000EB8BC}
        };
        set_hook();
        for (int i = 0; i < br_addr.length; i++) {
            long begin = br_addr[i][0];
            long end = br_addr[i][1];
            hook_and_anti(begin,end);
        }
        module.callFunction(emulator,0x000000000094368,114514);
    }
}



运行得到这一段段数据,直接贴到patch脚本即可

image-20250301220518204

patch脚本:

import idc 
import idaapi
def patcherr():
    global patcher,begin,end
    for address in patcher:
        patch_code = patcher[address]
        for addr in range(address,address+16):
            idc.patch_byte(addr,patch_code[addr-address])


    print("finish")


    def upc(begin,end):
        for i in range(begin,end):
            idc.del_items(i)

        for i in range(begin,end):
            idc.create_insn(i)
        idaapi.add_func(begin,end)

        print("Finish!!!")

    upc(begin,end)


begin,end = 0xe4c50,0xe58a4
patcher = {} 
patcher[0xe4d8c]  = [32, 87, 0, 84, 3, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4e4c]  = [-117, 0, 0, 84, 77, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4fc8]  = [-128, 0, 0, 84, 116, -1, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5188]  = [-128, 0, 0, 84, 4, -1, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4e84]  = [-117, 0, 0, 84, -48, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe53c4]  = [-128, 0, 0, 84, 117, -2, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5544]  = [-128, 0, 0, 84, 21, -2, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5784]  = [-128, 0, 0, 84, -123, -3, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5100]  = [-117, 0, 0, 84, -26, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5140]  = [-117, 0, 0, 84, -64, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe515c]  = [-128, 0, 0, 84, 15, -1, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe565c]  = [-128, 0, 0, 84, -49, -3, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4dd8]  = [-117, 0, 0, 84, -118, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4e18]  = [-128, 0, 0, 84, -32, -1, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5098]  = [-128, 0, 0, 84, 64, -1, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe52d8]  = [-128, 0, 0, 84, -80, -2, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5418]  = [-128, 0, 0, 84, 96, -2, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe51d4]  = [-128, 0, 0, 84, -15, -2, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4f10]  = [-117, 0, 0, 84, -25, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4f90]  = [-117, 0, 0, 84, 104, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5010]  = [-117, 0, 0, 84, -30, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5310]  = [-117, 0, 0, 84, -119, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5450]  = [-117, 0, 0, 84, -55, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5750]  = [-128, 0, 0, 84, -110, -3, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4f2c]  = [-128, 0, 0, 84, -101, -1, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4fac]  = [-117, 0, 0, 84, -43, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe502c]  = [-128, 0, 0, 84, 91, -1, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe532c]  = [-128, 0, 0, 84, -101, -2, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe546c]  = [-128, 0, 0, 84, 75, -2, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4e68]  = [-117, 0, 0, 84, -126, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe53a8]  = [-117, 0, 0, 84, -87, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe54a8]  = [-128, 0, 0, 84, 60, -2, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe50e4]  = [-21, -28, -1, 84, 3, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe5124]  = [96, 14, 0, 84, 29, -1, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4da0]  = [-117, 0, 0, 84, 41, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4ea0]  = [-128, 0, 0, 84, -66, -1, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4dbc]  = [-117, 0, 0, 84, 74, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe507c]  = [-117, 0, 0, 84, -36, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe52bc]  = [-117, 0, 0, 84, -116, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe53fc]  = [-117, 0, 0, 84, -47, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe54fc]  = [-128, 0, 0, 84, 39, -2, -1, 23, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4df4]  = [-117, 0, 0, 84, -31, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcher[0xe4ef4]  = [-117, 0, 0, 84, 118, 0, 0, 20, 31, 32, 3, -43, 31, 32, 3, -43]
patcherr()

去混淆效果如下:

去混淆前:

image-20250301220556295

去混淆后:

image-20250301220705939

看CFG有点像看O3编译优化后的控制流平坦化

image-20250301220743302

我只会去常规的控制流平坦化,不太会去这个,因此之后我通过手动patch的方式还原代码,或者硬读。

离散对数算法分析

算法的主要逻辑在 0x00000000009F0A8偏移的函数里。

这个算法比较好分析,一点一点的调试,跟函数即可,记录好函数传参以及返回值,不少函数纯黑盒就能猜出功能。

还原下来,算法如下:

def enc_test():
    base_inp = inp =   xxx
    base_mod = 0x0028a831a5bf4b902e95318e50c2075259f91094d08d84409e1b76eadfa0865d1278acc90fa7c6cf6acb375
    retval = 0
    for i in range(5):
        if i != 4:
            inp *= inp
        else:
            inp *= base_inp
    if inp > base_mod:
        res = inp // base_mod
        mod = base_mod * res
        remainder = inp - mod
        
        retval = remainder
    else:
        retval = inp

    return retval


assert enc_test() == 0x25f6b048b4f32e3ce9175bb64930f65101a706ae74988a4ec87b4d5ec7feb9223ab782bcf1ec9d7fee750 

实际上就是这个问题:

def enc_test():
    inp =   xxx
    base_mod = 0x0028a831a5bf4b902e95318e50c2075259f91094d08d84409e1b76eadfa0865d1278acc90fa7c6cf6acb375
    return pow(inp,17,base_mod)


assert enc_test() == 0x25f6b048b4f32e3ce9175bb64930f65101a706ae74988a4ec87b4d5ec7feb9223ab782bcf1ec9d7fee750 

大数能被直接分解成质数,解密脚本如下:

import gmpy2
def dec():
    cip = 0x25f6b048b4f32e3ce9175bb64930f65101a706ae74988a4ec87b4d5ec7feb9223ab782bcf1ec9d7fee750
    n = 0x0028a831a5bf4b902e95318e50c2075259f91094d08d84409e1b76eadfa0865d1278acc90fa7c6cf6acb375
    e = 17
    p = 555183147936225271626794036740589959032732535469347
    q = 640704384372038524783151782406101498608483916642951
    phi = (p-1) * (q-1)
    d = gmpy2.invert(e,phi)
    m = pow(cip,d,n)
    return m

m = dec()
print(hex(m))
# 0x7be300df8b2c

vm还原

调试配置/trace工具

推荐unidbg,内存与栈帧之类的是固定的,无论是trace和调试都很方便。

需要注意的是,需要hook 000000000009443C 处的strcmp的返回值才能进入vm还原的算法

算法分析

进入vm前的操作大致如下

image-20250228195826258

值得一提的是,程序读取了一个zip文件,并进行了解压,得到了a64.dat这个东西,好像还进行了解密之类的操作。我没有分析这个文件是干嘛的,可能是vm的opcode,不过这些都不重要。

vm分析

goto_vm函数比较大,手动patch了一下br混淆,大致是这样:

有点类似变种控制流平坦化。

__int64 __fastcall goto_vm(__int64 input, int w1_0)
{
  __int64 input_; // x11
  int v3; // w8
  bool v4; // zf
  int v5; // w9
  int v6; // w8
  unsigned __int64 v7; // x9
  int v8; // w9
  __int64 *v10; // [xsp+8h] [xbp-E8h]
  unsigned __int64 v11; // [xsp+10h] [xbp-E0h]
  bool v13; // [xsp+20h] [xbp-D0h]
  unsigned int v14; // [xsp+24h] [xbp-CCh]
  int v15; // [xsp+28h] [xbp-C8h]
  unsigned __int64 v16; // [xsp+30h] [xbp-C0h]
  unsigned __int64 v17; // [xsp+38h] [xbp-B8h]
  unsigned __int64 v18; // [xsp+40h] [xbp-B0h]
  int v19; // [xsp+4Ch] [xbp-A4h]
  int v20; // [xsp+50h] [xbp-A0h]
  __int64 a2; // [xsp+58h] [xbp-98h]
  __int64 v22; // [xsp+60h] [xbp-90h]
  __int64 *v23; // [xsp+68h] [xbp-88h]
  unsigned __int64 v24; // [xsp+70h] [xbp-80h]
  __int64 s2; // [xsp+78h] [xbp-78h]
  unsigned __int64 v26; // [xsp+80h] [xbp-70h]
  unsigned __int64 v27; // [xsp+88h] [xbp-68h]
  unsigned __int64 v28; // [xsp+90h] [xbp-60h]

  input_ = input;
  _ReadStatusReg(ARM64_SYSREG(3, 3, 0xD, 0, 2));
  a2 = *(_QWORD *)(input + 376);
  v10 = (__int64 *)(input + 0x108);
  v11 = w1_0;
  v3 = 0x2B2F3935;
  do
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          while ( v3 >= -35886379 )
          {
            if ( v3 >= 951268337 )
            {
              if ( v3 >= 0x6DD9AB8E )
              {
                if ( v3 >= 1911078787 )
                {
                  if ( v3 >= 2040010456 )
                  {
                    if ( v3 == 2040010456 )
                    {
                      v22 = sub_BAE2C(*(_QWORD *)(input_ + 400));
                      input_ = input;
                      v4 = v22 == 0;
                      v3 = 0xC30C485D;
                      v5 = 0xF0CF7AF;
                      goto LABEL_67;
                    }
                  }
                  else if ( v3 == 1911078787 )
                  {
                    v27 = v16;
                    v23 = v10;
                    v24 = *v10;
                    v15 = v16;
                    if ( *v10 == -1 )
                      v3 = 1565738013;
                    else
                      v3 = -2002346238;
                  }
                }
                else if ( v3 == 0x6DD9AB8E )
                {
                  v19 = 0;
                  v18 = v28;
                  v3 = -2142698382;
                }
              }
              else if ( v3 >= 0x5D53441D )
              {
                if ( v3 == 0x5D53441D )
                {
                  v20 = 0;
                  v6 = *(_DWORD *)(input_ + 300) + v15;
                  *(_DWORD *)(input_ + 296) = v15;
                  *(_DWORD *)(input_ + 300) = v6;
                  v3 = 951268337;
                }
              }
              else if ( v3 == 951268337 )
              {
                v3 = 0xC5C5E3A5;
                v14 = v20;
              }
            }
            else if ( v3 >= 0x2B3773CC )
            {
              if ( v3 >= 0x2C7C4DBC )
              {
                if ( v3 >= 828056523 )
                {
                  if ( v3 == 828056523 )
                  {
                    v7 = v28;
LABEL_62:
                    v18 = v7;
                    v3 = -2142698382;
                    v19 = 3;
                  }
                }
                else if ( v3 == 0x2C7C4DBC )
                {
                  v17 = v26;
                  v3 = 0xD4007AD4;
                  if ( !v13 )
                    v3 = 725054412;
                }
              }
              else if ( v3 == 0x2B3773CC )
              {
                v28 = v17;
                v3 = 828056523;
                if ( !*(_DWORD *)(input_ + 280) )
                  v3 = 1842981774;
              }
            }
            else if ( v3 >= 0x2B2F3935 )
            {
              if ( v3 == 0x2B2F3935 )
              {
                v4 = a2 == 0;
                v3 = -1356816398;
                v5 = -1966562382;
LABEL_67:
                v8 = v5 - 288394458;
                if ( !v4 )
                  v3 = v8;
              }
            }
            else if ( v3 == -35886379 )
            {
              v16 = 0LL;
              *(_BYTE *)(input_ + 392) = 1;
              v3 = 1911078787;
            }
          }
          if ( v3 >= -1022605219 )
            break;
          if ( v3 >= -1765623770 )
          {
            if ( v3 >= -1356816398 )
            {
              if ( v3 == -1356816398 )
              {
                v3 = -976886875;
                v14 = -1;
              }
            }
            else if ( v3 == -1765623770 )
            {
              *v23 = s2 + 4;
              v17 = v27;
              v3 = 725054412;
            }
          }
          else if ( v3 >= -2002346238 )
          {
            if ( v3 == -2002346238 )
            {
              *(_DWORD *)(input_ + 288) = 1;
              (*(void (__fastcall **)(_QWORD, __int64, __int64, __int64, __int64, __int64, __int64, __int64))(v22 + 8 * (v24 >> 2)))(
                *(unsigned int *)(a2 + 4 * (v24 >> 2)),
                input_,
                0x6DD9AB8ELL,
                0x5D53441DLL,
                0x2C7C4DBCLL,
                0x2B3773CCLL,
                0x2B2F3935LL,
                272LL);
              s2 = *v23;
              input_ = input;
              v3 = -1765623770;
              if ( *v23 != v24 )
                v3 = 0xD05B399C;
            }
          }
          else if ( v3 == -2142698382 )
          {
            v3 = 1911078787;
            if ( v19 )
              v3 = 1565738013;
            v15 = v18;
            v16 = v18;
          }
        }
        if ( v3 < -799327844 )
          break;
        if ( v3 >= -738166060 )
        {
          if ( v3 >= -591289714 )
          {
            if ( v3 == -591289714 )
            {
              v13 = *(_DWORD *)(input_ + 284) == 0;
              v3 = 746343868;
            }
          }
          else if ( v3 == -738166060 )
          {
            v7 = v26;
            goto LABEL_62;
          }
        }
        else if ( v3 == -799327844 )
        {
          v13 = 0;
          v26 = v27 + 1;
          v3 = 0xDCC1A28E;
          if ( v27 <= v11 )
            v3 = 0x2C7C4DBC;
        }
      }
      if ( v3 >= -976886875 )
        break;
      if ( v3 == -1022605219 )
      {
        v3 = 951268337;
        v20 = -1;
      }
    }
  }
  while ( v3 != -976886875 );
  return v14;
}

主要的就是 0x000000000099374地址处的vm函数指令调用

image-20250228200237584

用unidbg hook这个地址处的函数调用:

unidbg脚本:

package com.Tencent_game;


import capstone.api.Instruction;
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.ReadHook;
import com.github.unidbg.arm.backend.UnHook;
import com.github.unidbg.debugger.BreakPointCallback;
import com.github.unidbg.debugger.DebuggerType;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.listener.TraceCodeListener;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.virtualmodule.android.AndroidModule;
import java.util.HashMap;
import capstone.Capstone;
import capstone.Capstone.OpInfo;
import capstone.api.Instruction;
import keystone.Keystone;
import keystone.KeystoneArchitecture;
import keystone.KeystoneMode;
import keystone.KeystoneEncoded;
import com.github.unidbg.arm.context.RegisterContext;
import unicorn.Arm64Const;
import com.github.unidbg.arm.backend.CodeHook;
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashSet;
import java.util.Set;
import java.util.Arrays;
import com.github.unidbg.pointer.UnidbgPointer;
import java.io.*;
import java.io.IOException;


public class tracer_fin_2023 {
    public final AndroidEmulator emulator;
    public final VM vm;
    public final Memory memory;
    public final Module module;

    public tracer_fin_2023(){
        emulator = AndroidEmulatorBuilder.for64Bit().build();
        memory =  emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));
        emulator.getSyscallHandler().setEnableThreadDispatcher(true);
        vm = emulator.createDalvikVM();
        new AndroidModule(emulator,vm).register(memory);

        DalvikModule dalvikModule = vm.loadLibrary(new File("C:\\Users\\27236\\Desktop\\2023_tencent_game\\mobile\\final\\mouse_final.aligned.signed\\lib\\arm64-v8a\\libsec2023.so"), true);
        module = dalvikModule.getModule();
        vm.callJNI_OnLoad(emulator,module);
    }


    public  static  void main(String[] args) throws FileNotFoundException {
        tracer_fin_2023 mainActivity = new tracer_fin_2023();
        mainActivity.tracer();

    }

    public  long byteArrayToLong(byte[] byteArray) {
        ByteBuffer buffer = ByteBuffer.wrap(byteArray);
        buffer.order(ByteOrder.LITTLE_ENDIAN);  // 设置字节顺序为小端
        return buffer.getLong();
    }

    long fun_idx = 0;
    public void set_hook_vm(){
        emulator.getBackend().hook_add_new(new CodeHook() {
            @Override
            public void hook(Backend backend, long address, int size, Object user) {
                if(address == 0x099374 + module.base){

                    long x1_val = backend.reg_read(Arm64Const.UC_ARM64_REG_X1).longValue();
                    long x0_val = backend.reg_read(Arm64Const.UC_ARM64_REG_X0).longValue();
                    byte[] x1_mem1 = backend.mem_read(x1_val, 0x8);

                    long tar_addr  = backend.reg_read(Arm64Const.UC_ARM64_REG_X9).longValue();
                    System.out.printf("%d  0x%x: ( 0x%x , 0x%x): \n",fun_idx,tar_addr- module.base,x0_val,byteArrayToLong(x1_mem1));


                    fun_idx += 1;


                }

            }

            @Override
            public void onAttach(UnHook unHook) {
            }

            @Override
            public void detach() {
            }
        },0x000000000099370 + module.base,0x00000000009937C + module.base,null);

    }

    public byte[] mapfun = new byte[0x140000];
    private  void tracer() throws FileNotFoundException {

        set_hook_strcmp();
        set_hook_vm();

        padding_reg2val();


        traceStream =  new PrintStream(new FileOutputStream(traceFile), true);


        module.callFunction(emulator,0x000000000094368,0x1145114514114514L);     // 0x1bf52, 0x1145114514114514L,0x1939000076000000L
    }



    String  traceFile = "C:\\Users\\27236\\Desktop\\2023_tencent_game\\mobile\\final\\op_tracer\\all_trace.txt";
    PrintStream  traceStream = null;
    public void set_hook_strcmp()   {

        emulator.getBackend().hook_add_new(new CodeHook() {
            @Override
            public void hook(Backend backend, long address, int size, Object user) {
                if (address == 0x000000000094440 + module.base){
                    backend.reg_write(Arm64Const.UC_ARM64_REG_X0,0);

                }

            }
            @Override
            public void onAttach(UnHook unHook) {}

            @Override
            public void detach() {}
        },0x00000000009443C + module.base,0x000000000094444 + module.base,null);
    }

    public HashMap<String, Integer> reg2val = new HashMap<>();
    public long read_reg_by_str(Backend backend,String reg){
        long true_reg_val = -1;
        if(reg2val.containsKey(reg)){
            true_reg_val = backend.reg_read(reg2val.get(reg)).longValue();
        }else if(reg.equals("xzr")){
            true_reg_val = 0;
        }else{
            assert false;
        }
        return true_reg_val;
    }

    public  void padding_reg2val() {
        reg2val.put("x0",Arm64Const.UC_ARM64_REG_X0);
        reg2val.put("x1",Arm64Const.UC_ARM64_REG_X1);
        reg2val.put("x2",Arm64Const.UC_ARM64_REG_X2);
        reg2val.put("x3",Arm64Const.UC_ARM64_REG_X3);
        reg2val.put("x4",Arm64Const.UC_ARM64_REG_X4);
        reg2val.put("x5",Arm64Const.UC_ARM64_REG_X5);
        reg2val.put("x6",Arm64Const.UC_ARM64_REG_X6);
        reg2val.put("x7",Arm64Const.UC_ARM64_REG_X7);
        reg2val.put("x8",Arm64Const.UC_ARM64_REG_X8);
        reg2val.put("x9",Arm64Const.UC_ARM64_REG_X9);
        reg2val.put("x10",Arm64Const.UC_ARM64_REG_X10);
        reg2val.put("x11",Arm64Const.UC_ARM64_REG_X11);
        reg2val.put("x12",Arm64Const.UC_ARM64_REG_X12);
        reg2val.put("x13",Arm64Const.UC_ARM64_REG_X13);
        reg2val.put("x14",Arm64Const.UC_ARM64_REG_X14);
        reg2val.put("x15",Arm64Const.UC_ARM64_REG_X15);
        reg2val.put("x16",Arm64Const.UC_ARM64_REG_X16);
        reg2val.put("x17",Arm64Const.UC_ARM64_REG_X17);
        reg2val.put("x18",Arm64Const.UC_ARM64_REG_X18);
        reg2val.put("x19",Arm64Const.UC_ARM64_REG_X19);
        reg2val.put("x20",Arm64Const.UC_ARM64_REG_X20);
        reg2val.put("x21",Arm64Const.UC_ARM64_REG_X21);
        reg2val.put("x22",Arm64Const.UC_ARM64_REG_X22);
        reg2val.put("x23",Arm64Const.UC_ARM64_REG_X23);
        reg2val.put("x24",Arm64Const.UC_ARM64_REG_X24);
        reg2val.put("x25",Arm64Const.UC_ARM64_REG_X25);
        reg2val.put("x26",Arm64Const.UC_ARM64_REG_X26);
        reg2val.put("x27",Arm64Const.UC_ARM64_REG_X27);
        reg2val.put("x28",Arm64Const.UC_ARM64_REG_X28);

        reg2val.put("x29",Arm64Const.UC_ARM64_REG_FP);
        reg2val.put("x30",Arm64Const.UC_ARM64_REG_LR);

        reg2val.put("sp",Arm64Const.UC_ARM64_REG_SP);
        reg2val.put("pc",Arm64Const.UC_ARM64_REG_PC);
    }

}

结果:

// 调用次数 目标函数 x0参数 x1[0]对应的值
0  0xe2db4: ( 0xf01e0ff3 , 0x114514): 
1  0xe227c: ( 0x95417bfd , 0x114514): 
2  0xcf004: ( 0xd30043fd , 0x114514): 
3  0xe1148: ( 0x92003f3 , 0x114514): 
4  0xd0a88: ( 0x5000000 , 0x114514): 
5  0xcf004: ( 0xb200e000 , 0x0): 
6  0xd2ad0: ( 0x64000000 , 0x38): 
7  0xe1148: ( 0x761303e1 , 0x40502038): 
8  0xd2ad0: ( 0xf8000000 , 0x40502038): 
9  0xd6158: ( 0xbd417bfd , 0x40502038): 
10  0xe1148: ( 0x673303e0 , 0x40502038): 
11  0xd6e00: ( 0xc04207f3 , 0x114514): 
12  0xd1cc0: ( 0x14123456 , 0x114514): 
13  0xe6bf4: ( 0xc38043ff , 0x114514): 
14  0xd0a88: ( 0x91000009 , 0x114514): 
15  0xe1148: ( 0x541f03e8 , 0x114514): 
16  0xcf004: ( 0xcb856129 , 0x114514): 
17  0xcf004: ( 0xfd0033ea , 0x114514): 
18  0xe3e18: ( 0x75c03bff , 0x114514): 
19  0xe4c50: ( 0xfd401bff , 0x114514): 
20  0xe9564: ( 0x18137c0c , 0x114514): 
21  0xe0be8: ( 0x1e1c03eb , 0x114514): 
22  0xe1148: ( 0x6f00158c , 0x114514): 
23  0xe0be8: ( 0x7a9f03ed , 0x114514): 
24  0xdf75c: ( 0x31cb7d8e , 0x114514): 
25  0xd8b64: ( 0x424d6d2f , 0x114514): 
26  0xd5a78: ( 0x750b01ce , 0x114514): 
27  0xd0b2c: ( 0x3f001dd0 , 0x114514): 
28  0xe9564: ( 0x6f9e7610 , 0x114514): 
29  0xd2420: ( 0x63861dd0 , 0x114514): 
30  0xcfac4: ( 0x601001ee , 0x114514): 
31  0xe8054: ( 0x8f0001bf , 0x114514): 
32  0xe4980: ( 0xfdad694e , 0x114514): 
33  0xe6bf4: ( 0xe88005ad , 0x114514): 
34  0xe6bf4: ( 0x1d00216b , 0x114514): 
35  0xd1ae8: ( 0xaefffebc , 0x114514): 
36  0xdf75c: ( 0x31cb7d8e , 0x114514): 
37  0xd8b64: ( 0x424d6d2f , 0x114514): 
38  0xd5a78: ( 0x750b01ce , 0x114514): 
39  0xd0b2c: ( 0x3f001dd0 , 0x114514): 
40  0xe9564: ( 0x6f9e7610 , 0x114514): 
41  0xd2420: ( 0x63861dd0 , 0x114514): 
42  0xcfac4: ( 0x601001ee , 0x114514): 
43  0xe8054: ( 0x8f0001bf , 0x114514): 
44  0xe4980: ( 0xfdad694e , 0x114514): 
45  0xe6bf4: ( 0xe88005ad , 0x114514): 
46  0xe6bf4: ( 0x1d00216b , 0x114514): 
47  0xd1ae8: ( 0xaefffebc , 0x114514): 
48  0xdf75c: ( 0x31cb7d8e , 0x114514): 
49  0xd8b64: ( 0x424d6d2f , 0x114514): 
50  0xd5a78: ( 0x750b01ce , 0x114514): 
51  0xd0b2c: ( 0x3f001dd0 , 0x114514): 
52  0xe9564: ( 0x6f9e7610 , 0x114514): 
53  0xd2420: ( 0x63861dd0 , 0x114514): 
54  0xcfac4: ( 0x601001ee , 0x114514): 
55  0xe8054: ( 0x8f0001bf , 0x114514): 
56  0xe4980: ( 0xfdad694e , 0x114514): 
57  0xe6bf4: ( 0xe88005ad , 0x114514): 
58  0xe6bf4: ( 0x1d00216b , 0x114514): 
59  0xd1ae8: ( 0xaefffebc , 0x114514): 
60  0xe1148: ( 0xd53f03eb , 0x114514): 
61  0xd8b64: ( 0x77eb6d4c , 0x114514): 
62  0xd8b64: ( 0x400b6d2d , 0x114514): 
63  0xe9564: ( 0x75857d8e , 0x114514): 
64  0xd2420: ( 0x3d1d1d8e , 0x114514): 
65  0xd5a78: ( 0x2e2d01cc , 0x114514): 
66  0xe4980: ( 0xc8ab694c , 0x114514): 
67  0xcf004: ( 0xfa80056b , 0x114514): 
68  0xe8054: ( 0xbf000d7f , 0x114514): 
69  0xd1ae8: ( 0x1fffff11 , 0x114514): 
70  0xd8b64: ( 0x77eb6d4c , 0x114514): 
71  0xd8b64: ( 0x400b6d2d , 0x114514): 
72  0xe9564: ( 0x75857d8e , 0x114514): 
73  0xd2420: ( 0x3d1d1d8e , 0x114514): 
74  0xd5a78: ( 0x2e2d01cc , 0x114514): 
75  0xe4980: ( 0xc8ab694c , 0x114514): 
76  0xcf004: ( 0xfa80056b , 0x114514): 
77  0xe8054: ( 0xbf000d7f , 0x114514): 
78  0xd1ae8: ( 0x1fffff11 , 0x114514): 
79  0xd8b64: ( 0x77eb6d4c , 0x114514): 
80  0xd8b64: ( 0x400b6d2d , 0x114514): 
81  0xe9564: ( 0x75857d8e , 0x114514): 
82  0xd2420: ( 0x3d1d1d8e , 0x114514): 
83  0xd5a78: ( 0x2e2d01cc , 0x114514): 
84  0xe4980: ( 0xc8ab694c , 0x114514): 
85  0xcf004: ( 0xfa80056b , 0x114514): 
86  0xe8054: ( 0xbf000d7f , 0x114514): 
87  0xd1ae8: ( 0x1fffff11 , 0x114514): 
88  0xd7f4c: ( 0xdd003beb , 0x114514): 
89  0xcf004: ( 0x1e01d56b , 0x114514): 
90  0xe3e18: ( 0xbdc03beb , 0x114514): 
91  0xd7f4c: ( 0x558037eb , 0x114514): 
92  0xd5518: ( 0x719f196b , 0x114514): 
93  0xe3e18: ( 0x418037eb , 0x114514): 
94  0xd6e00: ( 0xb9400fec , 0x114514): 
95  0xe0be8: ( 0x7a9d03eb , 0x114514): 
96  0xcf004: ( 0x3f03058d , 0x114514): 
97  0xe3e18: ( 0xfdc033ed , 0x114514): 
98  0xe9564: ( 0x60907d8d , 0x114514): 
99  0xe9564: ( 0x18105d8c , 0x114514): 
100  0xe9564: ( 0x1e1f798c , 0x114514): 
101  0xd2420: ( 0x57871dac , 0x114514): 
102  0xd5518: ( 0x759f018c , 0x114514): 
103  0xe3e18: ( 0x55803bec , 0x114514): 
104  0xe9564: ( 0x71901d80 , 0x114514): 
105  0xe0be8: ( 0x340003ec , 0x4f0000): 
106  0xd8b64: ( 0x16ec654d , 0x4f0000): 
107  0xe8054: ( 0xbf00019f , 0x4f0000): 
108  0xe9564: ( 0x6f877dae , 0x4f0000): 
109  0xd2420: ( 0x639f1dae , 0x4f0000): 
110  0xd5a78: ( 0x610c01cd , 0x4f0000): 
111  0xe4980: ( 0x2ec6d4d , 0x4f0000): 
112  0xd0b2c: ( 0x3d001dad , 0x4f0000): 
113  0xdf458: ( 0x48eb35ad , 0x4f0000): 
114  0xe6bf4: ( 0x9d00058c , 0x4f0000): 
115  0xcfac4: ( 0x572001a0 , 0x4f0000): 
116  0xe6bf4: ( 0x5e80216b , 0x4f7d00): 
117  0xd1ae8: ( 0x3ffffeac , 0x4f7d00): 
118  0xd8b64: ( 0x16ec654d , 0x4f7d00): 
119  0xe8054: ( 0xbf00019f , 0x4f7d00): 
120  0xe9564: ( 0x6f877dae , 0x4f7d00): 
121  0xd2420: ( 0x639f1dae , 0x4f7d00): 
122  0xd5a78: ( 0x610c01cd , 0x4f7d00): 
123  0xe4980: ( 0x2ec6d4d , 0x4f7d00): 
124  0xd0b2c: ( 0x3d001dad , 0x4f7d00): 
125  0xdf458: ( 0x48eb35ad , 0x4f7d00): 
126  0xe6bf4: ( 0x9d00058c , 0x4f7d00): 
127  0xcfac4: ( 0x572001a0 , 0x4f7d00): 
128  0xe6bf4: ( 0x5e80216b , 0x4f7db1): 
129  0xd1ae8: ( 0x3ffffeac , 0x4f7db1): 
130  0xcf004: ( 0x61800508 , 0x4f7db1): 
131  0xe8054: ( 0x5804011f , 0x4f7db1): 
132  0xd1ae8: ( 0xbcfff8c1 , 0x4f7db1): 
133  0xe9564: ( 0x18137c0c , 0x4f7db1): 
134  0xe0be8: ( 0x1e1c03eb , 0x4f7db1): 
135  0xe1148: ( 0x6f00158c , 0x4f7db1): 
136  0xe0be8: ( 0x7a9f03ed , 0x4f7db1): 
137  0xdf75c: ( 0x31cb7d8e , 0x4f7db1): 
138  0xd8b64: ( 0x424d6d2f , 0x4f7db1): 
139  0xd5a78: ( 0x750b01ce , 0x4f7db1): 
140  0xd0b2c: ( 0x3f001dd0 , 0x4f7db1): 
141  0xe9564: ( 0x6f9e7610 , 0x4f7db1): 
142  0xd2420: ( 0x63861dd0 , 0x4f7db1): 
143  0xcfac4: ( 0x601001ee , 0x4f7db1): 
144  0xe8054: ( 0x8f0001bf , 0x4f7db1): 
145  0xe4980: ( 0xfdad694e , 0x4f7db1): 
146  0xe6bf4: ( 0xe88005ad , 0x4f7db1): 
147  0xe6bf4: ( 0x1d00216b , 0x4f7db1): 
148  0xd1ae8: ( 0xaefffebc , 0x4f7db1): 
149  0xdf75c: ( 0x31cb7d8e , 0x4f7db1): 
150  0xd8b64: ( 0x424d6d2f , 0x4f7db1): 
151  0xd5a78: ( 0x750b01ce , 0x4f7db1): 
152  0xd0b2c: ( 0x3f001dd0 , 0x4f7db1): 
153  0xe9564: ( 0x6f9e7610 , 0x4f7db1): 
154  0xd2420: ( 0x63861dd0 , 0x4f7db1): 
155  0xcfac4: ( 0x601001ee , 0x4f7db1): 
156  0xe8054: ( 0x8f0001bf , 0x4f7db1): 
157  0xe4980: ( 0xfdad694e , 0x4f7db1): 
158  0xe6bf4: ( 0xe88005ad , 0x4f7db1): 
159  0xe6bf4: ( 0x1d00216b , 0x4f7db1): 
160  0xd1ae8: ( 0xaefffebc , 0x4f7db1): 
161  0xdf75c: ( 0x31cb7d8e , 0x4f7db1): 
162  0xd8b64: ( 0x424d6d2f , 0x4f7db1): 
163  0xd5a78: ( 0x750b01ce , 0x4f7db1): 
164  0xd0b2c: ( 0x3f001dd0 , 0x4f7db1): 
165  0xe9564: ( 0x6f9e7610 , 0x4f7db1): 
166  0xd2420: ( 0x63861dd0 , 0x4f7db1): 
167  0xcfac4: ( 0x601001ee , 0x4f7db1): 
168  0xe8054: ( 0x8f0001bf , 0x4f7db1): 
169  0xe4980: ( 0xfdad694e , 0x4f7db1): 
170  0xe6bf4: ( 0xe88005ad , 0x4f7db1): 
171  0xe6bf4: ( 0x1d00216b , 0x4f7db1): 
172  0xd1ae8: ( 0xaefffebc , 0x4f7db1): 
173  0xe1148: ( 0xd53f03eb , 0x4f7db1): 
174  0xd8b64: ( 0x77eb6d4c , 0x4f7db1): 
175  0xd8b64: ( 0x400b6d2d , 0x4f7db1): 
176  0xe9564: ( 0x75857d8e , 0x4f7db1): 
177  0xd2420: ( 0x3d1d1d8e , 0x4f7db1): 
178  0xd5a78: ( 0x2e2d01cc , 0x4f7db1): 
179  0xe4980: ( 0xc8ab694c , 0x4f7db1): 
180  0xcf004: ( 0xfa80056b , 0x4f7db1): 
181  0xe8054: ( 0xbf000d7f , 0x4f7db1): 
182  0xd1ae8: ( 0x1fffff11 , 0x4f7db1): 
183  0xd8b64: ( 0x77eb6d4c , 0x4f7db1): 
184  0xd8b64: ( 0x400b6d2d , 0x4f7db1): 
185  0xe9564: ( 0x75857d8e , 0x4f7db1): 
186  0xd2420: ( 0x3d1d1d8e , 0x4f7db1): 
187  0xd5a78: ( 0x2e2d01cc , 0x4f7db1): 
188  0xe4980: ( 0xc8ab694c , 0x4f7db1): 
189  0xcf004: ( 0xfa80056b , 0x4f7db1): 
190  0xe8054: ( 0xbf000d7f , 0x4f7db1): 
191  0xd1ae8: ( 0x1fffff11 , 0x4f7db1): 
192  0xd8b64: ( 0x77eb6d4c , 0x4f7db1): 
193  0xd8b64: ( 0x400b6d2d , 0x4f7db1): 
194  0xe9564: ( 0x75857d8e , 0x4f7db1): 
195  0xd2420: ( 0x3d1d1d8e , 0x4f7db1): 
196  0xd5a78: ( 0x2e2d01cc , 0x4f7db1): 
197  0xe4980: ( 0xc8ab694c , 0x4f7db1): 
198  0xcf004: ( 0xfa80056b , 0x4f7db1): 
199  0xe8054: ( 0xbf000d7f , 0x4f7db1): 
200  0xd1ae8: ( 0x1fffff11 , 0x4f7db1): 
201  0xd7f4c: ( 0xdd003beb , 0x4f7db1): 
202  0xcf004: ( 0x1e01d56b , 0x4f7db1): 
203  0xe3e18: ( 0xbdc03beb , 0x4f7db1): 
204  0xd7f4c: ( 0x558037eb , 0x4f7db1): 
205  0xd5518: ( 0x719f196b , 0x4f7db1): 
206  0xe3e18: ( 0x418037eb , 0x4f7db1): 
207  0xd6e00: ( 0xb9400fec , 0x4f7db1): 
208  0xe0be8: ( 0x7a9d03eb , 0x4f7db1): 
209  0xcf004: ( 0x3f03058d , 0x4f7db1): 
210  0xe3e18: ( 0xfdc033ed , 0x4f7db1): 
211  0xe9564: ( 0x60907d8d , 0x4f7db1): 
212  0xe9564: ( 0x18105d8c , 0x4f7db1): 
213  0xe9564: ( 0x1e1f798c , 0x4f7db1): 
214  0xd2420: ( 0x57871dac , 0x4f7db1): 
215  0xd5518: ( 0x759f018c , 0x4f7db1): 
216  0xe3e18: ( 0x55803bec , 0x4f7db1): 
217  0xe9564: ( 0x71901d80 , 0x4f7db1): 
218  0xe0be8: ( 0x340003ec , 0x590000): 
...

初步估计的一下,大概有27个op vm指令函数,另外大致可以看到,整个vm算法经过了256次循环。

直接用unidbg对着ida硬调是很难还原算法的,这里我们用了另一种方式: trace

这是我的unidbg trace脚本,为了让trace出来的log更加整洁易读,这里我对trace函数进行了处理。标记了汇编指令所出的vm指令函数地址。

package com.Tencent_game;


import capstone.api.Instruction;
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.ReadHook;
import com.github.unidbg.arm.backend.UnHook;
import com.github.unidbg.debugger.BreakPointCallback;
import com.github.unidbg.debugger.DebuggerType;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.listener.TraceCodeListener;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.virtualmodule.android.AndroidModule;
import java.util.HashMap;
import capstone.Capstone;
import capstone.Capstone.OpInfo;
import capstone.api.Instruction;
import keystone.Keystone;
import keystone.KeystoneArchitecture;
import keystone.KeystoneMode;
import keystone.KeystoneEncoded;
import com.github.unidbg.arm.context.RegisterContext;
import unicorn.Arm64Const;
import com.github.unidbg.arm.backend.CodeHook;
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashSet;
import java.util.Set;
import java.util.Arrays;
import com.github.unidbg.pointer.UnidbgPointer;
import java.io.*;
import java.io.IOException;


public class tracer_fin_2023 {
    public final AndroidEmulator emulator;
    public final VM vm;
    public final Memory memory;
    public final Module module;

    public tracer_fin_2023(){
        emulator = AndroidEmulatorBuilder.for64Bit().build();
        memory =  emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));
        emulator.getSyscallHandler().setEnableThreadDispatcher(true);
        vm = emulator.createDalvikVM();
        new AndroidModule(emulator,vm).register(memory);

        DalvikModule dalvikModule = vm.loadLibrary(new File("C:\\Users\\27236\\Desktop\\2023_tencent_game\\mobile\\final\\mouse_final.aligned.signed\\lib\\arm64-v8a\\libsec2023.so"), true);
        module = dalvikModule.getModule();
        vm.callJNI_OnLoad(emulator,module);
    }


    public  static  void main(String[] args) throws FileNotFoundException {
        tracer_fin_2023 mainActivity = new tracer_fin_2023();
        mainActivity.tracer();

    }

    public  long byteArrayToLong(byte[] byteArray) {
        ByteBuffer buffer = ByteBuffer.wrap(byteArray);
        buffer.order(ByteOrder.LITTLE_ENDIAN);  // 设置字节顺序为小端
        return buffer.getLong();
    }

    long fun_idx = 0;
    public void set_hook_vm(){
        emulator.getBackend().hook_add_new(new CodeHook() {
            @Override
            public void hook(Backend backend, long address, int size, Object user) {
                if(address == 0x099374 + module.base){

                    fun_idx += 1;
                }

            }

            @Override
            public void onAttach(UnHook unHook) {
            }

            @Override
            public void detach() {
            }
        },0x000000000099370 + module.base,0x00000000009937C + module.base,null);

    }

    public byte[] mapfun = new byte[0x140000];
    private  void tracer() throws FileNotFoundException {

        set_hook_strcmp();
        set_hook_vm();

        padding_reg2val();


        long [][]hook_list= {
                { 0xcf004,0xcfac0 },
                { 0xcfac4,0xcfddc },
                { 0xd0b2c,0xd10a0 },
                { 0xd1ae8,0xd1cbc },
                { 0xd1cc0,0xd241c },
                { 0xd2420,0xd27bc },
                { 0xd2ad0,0xd31d0 },
                { 0xd5518,0xd5a74 },
                { 0xd5a78,0xd5d8c },
                { 0xd6158,0xd6df8 },
                { 0xd6e00,0xd7ac4 },
                { 0xd7f4c,0xd8b60 },
                { 0xd8b64,0xd8e58 },
                { 0xdf458,0xdf758 },
                { 0xdf75c,0xdfa68 },
                { 0xdf75c,0xdfa68 },
                { 0xe0be8,0xe1144 },
                { 0xe1148,0xe1454 },
                { 0xe227c,0xe2db0 },
                { 0xe2db4,0xe39fc },
                { 0xe3e18,0xe497c },
                { 0xe4980,0xe4c4c },
                { 0xe4c50,0xe58a4 },
                { 0xe6bf4,0xe76d8 },
                { 0xe8054,0xe8854 },
                { 0xe9564,0xe98b0 },
                { 0xd0a88, 0x0000000000D0B28},
                { 0xe1468, 0x0000000000E14DC}
        };

        for(int i=0;i<hook_list.length;i++){
            long be = hook_list[i][0];
//            long ed = hook_list[i][1];

            mapfun[(int)be] = 1;
        }


        traceStream =  new PrintStream(new FileOutputStream(traceFile), true);


        module.callFunction(emulator,0x000000000094368,0x1145114514114514L);     // 0x1bf52, 0x1145114514114514L,0x1939000076000000L
    }



    String  traceFile = "C:\\Users\\27236\\Desktop\\2023_tencent_game\\mobile\\final\\op_tracer\\all_trace.txt";
    PrintStream  traceStream = null;
    public void set_hook_strcmp()   {

        emulator.getBackend().hook_add_new(new CodeHook() {
            @Override
            public void hook(Backend backend, long address, int size, Object user) {
                if (address == 0x000000000094440 + module.base){
                    backend.reg_write(Arm64Const.UC_ARM64_REG_X0,0);

                    emulator.traceCode(module.base, 0x40150000, new TraceCodeListener() {
                        @Override
                        public void onInstruction(Emulator<?> emulator, long address, Instruction insn) {
                            if(mapfun[(int)address - (int)module.base] == 1){

                                traceStream.printf("\n=================================================================\n");
                                traceStream.printf("\n\n\n%d\tcall [0x%x]\n\n\n",fun_idx,address- module.base);
                                traceStream.printf("=================================================================\n");

                            }
                        }
                    }).setRedirect(traceStream);


                }

            }
            @Override
            public void onAttach(UnHook unHook) {}

            @Override
            public void detach() {}
        },0x00000000009443C + module.base,0x000000000094444 + module.base,null);
    }

    public HashMap<String, Integer> reg2val = new HashMap<>();
    public long read_reg_by_str(Backend backend,String reg){
        long true_reg_val = -1;
        if(reg2val.containsKey(reg)){
            true_reg_val = backend.reg_read(reg2val.get(reg)).longValue();
        }else if(reg.equals("xzr")){
            true_reg_val = 0;
        }else{
            assert false;
        }
        return true_reg_val;
    }

    public  void padding_reg2val() {
        reg2val.put("x0",Arm64Const.UC_ARM64_REG_X0);
        reg2val.put("x1",Arm64Const.UC_ARM64_REG_X1);
        reg2val.put("x2",Arm64Const.UC_ARM64_REG_X2);
        reg2val.put("x3",Arm64Const.UC_ARM64_REG_X3);
        reg2val.put("x4",Arm64Const.UC_ARM64_REG_X4);
        reg2val.put("x5",Arm64Const.UC_ARM64_REG_X5);
        reg2val.put("x6",Arm64Const.UC_ARM64_REG_X6);
        reg2val.put("x7",Arm64Const.UC_ARM64_REG_X7);
        reg2val.put("x8",Arm64Const.UC_ARM64_REG_X8);
        reg2val.put("x9",Arm64Const.UC_ARM64_REG_X9);
        reg2val.put("x10",Arm64Const.UC_ARM64_REG_X10);
        reg2val.put("x11",Arm64Const.UC_ARM64_REG_X11);
        reg2val.put("x12",Arm64Const.UC_ARM64_REG_X12);
        reg2val.put("x13",Arm64Const.UC_ARM64_REG_X13);
        reg2val.put("x14",Arm64Const.UC_ARM64_REG_X14);
        reg2val.put("x15",Arm64Const.UC_ARM64_REG_X15);
        reg2val.put("x16",Arm64Const.UC_ARM64_REG_X16);
        reg2val.put("x17",Arm64Const.UC_ARM64_REG_X17);
        reg2val.put("x18",Arm64Const.UC_ARM64_REG_X18);
        reg2val.put("x19",Arm64Const.UC_ARM64_REG_X19);
        reg2val.put("x20",Arm64Const.UC_ARM64_REG_X20);
        reg2val.put("x21",Arm64Const.UC_ARM64_REG_X21);
        reg2val.put("x22",Arm64Const.UC_ARM64_REG_X22);
        reg2val.put("x23",Arm64Const.UC_ARM64_REG_X23);
        reg2val.put("x24",Arm64Const.UC_ARM64_REG_X24);
        reg2val.put("x25",Arm64Const.UC_ARM64_REG_X25);
        reg2val.put("x26",Arm64Const.UC_ARM64_REG_X26);
        reg2val.put("x27",Arm64Const.UC_ARM64_REG_X27);
        reg2val.put("x28",Arm64Const.UC_ARM64_REG_X28);

        reg2val.put("x29",Arm64Const.UC_ARM64_REG_FP);
        reg2val.put("x30",Arm64Const.UC_ARM64_REG_LR);

        reg2val.put("sp",Arm64Const.UC_ARM64_REG_SP);
        reg2val.put("pc",Arm64Const.UC_ARM64_REG_PC);
    }

}

由于整个vm是一个256次的循环加密,因此我们不需要trace特别多的log,这里我trace了一个G的log进行分析。

image-20250228202514853

接下来就是漫长的扣算法过程。

这里我建议使用unidbg的内存访问断点功能来辅助我们扣算法、观察数据流向。

另外在最新版的unidbg项目里,在调试的时候下内存访问断点并不能生效,甚至traceRead/traceWrite函数如果设置的比较靠后也不能生效。

这是我的内存访问断点脚本,通过我在trace的时候设置的 函数idx以及函数地址,能够快速筛选出要找的内存访问的数据的流向。

image-20250228203106943

package com.Tencent_game;


import capstone.api.Instruction;
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.ReadHook;
import com.github.unidbg.arm.backend.UnHook;
import com.github.unidbg.debugger.BreakPointCallback;
import com.github.unidbg.debugger.DebuggerType;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.listener.TraceCodeListener;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.virtualmodule.android.AndroidModule;
import java.util.HashMap;
import capstone.Capstone;
import capstone.Capstone.OpInfo;
import capstone.api.Instruction;
import keystone.Keystone;
import keystone.KeystoneArchitecture;
import keystone.KeystoneMode;
import keystone.KeystoneEncoded;
import com.github.unidbg.arm.context.RegisterContext;
import unicorn.Arm64Const;
import com.github.unidbg.arm.backend.CodeHook;
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashSet;
import java.util.Set;
import java.util.Arrays;
import com.github.unidbg.pointer.UnidbgPointer;
import java.io.*;
import java.io.IOException;


public class tracer_fin_2023 {
    public final AndroidEmulator emulator;
    public final VM vm;
    public final Memory memory;
    public final Module module;

    public tracer_fin_2023(){
        emulator = AndroidEmulatorBuilder.for64Bit().build();
        memory =  emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));
        emulator.getSyscallHandler().setEnableThreadDispatcher(true);
        vm = emulator.createDalvikVM();
        new AndroidModule(emulator,vm).register(memory);

        DalvikModule dalvikModule = vm.loadLibrary(new File("C:\\Users\\27236\\Desktop\\2023_tencent_game\\mobile\\final\\mouse_final.aligned.signed\\lib\\arm64-v8a\\libsec2023.so"), true);
        module = dalvikModule.getModule();
        vm.callJNI_OnLoad(emulator,module);
    }


    public  static  void main(String[] args) throws FileNotFoundException {
        tracer_fin_2023 mainActivity = new tracer_fin_2023();
        mainActivity.tracer();

    }

    public  long byteArrayToLong(byte[] byteArray) {
        ByteBuffer buffer = ByteBuffer.wrap(byteArray);
        buffer.order(ByteOrder.LITTLE_ENDIAN);  // 设置字节顺序为小端
        return buffer.getLong();
    }

    long fun_idx = 0;
    public void set_hook_vm(){
        emulator.getBackend().hook_add_new(new CodeHook() {
            @Override
            public void hook(Backend backend, long address, int size, Object user) {
                if(address == 0x099374 + module.base){

                    if(fun_idx >= 22+1){
                        try {
                            System.out.printf("%d:\n",fun_idx);
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                    }

                    fun_idx += 1;


                }

            }

            @Override
            public void onAttach(UnHook unHook) {
            }

            @Override
            public void detach() {
            }
        },0x000000000099370 + module.base,0x00000000009937C + module.base,null);

    }

    public byte[] mapfun = new byte[0x140000];
    private  void tracer() throws FileNotFoundException {
        emulator.traceWrite(0x404f2010L + (0xe<<3), 0x404f2010L + (0xe<<3) + 0x4);
        emulator.traceRead(0x404f2010L + (0xe<<3), 0x404f2010L + (0xe<<3) + 0x4);

        set_hook_strcmp();
        set_hook_vm();

        padding_reg2val();



        traceStream =  new PrintStream(new FileOutputStream(traceFile), true);


        module.callFunction(emulator,0x000000000094368,0x1145114514114514L);     // 0x1bf52, 0x1145114514114514L,0x1939000076000000L
    }



    String  traceFile = "C:\\Users\\27236\\Desktop\\2023_tencent_game\\mobile\\final\\op_tracer\\all_trace.txt";
    PrintStream  traceStream = null;
    public void set_hook_strcmp()   {

        emulator.getBackend().hook_add_new(new CodeHook() {
            @Override
            public void hook(Backend backend, long address, int size, Object user) {
                if (address == 0x000000000094440 + module.base){
                    backend.reg_write(Arm64Const.UC_ARM64_REG_X0,0);


                }

            }
            @Override
            public void onAttach(UnHook unHook) {}

            @Override
            public void detach() {}
        },0x00000000009443C + module.base,0x000000000094444 + module.base,null);
    }

    public HashMap<String, Integer> reg2val = new HashMap<>();
    public long read_reg_by_str(Backend backend,String reg){
        long true_reg_val = -1;
        if(reg2val.containsKey(reg)){
            true_reg_val = backend.reg_read(reg2val.get(reg)).longValue();
        }else if(reg.equals("xzr")){
            true_reg_val = 0;
        }else{
            assert false;
        }
        return true_reg_val;
    }

    public  void padding_reg2val() {
        reg2val.put("x0",Arm64Const.UC_ARM64_REG_X0);
        reg2val.put("x1",Arm64Const.UC_ARM64_REG_X1);
        reg2val.put("x2",Arm64Const.UC_ARM64_REG_X2);
        reg2val.put("x3",Arm64Const.UC_ARM64_REG_X3);
        reg2val.put("x4",Arm64Const.UC_ARM64_REG_X4);
        reg2val.put("x5",Arm64Const.UC_ARM64_REG_X5);
        reg2val.put("x6",Arm64Const.UC_ARM64_REG_X6);
        reg2val.put("x7",Arm64Const.UC_ARM64_REG_X7);
        reg2val.put("x8",Arm64Const.UC_ARM64_REG_X8);
        reg2val.put("x9",Arm64Const.UC_ARM64_REG_X9);
        reg2val.put("x10",Arm64Const.UC_ARM64_REG_X10);
        reg2val.put("x11",Arm64Const.UC_ARM64_REG_X11);
        reg2val.put("x12",Arm64Const.UC_ARM64_REG_X12);
        reg2val.put("x13",Arm64Const.UC_ARM64_REG_X13);
        reg2val.put("x14",Arm64Const.UC_ARM64_REG_X14);
        reg2val.put("x15",Arm64Const.UC_ARM64_REG_X15);
        reg2val.put("x16",Arm64Const.UC_ARM64_REG_X16);
        reg2val.put("x17",Arm64Const.UC_ARM64_REG_X17);
        reg2val.put("x18",Arm64Const.UC_ARM64_REG_X18);
        reg2val.put("x19",Arm64Const.UC_ARM64_REG_X19);
        reg2val.put("x20",Arm64Const.UC_ARM64_REG_X20);
        reg2val.put("x21",Arm64Const.UC_ARM64_REG_X21);
        reg2val.put("x22",Arm64Const.UC_ARM64_REG_X22);
        reg2val.put("x23",Arm64Const.UC_ARM64_REG_X23);
        reg2val.put("x24",Arm64Const.UC_ARM64_REG_X24);
        reg2val.put("x25",Arm64Const.UC_ARM64_REG_X25);
        reg2val.put("x26",Arm64Const.UC_ARM64_REG_X26);
        reg2val.put("x27",Arm64Const.UC_ARM64_REG_X27);
        reg2val.put("x28",Arm64Const.UC_ARM64_REG_X28);

        reg2val.put("x29",Arm64Const.UC_ARM64_REG_FP);
        reg2val.put("x30",Arm64Const.UC_ARM64_REG_LR);

        reg2val.put("sp",Arm64Const.UC_ARM64_REG_SP);
        reg2val.put("pc",Arm64Const.UC_ARM64_REG_PC);
    }

}

算法还原

扣了近一天半,扣除的算法如下:

#include <stdio.h>
#define  int64 long long
#define  uint64 unsigned int64
#define  uint unsigned int
#define uint8 unsigned char

int main(){
    // (idx3,0xe1148,0x92003f3)
    uint64 inp = 0x114514;                      // 0x404f2010[0]
    inp &= 0xffffffff;
    uint64 idx3_1 = inp << 0;                   // [sp, #0x10]
    inp >> 0;                                   // [sp, #0x18]
    inp;                                        // [sp, #0x38]
    uint64 idx3_2 = idx3_1 | 0;                 // 0x404f2010[0x13]



    // (idx7,0xe1148,0x761303e1)
    idx3_2 &= 0xffffffff;  
    uint64 idx7_1 = idx3_2 << 0;                // [sp, #0x10]
    idx3_2 >> 0;                                // [sp, #0x18]
    idx3_2;                                     // [sp, #0x38]
    uint64 idx7_2 = idx7_1 | 0;                 // 0x404f2010[0x1]
    

    // (idx8,0xd2ad0,0xf8000000)
    idx3_2;                                     // [sp, #0x20],[sp, #0x40],[sp, #0x60],[0xbfffea70, #-0x78]



    // (idx10,0xe1148,0x673303e0)
    uint64 idx10_1 =  idx3_2 = 0xffffffff;      // [sp, #0x38]
    uint64 idx10_1 =  idx10_1 << 0;             // [sp, #0x10]
    idx10_1 >> 0;            // [sp, #0x18]
    uint64 idx10_2 =  idx10_1 | 0;              // 0x404f2010[0]
    

    // (idx20,0xe9564,0x18137c0c)
    uint64 idx20_1 = idx10_2 & 0xffffffff;
    uint64 idx20_2 = (idx20_1 >> 0x13) | (idx20_1 << 0xd);          // (0x2 | 0x228a28000) -> 0x228a28002  // 373964
    uint64 idx20_3 = (idx20_2 & 0xffffffff) & 0x1fff;               // 0x2    0x404f2010[0xc]  // 373049
    

    

    // (idx22,0xe1148,0x6f00158c)
    uint64 idx22_1 = idx10_2 & 0xffffffff;                      // [sp, #0x38]
    uint64 idx22_2 = idx22_1 << 0x5;                             // 0x228a280 // [sp, #0x10]
    idx22_1 >> 0x5;                                             // 0x8a28    // [sp, #0x18]     // 389733       不用管,这个东西后面直接被覆写了
    uint64 idx22_3 =  idx20_3 | idx22_2;                        // 0x228a282!!!,还没处理完这个,等会与idx48一块    0x404f2010[0xc]
    

    // (idx24,0xdf75c,0x31cb7d8e)
    uint64 idx24_1 = idx22_3 & 0xffffffff;  //[sp, #0x38]
    idx24_1 << 0x10;                        //[sp, #0x10]   // 0x228a2820000 // 直接被复写了
    uint64 idx24_2 = idx24_1 >> 0x10;                        //[sp, #0x18]   // 0x228         // 405607
    uint64 idx24_3 = idx24_2 & 0xffffffff;                  // 0x404f2010[0xe]


    // (idx26,0xd5a78,0x750b01ce)
    uint64 idx24_4 = idx24_3 ^ 0x10;                     // 0x238 //409597   // 0x404f2010[0xe]


    // (idx27,0xd0b2c,0x3f001dd0)
    uint64 idx27_1 =  idx24_4 & 0xff;                // 0x38  // 424207       0x404f2010[0x10]

    
    // (idx28,0xe9564,0x6f9e7610)
    uint64 idx28_1 = idx27_1 & 0xffffffff;                          // 438949
    uint64 idx28_2 = (idx28_1 >> 0x1e) | (idx28_1 << 0x2);           // 0x0 | 0xe0 --> 0xe0  // 439084
    uint64 idx28_3 = idx28_2 & 0xfffffffc;                   //0xe0 ,439165  0x404f2010[0x10]
    
    
    // (idx29,0xd2420,0x63861dd0)
    uint64 idx29_1 = idx28_3 & 0x303fffffc;                  // 0xe0, 453940 ,x20
    idx28_3;    // 0x24
    uint64 idx29_0_1 = idx24_4 & 0xffffffff;       
    uint64 idx29_0_2 = (idx29_0_1 >> 0x6) | (idx29_0_1 << 0x1a);        // 0x8e0000008 // 454068
    uint64 idx29_0_3 =  idx29_0_2 & 0x3fc000003;             // 0xe0000000
    uint64 idx29_2 = idx29_0_3 | idx29_1;                   // 0xe00000e0
    idx29_2 &= 0x3;                                         // 0x0 454140
    uint64 idx29_3 =  idx28_3 & 0xfffffffc;                  // 0xe0 , x11 , 454139
    idx29_2 |= idx29_3;                                     // 0xe0,x8, 0x404f2010[0x10]



    // (idx30,0xcfac4,0x601001ee)
    uint64 idx30_1 =  idx29_2 & 0xffffffff;     //[sp, #0x38]
    uint64 idx30_2 = idx30_1 << 0;              //[sp, #0x10]
    idx30_1 >> 0;                               //[sp, #0x18]
    uint64 idx30_3 = idx30_2 + 0x6b;            // 0x14b,x10    //455295
    uint64 idx30_4 = idx30_3 + 0;               // x21 
    // tst 0x80000000,idx30_2 

    uint64 idx30_5 = idx30_2 + 0x6b;            // 0x14b //455562 , x20
    // cmp idx30_4 , 0          
    // cmp idx30_5,0x14b        // 455714
    // mov x0, x21      // 45577
    uint64 idx30_7 = (idx30_4 & 0xffffffff) ;
    // tst idx30_7
    idx30_4;            // 0x404f2010[0xe] 0x14b


    // (idx32,0xe4980,0xfdad694e)
    uint64 idx32_1 =  idx30_4 & 0xff;       //[0x40502000,0x1011e] , 0x4b!!!   // 460566
                                            //[0x40502000,0x1011d] , 0x4c!!!    // 522604
                                            //[0x40502000,0x1011c] , 0x20!!!    // 584642
    
    // =============================================  Algorithm1 ===============================================================
    // ... 
    // ...
    // ...
    // 24->36 36->48 48->60








 // =============================================  Algorithm2 ===============================================================
    uint8 cip1[3] = {0x4b,0x4c,0x20};
    // (idx61,0xd8b64,0x77eb6d4c)       // 0x20
    uint64 idx61_1 = cip1[2];           // 594143
    uint64 idx61_2 = idx61_1 & 0xff;    // 0x404f2010[0xc]
    
    // (idx63,0xe9564,0x75857d8e)
    uint64 idx63_1 = idx61_2;
    uint64 idx63_2 = (idx63_1 >> 0x5) | (idx63_1 << 0x1b);      // 0x100000000 | 0x1 --> 0x100000001(1) // 611928
    uint64 idx63_3 = (idx63_2 & 0xffffffff) & 0x7ffffff;        // 0x1 //611998 0x404f2010[0xe]
    

    // (idx64,0xd2420,0x3d1d1d8e)
    uint64 idx64_0_1 = idx63_3;
    uint64 idx64_0_2 = idx64_0_1 & 0xfffff807; // 0x1   x20
    idx64_0_1;              // x24
    uint64 idx64_0_3 = 0xfffff800 & idx64_0_1; //0x0   // 626972
    idx32_1;                //  x1
    uint64 idx64_1 = cip1[2];           // 626731   // [sp, #0x1c] x3,
    uint64 idx64_2 = 0x20-1;         // x8,
    uint64 idx64_4 = idx64_2 & 0x1d;     // 0x1d  626896
    uint64 idx64_3 = 0x20-0x1d;      
    uint64 idx64_5 = (idx32_1 >> idx64_4) | (idx32_1 << idx64_3);   // 0 | 0x100 --> 0x100  626903   特征码: [0xd2420] [libsec2023.so 0x0eb080] [93010baa] 0x400eb080: "orr x19, x12, x11"
    uint64 idx64_6 = idx64_5 & 0x7f8;        // 0x100
    idx64_6 |= idx64_0_2;                     // 0x101
    idx64_6 &= 0x7ff;                       // 0x101    // 626973
    idx64_6 |= idx64_0_3;                    // 0x404f2010[0xe]   (0x101)    // 626979  特征码:[0xd2420] [libsec2023.so 0x0d2678] [08010baa] 0x400d2678: "orr x8, x8, x11"
    
    // (idx65,0xd5a78,0x2e2d01cc)
    uint64 idx65_1 = idx64_6;
    uint64 idx65_2 = idx65_1 ^ 0x16;        // 0x117 // 628110      特征码: [0xd5a78] [libsec2023.so 0x0d5cac] [0900144a] 0x400d5cac: "eor x9, x0, x20
    
    // (idx66,0xe4980,0xc8ab694c)
    uint64 idx66_1 = idx65_2 & 0xff;        // 0x17  // 630452       [0x40502000,#0x1011c]  , goto idx94  : 特征码: [0xe4980] [libsec2023.so 0x0e4c10] [00693438] 0x400e4c10: "strb x0, [x8, x20]"
                                            // [0x40502000, #0x1011c] = 0x17
    

        



    // (idx70,0xd8b64,0x77eb6d4c)   // 0x4c
    uint64 idx70_1 = cip1[1];       // 638885  0x404f2010[0xc]
    
    // (idx72,0xe9564,0x75857d8e)

    // (idx73,0xd2420,0x3d1d1d8e)
    
    // (idx74,0xd5a78,0x2e2d01cc)

    // (idx75,0xe4980,0xc8ab694c)               [0x40502000, #0x1011d] = 0xc0



    // (idx79,0xd8b64,0x77eb6d4c)
    uint64 idx79_1 = cip1[0]; //  683973      0x404f2010[0xc]
    
    // (idx81,0xe9564,0x75857d8e)

    // (idx82,0xd2420,0x3d1d1d8e)
    
    // (idx83,0xd5a78,0x2e2d01cc)

    // (idx84,0xe4980,0xc8ab694c)               [0x40502000,#0x1011e] = 0x31

    
 // =============================================  Algorithm2 ===============================================================


    //  ========================================================================================= 
    uint8 cip2[3] = { 0x31 , 0xc0 , 0x17}; 
    // 接下来对 [0x40502000,#0x1011e] = 0x31、[0x40502000, #0x1011d] = 0xc0、 [0x40502000, #0x1011c] = 0x17 下内存访问断点就行
    // (idx88,0xd7f4c,0xdd003beb)   // 0x31
    uint64 idx88_1 = cip2[0];
    uint64 idx88_2 = idx88_1 & 0xff;                // 0x404f2010[0xb]


    // (idx89,0xcf004,0x1e01d56b)
    uint64 idx89_1 = idx88_2;
    uint64 idx89_2 = idx89_1  + 0x75;               // 0xa6 728462  // 特征码: [0xcf004] [libsec2023.so 0x0e9fc0] [8a02088b] 0x400e9fc0: "add x10, x20, x8" 
    uint64 idx89_4 = idx89_2 + 0;                   // x21 , 0xbfffef58[0]   0x404f2010[0xb]!!!!!!
    // "tst x8, x1" x1=0x31 => nzcv: N=0, Z=1, C=0, V=0 x8=0x80000000
    // cmp x0, x20" x20=0xa6

    // (idx90,0xe3e18,0xbdc03beb)
    uint64 idx90_1 = idx89_4;           // 730269   strb [0x40502000,#0x1011e](0xa6) !!!           read1================================





    // (idx91,0xd7f4c,0x558037eb)   // 0xc0
    uint64 idx91_1 = cip2[1];       // 0x404f2010[0xb]      // 732045

    // (idx92,0xd5518,0x719f196b)   
    uint64 idx92_1 = idx91_1 ^ 0xfe;             // 0x404f2010[0xb] // 746803<=

    // (idx93,0xe3e18,0x418037eb)
    uint64 idx93 = idx92_1;                 // strb [0x40502000,#0x1011d](0x3e) !!!              read2================================





    // (idx94,0xd6e00,0xb9400fec)   // 0x17,不过是直接读了四字节来着,这里有点怪  // 0xff a6 3e 17    ,mem read, PC=RX@0x400cd30c
    uint64 idx94_1 = 0xffa63e17;       // 0x404f2010[0xc]
    
    // (idx96,0xcf004,0x3f03058d)
    uint64 idx96_0 = idx94_1;       // 765193        // 0x404f2010[0xc]          //0xffa63e17
    uint64 idx96_2 = idx96_0 + 0xc1;                 // 0xffa63ed8  // 765375     0x404f2010[0xd]
    // "tst x8, x1" x1=0xffa63ed8 
    //"tst x8, x1" x1=0xffa63e17 

    // (idx97,0xe3e18,0xfdc033ed)
    uint64 idx97_1 = idx96_2;         // strb [0x40502000,#0x1011c](0xd8)   0xffa63ed8=> 0xd8   read3================================
    //  =========================================================================================





 // =============================================  Algorithm3 ===============================================================

    // read1==================================================================================================================================
    // (idx98,0xe9564,0x60907d8d)
    uint64 idx98_1 = idx96_0;               
    uint64 idx98_2 = (idx98_1 >> 0x10 | idx98_1 << 0x10);     // (0xffa6 | 0xffa63e170000), 0xffa63e17ffa6, 0x3e17ffa6
    uint64 idx98_3 = idx98_2 & 0xffff;               //0xffa6   // 0x404f2010[0xd]  // 782205
    

    // (idx99,0xe9564,0x18105d8c)
    uint64 idx99_1 = idx96_0;
    uint64 idx99_2 = (idx99_1 >> 0x10) | (idx99_1 >> 0x10);          // (0xffa63e170000 | 0xffa6) ==> 0xffa63e17ffa6!!!
    uint64 idx99_3 = idx99_2 & 0xff;                    // 0xa6     0x404f2010[0xc]     // 797068
    
    

    // (idx100,0xe9564,0x1e1f798c)
    uint64 idx100_1 = idx99_3;
    uint64 idx100_2 = (idx100_1 >> 0x1f) | (idx100_1 << 0x1);         // 0x14c  //811850
    uint64 idx100_3 =  idx100_2 & 0xfffffffe;      // 0x14c 0x404f2010[0xc]



    // (idx101, 0xd2420,0x57871dac)     // 0xffa6 , 0x14c   ,x24
    uint64 idx101_1 = idx100_3;         // 826542
    uint64 idx101_2 = idx101_1 & 0x101fffffe;   // 0x14c x20 , 826706
    uint64 idx101_8 = idx98_3;          // 826664  0xffa6
    uint64 idx101_9 = (idx101_8 >> 0x7) | (idx101_8 << 0x19);  // 0x1ff4c000000   // 826834
    uint64 idx101_10 = idx101_9 | 0x1ff;            // 0x1ff4c0001ff
    uint64 idx101_11 = idx101_10 & 0x1fe000001;        // 0x14c000001   // 826900
    uint64 idx101_3 = idx101_2 | idx101_11;     // 0x14c00014d x8, // 826903
    uint64 idx101_6 =  idx101_1 & 0xfffffffe;      // 0x14c  x11,  // 826905  
    uint64 idx101_13 = idx101_3 & 1;                   // 0x1  // 826906
    uint64 idx101_5 = idx101_13 | idx101_6;       // 0x14d   // 826912   0x404f2010[0xc]
    

    // (idx102,0xd5518,0x759f018c)      // 0x14d
    uint64 idx102_1 = idx101_5;                  // 841564
    uint64 idx102_2 = idx102_1 ^ 0x2;           // 0x14f    0x404f2010[0xc] // 841597


    // (idx103,0xe3e18,0x55803bec)          // 0x14f
    uint64 idx103_1 = idx102_2;             // 842910   strb [0x40502000,#0x1011e] 0x14f(0x4f)
    
    

    // (idx104,0xe9564,0x71901d80)          // 0x14f
    uint64 idx104_1 = idx102_2;
    uint64 idx104_2 = (idx104_1 >> 0x10) | (idx104_1 << 0x10);        // 0x14f0000
    uint64 idx104_3 =  idx100_2 & 0xff0000;                     // 0x4f0000     0x404f2010[0] = 0x4f0000 , first=======================
    


    // read2==================================================================================================================================
    // (idx106,0xd8b64,0x16ec654d)
    uint64 idx106_1 = idx93;                // 874917       0x404f2010[0xd] (0x3e)

    // (idx108,0xe9564,0x6f877dae)              // 0x3e
    uint64 idx108_1 = idx106_1;
    uint64 idx108_2 = (idx108_1 >> 0x7) | ( idx108_1 << 0x19); // 0x7c000000
    uint64 idx108_3 = (idx108_2 & 0x1ffffff);   // 0x0   //892589        0x404f2010[0xe];
    

    // (idx109,0xd2420,0x639f1dae)      // 0x3e ,x24
    uint64 idx109_1 = idx108_3;         // 0x0  // 907200

    uint64 idx109_2 = idx106_1;         // 0x3e // 907322
    uint64 idx109_2_1 = (idx109_2 >> 0x1f) | (idx109_2 << 1);   // 0x7c //907494
    uint64 idx109_2_2 = idx109_2_1 & 0x1fe;     // 0x7c
    uint64 idx109_1_1 = idx109_1 & 0xfffffe01;          // x20=0x0  // 907364
    uint64 idx109_1_1_1 = idx109_1_1 | idx109_2_2;      // x8=0x7c   // 907561
    uint64 idx109_1_2 = idx109_1 & 0xfffffe00;          // x11= 0  // 907563
    uint64 idx109_1_1_1_1 = (idx109_1_1_1 & 0x1ff) | idx109_1_2;       // x8 = 0x7c  0x404f2010[0xe] =0x7c  // 907570
    
    // (idx110,0xd5a78,0x610c01cd)
    uint64 idx110_1 = idx109_1_1_1_1;
    uint64 idx110_2 = idx110_1 ^ 1;         // 0x7d      0x404f2010[0xd] = 0x7d;

    // (idx111,0xe4980,0x2ec6d4d)           // 0x7d
    uint64 idx111_1 = idx110_2;             // strb 0x7d,[0x40502000, 0x1011d] 

    // (idx112,0xd0b2c,0x3d001dad)          // 0x7d
    uint64 idx112_1 = idx110_2;             // 0x404f2010[0xd]= 0x7d
    
    // (idx113,0xdf458,0x48eb35ad)
    uint64 idx113_1 = idx112_1;     // [sp, #0x38]
    uint64 idx113_2 = idx113_1 << 0x8;    // 0x7d00   // [sp, #0x10]
    uint64 idx113_3 = idx113_2 & 0xffffffff;    // 0x404f2010[0xd] = 0x7d00

    // (idx115,0xcfac4,0x572001a0)  
    uint64 idx115_0 =  idx113_3;         // read from 0x404f2010[0xd]
    uint64 idx115_2 = idx104_3;          // read from 0x404f2010[0]
    uint64 idx115_1 =  idx115_0 + 0x4f0000; // x10=0x4f7d00  //930908    0x404f2010[0] = 0x4f7d00!!! second=======================

    // read3==================================================================================================================================
    // (idx118,0xd8b64,0x16ec654d)
    uint64 idx118_1 = idx97_1;          // read from [0x4051211c]   // 936898   // 0x404f2010[0xd](0xd8)
    

    // (idx120,0xe9564,0x6f877dae)      // (0xd8)
    


    // (idx121,0xd2420,0x639f1dae)      // (0xd8)
 // =============================================  Algorithm3 ===============================================================

    return 0;
}

整理一下不难发现,加密算法中充斥着大量无用的加密逻辑,莫非是指令混淆,整理之后的加密结果如下;

#include <stdio.h>
#define  int64 long long
#define  uint64 unsigned int64
#define  uint unsigned int
#define  uint8 unsigned char 

int main(){
    // (idx3,0xe1148,0x92003f3)
    uint64 inp = 0x114514;
    // uint64 inp = 0x193976;
    // uint64 inp = 0xc9d583;

    for(int z=0;z<256;z++){
        uint64 idx10_2 = inp & 0xffffffff;
        uint64 idx22_3 = inp  << 5 | inp >> 19;         // 实际上是基于 24位的循环移位
        uint8 key[3] = {0x6b,0xa2,0x16};
        uint8 cip1[3] = {0};        // 0x4b,0x4c,0x20,
        for(int i=0;i<3;i++){
            uint64 cur = (2-i)*8;
            uint64 idx24_3 = ((idx22_3 >> cur) ^  cur) & 0xff;
            uint64 idx29_2 =   (idx24_3 >> 6)  | ( idx24_3 << 2);
            uint8 idx30_4 = (idx29_2 + key[i]) & 0xff;
            cip1[i] = idx30_4;
            // printf("0x%x,",cip1[i]);  0x13,0x84,0xfb,
        }
        // puts("");//0x47,0x3a,0x25,
        // 460566
        // 522604
        // 584642
        // 这三个行数可以进行验证 
         
        
        
        uint8 cip2[3] = {0};  // 0x31 , 0xc0 , 0x17
        for(int i=2;i>=0;i--){
            uint64 idx61_1 = cip1[i] & 0xff;
            uint64 idx64_5 = (idx61_1 >> 0x5) | (idx61_1 << 0x3);
            uint64 idx65_2 = (idx64_5 ^ key[i]) & 0xff;
            cip2[i] = idx65_2;
            // printf("0x%x,",cip2[i]);        // 0xc9,0x86,0xf3,

        }
        // 检测位置:
        // 630452: 0x3f
        // 675194: 0x73
        // 719936: 0x51
    
    
        cip2[0] += 0x75;    
        cip2[1] ^= 0xfe;
        cip2[2] += 0xc1;
        // 检测位置:
        // 728462: cip2[0]  :0xc6
        // 746803: cip2[1]  :0x8d
        // 765375: cip2[2]  :0x00
        // printf("0x%x,0x%x,0x%x",cip2[0],cip2[1],cip2[2]); //0x68,0x78,0x8a
    
    
    
        // 0xa6,0x3e,0xd8
        uint64 sum = 0;
        for(int i=0;i<3;i++){
            uint64 idx109_1_1 =  cip2[i] >> 7 |  cip2[i]  << 1;
            uint64 idx109_1_1_1_1 = (idx109_1_1  ^ (2-i)) & 0xff;        
            uint64 idx113_3 = idx109_1_1_1_1 << (0x8*(2-i));  
            sum += idx113_3;
        }
        // printf("0x%x\n",sum);
        inp = sum;
    }
    
    printf("enc=>0x%x\n",inp);


    
    return 0;
}

解密算法

大致如下:

#include <stdio.h>
#define int64 long long
#define uint64 unsigned long long
#define uint unsigned int
#define uint8 unsigned char 



int main() {

    uint64 final = token;
    uint8 key[3] = {0x6b,0xa2,0x16};
    
    uint8 cip2[3] = {0};
    uint8 cip1[3] = {0};
    uint64 m = 0;

    for(int z=0;z<256;z++){
        uint64 cip = 0;

        for(int i=0;i<3;i++){
            uint8 cip3 = ((final >> (8*(2-i))) & 0xff) ^ (2-i);
            cip2[i] = cip3 >> 1 | cip3 << 7;
        }
        cip2[2] -= 0xc1;
        cip2[1] ^= 0xfe;
        cip2[0] -= 0x75;
    
        for(int i=0;i<3;i++){
            uint8 tmp = cip2[i] ^ key[i];
            cip1[i] = tmp >> 0x3 | tmp << 0x5;
        }
    
        for(int i=0;i<3;i++){
            uint64 cur = (2-i)*8;
            uint8 tmp1 = cip1[i] - key[i];
            uint8 tmp2 = tmp1 >> 2 | tmp1 << 6;
            uint8 tmp3 = tmp2 ^ cur;
            cip += tmp3 << cur;
        }
        

        m = (cip << 19 | cip >> 5) & 0xffffff;
        final = m;
    }
    
    // printf("0x%x\n",final);
    return 0;
}

注册机算法

#include <stdio.h>
#define int64 long long
#define uint64 unsigned long long
#define uint unsigned int
#define uint8 unsigned char 

uint64 keygen(uint64 token){
    uint64 final = token;
    uint8 key[3] = {0x6b,0xa2,0x16};
    
    uint8 cip2[3] = {0};
    uint8 cip1[3] = {0};
    uint64 m = 0;

    for(int z=0;z<256;z++){
        uint64 cip = 0;

        for(int i=0;i<3;i++){
            uint8 cip3 = ((final >> (8*(2-i))) & 0xff) ^ (2-i);
            cip2[i] = cip3 >> 1 | cip3 << 7;
        }
        cip2[2] -= 0xc1;
        cip2[1] ^= 0xfe;
        cip2[0] -= 0x75;
    
        for(int i=0;i<3;i++){
            uint8 tmp = cip2[i] ^ key[i];
            cip1[i] = tmp >> 0x3 | tmp << 0x5;
        }
    
        for(int i=0;i<3;i++){
            uint64 cur = (2-i)*8;
            uint8 tmp1 = cip1[i] - key[i];
            uint8 tmp2 = tmp1 >> 2 | tmp1 << 6;
            uint8 tmp3 = tmp2 ^ cur;
            cip += tmp3 << cur;
        }
        // printf("0x%x\n",cip);

        m = (cip << 19 | cip >> 5) & 0xffffff;
        final = m;
    }

    return ((final & 0xff) << 24) | ((final >> 8) <<48 ) | 0x7be300df8b2c;
}


int main() {
    uint64 cheat_code= keygen(4612901);
    printf("cheat code is: %llu\n",cheat_code);

    
    
    return 0;
}
// 136214904564590
posted @ 2025-03-01 22:18  TLSN  阅读(85)  评论(0)    收藏  举报