Binary Bomb
-
Hallo :). Ich habe die Aufgabe eine binäre Bombe zu entschärfen. Dabei gibt es verschiedene Phasen, ich bin jetzt bei Phase 5. Lieder komme ich jetzt nicht weiter. Hier erstmal der Assembler Code.
08048efb <phase_5>: 8048efb: 55 push %ebp 8048efc: 89 e5 mov %esp,%ebp 8048efe: 56 push %esi 8048eff: 53 push %ebx 8048f00: 83 ec 20 sub $0x20,%esp 8048f03: 8d 45 f0 lea -0x10(%ebp),%eax 8048f06: 89 44 24 0c mov %eax,0xc(%esp) 8048f0a: 8d 45 f4 lea -0xc(%ebp),%eax 8048f0d: 89 44 24 08 mov %eax,0x8(%esp) 8048f11: c7 44 24 04 e4 a6 04 movl $0x804a6e4,0x4(%esp) 8048f18: 08 8048f19: 8b 45 08 mov 0x8(%ebp),%eax 8048f1c: 89 04 24 mov %eax,(%esp) 8048f1f: e8 8c f9 ff ff call 80488b0 <__isoc99_sscanf@plt> 8048f24: 83 f8 01 cmp $0x1,%eax 8048f27: 7f 05 jg 8048f2e <phase_5+0x33> 8048f29: e8 d3 06 00 00 call 8049601 <explode_bomb> 8048f2e: 8b 45 f4 mov -0xc(%ebp),%eax 8048f31: 83 e0 0f and $0xf,%eax 8048f34: 89 45 f4 mov %eax,-0xc(%ebp) 8048f37: 83 f8 0f cmp $0xf,%eax 8048f3a: 74 29 je 8048f65 <phase_5+0x6a> 8048f3c: b9 00 00 00 00 mov $0x0,%ecx 8048f41: ba 00 00 00 00 mov $0x0,%edx 8048f46: bb c0 a5 04 08 mov $0x804a5c0,%ebx 8048f4b: 83 c2 01 add $0x1,%edx 8048f4e: 8b 04 83 mov (%ebx,%eax,4),%eax 8048f51: 01 c1 add %eax,%ecx 8048f53: 83 f8 0f cmp $0xf,%eax 8048f56: 75 f3 jne 8048f4b <phase_5+0x50> 8048f58: 89 45 f4 mov %eax,-0xc(%ebp) 8048f5b: 83 fa 0f cmp $0xf,%edx 8048f5e: 75 05 jne 8048f65 <phase_5+0x6a> 8048f60: 39 4d f0 cmp %ecx,-0x10(%ebp) 8048f63: 74 05 je 8048f6a <phase_5+0x6f> 8048f65: e8 97 06 00 00 call 8049601 <explode_bomb> 8048f6a: 83 c4 20 add $0x20,%esp 8048f6d: 5b pop %ebx 8048f6e: 5e pop %esi 8048f6f: 5d pop %ebp 8048f70: c3 ret
So, was ich bis jetzt herausgefunden habe ist, dass an Adresse 8048f11 mit "movl $0x804a6e4,0x4(%esp)" das Format der Eingabe an sscanf übergeben wird. Mit "x/s 0x804a6e4" habe ich mir der Format anzeigen lassen "%d %d", das heißt man muss 2 Integers eingeben. Es wird an 8048f24 und 8048f27 überprüft, ob die eingabe > 1 ist.
Was jetzt glaube ich ziemlich wichtig ist, ist 8048f31. Dort wird eax mit 0xf geundet. 0xf ist in binärer Schreibweise 1111.
Nach dem and-Befehl wird dann in 8048f37 geschaut, ob eax 15 ist. Wenn ja, springt es zu explode_bomb. edx ist danach der Zähler einer Schleife und wird am Anfang von jedem Durchlauf um 1 erhöht. In 8048f53 wird nochmal überprüft ob eax 15 ist, wenn ja geht es zum Anfang der Schleife. Falls nicht, wird edx mit 15 in 8048f5b verglichen. Solange dies nicht der Fall ist, springt man zum Anfang der Schleife zurück. Dh es wird max 15 Schleifendurchgänge geben.
Wenn die Schleife erfolgreich durchgelaufen ist, wird in 8048f60 %ecx mit -0x10(%ebp) vergleichen. Wenn ecx gleich ist, hat man das richtige Ergebnis gefunden, falls nicht explodiert die Bombe.
Das ist glaube ich alles, was ich zur Zeit habe. Danke schonmal für Eure Hilfe !!
-
Wie wäre es mit einem Syntax, der für Menschen gemacht ist und nicht für eine back end Assembler?
-
Naja ich habe nur die ausführbare Datei der Bombe bekommen und keinen c-Code. Deswegen kann ich nur den Assembler Code posten, den mir objdump ausgespuckt hat. Ich hoffe ich habe dich richtig verstanden :D.
-
einfach die Option -M intel benutzen - dann ist die ganze Sache besser lesbar, macht Sinn und passt auch zur Dokumentation von Intel und AMD.
-
Alles klar. Danke schonmal für den Tipp :). Hier ist die Ausgabe:
08048efb <phase_5>: 8048efb: 55 push ebp 8048efc: 89 e5 mov ebp,esp 8048efe: 56 push esi 8048eff: 53 push ebx 8048f00: 83 ec 20 sub esp,0x20 8048f03: 8d 45 f0 lea eax,[ebp-16] 8048f06: 89 44 24 0c mov DWORD PTR [esp+12],eax 8048f0a: 8d 45 f4 lea eax,[ebp-12] 8048f0d: 89 44 24 08 mov DWORD PTR [esp+8],eax 8048f11: c7 44 24 04 e4 a6 04 mov DWORD PTR [esp+4],0x804a6e4 8048f18: 08 8048f19: 8b 45 08 mov eax,DWORD PTR [ebp+8] 8048f1c: 89 04 24 mov DWORD PTR [esp],eax 8048f1f: e8 8c f9 ff ff call 80488b0 <__isoc99_sscanf@plt> 8048f24: 83 f8 01 cmp eax,0x1 8048f27: 7f 05 jg 8048f2e <phase_5+0x33> 8048f29: e8 d3 06 00 00 call 8049601 <explode_bomb> 8048f2e: 8b 45 f4 mov eax,DWORD PTR [ebp-12] 8048f31: 83 e0 0f and eax,0xf 8048f34: 89 45 f4 mov DWORD PTR [ebp-12],eax 8048f37: 83 f8 0f cmp eax,0xf 8048f3a: 74 29 je 8048f65 <phase_5+0x6a> 8048f3c: b9 00 00 00 00 mov ecx,0x0 8048f41: ba 00 00 00 00 mov edx,0x0 8048f46: bb c0 a5 04 08 mov ebx,0x804a5c0 8048f4b: 83 c2 01 add edx,0x1 8048f4e: 8b 04 83 mov eax,DWORD PTR [ebx+eax*4] 8048f51: 01 c1 add ecx,eax 8048f53: 83 f8 0f cmp eax,0xf 8048f56: 75 f3 jne 8048f4b <phase_5+0x50> 8048f58: 89 45 f4 mov DWORD PTR [ebp-12],eax 8048f5b: 83 fa 0f cmp edx,0xf 8048f5e: 75 05 jne 8048f65 <phase_5+0x6a> 8048f60: 39 4d f0 cmp DWORD PTR [ebp-16],ecx 8048f63: 74 05 je 8048f6a <phase_5+0x6f> 8048f65: e8 97 06 00 00 call 8049601 <explode_bomb> 8048f6a: 83 c4 20 add esp,0x20 8048f6d: 5b pop ebx 8048f6e: 5e pop esi 8048f6f: 5d pop ebp 8048f70: c3 ret
-
Warum ist das jetzt besser lesbar? Die AT&T Syntax ist genauso gut lesbar, das ist reine Gewohnheitssache.
-
Mechanics schrieb:
Warum ist das jetzt besser lesbar? Die AT&T Syntax ist genauso gut lesbar, das ist reine Gewohnheitssache.
Das vielleicht schon, aber --demangle wird
__isoc99_sscanf@plt
effektiv besser lesbar
Nur dem Verständnis hilfts wenig.
-
Falls es helfen würde, könnte ich auch das komplette Programm hochladen...
-
Soweit ich das sehen kann, häng alles von dem Inhalt eines Arrays ab:
int n = sscanf(func_arg1,"%d %d",&local1,&local2); if (n <= 1) explode; local1 = local1 & 15; int i,k; for (i=0,k=0; local1 != 15; i++) { local1 = int_array[local1]; k = k + local1; } if(i != 15 || k != local2) explode; return local1;
Die erste Zahl muss auf jeden Fall kleiner als 15 sein.
-
Nur wie kann ich auf das Array zugreifen und den Inhalt auslesen?
Außerdem, sehe ich das richtig, dass bei 8048f11 Informationen über das Eingabeformat für sscanf stehen sollten?
-
Die Adresse ist in EBX: 0x804a5c0
-
Hier ist nochmal eine decompilierte Version:
int result; // eax@3
int v2; // edx@4
int v3; // ecx@4
int v4; // [sp+18h] [bp-10h]@1
int v5; // [sp+1Ch] [bp-Ch]@1if ( __isoc99_sscanf(a1, "%d %d", &v5, &v4) <= 1 )
explode_bomb();
result = v5 & 0xF;
v5 = result;
if ( result == 15 )
goto LABEL_11;
v3 = 0;
v2 = 0;
do
{
++v2;
result = *(_DWORD *)&array_3459[4 * result];
v3 += result;
}
while ( result != 15 );
v5 = 15;
if ( v2 != 15 || v4 != v3 )
LABEL_11:
explode_bomb();
return result;
}
-
Wenn ich mir mit "x/16c 0x804a5c0" den Inhalt ausgeben lasse, kommt
0x804a5c0 <array.3459>: 10 '\n' 0 '\000' 0 '\000' 0 '\000'
2 '\002' 0 '\000' 0 '\000' 0 '\000'
0x804a5c8 <array.3459+8>: 14 '\016' 0 '\000' 0 '\000'
0 '\000' 7 '\a' 0 '\000' 0 '\000' 0 '\000'raus... Soll das das Array sein? Danke nochmal für deine Zeit und Hilfe
-
Hier ist die Datei, falls es weiterhilft: http://filebin.ca/jaby5lrl4bo/bomb
die passwörter bis Phase_5 kann ich dann postenOkay hier sind sie:
The future will be better tomorrow.
0 1 3 6 10 15
1 v 899
162 3
-
Die Start-Adresse auf das Array liegt bei 0x804a5c0, EBX wird damit belegt:
mov ebx,0x804a5c0
EAX enthält den Index des Array Elements. Da dieser mit 4, also sizeof(DWORD), multipliziert wird, handelt es sich um ein DWORD-Array, das DWORD wird ja auch nach EAX kopiert, mittels DWORD PTR[].
add edx,0x1 mov eax,DWORD PTR [ebx+eax*4]
-
Hallo squay,
ich weiß zwar nicht, was die Funktion eigentlich bezwecken soll, da ich den gesamten Kontext nicht kenne. Aber dennoch habe ich das Disassembly mal kommentiert und eine mögliche C-Implementation geschrieben. Aufgrund des oben genannten Problems habe ich mich beim C Code sehr nah an das Disassembly Listing gehalten. Ich hoffe, dass es dir weiterhilft.
Ich gehe mal davon aus, dass du verhindern willst, dass explode_bomb() aufgerufen wird. Wenn du dir die Funktion ansiehst, dann wirst du bemerken, dass es da letzten Endes doch auf den Wert eines spezifischen Array Elements ankommt (wie es mir scheint).
08048efb <phase_5>: ; Stack frame of phase_5: ; function typedef: DWORD __cdecl phase_5(char* pszStringToScan) ; Segment: ; EBP+0x08: pszStringToScan ; EBP+0x04: Return address ; EBP+0x00: Old EBP value ; EBP-0x04: ESI backup ; EBP-0x08: EBX backup ; ... ; EBP-0x12: First sscanf format list argument ; EBP-0x16: Second sscanf format list argument 8048efb: 55 push ebp ; Backup old EBP value to use as stack pointer 8048efc: 89 e5 mov ebp,esp ; Copy value from ESP to EBP. EBP stack frame pointer setup done 8048efe: 56 push esi ; Backup ESI to use it 8048eff: 53 push ebx ; Backup EBX to use it 8048f00: 83 ec 20 sub esp,0x20 ;Subtract 0x20 bytes from ESP to allocate stack memory 8048f03: 8d 45 f0 lea eax,[ebp-16] ; Load expression ebp-0x16 to EAX. It's the pointer to the second format list arg for sscanf 8048f06: 89 44 24 0c mov DWORD PTR [esp+12],eax ; Copy value from EAX to [ESP+0x12]. At ESP+0x12 is the fourth function arg 8048f0a: 8d 45 f4 lea eax,[ebp-12] ; Load expression EBP-0x12 to EAX. It's the pointer to the first format list arg for sscanf 8048f0d: 89 44 24 08 mov DWORD PTR [esp+8],eax ; Copy value from EAX to [ESP+0x08]. At ESP+0x08 is the third function arg 8048f11: c7 44 24 04 e4 a6 04 mov DWORD PTR [esp+4],0x804a6e4 ; Copy constant VA value to [ESP+0x04]. At ESP+0x04 is the second function arg 8048f19: 8b 45 08 mov eax,DWORD PTR [ebp+8] ; Copy value at [EBP+0x08] (argument of phase_5()) to EAX. The string which shall be scanned is passed to phase_5() function 8048f1c: 89 04 24 mov DWORD PTR [esp],eax ; Copy value from EAX to [ESP]. At ESP is the first function arg 8048f1f: e8 8c f9 ff ff call 80488b0 <__isoc99_sscanf@plt> ; Call sscanf function (cdecl) 8048f24: 83 f8 01 cmp eax,0x1 ; Perform comparition with EAX and 0x01 8048f27: 7f 05 jg 8048f2e <phase_5+0x33> ; If EAX is greater then jump to address 8048f29: e8 d3 06 00 00 call 8049601 <explode_bomb> ; Else call explode_bomb(). So we don't want to get to this place 8048f2e: 8b 45 f4 mov eax,DWORD PTR [ebp-12] ; Copy DWORD at [EBP-12] (first format list arg) to EAX 8048f31: 83 e0 0f and eax,0xf ; Perform AND operation with EAX and 0x0F 8048f34: 89 45 f4 mov DWORD PTR [ebp-12],eax ; Copy new value back to the stack var 8048f37: 83 f8 0f cmp eax,0xf ; Perform comparision with EAX and 0x0F 8048f3a: 74 29 je 8048f65 <phase_5+0x6a> ; If both are equal jump to the address. That shall not happen. 8048f3c: b9 00 00 00 00 mov ecx,0x0 ; Initialize ECX with 0x00000000 by copying 8048f41: ba 00 00 00 00 mov edx,0x0 ; Initialize EDX with 0x00000000 by copying 8048f46: bb c0 a5 04 08 mov ebx,0x804a5c0 ; Copy VA constant to EBX. It is the base address of a DWORD array ;Begin loop 8048f4b: 83 c2 01 add edx,0x1 ; Add 0x01 to EDX 8048f4e: 8b 04 83 mov eax,DWORD PTR [ebx+eax*4] ; Copy the DWORD at EBX+EAX*4 to EAX. Get index offset by EAX*4 8048f51: 01 c1 add ecx,eax ; Add EAX to ECX 8048f53: 83 f8 0f cmp eax,0xf ; Perform comparison with EAX and 0x0F. To end this loop EAX must have the value 0x0F at its lowest byte 8048f56: 75 f3 jne 8048f4b <phase_5+0x50> ; If both are not equal jump to loop begin. ; End loop 8048f58: 89 45 f4 mov DWORD PTR [ebp-12],eax ; Copy EAX back to the stack var 8048f5b: 83 fa 0f cmp edx,0xf ; Compare EDX with 0x0F 8048f5e: 75 05 jne 8048f65 <phase_5+0x6a> ; If not equal jump to the fail part. So, basically, EDX must have the value 0x0F at its lowest byte to avoid explode_bomb() call 8048f60: 39 4d f0 cmp DWORD PTR [ebp-16],ecx ; Compare DWORD at [EBP-0x016] with ECX 8048f63: 74 05 je 8048f6a <phase_5+0x6f> ; If both are equal jump to the success part! 8048f65: e8 97 06 00 00 call 8049601 <explode_bomb> ; Call explode_bomb() function. So we don't want to get to this place from 8048f3a and 8048f5e 8048f6a: 83 c4 20 add esp,0x20 ; Remove the allocated stack memory by adding 8048f6d: 5b pop ebx ; Restore EBX 8048f6e: 5e pop esi ; Restore ESI 8048f6f: 5d pop ebp ; Restore old EBP 8048f70: c3 ret ; Restore return address // Possible C implementation DWORD __cdecl phase_5_8048efb(char* pszStringToScan) { static unsigned int uia804a5c0[...] = {...}; DWORD dwEBP12; DWORD dwEBP16; if (sscanf(pszStringToScan, "%d %d", &dwEBP12, &dwEBP16) <= 0x01) explode_bomb(); DWORD dwEAX = dwEBP12 & 0x0F; dwEBP12 = dwEAX; if (dwEAX == 0x0F) explode_bomb(); DWORD dwECX, dwEDX; dwECX = dwEDX = 0; while (dwEAX != 0x0F) { dwEAX = *(DWORD*)((DWORD)uia804a5c0 + dwEAX * 4); //uia804a5c0[dwEAX]; dwECX += dwEAX; dwEDX++; } dwEBP12 = dwEAX; if ((dwEDX != 0x0F) || (dwECX != dwEBP16)) explode_bomb(); return dwEAX; } //Conclusion: If you want the function phase_5() to succeed then the values of the //important registers need the following values (context beginning at 8048f3c till the end): //EAX==0x0F && EDX!=0x0F && ECX!=dwEBP16 //Since ECX and EDX get changed inside the loop it all depends on the array element value at a certain position
Ich kann natürlich auch was falsch interpretiert haben, bin gerade nicht so konzentriert...
Gruß