Masm Code Generation Tutorial Source Code Rebuilding Using PVDasm Example: COMCTL.EXE \masm32\ICZTUTES\TUTE18\ Compileable Result load comctl.exe into pvdasm, and be sure the default, options are set and disassemble the file. we should see something like that:
..Snip.. ; ===========[ Program Entry Point ]=========== 00401000 6A00 PUSH 00H ; lpModuleName 00401002 E8 E3020000 CALL KERNEL32!GetModuleHandleA 00401007 A3 4C304000 MOV DWORD PTR DS:[0040304CH], EAX 0040100C 6A0A PUSH 0AH 0040100E 6A00 PUSH 00H 00401010 6A00 PUSH 00H 00401012 FF354C304000 PUSH DWORD PTR DS:[0040304CH] 00401018 E8 0B000000 CALL 00401028 0040101D 50 PUSH EAX ; uExitCode 0040101E E8 C1020000 CALL KERNEL32!ExitProcess 00401023 E8 68020000 CALL COMCTL32!Ordinal: 17 ; ===========[ Subroutine ]=========== 00401028 55 PUSH EBP 00401029 8BEC MOV EBP, ESP 0040102B 83C4B0 ADD ESP, -50H 0040102E C745D0 30000000 MOV DWORD PTR SS:[EBP-30H],00000030H 00401035 C745D4 03000000 MOV DWORD PTR SS:[EBP-2CH],00000003H 0040103C C745D8 FD104000 MOV DWORD PTR SS:[EBP-28H],004010FDH 00401043 C745DC 00000000 MOV DWORD PTR SS:[EBP-24H],00000000H 0040104A C745E0 00000000 MOV DWORD PTR SS:[EBP-20H],00000000H 00401051 FF7508 PUSH DWORD PTR SS:[EBP+08H] 00401054 8F45E4 POP DWORD PTR SS:[EBP-1CH] 00401057 C745F0 0C000000 MOV DWORD PTR SS:[EBP-10H],0000000CH 0040105E C745F4 00000000 MOV DWORD PTR SS:[EBP-0CH],00000000H 00401065 C745F8 00304000 MOV DWORD PTR SS:[EBP-08H],00403000H 0040106C 68 007F0000 PUSH 00007F00H ; lpIconName 00401071 6A00 PUSH 00H ; hInstance 00401073 E8 42020000 CALL USER32!LoadIconA ..Snip.. nothing fancy i know .. :) let see what Functions EntryPoint, the Simple FirstPass analyzer has Marked: press Ctrl+Alt+E to show the FEP Manager. we see 2 functions Marked, although if we browes the file, we can cleary see that there is another function/subroutine unmarked. lets select the range of addresses, to convert to FEP (Function EntryPoint), or from the FEP manager to enter the start/end address of the function, i'll use the marking approach, so lets mark address: 004010FE 8BEC MOV EBP, ESP and scroll till (while selecting lines): 00401286 C2 1000 RET 0010H and press Alt+Insert . output window will show us this message: Address Range 004010FE : 00401286 Transformed, to Function EntryPoint. you can see it added in the FEP Manager [Alt+Ctrl+E] now, to make some visual changes, lets ReDisassemble: Alt+R and there is it: ..Snip.. ; ===========[ Subroutine ]=========== 004010FE 8BEC MOV EBP, ESP 00401100 837D0C01 CMP DWORD PTR SS:[EBP+0CH],01H 00401104 0F85 95000000 JNZ 0040119F 0040110A 6A00 PUSH 00H ; lpParam 0040110C FF354C304000 PUSH DWORD PTR DS:[0040304CH] ..Snip.. ok, there are only 3 functions.. no more, lets now build the Source. PVDasm comes with a small and easy, to use Source Builder Wizard for MASM Output. Creating Source File: ===================== File->Produce->Masm Project... 1. Setting up Path(s) ================== we need here to setup the output filename (*.asm) and the MASM patch, (e.g: c:) when done, clicking Next for next Window. 2. Setting up Intialized Variables =============================== Mostly here the intialized strings will be created, no other globals will be defined by pvdasm. in this dialog we are presented with the name of the string, and the string preview it self. i have restricted the var name to 25 chars, and includes only A-Z/a-z characters as a filter. 1. to Redefine an var, simply dbl-click it's name, and it will be loaded to the EditBox. e,g: msctls_progress___ changing it to: msctls_progress and click the Redefine button. 2. we can also Delete duplicated strings, select your string and hit Delete Button. click Next 3. Setting up the Functions: ========================= here on the 'Select Range' combobox we are presented with the Function ranges that we and the FirstPass analyzer has marked. usually i think hand-marking is better than automatic feature. to define the functions, we must MOVe from the top->down as we see, from the dropdown comboBox, creating in that order will give us the same order on the output asm!!. [The EntryPoint Subroutine] selecting range:00401000 :: 0040101E Corresponding Assembly Function Block, will be shown alongside the remarks. if this function is your entry point, Delete the 2 auto defined proto/proc text and create an empty skeleton. or press the Empty Button to automaticlly delete the proc info. messgaebox will tell us the function has an empry skeleton. [The Subroutines] now lets select the next Range: 00401028 :: 004010FA the code will be showen to us. notice the the main pvdasm is still selectable, so we can scroll and still use the disassembler in the background. since this range is not an entrypoint startup code, we need or not, to create parameters for the function. 1.lets goto address 00401028 in the pvdasm, (using goto option, or just scroll), selecing the address will tell us that the address has an XReference to it. right-click -> XReferences -> dbl-click the adress, and we jump back to the caller. we will see this: 0040100C 6A0A PUSH 0AH 0040100E 6A00 PUSH 00H 00401010 6A00 PUSH 00H 00401012 FF354C304000 PUSH DWORD PTR DS:[0040304CH] 00401018 E8 0B000000 CALL 00401028 this function requires 4 parameters to be sent on the stack. so, select the params you want to be declaire, from the drop down combobox. usually i use DWORD, but its ur call, to change what ever you want, or use a custom param and add. 2. we can use the Auto Search feature, here to search for us the number of parameters, that he function needs, once clicked and found, it will automatically define the subroutine for us. default param type is DWORD. all we need to do is to press Create button to define the Function. note: no remove button for now, manual edit your editbox and click Create to make changes. selecting the last Function range from the list: 004010FD :: 00401286 trying to find an xref for 004010FD won't work, since there is no call to this address using any branch instruction located in the code section, rather, this function is being reffered by a memory access. see this code snippet: ..Snip.. 00401028 55 PUSH EBP 00401029 8BEC MOV EBP, ESP 0040102B 83C4B0 ADD ESP, -50H 0040102E C745D0 30000000 MOV DWORD PTR SS:[EBP-30H],00000030H 00401035 C745D4 03000000 MOV DWORD PTR SS:[EBP-2CH],00000003H 0040103C C745D8 FD104000 MOV DWORD PTR SS:[EBP-28H],004010FDH 00401043 C745DC 00000000 MOV DWORD PTR SS:[EBP-24H],00000000H 0040104A C745E0 00000000 MOV DWORD PTR SS:[EBP-20H],00000000H ..Snip.. well, if we check several Win32ASM sources, we might see that this code reffers to the WNDCLASSEXA struct using the RegisterClass api, so this function is the actuall Event Handler Function, you may know it as the 'WndProc' function where we handle the 'WM_INITDIALOG / WM_PAINT' messages...etc ok, we got it.. this function also require 4 params (hwnd/msg/wparam/lparam). same thing as above, i added 4 DWORDS to the skeleton of the function and defined it. Click Next to continue. The MASM Compiler Options: ========================== this is a nice little dialog where we can change the most used options for the compiler. (MASM32) such as the machine type, entrypoint name, calling convertion type, adding directives..etc click next and see final result of the assembly file. you can always go back and change your settings. now since PVDasm created for us most of the stuff, we need to make hand modifications, untill i will add some stuff to ease this process. what do we need to change: 1. add the defined strings to our code insted of PUSH xxxxxxxx, change into PUSH offset_myString 2. when need, add 'offset proc_xxxxxxxx', into some code parts [example: WndProc caller]. lets see created code by PVDasm:
; # This File is generated by Proview Disassembler (PVDasm) # ; # Copyright (c) 2005 by Bengaly. <pvdasm.anticrack.de> # .386 ; create 32 bit code .model flat, stdcall ; 32 bit memory model option casemap:none ; case sensitive include C:\masm32\include\windows.inc include C:\masm32\include\kernel32.inc include C:\masm32\include\user32.inc include C:\masm32\include\gdi32.inc include C:\masm32\include\comctl32.inc include C:\masm32\include\shell32.inc include C:\masm32\include\comdlg32.inc includelib C:\masm32\lib\user32.lib includelib C:\masm32\lib\kernel32.lib includelib C:\masm32\lib\gdi32.lib includelib C:\masm32\lib\comctl32.lib includelib C:\masm32\lib\shell32.lib includelib C:\masm32\lib\comdlg32.lib ; ######################## proc_00401028 proto :DWORD,:DWORD,:DWORD,:DWORD proc_004010FD proto :DWORD,:DWORD,:DWORD,:DWORD .data CommonControlWinClass db "CommonControlWinClass",0 Common_Control_Demo_ db "Common Control Demo",0 msctls_progress db "msctls_progress32",0 Finished db "Finished!",0 .data? .code start: PUSH 00H ; lpModuleName CALL GetModuleHandleA MOV DWORD PTR DS:[0040304CH], EAX PUSH 0AH PUSH 00H PUSH 00H PUSH DWORD PTR DS:[0040304CH] CALL proc_00401028 PUSH EAX ; uExitCode CALL ExitProcess proc_00401028 proc Var1:DWORD,Var2:DWORD,Var3:DWORD,Var4:DWORD ADD ESP, -50H MOV DWORD PTR SS:[EBP-30H],00000030H MOV DWORD PTR SS:[EBP-2CH],00000003H MOV DWORD PTR SS:[EBP-28H],004010FDH MOV DWORD PTR SS:[EBP-24H],00000000H MOV DWORD PTR SS:[EBP-20H],00000000H PUSH DWORD PTR SS:[EBP+08H] POP DWORD PTR SS:[EBP-1CH] MOV DWORD PTR SS:[EBP-10H],0000000CH MOV DWORD PTR SS:[EBP-0CH],00000000H MOV DWORD PTR SS:[EBP-08H],00403000H PUSH 00007F00H ; lpIconName PUSH 00H ; hInstance CALL LoadIconA MOV DWORD PTR SS:[EBP-18H],EAX MOV DWORD PTR SS:[EBP-04H],EAX PUSH 00007F00H ; lpCursorName PUSH 00H ; hInstance CALL LoadCursorA MOV DWORD PTR SS:[EBP-14H],EAX LEA EAX,DWORD PTR SS:[EBP-30H] PUSH EAX ; pcWndClassEx CALL RegisterClassExA PUSH 00H ; lpParam PUSH DWORD PTR SS:[EBP+08H] ; hInstance PUSH 00H ; hMenu PUSH 00H ; hWndParent PUSH 80000000H ; nHeight PUSH 80000000H ; nWidth PUSH 80000000H ; y PUSH 80000000H ; x PUSH 10CB0000H ; dwStyle PUSH 00403016H ; lpWindowName PUSH 00403000H ; lpClassName PUSH 00000200H ; dwExStyle CALL CreateWindowExA MOV DWORD PTR SS:[EBP-50H],EAX ref_004010CF: PUSH 00H PUSH 00H ; wMsgFilterMax PUSH 00H ; wMsgFilterMin LEA EAX,DWORD PTR SS:[EBP-4CH] ; hwnd PUSH EAX ; lpMsg CALL GetMessageA OR EAX, EAX JZ ref_004010F6 LEA EAX,DWORD PTR SS:[EBP-4CH] PUSH EAX ; lpMsg CALL TranslateMessage LEA EAX,DWORD PTR SS:[EBP-4CH] PUSH EAX ; lpMsg CALL DispatchMessageA JMP ref_004010CF ref_004010F6: MOV EAX,DWORD PTR SS:[EBP-44H] RET ; proc_00401028 endp proc_00401028 endp proc_004010FD proc Var1:DWORD,Var2:DWORD,Var3:DWORD,Var4:DWORD CMP DWORD PTR SS:[EBP+0CH],01H JNZ ref_0040119F PUSH 00H ; lpParam PUSH DWORD PTR DS:[0040304CH] ; hInstance PUSH 01H ; hMenu PUSH DWORD PTR SS:[EBP+08H] ; hWndParent PUSH 14H ; nHeight PUSH 0000012CH ; nWidth PUSH 000000C8H ; y PUSH 64H ; x PUSH 50000000H ; dwStyle PUSH 00H ; lpWindowName PUSH 0040302AH ; lpClassName PUSH 00H ; dwExStyle CALL CreateWindowExA MOV DWORD PTR DS:[00403050H], EAX MOV EAX, 000003E8H MOV DWORD PTR DS:[00403058H], EAX SHL EAX, 10H PUSH EAX ; lParam PUSH 00H ; wParam PUSH 00000401H ; wMsg PUSH DWORD PTR DS:[00403050H] ; hwnd CALL SendMessageA PUSH 00H ; lParam PUSH 0AH ; wParam PUSH 00000404H ; wMsg PUSH DWORD PTR DS:[00403050H] ; hwnd CALL SendMessageA PUSH 02H PUSH DWORD PTR SS:[EBP+08H] PUSH 00H PUSH 50000000H CALL Ordinal: 6 MOV DWORD PTR DS:[00403054H], EAX PUSH 00H ; lpTimerFunc PUSH 64H ; uElapse PUSH 03H ; nIDEvent PUSH DWORD PTR SS:[EBP+08H] ; hWnd CALL SetTimer MOV DWORD PTR DS:[00403046H], EAX JMP ref_00401283 ref_0040119F: CMP DWORD PTR SS:[EBP+0CH],02H JNZ ref_004011CC PUSH 00H ; nExitCode CALL PostQuitMessage CMP DWORD PTR DS:[00403046H],00H JZ ref_00401283 PUSH DWORD PTR DS:[00403046H] ; nIDEvent PUSH DWORD PTR SS:[EBP+08H] ; hwnd CALL KillTimer JMP ref_00401283 ref_004011CC: CMP DWORD PTR SS:[EBP+0CH],00000113H JNZ ref_0040126E PUSH 00H ; lParam PUSH 00H ; wParam PUSH 00000405H ; wMsg PUSH DWORD PTR DS:[00403050H] ; hwnd CALL SendMessageA SUB DWORD PTR DS:[00403058H],0AH CMP DWORD PTR DS:[00403058H],00H JNZ ref_00401283 PUSH DWORD PTR DS:[00403046H] ; nIDEvent PUSH DWORD PTR SS:[EBP+08H] ; hwnd CALL KillTimer MOV DWORD PTR DS:[00403046H],00000000H PUSH 0040303CH ; lParam [ ;ASCIIZ: "Finished!",0 ] PUSH 00H ; wParam PUSH 00000401H ; wMsg PUSH DWORD PTR DS:[00403054H] ; hwnd CALL SendMessageA PUSH 40H ; wType PUSH 00403016H ; lpCaption PUSH 0040303CH ; lpText PUSH DWORD PTR SS:[EBP+08H] ; hwnd CALL MessageBoxA PUSH 00H ; lParam PUSH 00H ; wParam PUSH 00000401H ; wMsg PUSH DWORD PTR DS:[00403054H] ; hwnd CALL SendMessageA PUSH 00H ; lParam PUSH 00H ; wParam PUSH 00000402H ; wMsg PUSH DWORD PTR DS:[00403050H] ; hwnd CALL SendMessageA JMP ref_00401283 ref_0040126E: PUSH DWORD PTR SS:[EBP+14H] ; lParam PUSH DWORD PTR SS:[EBP+10H] ; wParam PUSH DWORD PTR SS:[EBP+0CH] ; wMsg PUSH DWORD PTR SS:[EBP+08H] ; hwnd CALL DefWindowProcA RET ref_00401283: XOR EAX, EAX RET ; proc_004010FD endp proc_004010FD endp end start Hand Modfications - full compilble Source:
; # This File is generated by Proview Disassembler (PVDasm) # ; # Copyright (c) 2005 by Bengaly. <pvdasm.anticrack.de> # .386 ; create 32 bit code .model flat, stdcall ; 32 bit memory model option casemap:none ; case sensitive include C:\masm32\include\windows.inc include C:\masm32\include\kernel32.inc include C:\masm32\include\user32.inc include C:\masm32\include\gdi32.inc include C:\masm32\include\comctl32.inc include C:\masm32\include\shell32.inc include C:\masm32\include\comdlg32.inc includelib C:\masm32\lib\user32.lib includelib C:\masm32\lib\kernel32.lib includelib C:\masm32\lib\gdi32.lib includelib C:\masm32\lib\comctl32.lib includelib C:\masm32\lib\shell32.lib includelib C:\masm32\lib\comdlg32.lib ; ########################## proc_004010FD proto :DWORD,:DWORD,:DWORD,:DWORD proc_00401028 proto :DWORD,:DWORD,:DWORD,:DWORD .data CommonControlWinClass db "CommonControlWinClass",0 Common_Control_Demo db "Common Control Demo",0 msctls_progress db "msctls_progress32",0 Finished db "Finished!",0 .data? hInstance dd ? g_hwnd dd ? g_param dd ? g_param2 dd ? g_param3 dd ? g_param4 dd ? .code start: PUSH 00H ; lpModuleName CALL GetModuleHandleA MOV hInstance , EAX ; changed PUSH 0AH PUSH 00H PUSH 00H PUSH hInstance ; changed CALL proc_00401028 ; changed PUSH EAX ; uExitCode CALL ExitProcess proc_00401028 proc Var1:DWORD,Var2:DWORD,Var3:DWORD,Var4:DWORD PUSH EBP MOV EBP, ESP ADD ESP, -50H MOV DWORD PTR SS:[EBP-30H],00000030H MOV DWORD PTR SS:[EBP-2CH],00000003H MOV DWORD PTR SS:[EBP-28H],offset proc_004010FD ; changed MOV DWORD PTR SS:[EBP-24H],00000000H MOV DWORD PTR SS:[EBP-20H],00000000H PUSH DWORD PTR SS:[EBP+08H] POP DWORD PTR SS:[EBP-1CH] MOV DWORD PTR SS:[EBP-10H],0000000CH MOV DWORD PTR SS:[EBP-0CH],00000000H MOV DWORD PTR SS:[EBP-08H],offset CommonControlWinClass PUSH 00007F00H ; lpIconName PUSH 00H ; hInstance CALL LoadIconA MOV DWORD PTR SS:[EBP-18H],EAX MOV DWORD PTR SS:[EBP-04H],EAX PUSH 00007F00H ; lpCursorName PUSH 00H ; hInstance CALL LoadCursorA MOV DWORD PTR SS:[EBP-14H],EAX LEA EAX,DWORD PTR SS:[EBP-30H] PUSH EAX ; pcWndClassEx CALL RegisterClassExA PUSH 00H ; lpParam PUSH DWORD PTR SS:[EBP+08H] ; hInstance PUSH 00H ; hMenu PUSH 00H ; hWndParent PUSH 80000000H ; nHeight PUSH 80000000H ; nWidth PUSH 80000000H ; y PUSH 80000000H ; x PUSH 10CB0000H ; dwStyle PUSH offset Common_Control_Demo ; lpWindowName - changed PUSH offset CommonControlWinClass ; lpClassName - changed PUSH 00000200H ; dwExStyle CALL CreateWindowExA MOV DWORD PTR SS:[EBP-50H],EAX ref_004010CF: PUSH 00H PUSH 00H ; wMsgFilterMax PUSH 00H ; wMsgFilterMin LEA EAX,DWORD PTR SS:[EBP-4CH] ; hwnd PUSH EAX ; lpMsg CALL GetMessageA OR EAX, EAX JZ ref_004010F6 ; changed LEA EAX,DWORD PTR SS:[EBP-4CH] PUSH EAX ; lpMsg CALL TranslateMessage LEA EAX,DWORD PTR SS:[EBP-4CH] PUSH EAX ; lpMsg CALL DispatchMessageA JMP ref_004010CF ; changed ref_004010F6: MOV EAX,DWORD PTR SS:[EBP-44H] ;LEAVE ;Releases the local variables - ; changed RET ; changed proc_00401028 endp ; this is our WndProc proc_004010FD proc Var1:DWORD,Var2:DWORD,Var3:DWORD,Var4:DWORD ;PUSH EBP ; masm creates stack frame ;MOV EBP, ESP ; for us, so no need to make twice CMP DWORD PTR SS:[EBP+0CH],01H JNZ ref_0040119F ; changed PUSH 00H ; lpParam PUSH hInstance ; hInstance - changed PUSH 01H ; hMenu PUSH DWORD PTR SS:[EBP+08H] ; hWndParent PUSH 14H ; nHeight PUSH 0000012CH ; nWidth PUSH 000000C8H ; y PUSH 64H ; x PUSH 50000000H ; dwStyle PUSH 00H ; lpWindowName PUSH offset msctls_progress ; lpClassName - changed PUSH 00H ; dwExStyle CALL CreateWindowExA MOV g_hwnd, EAX ; changed MOV EAX, 000003E8H MOV g_param, EAX ; changed SHL EAX, 10H PUSH EAX ; lParam PUSH 00H ; wParam PUSH 00000401H ; wMsg PUSH g_hwnd ; hwnd - changed CALL SendMessageA PUSH 00H ; lParam PUSH 0AH ; wParam PUSH 00000404H ; wMsg PUSH g_hwnd ; hwnd - changed CALL SendMessageA PUSH 02H PUSH DWORD PTR SS:[EBP+08H] PUSH 00H PUSH 50000000H CALL CreateStatusWindow ; Added MOV g_param4, EAX PUSH 00H ; lpTimerFunc PUSH 64H ; uElapse PUSH 03H ; nIDEvent PUSH DWORD PTR SS:[EBP+08H] ; hWnd CALL SetTimer MOV g_param3, EAX JMP ref_00401283 ; changed ref_0040119F: CMP DWORD PTR SS:[EBP+0CH],02H JNZ ref_004011CC PUSH 00H ; nExitCode CALL PostQuitMessage CMP g_param3,00H JZ ref_00401283 ; changed PUSH g_param3 ; nIDEvent PUSH DWORD PTR SS:[EBP+08H] ; hwnd CALL KillTimer JMP ref_00401283 ; changed ref_004011CC: CMP DWORD PTR SS:[EBP+0CH],00000113H JNZ ref_0040126E ; changed PUSH 00H ; lParam PUSH 00H ; wParam PUSH 00000405H ; wMsg PUSH g_hwnd ; hwnd CALL SendMessageA SUB g_param,0AH CMP g_param,00H JNZ ref_00401283 ; changed PUSH g_param3 ; nIDEvent PUSH DWORD PTR SS:[EBP+08H] ; hwnd CALL KillTimer MOV g_param3,00000000H PUSH offset Finished ; lParam [ ;ASCIIZ: "Finished!",0 ] PUSH 00H ; wParam PUSH 00000401H ; wMsg PUSH g_param4 ; hwnd CALL SendMessageA PUSH 40H ; wType PUSH offset Common_Control_Demo ; lpCaption PUSH offset Finished ; lpText [ ;ASCIIZ: "Finished!",0 ] PUSH DWORD PTR SS:[EBP+08H] ; hwnd CALL MessageBoxA PUSH 00H ; lParam PUSH 00H ; wParam PUSH 00000401H ; wMsg PUSH g_param4 ; hwnd CALL SendMessageA PUSH 00H ; lParam PUSH 00H ; wParam PUSH 00000402H ; wMsg PUSH g_hwnd ; hwnd CALL SendMessageA JMP ref_00401283 ; changed ref_0040126E: PUSH DWORD PTR SS:[EBP+14H] ; lParam PUSH DWORD PTR SS:[EBP+10H] ; wParam PUSH DWORD PTR SS:[EBP+0CH] ; wMsg PUSH DWORD PTR SS:[EBP+08H] ; hwnd CALL DefWindowProcA ;LEAVE ;Releases the local variables RET ; changed ref_00401283: XOR EAX, EAX ;LEAVE ;Releases the local variables RET ; changed proc_004010FD endp end start