BUUCTF-[网鼎杯 2020 青龙组]singal

[网鼎杯 2020 青龙组]singal

查壳,无壳32位

main函数看起来非常简单,就只有几行。这就有点做数学证明题的感觉了,就给你一行信息,让你去证明某个东西。image-20250329222252371

久闻vm的大名,第一次去尝试把它做出来,之前也是看过一个wp,感觉还行,就是有点麻烦。所以这次好好记录,好好地去分析,去学习,去做题。

vm_operad函数里面是指令集吧?这个说法应该没错,列一下vm函数

int __cdecl vm_operad(int *a1, int a2)
{
  int result; // eax
  char Str[200]; // [esp+13h] [ebp-E5h] BYREF
  char v4; // [esp+DBh] [ebp-1Dh]
  int v5; // [esp+DCh] [ebp-1Ch]
  int v6; // [esp+E0h] [ebp-18h]
  int v7; // [esp+E4h] [ebp-14h]
  int v8; // [esp+E8h] [ebp-10h]
  int v9; // [esp+ECh] [ebp-Ch]

  v9 = 0;
  v8 = 0;
  v7 = 0;
  v6 = 0;
  v5 = 0;
  while ( 1 )
  {
    result = v9;
    if ( v9 >= a2 )
      return result;
    switch ( a1[v9] )
    {
      case 1:
        Str[v6 + 100] = v4;
        ++v9;
        ++v6;
        ++v8;
        break;
      case 2:
        v4 = a1[v9 + 1] + Str[v8];
        v9 += 2;
        break;
      case 3:
        v4 = Str[v8] - LOBYTE(a1[v9 + 1]);
        v9 += 2;
        break;
      case 4:
        v4 = a1[v9 + 1] ^ Str[v8];
        v9 += 2;
        break;
      case 5:
        v4 = a1[v9 + 1] * Str[v8];
        v9 += 2;
        break;
      case 6:
        ++v9;
        break;
      case 7:
        if ( Str[v7 + 100] != a1[v9 + 1] )
        {
          printf("what a shame...");
          exit(0);
        }
        ++v7;
        v9 += 2;
        break;
      case 8:
        Str[v5] = v4;
        ++v9;
        ++v5;
        break;
      case 0xA:
        read(Str);
        ++v9;
        break;
      case 0xB:
        v4 = Str[v8] - 1;
        ++v9;
        break;
      case 0xC:
        v4 = Str[v8] + 1;
        ++v9;
        break;
      default:
        continue;
    }
  }
}

这个unk_403040里面的是操作数,到时候提出来解码就行了

主要分析这个vm_operad,大致应该是这样,case8不知道是啥image-20250330192103883

然后找把操作数提取出来,0x07后面的就是待比较的密文了,把他们提出来,看看前面对flag进行了什么操作image-20250330195058351

def disassemble_bytecode(bytecode):
    # 操作码映射表
    opcode_map = {
        1: "STORE",
        2: "ADD",
        3: "SUB",
        4: "XOR",
        5: "MUL",
        6: "NOP",
        7: "VERIFY",
        8: "LOAD",
        10: "READ",
        11: "DEC",
        12: "INC"
    }

    instructions = []
    i = 0
    length = len(bytecode)

    while i < length:
        op = bytecode[i]
        instr = opcode_map.get(op, f"UNKNOWN({op})")

        # 处理带操作数的指令
        if op in [2, 3, 4, 5, 7]:  # 这些指令带1个操作数
            if i+1 >= length:
                instructions.append(("INCOMPLETE", op))
                break
            operand = bytecode[i+1]
            instructions.append((instr, operand))
            i += 2
        elif op in [1, 6, 8, 10, 11, 12]:  # 无操作数指令
            instructions.append((instr, None))
            i += 1
        else:  # 未知指令
            instructions.append((f"UNKNOWN({op})", None))
            i += 1

    return instructions

# 测试数据
bytecode = [
    0x0A, 0x04, 0x10, 0x08, 
    0x03, 0x05, 0x01, 0x04, 
    0x20, 0x08, 0x05, 0x03, 
    0x01, 0x03, 0x02, 0x08, 
    0x0B, 0x01, 0x0C, 0x08, 
    0x04, 0x04, 0x01, 0x05, 
    0x03, 0x08, 0x03, 0x21, 
    0x01, 0x0B, 0x08, 0x0B, 
    0x01, 0x04, 0x09, 0x08, 
    0x03, 0x20, 0x01, 0x02, 
    0x51, 0x08, 0x04, 0x24, 
    0x01, 0x0C, 0x08, 0x0B, 
    0x01, 0x05, 0x02, 0x08, 
    0x02, 0x25, 0x01, 0x02, 
    0x36, 0x08, 0x04, 0x41, 
    0x01, 0x02, 0x20, 0x08, 
    0x05, 0x01, 0x01, 0x05, 
    0x03, 0x08, 0x02, 0x25, 
    0x01, 0x04, 0x09, 0x08, 
    0x03, 0x20, 0x01, 0x02, 
    0x41, 0x08, 0x0C, 0x01,
]

# 反汇编输出
instructions = disassemble_bytecode(bytecode)

# 打印带注释的反汇编结果
print("地址\t操作码\t参数\t指令描述")
print("----------------------------------------")
pc = 0
for instr in instructions:
    op, arg = instr
    desc = f"{op}"
    if arg is not None:
        desc += f" 0x{arg:x}"
    
    # 添加注释说明
    if op == "READ":
        desc += "      # 读取flag到内存"
    elif op == "VERIFY":
        desc += f"    # 验证内存[100+rc] == 0x{arg:x}"
    elif op == "STORE":
        desc += "    # 存储v4到内存[100+rb]"
    elif op == "LOAD":
        desc += "     # 加载v4到内存[rd]"
    
    print(f"0x{pc:04x}\t0x{bytecode[pc]:02x}\t{arg if arg is not None else '':4} \t{desc}")
    
    # 计算PC偏移
    if op in ["ADD", "SUB", "XOR", "MUL", "VERIFY"]:
        pc += 2
    else:
        pc += 1

image-20250330200156672

根据翻译的结果写脚本逆flag

enc=[0x22,0x3F,0x34,0x32,0x72,0x33,0x18,0xA7,0x31,0xF1,0x28,0x84,0xC1,0x1E,0x7A]

enc[0]=(enc[0]+5)^16
enc[1]=(enc[1]//3)^32
enc[2]=enc[2]+1+2
enc[3]=(enc[3]^4)-1
enc[4]=(enc[4]+33)//3
enc[5]=enc[5]+1+1
enc[6]=(enc[6]+32)^9
enc[7]=(enc[7]^36)-81
enc[8]=enc[8]
enc[9]=(enc[9]-37)//2
enc[10]=(enc[10]^65)-54
enc[11]=enc[11]-32
enc[12]=(enc[12]-37)//3
enc[13]=(enc[13]+32)^9
enc[14]=enc[14]-1-65
for i in range(len(enc)):
    print(chr(enc[i]),end='')
#757515121f3d478
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值