Un exécutable nous est donné. Celui-ci ne fait rien de spécial ; il affiche une boite de message disant « hello, my name is egoist », puis affiche une image BMP sans importance.
On l’ouvre avec OllyDBG. On peut voir des chaînes de caractères intéressantes, comme « congratulation », en 009B13F2.
Remontons un peu plus haut, à partir de 009B1331. Nous avons une petite routine.
009B1331 > 68 80000000 PUSH 80 ; /Count = 80 (128.); Case 1 of switch 009B1309 009B1336 . 8D85 7CFFFFFF LEA EAX,DWORD PTR SS:[EBP-84] ; | 009B133C . 50 PUSH EAX ; |Buffer 009B133D . FF35 70339B00 PUSH DWORD PTR DS:[9B3370] ; |hWnd = NULL 009B1343 . FF15 DC209B00 CALL DWORD PTR DS:[<&USER32.GetWindowTex>; \GetWindowTextA 009B1349 . 8D85 7CFFFFFF LEA EAX,DWORD PTR SS:[EBP-84] 009B134F . 50 PUSH EAX ; /Text 009B1350 . 53 PUSH EBX ; |hWnd 009B1351 . FF15 FC209B00 CALL DWORD PTR DS:[<&USER32.SetWindowTex>; \SetWindowTextA 009B1357 . B2 05 MOV DL,5 009B1359 > 2895 7CFFFFFF SUB BYTE PTR SS:[EBP-84],DL 009B135F . 80B5 7CFFFFFF >XOR BYTE PTR SS:[EBP-84],3 009B1366 . FECA DEC DL 009B1368 . 80FA 00 CMP DL,0 009B136B . 74 02 JE SHORT PE_time.009B136F 009B136D .^EB EA JMP SHORT PE_time.009B1359 009B136F > B2 04 MOV DL,4 009B1371 > 2895 7DFFFFFF SUB BYTE PTR SS:[EBP-83],DL 009B1377 . 80B5 7DFFFFFF >XOR BYTE PTR SS:[EBP-83],4 009B137E . FECA DEC DL 009B1380 . 80FA 00 CMP DL,0 009B1383 . 74 02 JE SHORT PE_time.009B1387 009B1385 .^EB EA JMP SHORT PE_time.009B1371 009B1387 > B2 03 MOV DL,3 009B1389 > 2895 7EFFFFFF SUB BYTE PTR SS:[EBP-82],DL 009B138F . 80B5 7EFFFFFF >XOR BYTE PTR SS:[EBP-82],5 009B1396 . FECA DEC DL 009B1398 . 80FA 00 CMP DL,0 009B139B . 74 02 JE SHORT PE_time.009B139F 009B139D .^EB EA JMP SHORT PE_time.009B1389 009B139F > B2 02 MOV DL,2 009B13A1 > 2895 7FFFFFFF SUB BYTE PTR SS:[EBP-81],DL 009B13A7 . 80B5 7FFFFFFF >XOR BYTE PTR SS:[EBP-81],6 009B13AE . FECA DEC DL 009B13B0 . 80FA 00 CMP DL,0 009B13B3 . 74 02 JE SHORT PE_time.009B13B7 009B13B5 .^EB EA JMP SHORT PE_time.009B13A1 009B13B7 > B9 C0219B00 MOV ECX,PE_time.009B21C0 ; ASCII "C;@R" 009B13BC . 8D85 7CFFFFFF LEA EAX,DWORD PTR SS:[EBP-84] 009B13C2 > 8A10 MOV DL,BYTE PTR DS:[EAX] 009B13C4 . 3A11 CMP DL,BYTE PTR DS:[ECX] 009B13C6 . 75 1A JNZ SHORT PE_time.009B13E2 009B13C8 . 84D2 TEST DL,DL 009B13CA . 74 12 JE SHORT PE_time.009B13DE 009B13CC . 8A50 01 MOV DL,BYTE PTR DS:[EAX+1] 009B13CF . 3A51 01 CMP DL,BYTE PTR DS:[ECX+1] 009B13D2 . 75 0E JNZ SHORT PE_time.009B13E2 009B13D4 . 83C0 02 ADD EAX,2 009B13D7 . 83C1 02 ADD ECX,2 009B13DA . 84D2 TEST DL,DL 009B13DC .^75 E4 JNZ SHORT PE_time.009B13C2 009B13DE > 33C0 XOR EAX,EAX 009B13E0 . EB 05 JMP SHORT PE_time.009B13E7 009B13E2 > 1BC0 SBB EAX,EAX 009B13E4 . 83C8 01 OR EAX,1 009B13E7 > 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL 009B13E9 . 68 C8219B00 PUSH PE_time.009B21C8 ; |Title = "ohtahacker" 009B13EE . 85C0 TEST EAX,EAX ; | 009B13F0 . 75 20 JNZ SHORT PE_time.009B1412 ; | 009B13F2 . 68 D4219B00 PUSH PE_time.009B21D4 ; |Text = "congratulation" 009B13F7 . 53 PUSH EBX ; |hOwner 009B13F8 . FF15 E4209B00 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA 009B13FE > 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4] ; Case 64 of switch 009B1309 009B1401 . 5E POP ESI 009B1402 . 33CD XOR ECX,EBP 009B1404 . 33C0 XOR EAX,EAX 009B1406 . 5B POP EBX 009B1407 . E8 1B000000 CALL PE_time.009B1427 009B140C . 8BE5 MOV ESP,EBP 009B140E . 5D POP EBP 009B140F . C2 1000 RETN 10
Le programme à l’air d’appliquer un petit algorithme sur 4 octets nuls dans la mémoire, et vérifie si le résultat est égal à « C;@R ». Il faut donc modifier ces octets afin de passer la condition. (en fait ce sera inutile car ces 4 octets représenteront le flag directement validable)
On peut retranscrire l’algorithme en pseudocode comme ceci, avec a, b, c et d les 4 octets à transformer :
n = 5 do { a = a - n a = a xor 3 n = n - 1 } while (n != 0) n = 4 do { b = b - n b = b xor 4 n = n - 1 } while (n != 0) n = 3 do { c = c - n c = c xor 5 n = n - 1 } while (n != 0) n = 2 do { d = d - n d = d xor 6 n = n - 1 } while (n != 0)
Chaque octet subit des soustractions et des XOR. Cet algorithme est facilement reversible.
Par exemple, pour le premier caractère « C », il suffit de prendre sa correspondance ASCII (67), puis de faire l’algo à l’envers :
67 ^ 3 = 64
64 + 1 = 65
65 ^ 3 = 66
66 + 2 = 68
68 ^ 3 = 71
71 + 3 = 74
74 ^ 3 = 73
73 + 4 = 77
77 ^ 3 = 78
78 + 5 = 83
On obtient donc 83, qui en ASCII, donne la lettre « S ».
En procédant comme ceci avec les 3 autres lettres, on obtient finalement « SECU », qui est le flag de validation !