2023 腾讯游戏安全 mobile 决赛 wp
拿flag的思路和初赛一样,这里主要讲解算法的还原。
相关混淆的处理
变量 + 具体值的间接跳转混淆
全局变量 + 具体值
该一下变量类型即可:
由于间接跳转过多这里写了个批量处理的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)
处理完之后大致是这样:
传参 + 具体值
类似于这种的,通过传入固定的参数与具体值相加后进行函数调用。
去混淆方法: patch,把 blr跳转寄存器,patch成跳转具体地址。
由于在本题中这种混淆出现的敌方不是很多,因此笔者未做处理,只在调试的时候打注释标记了一下目的地址。
br混淆
存在两种br混淆,不建议去混淆,太麻烦,很难去,会浪费大量时间还不一定有成功。
这里我更推荐手动patch,调试的时候知道基本块执行流程,就可以尝试patch br混淆,来连接两个基本块。
类似于这样:


不过显然这样只能解决br混淆程度比较低的函数,不过已经够了。
我只写了其中一种br混淆的去混淆脚本(而且去的不是很完美):
首先是混淆函数的筛选:
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
这样的条件分支形式。
->
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脚本即可
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()
去混淆效果如下:
去混淆前:
去混淆后:
看CFG有点像看O3编译优化后的控制流平坦化
我只会去常规的控制流平坦化,不太会去这个,因此之后我通过手动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前的操作大致如下

值得一提的是,程序读取了一个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函数指令调用
用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进行分析。
接下来就是漫长的扣算法过程。
这里我建议使用unidbg的内存访问断点功能来辅助我们扣算法、观察数据流向。
另外在最新版的unidbg项目里,在调试的时候下内存访问断点并不能生效,甚至traceRead/traceWrite函数如果设置的比较靠后也不能生效。
这是我的内存访问断点脚本,通过我在trace的时候设置的 函数idx以及函数地址,能够快速筛选出要找的内存访问的数据的流向。
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