網鼎杯2020 偽虛擬機wp


解題速度太慢了,導致下午開始肝ta的時候,分數不過200了。

 

終端程序,無殼,gcc編譯:

 

復制完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]明顯每次比較的時候都是一個定值,動態時候記錄下來:

斷在4016E2處,動態調試記錄每次eax值:

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

 

比較的關鍵是

 

而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

 

沒辦法,師傅們都是秒題,我只能一個一個還原。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM