Anatomizer Decompiler Test
Program-Transformation.Org: The Program Transformation Wiki
Hello_release
From Boomerang's test/windows/hello_release.exe (I had to force the entry point):
Original source code:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
RECT rt;
GetClientRect(hWnd, &rt);
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER); # Note (1)
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Disassembly:
4011b0: 8b 0d 58 55 40 00 mov 0x405558,%ecx
4011b6: 81 ec b4 00 00 00 sub $0xb4,%esp
4011bc: 8d 44 24 50 lea 0x50(%esp),%eax
4011c0: 6a 64 push $0x64
4011c2: 50 push %eax
4011c3: 6a 6a push $0x6a
4011c5: 51 push %ecx
4011c6: ff 15 d0 40 40 00 call *0x4040d0
4011cc: 8b 8c 24 bc 00 00 00 mov 0xbc(%esp),%ecx
4011d3: 8b c1 mov %ecx,%eax
4011d5: 83 e8 02 sub $0x2,%eax
4011d8: 0f 84 14 01 00 00 je 0x4012f2
4011de: 83 e8 0d sub $0xd,%eax
4011e1: 0f 84 ab 00 00 00 je 0x401292
4011e7: 2d 02 01 00 00 sub $0x102,%eax
4011ec: 74 28 je 0x401216
4011ee: 8b 94 24 c4 00 00 00 mov 0xc4(%esp),%edx
4011f5: 8b 84 24 c0 00 00 00 mov 0xc0(%esp),%eax
4011fc: 52 push %edx
4011fd: 50 push %eax
4011fe: 51 push %ecx
4011ff: 8b 8c 24 c4 00 00 00 mov 0xc4(%esp),%ecx
401206: 51 push %ecx
401207: ff 15 98 40 40 00 call *0x404098
40120d: 81 c4 b4 00 00 00 add $0xb4,%esp
401213: c2 10 00 ret $0x10
401216: 8b 8c 24 c0 00 00 00 mov 0xc0(%esp),%ecx
40121d: 8b c1 mov %ecx,%eax
40121f: 25 ff ff 00 00 and $0xffff,%eax
401224: 83 e8 68 sub $0x68,%eax
401227: 74 41 je 0x40126a
401229: 48 dec %eax
40122a: 74 25 je 0x401251
40122c: 8b 94 24 c4 00 00 00 mov 0xc4(%esp),%edx
401233: 8b 84 24 b8 00 00 00 mov 0xb8(%esp),%eax
40123a: 52 push %edx
40123b: 51 push %ecx
40123c: 68 11 01 00 00 push $0x111
401241: 50 push %eax
401242: ff 15 98 40 40 00 call *0x404098
401248: 81 c4 b4 00 00 00 add $0xb4,%esp
40124e: c2 10 00 ret $0x10
401251: 8b 8c 24 b8 00 00 00 mov 0xb8(%esp),%ecx
401258: 51 push %ecx
401259: ff 15 9c 40 40 00 call *0x40409c
40125f: 33 c0 xor %eax,%eax
401261: 81 c4 b4 00 00 00 add $0xb4,%esp
401267: c2 10 00 ret $0x10
40126a: 8b 94 24 b8 00 00 00 mov 0xb8(%esp),%edx
401271: a1 58 55 40 00 mov 0x405558,%eax
401276: 6a 00 push $0x0
401278: 68 10 13 40 00 push $0x401310
40127d: 52 push %edx
40127e: 6a 67 push $0x67
401280: 50 push %eax
401281: ff 15 a0 40 40 00 call *0x4040a0
401287: 33 c0 xor %eax,%eax
401289: 81 c4 b4 00 00 00 add $0xb4,%esp
40128f: c2 10 00 ret $0x10
401292: 53 push %ebx
401293: 56 push %esi
401294: 8b b4 24 c0 00 00 00 mov 0xc0(%esp),%esi
40129b: 8d 4c 24 18 lea 0x18(%esp),%ecx
40129f: 57 push %edi
4012a0: 51 push %ecx
4012a1: 56 push %esi
4012a2: ff 15 a4 40 40 00 call *0x4040a4
4012a8: 8d 54 24 0c lea 0xc(%esp),%edx
4012ac: 8b d8 mov %eax,%ebx
4012ae: 52 push %edx
4012af: 56 push %esi
4012b0: ff 15 a8 40 40 00 call *0x4040a8
4012b6: 8d 44 24 0c lea 0xc(%esp),%eax
4012ba: 6a 01 push $0x1
4012bc: 50 push %eax
4012bd: 8d 7c 24 64 lea 0x64(%esp),%edi
4012c1: 83 c9 ff or $0xffffffff,%ecx
4012c4: 33 c0 xor %eax,%eax
4012c6: f2 ae repnz scas %es:(%edi),%al # Note (1)
4012c8: f7 d1 not %ecx
4012ca: 49 dec %ecx
4012cb: 51 push %ecx
4012cc: 8d 4c 24 68 lea 0x68(%esp),%ecx
4012d0: 51 push %ecx
4012d1: 53 push %ebx
4012d2: ff 15 ac 40 40 00 call *0x4040ac
4012d8: 8d 54 24 1c lea 0x1c(%esp),%edx
4012dc: 52 push %edx
4012dd: 56 push %esi
4012de: ff 15 b0 40 40 00 call *0x4040b0
4012e4: 5f pop %edi
4012e5: 5e pop %esi
4012e6: 5b pop %ebx
4012e7: 33 c0 xor %eax,%eax
4012e9: 81 c4 b4 00 00 00 add $0xb4,%esp
4012ef: c2 10 00 ret $0x10
4012f2: 6a 00 push $0x0
4012f4: ff 15 b4 40 40 00 call *0x4040b4
4012fa: 33 c0 xor %eax,%eax
4012fc: 81 c4 b4 00 00 00 add $0xb4,%esp
401302: c2 10 00 ret $0x10
Anatomizer's decompiled output:
long Main(long arg1, void arg2, long arg3, long arg4)
/* 004011B0 - 00401304
* Size : 341 ( 0x00000155 )
* Takes 16 Bytes parameters.
* Pascal calling convention.
* Have 180Byte(s) local variable(s).
*/
{
void loc1; /* ESP -180 */
void loc2; /* ESP -164 */
void loc3; /* ESP -100 */
register long loc4; /* ECX */
register long loc5; /* EAX */
register long loc6; /* ESI */
register long loc7; /* EBX */
(void) LoadStringA(var00405558, 106, &loc3, 100);
loc4 = arg2;
loc5 = loc4;
loc5 = loc5 - 2;
if (loc5 != 0) {
loc5 = loc5 - 13;
if (loc5 != 0) {
loc5 = loc5 - 258;
if (loc5 != 0) {
loc5 = DefWindowProcA(arg1, loc4, arg3, arg4);
return (loc5);
}
loc4 = arg3;
loc5 = loc4 & 0x0000FFFF;
loc5 = loc5 - 104;
if (loc5 != 0) {
loc5 = loc5 - 1;
if (loc5 != 0) {
loc5 = DefWindowProcA(arg1, 273, loc4, arg4);
return (loc5);
}
(void) DestroyWindow(arg1);
return (0);
}
else {
(void) DialogBoxParamA(var00405558, 103, arg1, &var00401310, 0);
return (0);
}
}
else {
loc6 = arg1;
loc7 = BeginPaint(loc6, &loc2);
(void) GetClientRect(loc6, &loc1);
(void) DrawTextA(loc7, &loc3, strlen(&loc3), &loc1, 1); # Note (1)
(void) EndPaint(loc6, &loc2);
return (0);
}
}
else {
(void) PostQuitMessage(0);
return (0);
}
}
Note (1): The string scan instruction at 0x4012c6 is converted cleanly into a strlen call (the third parameter to
DrawTextA); this is quite impressive.
switch_gcc.exe
The following test is from Boomerang's test/windows/switch_gcc.exe.
Original source code:
int main(int argc)
{
switch(argc)
{
case 2:
printf("Two!\n"); break;
case 3:
printf("Three!\n"); break;
case 4:
printf("Four!\n"); break;
case 5:
printf( "Five!\n"); break;
case 6:
printf( "Six!\n"); break;
case 7:
printf( "Seven!\n"); break;
default:
printf( "Other!\n"); break;
}
return 0;
}
Disassembly:
401080: 55 push %ebp
401081: 31 c0 xor %eax,%eax
401083: 89 e5 mov %esp,%ebp
401085: 83 ec 08 sub $0x8,%esp
401088: 83 e4 f0 and $0xfffffff0,%esp
40108b: 89 5d fc mov %ebx,0xfffffffc(%ebp)
40108e: 8b 5d 08 mov 0x8(%ebp),%ebx
401091: e8 aa 03 00 00 call 401440 <___chkstk>
401096: e8 35 04 00 00 call 4014d0 <___main>
40109b: 83 fb 07 cmp $0x7,%ebx
40109e: 77 40 ja 4010e0 <_main+0x60>
4010a0: ff 24 9d a8 10 40 00 jmp *0x4010a8(,%ebx,4)
4010a7: 90 nop
4010a8: e0104000 e0104000 c8104000 e9104000 f2104000 fb104000
4010c0: 04114000 0d114000
4010c8: c7 04 24 50 10 40 00 movl $0x401050,(%esp)
4010cf: 90 nop
4010d0: e8 0b 04 00 00 call 4014e0 <_puts>
4010d5: 8b 5d fc mov 0xfffffffc(%ebp),%ebx
4010d8: 31 c0 xor %eax,%eax
4010da: 89 ec mov %ebp,%esp
4010dc: 5d pop %ebp
4010dd: c3 ret
4010de: 89 f6 mov %esi,%esi
4010e0: c7 04 24 55 10 40 00 movl $0x401055,(%esp)
4010e7: eb e7 jmp 4010d0 <_main+0x50>
4010e9: c7 04 24 5c 10 40 00 movl $0x40105c,(%esp)
4010f0: eb de jmp 4010d0 <_main+0x50>
4010f2: c7 04 24 63 10 40 00 movl $0x401063,(%esp)
4010f9: eb d5 jmp 4010d0 <_main+0x50>
4010fb: c7 04 24 69 10 40 00 movl $0x401069,(%esp)
401102: eb cc jmp 4010d0 <_main+0x50>
401104: c7 04 24 6f 10 40 00 movl $0x40106f,(%esp)
40110b: eb c3 jmp 4010d0 <_main+0x50>
40110d: c7 04 24 74 10 40 00 movl $0x401074,(%esp)
401114: eb ba jmp 4010d0 <_main+0x50>
Anatomizer Decompiler decompiled output (entry point forced):
long Main()
/* 00401080 - 00401115
* Size : 150 ( 0x00000096 )
* Takes no parameters.
* Stack unresolve.
* Have 8Byte(s) local variable(s).
*/
{
void loc1; /* ESP -12 */
void loc2; /* ESP 0 */
register long loc3; /* EBP */
register long loc4; /* EBX */
register long loc5; /* ESP */
*(loc3 - 4) = loc4;
loc4 = *(loc3 + 8);
(void) proc_0002(0, loc5 & -16);
(void) Red___main();
if (loc4 <= 7) {
switch (loc4) {
case 0:
case 1:
L1:
*loc5 = &var00401055;
break;
case 2:
*loc5 = &var00401050;
break;
case 3:
*loc5 = &var0040105C;
break;
case 4:
*loc5 = &var00401063;
break;
case 5:
*loc5 = &var00401069;
break;
case 6:
*loc5 = &var0040106F;
break;
case 7:
*loc5 = &var00401074;
break;
} /* end of switch */
}
else {
goto L1;
}
(void) Red_puts();
loc4 = *(loc3 - 4);
return (0);
}
Perhaps "Stack Unresolve" results from forcing the entry point. (This is a CygWin executable; the only reference to this main function is a move indirect on the stack pointer; it is not called directly). The switch statement is handled reasonably well, apart from the default statement. The parameter to
puts is missing. No strings are resolved as a result.
Anatomizer hello world example
The above example is similar to one I found on the Anatomizer web page; both come from the MSVC C++ Wizard, and both implement the commonly used "hello world" program.
--
MikeVanEmmerik - 01 Aug 2005