2020——网鼎杯 (青龙组)signal

vm_operad

int __cdecl vm_operad(int *a1, int a2)
{
    
    
  int result; // eax@2
  char v3[100]; // [sp+13h] [bp-E5h]@4
  char v4[100]; // [sp+77h] [bp-81h]@5
  char v5; // [sp+DBh] [bp-1Dh]@5
  int v6; // [sp+DCh] [bp-1Ch]@1
  int v7; // [sp+E0h] [bp-18h]@1
  int v8; // [sp+E4h] [bp-14h]@1
  int v9; // [sp+E8h] [bp-10h]@1
  int v10; // [sp+ECh] [bp-Ch]@1

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

函数功能

利用文件字符串中保存的流程数据(以及加密数据)和控制台数据配合进行验证flag(这个文件字符串中保存的数据既起到了流程的作用还有加密作用)

read

size_t __cdecl read(char *a1)
{
    
    
  size_t result; // eax@1

  printf("string:");
  scanf("%s", a1);
  result = strlen(a1);
  if ( result != 15 )
  {
    
    
    puts("WRONG!\n");
    exit(0);
  }
  return result;
}

函数功能

这个read函数用来读取控制台输入的命令,我觉得就是flag

0A 00 00 00 04 00 00 00  10 00 00 00 08 00 00 00
03 00 00 00 05 00 00 00  01 00 00 00 04 00 00 00
20 00 00 00 08 00 00 00  05 00 00 00 03 00 00 00
01 00 00 00 03 00 00 00  02 00 00 00 08 00 00 00
0B 00 00 00 01 00 00 00  0C 00 00 00 08 00 00 00
04 00 00 00 04 00 00 00  01 00 00 00 05 00 00 00
03 00 00 00 08 00 00 00  03 00 00 00 21 00 00 00
01 00 00 00 0B 00 00 00  08 00 00 00 0B 00 00 00
01 00 00 00 04 00 00 00  09 00 00 00 08 00 00 00
03 00 00 00 20 00 00 00  01 00 00 00 02 00 00 00
51 00 00 00 08 00 00 00  04 00 00 00 24 00 00 00
01 00 00 00 0C 00 00 00  08 00 00 00 0B 00 00 00
01 00 00 00 05 00 00 00  02 00 00 00 08 00 00 00
02 00 00 00 25 00 00 00  01 00 00 00 02 00 00 00
36 00 00 00 08 00 00 00  04 00 00 00 41 00 00 00
01 00 00 00 02 00 00 00  20 00 00 00 08 00 00 00
05 00 00 00 01 00 00 00  01 00 00 00 05 00 00 00
03 00 00 00 08 00 00 00  02 00 00 00 25 00 00 00
01 00 00 00 04 00 00 00  09 00 00 00 08 00 00 00
03 00 00 00 20 00 00 00  01 00 00 00 02 00 00 00
41 00 00 00 08 00 00 00  0C 00 00 00 01 00 00 00
07 00 00 00 22 00 00 00  07 00 00 00 3F 00 00 00
07 00 00 00 34 00 00 00  07 00 00 00 32 00 00 00
07 00 00 00 72 00 00 00  07 00 00 00 33 00 00 00
07 00 00 00 18 00 00 00  07 00 00 00 A7 FF FF FF
07 00 00 00 31 00 00 00  07 00 00 00 F1 FF FF FF
07 00 00 00 28 00 00 00  07 00 00 00 84 FF FF FF
07 00 00 00 C1 FF FF FF  07 00 00 00 1E 00 00 00
07 00 00 00 7A 00 00 00

流程代码

  case 10:
        read(v3);
        ++v10;
        break;
      case 1:
        v4[v7] = v5;
        ++v10;
        ++v7;
        ++v9;
        break;
      case 2:
        v5 = a1[v10 + 1] + v3[v9];
        v10 += 2;
        break;
      case 3:
        v5 = v3[v9] - LOBYTE(a1[v10 + 1]);
        v10 += 2;
        break;
      case 4:
        v5 = a1[v10 + 1] ^ v3[v9];
        v10 += 2;
        break;
      case 5:
        v5 = a1[v10 + 1] * v3[v9];
        v10 += 2;
        break;
      case 6:
        ++v10;
        break;
      case 7:
        if ( v4[v8] != a1[v10 + 1] )
        {
    
    
          printf("what a shame...");
          exit(0);
        }
        ++v8;
        v10 += 2;
        break;
      case 11:
        v5 = v3[v9] - 1;
        ++v10;
        break;
      case 12:
        v5 = v3[v9] + 1;
        ++v10;
        break;
      case 8:
        v3[v6] = v5;
        ++v10;
        ++v6;
        break;
      default:
        continue;

简介每个数字所要做的事(但是流程不是按照这样进行的)

  1. 0x0A:读取控制台所输入的15个字符
  2. 0x4:求v5值,文件字符串下一个位置值 ^ 控制台第一个数据
  3. 0x10:continue
  4. 0x08:v5赋给v3数组的第一个元素
  5. 0x03:(v3数组的第一个元素-文件字符串下一个位置值)赋给v5
  6. 0x05:求V5值,文件字符串下一个位置值 * 控制台第一个数据
  7. 0x01:v5赋给v4数组的第一个元素,然后v9自增,也就代表接下来需要利用到控制台第二个数据
  8. 0x4:求v5值,文件字符串下一个位置值 ^ 控制台第一个数据
  9. 0x20:continue
  10. 0x08:v5赋给v3数组的第二个元素
  11. 0x05:求V5值,文件字符串下一个位置值 * 控制台第二个数据
  12. 0x03:(v3数组的第二个元素 - 文件字符串下一个位置值)赋给v5
  13. 0x01:v5赋给v4数组的第二个元素,然后v9自增,也就代表接下来需要利用到控制台第三个数据
    ……………………………………
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

注意:

文件字符串遇到2 ,3,4,5,7时,那么下一个值并不控制流程(流程直接跳过!),而是被当计算数据所用了。。所以才说执行流程并非是上面所写

验证数据(逆向重点)

07 00 00 00 22 00 00 00  07 00 00 00 3F 00 00 00
07 00 00 00 34 00 00 00  07 00 00 00 32 00 00 00
07 00 00 00 72 00 00 00  07 00 00 00 33 00 00 00
07 00 00 00 18 00 00 00  07 00 00 00 A7 FF FF FF
07 00 00 00 31 00 00 00  07 00 00 00 F1 FF FF FF
07 00 00 00 28 00 00 00  07 00 00 00 84 FF FF FF
07 00 00 00 C1 FF FF FF  07 00 00 00 1E 00 00 00
07 00 00 00 7A 00 00 00

这里全是用来验证的:
依次是 22h 3fh 34h 32h 72h 33h 18h ffffffa7h 31h fffff1h 28h ffff84h 1eh 7ah
所以按照标准字符串,然后把每个字符都逆着做一遍操作,然后就得到了我们所输在控制台的东西,紧接着就结束了。。。

逆向思维

  1. (0x22+5)^ 0x10
  2. (0x3f/3) ^ 0x20
  3. (0x34 + 1) + 2
  4. (0x32 ^ 4) - 1
  5. (0x72 + 0x21) / 3
  6. (0x33 + 1) + 1
  7. (0x18 + 0x20) ^ 9
  8. (0xa7 ^ 0x24) -0x51
  9. (0x31 + 1) - 1
  10. (0xf1 - 0x25) / 2
  11. (0x28 ^ 0x41) - 0x36
  12. (0x84 / 1) - 0x20
  13. (0xc1 - 0x25) / 3
  14. (0x1e + 0x20) ^ 9
  15. (0x7a - 1) - 0x41
flag{
    
    757515121f3d478}

猜你喜欢

转载自blog.csdn.net/CSNN2019/article/details/115314613