网鼎杯2020 伪虚拟机wp

解题速度太慢了,导致下午开始肝ta的时候,分数不过200了。

 

终端程序,无壳,gcc编译:

网鼎杯2020 伪虚拟机wp网鼎杯2020 伪虚拟机wp

 

复制完vmtable之后进入调度算法:

1 2 3 4 5 6 7 8 9 10 int __cdecl main(int argc, const char **argv, const char **envp) {   int table2; // [esp+18h] [ebp-1D4h]     __main();   qmemcpy(&table2, byte_403040, 0x1C8u);   vm_operad(&table2, 'r');   puts("good,The answer format is:flag {}");   return 0; }

 

说是伪虚拟机,因为这个明显是仿照vm的意思自己完成switch小demo,没有寄存器也没啥调度算法:

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 76 77 78 79 80 int __cdecl vm_operad(int *table, int a2) {   int result; // eax   char input[100]; // [esp+13h] [ebp-E5h]   char v4[100]; // [esp+77h] [ebp-81h]   char v5; // [esp+DBh] [ebp-1Dh]   int v6; // [esp+DCh] [ebp-1Ch]   int v7; // [esp+E0h] [ebp-18h]   int v8; // [esp+E4h] [ebp-14h]   int v9; // [esp+E8h] [ebp-10h]   int v10; // [esp+ECh] [ebp-Ch]     v10 = 0;   v9 = 0;   v8 = 0;   v7 = 0;   v6 = 0;   while ( 1 )   {     result = v10;     if ( v10 >= a2 )       return result;     switch ( table[v10] )     {       case 1:         v4[v7] = v5;         ++v10;         ++v7;         ++v9;         break;       case 2:         v5 = table[v10 + 1] + input[v9];         v10 += 2;         break;       case 3:         v5 = input[v9] - LOBYTE(table[v10 + 1]);         v10 += 2;         break;       case 4:         v5 = table[v10 + 1] ^ input[v9];         v10 += 2;         break;       case 5:         v5 = table[v10 + 1] * input[v9];         v10 += 2;         break;       case 6:         ++v10;         break;       case 7:         if ( v4[v8] != table[v10 + 1] )         // 最终比较         {           printf("what a shame...");           exit(0);         }         ++v8;         v10 += 2;         break;       case 8:         input[v6] = v5;                         // 把之前的处理值放回到input中         ++v10;         ++v6;         break;       case 10:         read(input);                            // 先执行read函数         ++v10;         break;       case 11:         v5 = input[v9] - 1;         ++v10;         break;       case 12:         v5 = input[v9] + 1;         ++v10;         break;       default:         continue;     }   } }

 

table:

int table[] = { 0x0A, 4, 0x10, 3, 5, 1, 4, 0x20, 8, 5, 3, 1, 3, 2, 0x8, 0x0B, 1, 0x0C, 8, 4, 4, 1, 5, 3, 8, 3, 0x21, 1, 0x0B, 8, 0x0B, 1, 4, 9, 8, 3, 0x20, 1, 2, 0x51, 8, 4, 0x24, 1, 0x0C, 8, 0x0B, 1, 5, 2, 8, 2, 0x25, 1, 2, 0x36, 8, 4, 0x41, 1, 2, 0x20, 8, 5, 1, 1, 5, 3, 8, 2, 0x25, 1, 4, 9, 8, 3,

0x20, 1, 2, 0x41,

8, 0x0C, 1, 7,

0x22, 7, 0x3F, 7,

0x34, 7, 0x32, 7,

0x72, 7, 0x33, 7,

0x18, 7, 0xA7, 0xFF, 0xFF, 0xFF, 7,

0x31, 7, 0xF1, 0xFF, 0xFF,

0xFF, 7, 0x28, 7, 0x84, 0xFF,

0xFF, 0xFF, 7, 0xC1, 0xFF, 0xFF, 0xFF, 7,

0x1E, 7, 0x7A };

 

 

第一个关键地方是case 7下的比较,table[10+1]明显每次比较的时候都是一个定值,动态时候记录下来:

网鼎杯2020 伪虚拟机wp网鼎杯2020 伪虚拟机wp

断在4016E2处,动态调试记录每次eax值:

1 0x22,0x3F,0x34,0x32,0x72,0x33,0x18,0xFA7,0x31,0xF1,0x28,0xF84,0xC1,0x1E,0x7A

 

比较的关键是

网鼎杯2020 伪虚拟机wp网鼎杯2020 伪虚拟机wp

 

而v4是case 1的时候保存。

所以分析一下指令:

table[1], 的read函数就是接收用户输入,然后4, 0x10, 3, 5, 1, 这样类似的一套就是一个handler,并且计算值等于最后比较的数组。

 

所有的handler:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 10h ^ input[1]-5 = 22h (20h ^input[2])*3=3Fh input[3]-2-1=34h (input[4]+1 )^4 =32 h input[5]*3-21h=72h input[6]-1-1=33h 9^input[7]-20=18 (51h +input[8])^24h=FA7 input[9]+1-1=31h 2*input[10]+25h=F1h (36h+input[11]) ^41h =28h (20h + input[12])*1=F84h 3*input[13]+25h=C1h 9^input[14]-20h=1E h 41h + input[15] +1 =7A h

 

757515121f3d478

 

没办法,师傅们都是秒题,我只能一个一个还原。

上一篇:PDA应用在WMS仓储管理系统 实现无线扫描出入库作业


下一篇:Composer概述及其自动加载探秘