2020——网鼎杯 (青龙组)signal
发布日期:2021-05-07 12:08:46 浏览次数:29 分类:原创文章

本文共 5318 字,大约阅读时间需要 17 分钟。

文章目录

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 0003 00 00 00 05 00 00 00  01 00 00 00 04 00 00 0020 00 00 00 08 00 00 00  05 00 00 00 03 00 00 0001 00 00 00 03 00 00 00  02 00 00 00 08 00 00 000B 00 00 00 01 00 00 00  0C 00 00 00 08 00 00 0004 00 00 00 04 00 00 00  01 00 00 00 05 00 00 0003 00 00 00 08 00 00 00  03 00 00 00 21 00 00 0001 00 00 00 0B 00 00 00  08 00 00 00 0B 00 00 0001 00 00 00 04 00 00 00  09 00 00 00 08 00 00 0003 00 00 00 20 00 00 00  01 00 00 00 02 00 00 0051 00 00 00 08 00 00 00  04 00 00 00 24 00 00 0001 00 00 00 0C 00 00 00  08 00 00 00 0B 00 00 0001 00 00 00 05 00 00 00  02 00 00 00 08 00 00 0002 00 00 00 25 00 00 00  01 00 00 00 02 00 00 0036 00 00 00 08 00 00 00  04 00 00 00 41 00 00 0001 00 00 00 02 00 00 00  20 00 00 00 08 00 00 0005 00 00 00 01 00 00 00  01 00 00 00 05 00 00 0003 00 00 00 08 00 00 00  02 00 00 00 25 00 00 0001 00 00 00 04 00 00 00  09 00 00 00 08 00 00 0003 00 00 00 20 00 00 00  01 00 00 00 02 00 00 0041 00 00 00 08 00 00 00  0C 00 00 00 01 00 00 0007 00 00 00 22 00 00 00  07 00 00 00 3F 00 00 0007 00 00 00 34 00 00 00  07 00 00 00 32 00 00 0007 00 00 00 72 00 00 00  07 00 00 00 33 00 00 0007 00 00 00 18 00 00 00  07 00 00 00 A7 FF FF FF07 00 00 00 31 00 00 00  07 00 00 00 F1 FF FF FF07 00 00 00 28 00 00 00  07 00 00 00 84 FF FF FF07 00 00 00 C1 FF FF FF  07 00 00 00 1E 00 00 0007 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 0007 00 00 00 34 00 00 00  07 00 00 00 32 00 00 0007 00 00 00 72 00 00 00  07 00 00 00 33 00 00 0007 00 00 00 18 00 00 00  07 00 00 00 A7 FF FF FF07 00 00 00 31 00 00 00  07 00 00 00 F1 FF FF FF07 00 00 00 28 00 00 00  07 00 00 00 84 FF FF FF07 00 00 00 C1 FF FF FF  07 00 00 00 1E 00 00 0007 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}
上一篇:2020——网鼎杯 (青龙组)jocker
下一篇:物理机Windows系统下使用SSH连接虚拟机Ubuntu

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2025年04月09日 16时51分52秒