CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】

文章目录

  • 前言
  • 0x1[HGAME 2023 week4]vm
    • 提取汇编指令
      • mov指令
      • push指令&pop指令
      • 运算操作
      • cmp指令
      • jmp指令
      • je 和 jne
    • exp

前言

没有前言。终于搞定第二题了。费劲是真的费。
题目在nssctf上有。
这一题写完才看到有提示,是关于构建结构体的,下次试试。


0x1[HGAME 2023 week4]vm

CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第1张图片
CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第2张图片

这里有几个技巧:

  • 将__int64 a1 改为 _DWORD *a1
  • a1 可以 改名为 reg
  • 函数返回值改为void

这样方便观看,还有其他一些函数的名称,不一一做解释。

sub_1400010B0 点进来,一个里面放着字节码改为opcode,一个是调度器。 当opcode当前的索引的值不为255的时候就一直读取下去。

CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第3张图片
CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第4张图片
CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第5张图片

这里是做过修过后的,可以看到特别的简洁明了。下面具体分析一下,汇编的实现过程。先给出完整的。

提取汇编指令

opcode = [0x00, 0x03, 0x02, 0x00, 0x03, 0x00, 0x02, 0x03, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x03, 0x02, 0x32,
          0x03, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
          0x01, 0x00, 0x00, 0x03, 0x02, 0x64, 0x03, 0x00, 0x02, 0x03,
          0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x01, 0x00, 0x00, 0x03,
          0x00, 0x08, 0x00, 0x02, 0x02, 0x01, 0x03, 0x04, 0x01, 0x00,
          0x03, 0x05, 0x02, 0x00, 0x03, 0x00, 0x01, 0x02, 0x00, 0x02,
          0x00, 0x01, 0x01, 0x00, 0x00, 0x03, 0x00, 0x01, 0x03, 0x00,
          0x03, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x01, 0x28,
          0x04, 0x06, 0x5F, 0x05, 0x00, 0x00, 0x03, 0x03, 0x00, 0x02,
          0x01, 0x00, 0x03, 0x02, 0x96, 0x03, 0x00, 0x02, 0x03, 0x00,
          0x00, 0x00, 0x00, 0x04, 0x07, 0x88, 0x00, 0x03, 0x00, 0x01,
          0x03, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03,
          0x01, 0x28, 0x04, 0x07, 0x63, 0xFF, 0xFF]
input1 = []
i = 0
while opcode[i] != 0xFF:
    match opcode[i]:
        case 0x00:
            print(f'{i}', end=' ')
            o = i + 1
            if opcode[o]:
                match opcode[o]:
                    case 0x01:
                        print("mov input[reg[2]], reg[0]")
                    case 0x02:
                        print("mov reg[%d], reg[%d]" % (opcode[i+2],opcode[i+3]))
                    case 0x03:
                        print("mov reg[%d], %d" % (opcode[i+2], opcode[i+3]))
            else:
                print("mov reg[0], input[reg[2]]")
            i += 4
        case 0x01:
            print(f'{i}', end=' ')
            o = i + 1
            if opcode[o]:
                match opcode[o]:
                    case 0x01:
                        print("push reg[0]")
                    case 0x02:
                        print("push reg[2]")
                    case 0x03:
                        print("push reg[3]")
            else:
                print("push reg[0]")
            i += 2
        case 0x02:
            print(f'{i}', end=' ')
            o = i + 1
            if opcode[o]:
                match opcode[o]:
                    case 0x01:
                        print("pop reg[1]")
                    case 0x02:
                        print("pop reg[2]")
                    case 0x03:
                        print("pop reg[3]")
            else:
                print("pop reg[0]")
            i += 2
        case 0x03:
            print(f'{i}', end=' ')
            o = i + 1
            match opcode[o]:
                case 0:
                    print("add reg[%d],reg[%d]" % (opcode[i + 2], opcode[i + 3]))
                case 1:
                    print("sup reg[%d],reg[%d]" % (opcode[i + 2], opcode[i + 3]))
                case 2:
                    print("mul reg[%d],reg[%d]" % (opcode[i + 2], opcode[i + 3]))
                case 3:
                    print("xor reg[%d],reg[%d]" % (opcode[i + 2], opcode[i + 3]))
                case 4:
                    print("shl reg[%d],reg[%d]" % (opcode[i + 2], opcode[i + 3]))
                case 5:
                    print("shr reg[%d],reg[%d]" % (opcode[i + 2], opcode[i + 3]))
            i += 4
        case 0x04:
            print(f'{i} cmp reg[0], reg[1]')
            i += 1
        case 0x05:
            print(f'{i} jmp %d ' % (opcode[i+1]))
            i += 2
        case 0x06:
            print(f'{i} je %d ' % (opcode[i+1]))
            i += 2
        case 0x07:
            print(f'{i} jne %d ' % (opcode[i+1]))
            i += 2

我第一次写,没有区分函数,最好可以写成 def mov(): 这样的形式。

mov指令

CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第6张图片

其实我也不太理解,为什么是reg[6](a1[6])这样子, 最后也只理解了它 等同于 i 索引值。

这里经过修改,还是蛮清楚的,reg是寄存器,reg[6] 当做是 i;这里例如case 1:可以理解为将reg[0] 的东西放入 input[reg[2]]里下面也是类似的。case2 是俩个寄存器,case 3就是将opcode[reg[3]]的数据放入寄存器。注意的是最后有个 i += 4 。

其实 i 可以理解为 rip。也就是读取指令的位置。

push指令&pop指令

CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第7张图片
栈 + 1,然后 将 reg[0] 的值放进去 ,就是push 指令 ,最后有 i += 2

pop指令同理,寄存器取了栈当前位置的值,然后栈再-1,

运算操作

CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第8张图片

这里其实蛮清楚的,就是寄存器之间的加减之类的运算。

cmp指令

CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第9张图片
比较函数,返回 0 或者 1;

jmp指令

在这里插入图片描述
改完后简单明了,就是 i = 下一个位置

je 和 jne

一个是不为 0 跳转 一个 是为零 跳转。
CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第10张图片
CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第11张图片

这里就分析完了。运行一开始的exp

得到近似的汇编

0 mov reg[2], 0
4 add reg[2],reg[3]
8 mov reg[0], input[reg[2]]
12 mov reg[1], reg[0]
16 mov reg[2], 50
20 add reg[2],reg[3]
24 mov reg[0], input[reg[2]]
28 add reg[1],reg[0]
32 mov reg[2], 100
36 add reg[2],reg[3]
40 mov reg[0], input[reg[2]]
44 xor reg[1],reg[0]
48 mov reg[0], 8
52 mov reg[2], reg[1]
56 shl reg[1],reg[0]
60 shr reg[2],reg[0]
64 add reg[1],reg[2]
68 mov reg[0], reg[1]
72 push reg[0]
74 mov reg[0], 1
78 add reg[3],reg[0]
82 mov reg[0], reg[3]
86 mov reg[1], 40
90 cmp reg[0], reg[1]
91 je 95 
93 jmp 0 
95 mov reg[3], 0
99 pop reg[1]
101 mov reg[2], 150
105 add reg[2],reg[3]
109 mov reg[0], input[reg[2]]
113 cmp reg[0], reg[1]
114 jne 136 
116 mov reg[0], 1
120 add reg[3],reg[0]
124 mov reg[0], reg[3]
128 mov reg[1], 40
132 cmp reg[0], reg[1]
133 jne 99 

分析后大概就是这样
CTF-Reverse---VM虚拟机逆向&[HGAME 2023 week4]vm题目复现【详解】_第12张图片

  • a1 是 input[50 + i]
  • a2 是 input[100 + i]
  • a3 是 input[150 + i]

就是,取 input[50 + i]开始的值 和我们输入的flag 相加,然后和input[100+i]的值异或 。将异或后的值再做俩个移位处理相加起来,得到的值等于 input[150+i]的值。

将值都取出来,写个exp

exp

a1 = [155, 168, 2, 188, 172, 156, 206, 250, 2, 185, 255, 58, 116, 72, 25, 105, 232, 3, 203, 201,
      255, 252, 128, 214, 141, 215, 114, 0, 167, 29, 61, 153, 136, 153, 191, 232, 150, 46, 93, 87]
a2 = [201, 169, 189, 139, 23, 194, 110, 248, 245, 110, 99, 99, 213, 70, 93, 22, 152, 56, 48, 115, 56,
      193, 94, 237, 176, 41, 90, 24, 64, 167, 253, 10, 30, 120, 139, 98, 219, 15, 143, 156]
a3 = [18432, 61696, 16384, 8448, 13569, 25600, 30721, 63744, 6145, 20992, 9472, 23809, 18176, 64768, 26881, 23552,
      44801, 45568, 60417,
      20993, 20225, 6657, 20480, 34049, 52480, 8960, 63488, 3072, 52992, 15617, 17665, 33280, 53761, 10497, 54529, 1537,
      41473, 56832, 42497, 51713]
a4 = a3[::-1]
# a4 = [51713, 42497, 56832, 41473, 1537, 54529, 10497, 53761, 33280, 17665, 15617, 52992, 3072, 63488, 8960, 52480, 34049, 20480, 6657, 20225, 20993, 60417, 45568, 44801, 23552, 26881, 64768, 18176, 23809, 9472, 20992, 6145, 63744, 30721, 25600, 13569, 8448, 16384, 61696, 18432]
flag = [0] * 40
for i in range(40):
    flag[i] = ((a4[i] >> 8) & 0xff + (a4[i] << 8))
    flag[i] ^= a2[i]
    flag[i] -= a1[i]
print("".join([chr(a&0xff) for a in flag]))

# hgame{y0ur_rever5e_sk1ll_i5_very_g0od!!}

你可能感兴趣的:(CTF学习笔记,CTF,Reverse,网络安全,学习,python)