2018/12/03-NCTF-WcyVM

题目链接:https://pan.baidu.com/s/17upwsge3pVrAbANqkeGkwA 密码:30b4

如果对VM题不太了解的话,可以先看看这一篇文章(https://www.52pojie.cn/forum.php?mod=viewthread&tid=713219),基本上有汇编功底的话很快就能入门的。

分析vm首先先找到这四个。

我们来看这个题,函数sub_400DAB()里有一个虚拟机,dword_6021C0处存放的即是VM_data,进行分析后可以初步确定VM_data,VM_IP,VM_context,VM_stack。

 

下面就是逐条分析每个Handler,有汇编功底的话基本能根据脚本去理解过程,就不具体分析了,只简单说明一下。

这三个是虚拟机寄存器数组,可以理解为R0,R1,R2。

 

每个Handler都要传入VM_EIP,因为执行完 Handler 后,VM_EIP 需要向后移动,指向下一条指令。在函数中VM_EIP会增加,增加一个字节就+4。

关于mov指令有不少,要注意它们引用的区别,如果不太清楚可以通过脚本来理解。

关于Handler13和Handler15的伪代码比较麻烦,可以看汇编指令来写。

其他的可以看脚本来理解。

arr = \
    [0x8,0x1,0x0,0x8,0x3,0x46,0xe,0x15,0xa,0x1,
     0x9,0x2,0xb,0xa,0x1,0xa,0x2,0x9,0x1,0x11,
     0x1,0xd,0x1,0x3,0xf,0x8,0x8,0x1,0x0,0x8,0x3,
     0x47,0xe,0x46,0xa,0x1,0x1a,0x2,0x6,0x1d,
     0x1,0x4,0x14,0x2,0x1,0x19,0x1,0x2,0x1b,
     0x1,0x1,0x1d,0x1,0x6e,0x13,0x1,0x63,0x15,
     0x1,0x74,0x13,0x1,0x66,0x1c,0x2,0x1,0x9,
     0x1,0x11,0x1,0xd,0x1,0x3,0xf,0x22,0x64]
i = 0
while(i < len(arr)):
    if(arr[i] == 8):
        print('%d   mov R%d, %d'%(i, arr[i+1]-1, arr[i+2]))
        i += 3
    if(arr[i] == 9):
        print('%d   pop R%d'%(i, arr[i+1]-1))
        i += 2
    if(arr[i] == 10):
        print('%d   push R%d'%(i, arr[i+1]-1))
        i += 2
    if(arr[i] == 11):
        print('%d   R0 = getchar()'%i)
        i += 1
    if(arr[i] == 12):
        print('%d   R0  = putchar()'%i)
        i += 1
    if(arr[i] == 13):
        print("     cmp R%d, R%d\n"%(arr[i+1]-1, arr[i+2]-1),
              "    jnz %d\n"%(i+3),
              "    mov a, 80")
        i += 3
    if(arr[i] == 14):
        print('%d   jmp %d'%(i,arr[i+1]))
        i +=2
    if(arr[i] == 15):
        print("%d"%i,
              " and a, 0x80\n"
              "     test a\n"
              "     jnz %d"%arr[i+1])
        i += 2
    if(arr[i] == 17):
        print('%d   inc R%d'%(i,arr[i+1]-1))
        i += 2
    if(arr[i] == 18):
        print('%d   dec R%d'%(i,arr[i+1]-1))
        i += 2
    if(arr[i] == 19):
        print("%d   add R%d, %d"%(i, arr[i+1]-1, arr[i+2]))
        i += 3
    if(arr[i] == 20):
        print('%d   sub R%d, R%d'%(i, arr[i+1]-1, arr[i+2] - 1))
        i += 3
    if(arr[i] == 21):
        print('%d   xor R%d, %d'%(i, arr[i+1]-1, arr[i+2]))
        i += 3
    if(arr[i] == 22):
        print('%d   and R%d, R%d'%(i, arr[i+1]-1, arr[i+2]-1))
        i += 3
    if(arr[i] == 23):
        print('%d   or R%d, R%d'%(i, arr[i+1]-1, arr[i+2]-1))
        i += 3
    if(arr[i] == 25):
        print('%d   mov R%d, R%d'%(i, arr[i+1]-1, arr[i+2]-1))
        i += 3
    if(arr[i] == 26):
        print('%d   mov R%d, R%d'%(i, arr[i+1]-1, arr[i+2]-1))
        i += 3
    if(arr[i] == 27):
        print('%d   mov R%d, [R%d]'%(i, arr[i+1]-1, arr[i+2]-1))
        i += 3
    if(arr[i] == 28):
        print('%d   mov [R%d], R%d'%(i, arr[i+1]-1, arr[i+2]-1))
        i += 3
    if(arr[i] == 29):
        print('%d   mul R%d, %d'%(i, arr[i+1]-1, arr[i+2]))
        i += 3

运行结果如下,加上简单注释:

0  mov R0, 0
3  mov R2, 70
6  jmp 21

//获取70个字符的输入
8  push R0
10 pop R1
12 R0 = getchar()
13 push R0
15 push R1
17 pop R0
19 inc R0
   cmp R0, R2
   jnz 24
   mov a, 80
24 and a, 0x80
   test a
   jnz 8

26 mov R0, 0
29 mov R2, 71
32 jmp 70

//进行70个字符的流加密,加*为运算
34 push R0
36 mov R1, 5
39 mul R0, 4
42 sub R1, R0
45 mov R0, R1
48 mov R0, [R0]
51 mul R0, 110 *
54 add R0, 99 *
57 xor R0, 116 *
60 add R0, 102 *
63 mov [R1], R0
66 pop R0
68 inc R0
  cmp R0, R2
  jnz 73
  mov a, 80
73 and a, 0x80
  test a
  jnz 34

 可以分析得到运算为 ((a*110)+99)^116+102,最后再调用函数和数据比较,我们把比较数据dump下来然后写脚本即可。

arr = [
    0x36D3, 0x2AFF, 0x2ACB, 0x2B95, 0x2B95, 0x2B95, 0x169F, 0x186D,
    0x18D7, 0x1611, 0x18D7, 0x2B95, 0x2C23, 0x2CA9, 0x1611, 0x1611,
    0x18D7, 0x2AFF, 0x1849, 0x18FB, 0x2ACB, 0x2A71, 0x1735, 0x18D7,
    0x1611, 0x2ACB, 0x15DD, 0x18D7, 0x2C23, 0x169F, 0x15DD, 0x2B95,
    0x169F, 0x156B, 0x186D, 0x2AFF, 0x1611, 0x1611, 0x15DD, 0x2AFF,
    0x2C23, 0x2ACB, 0x15DD, 0x15DD, 0x186D, 0x1849, 0x2B95, 0x156B,
    0x1735, 0x18FB, 0x18FB, 0x2A71, 0x2AFF, 0x1735, 0x2C23, 0x15DD,
    0x18D7, 0x2A71, 0x18D7, 0x18D7, 0x2C23, 0x2AFF, 0x156B, 0x2C23,
    0x169F, 0x35AF, 0x2CA9, 0x32B5, 0x2AFF, 0x3039
]
flag = [0 for i in range(70)]
for i in range(70):
    flag[i] = int((((arr[i] - 102) ^ 116) - 99) / 110)
flag.reverse()
print(''.join(map(chr,flag)))

运行可得flag为”nctf{3e1ce77b70e4cb9941d6800aec022c813d03e70a274ba96c722fed72783dddac}“。

猜你喜欢

转载自www.cnblogs.com/Fingerprint/p/10061943.html