史vm题
ida打开main函数看到进入就是vm虚拟机

点进去发现是一个巨大的switch case循环,结构非常明显,有四个32位寄存器,其他和题目关系不大
二十多个case全部写handle去解析opcode的话难度很大,而且还要指令长度之类的问题,可以采用在指令入口点下条件断点的方式,然后动态执行整个vm,在执行指令的同时输出执行的操作,这样就可以获取vm指令的伪代码了



然后跑一遍就能拿到执行的指令了

可以看到非常长,这里我同时在指令前输出了执行前寄存器的值,同时这里的下标也是处理过的,如果直接输出寄存器的值下标会非常大,用了一个python脚本对下标做了偏移让伪代码好看点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
   | import re import sys
 
  def process_text(text):          pattern1 = r'heap\[(938\d+)\]'     matches1 = re.findall(pattern1, text)
           pattern2 = r'heap\[(1844\d+)\]'     matches2 = re.findall(pattern2, text)
           if matches1:         indices1 = [int(idx) for idx in matches1]         base1 = min(indices1)
                   for idx in sorted(set(indices1), reverse=True):               offset = idx - base1             text = text.replace(f'heap[{idx}]', f'heap_1[{offset}]')
      if matches2:         indices2 = [int(idx) for idx in matches2]         base2 = min(indices2)
                   for idx in sorted(set(indices2), reverse=True):               offset = idx - base2             text = text.replace(f'heap[{idx}]', f'heap_2[{offset}]')
      return text
 
  def main():          if len(sys.argv) > 1:         input_file = sys.argv[1]         with open(input_file, 'r') as f:             text = f.read()     else:                  text = sys.stdin.read()
      processed_text = process_text(text)
           print(processed_text)
 
  if __name__ == "__main__":     main()
 
   | 
 
然后看cmp xx 48可以看出来明显有一个循环,结合各种左右移操作,猜测是tea系列的加密,于是截取一段循环抄算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
   |                reg3 = heap_2[56];           reg3 >>= 6;          reg0 = heap_2[56];           reg0 <<= 5;          reg3 ^= reg0;           reg3 += heap_2[56];           reg2 = heap_2[64];           reg2 &= 3;          reg0 = heap_2[68];           reg2 = heap_1[0];           reg2 += heap_2[64];           reg3 ^= reg2;           reg3 += heap_2[60];           heap_2[60] = 1352750335;          reg3 = heap_2[64];           reg3 -= heap_2[32];           heap_2[64] = 2189458126;          reg0 = heap_2[60];           reg0 >>= 7;          reg2 = heap_2[60];           reg2 <<= 3;          reg0 ^= reg2;           reg0 += heap_2[60];           reg3 = heap_2[64];           reg3 >>= 11;          reg3 &= 3;          reg2 = heap_2[68];           reg3 = heap_1[12];           reg3 += heap_2[64];           reg0 ^= reg3;           reg0 += heap_2[56];           heap_2[56] = 3924216427;               reg2 = heap_2[44];           reg2 += 1;          heap_2[44] = 5;          
 
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   |  void enc(unsigned int v0, unsigned int v1, unsigned int *key) {                    unsigned int sum = 0;     unsigned int tmp_reg3 = 0, tmp_reg2 = 0, tmp_reg0 = 0;     for (int i = 0; i < 48; i++)     {         v0 += (((v1 >> 6) ^ (v1 << 5) )+ v1) ^ (key[sum & 3] + sum);         sum -= 421101834;         v1 += (((v0 >> 7) ^ (v0 << 3)) + v0) ^ (key[(sum >> 11) & 3] + sum);     } }
 
  | 
 
key 的来源是 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
   | heap_2[0] = 67;
  heap_2[1] = 104;
  heap_2[2] = 111;
  heap_2[3] = 118;
  heap_2[4] = 121;
  heap_2[5] = 95;
  heap_2[6] = 105;
  heap_2[7] = 110;
  heap_2[8] = 107;
  heap_2[9] = 101;
  heap_2[10] = 121;
  heap_2[11] = 95;
  heap_2[12] = 119;
  heap_2[13] = 51;
  heap_2[14] = 54;
  heap_2[15] = 95;
   | 
 
其中可能在整理heap时脚本出了点问题,储存key的被错误命名成了heap2,但是还是能辨别出key
于是写解密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | void dec(unsigned int *v, unsigned int *key) {     unsigned int v0 = v[0];     unsigned int v1 = v[1];     unsigned int delta = 421101834;     unsigned int sum = 0;     for (int i = 0; i < 48; i++)         sum -= delta;     for (int i = 0; i < 48; i++)     {         v1 -= (((v0 >> 7) ^ (v0 << 3)) + v0) ^ (key[(sum >> 11) & 3] + sum);         sum += delta;         v0 -= (((v1 >> 6) ^ (v1 << 5)) + v1) ^ (key[sum & 3] + sum);     }     for (int i = 0; i < 4; i++)         printf("%c", ((unsigned char *)&v0)[i]);     for (int i = 0; i < 4; i++)         printf("%c", ((unsigned char *)&v1)[i]); } int main() {     unsigned char key[] = "Chovy_inkey_w36_";     unsigned char cipher[] = "\xE5\xDF\xF0\xA1\xF4\xBD\x6A\xDB\x1B\xE9\xDD\x20\r\x9D!YгY)\xB9\xEC\x2F\xC0\"~\xAD\xE1\xB0\x15\xB6)";     for (int i = 0; i < 32; i += 8)         dec((unsigned int *)&cipher[i], (unsigned int *)key);     return 0; }
 
   | 
 
flag{D0_yOu_l1k3_VmmmmMMMMMmmm?}