2016-10-06 8 views
4

ich als Hausaufgaben haben eine FunktionReverse Engineering eine rekursive Funktion

Der Assembler Ausgang ist dies umgekehrt:

0x00000000004010c4 <+0>: sub $0x18,%rsp 
0x00000000004010c8 <+4>: lea 0xc(%rsp),%rcx 
0x00000000004010cd <+9>: lea 0x8(%rsp),%rdx 
0x00000000004010d2 <+14>: mov $0x402995,%esi 
0x00000000004010d7 <+19>: mov $0x0,%eax 
0x00000000004010dc <+24>: callq 0x400cb0 <[email protected]> 
0x00000000004010e1 <+29>: cmp $0x2,%eax 
0x00000000004010e4 <+32>: jne 0x4010ed <phase_4+41> 
0x00000000004010e6 <+34>: cmpl $0xe,0x8(%rsp) 
0x00000000004010eb <+39>: jbe 0x4010f2 <phase_4+46> 
0x00000000004010ed <+41>: callq 0x401671 <explode_bomb> 
0x00000000004010f2 <+46>: mov $0xe,%edx 
0x00000000004010f7 <+51>: mov $0x0,%esi 
0x00000000004010fc <+56>: mov 0x8(%rsp),%edi 
0x0000000000401100 <+60>: callq 0x401086 <func4> 
0x0000000000401105 <+65>: cmp $0x3,%eax 
0x0000000000401108 <+68>: jne 0x401111 <phase_4+77> 
0x000000000040110a <+70>: cmpl $0x3,0xc(%rsp) 
0x000000000040110f <+75>: je  0x401116 <phase_4+82> 
0x0000000000401111 <+77>: callq 0x401671 <explode_bomb> 
0x0000000000401116 <+82>: add $0x18,%rsp 
0x000000000040111a <+86>: retq 

Meine Lösung für diese Funktion sieht wie folgt aus: denke ich func4 3 zurückkehren sollte

int phase4(const char* read) { 
int var1, var2; 
if ((sscanf(read, "%d %d", &var1, &var2) != 2) || (var1 < 0xe)) 
    explode_bomb(); 

if (func4(var1, 0, 0xe /*14*/) != 3) 
    explode_bomb(); 

if (var2 != 3) 
    explode_bomb(); 
return 3; 
} 

func4 sieht wie folgt aus:

0x0000000000401086 <+0>: sub $0x8,%rsp 
0x000000000040108a <+4>: mov %edx,%eax 
0x000000000040108c <+6>: sub %esi,%eax 
0x000000000040108e <+8>: mov %eax,%ecx 
0x0000000000401090 <+10>: shr $0x1f,%ecx 
0x0000000000401093 <+13>: add %ecx,%eax 
0x0000000000401095 <+15>: sar %eax 
0x0000000000401097 <+17>: lea (%rax,%rsi,1),%ecx 
0x000000000040109a <+20>: cmp %edi,%ecx 
0x000000000040109c <+22>: jle 0x4010aa <func4+36> 
0x000000000040109e <+24>: lea -0x1(%rcx),%edx 
0x00000000004010a1 <+27>: callq 0x401086 <func4> 
0x00000000004010a6 <+32>: add %eax,%eax 
0x00000000004010a8 <+34>: jmp 0x4010bf <func4+57> 
0x00000000004010aa <+36>: mov $0x0,%eax 
0x00000000004010af <+41>: cmp %edi,%ecx 
0x00000000004010b1 <+43>: jge 0x4010bf <func4+57> 
0x00000000004010b3 <+45>: lea 0x1(%rcx),%esi 
0x00000000004010b6 <+48>: callq 0x401086 <func4> 
0x00000000004010bb <+53>: lea 0x1(%rax,%rax,1),%eax 
0x00000000004010bf <+57>: add $0x8,%rsp 
0x00000000004010c3 <+61>: retq 

sieht My C-Code wie folgt aus:

int func4(unsigned rsi, unsigned rdi, unsigned rdx) { 
unsigned rax = rdx; 
rax -= rsi; 
unsigned rcx = rax; 
rcx >>= (unsigned)0x1f; 
rax += rcx; 
rax >>= (signed)1; 
rcx = rax + rsi; 
if (rcx <= rdi) { 
    rax = 0; 
    if (rcx >= rdi) 
     return rax; 
    else { 
     rax = func4(rdi, rsi + 1, rdx); 
     rax = rax + rax + 1; 
    } 
} else { 
    rdx = rcx - 1; 
    rax = func4(rdi, rsi, rdx); 
    rax = rax + rax; 
} 
return rax; 
} 

Aber wenn ich die Werte von -512 bis 512 niemals versuchen, I 3 als Ergebnis erhalten; Was mache ich falsch?

EDIT:

ich die Lösung fand es wie folgt aussieht:

int func4(int32_t di, int32_t si, int32_t dx) { 
int32_t ax = dx; 
ax = ax - si; 
int32_t cx = ax; 
cx = (uint32_t)cx >> (uint32_t)0x1f; 
ax = ax + cx; 
ax = (int32_t)ax >> (int32_t)1; 
cx = ax + si; 

if (cx <= di) 
    goto first; 

dx = cx - 1; 
ax = func4(di, si, dx); 
ax = ax + ax; 
goto fin; 

first: 
    ax = 0; 
    if (cx >= di) 
     goto fin; 

si = cx + 1; 
ax = func4(di, si, dx); 
ax = ax + ax + 1; 

fin: 
    return ax; 
} 
+1

Einzelschritt sie beide in einem Debugger und finden Sie, wo sie auseinander gehen. – KevinDTimm

Antwort

4

Von einem schnellen Blick könnte das Problem hier:

rax >>= (signed)1;   // sar %eax 

Dies entspricht:

rax = rax >> (signed)1; 

Wh Ich mache eine vorzeichenlose Verschiebung (weil die Signedness des Shift-Operators vom ersten Operanden bestimmt wird, nicht vom zweiten). Anstatt also sollten Sie schreiben:

rax = (unsigned)((signed)rax >> 1); 

EDIT: ähnlich, übersetzt Sie jle und jge falsch. Diese Anweisungen führen einen vorzeichenbehafteten Vergleich durch, während Ihr entsprechender C-Code einen vorzeichenlosen Vergleich durchführt. Fix, dass auch:

if ((signed)rcx <= (signed)rdi) { 
    rax = 0; 
    if ((signed)rcx >= (signed)rdi) 
... 
0

Wie C von der Montage generieren:

die Versammlung auszuschreiben. Deklarieren Sie dann C-Variablen mit denselben Namen wie die Register und gehen Sie durch die Assembly, wobei Sie jede arithmetische oder logische Assembly-Anweisung durch eine C-Anweisung ersetzen, und jede Verzweigung mit if goto-Konstrukten. Wenn Sie Anrufe haben, müssen Sie natürlich die Anrufkonvention kennen.

Sobald das C funktionsfähig ist, machen Sie es allmählich menschenähnlicher, testen Sie sein Verhalten gegen die Baugruppe (falls vorhanden) oder das assemblyartige C (wenn Sie die Baugruppe nicht zusammenbauen können) .