W32DasmDisassembled

Part1:Making a Permenant Patcher
 byHarlequin

  July 2000

 

  

Tools Used:

 
 W32DasmV 8.93
 Text/HexEditor

ResHacker-
The only Resource editor I could find which allowed me to insert the button without adding bytes to the file size.

 

 

After starting on the ReversingCourse I was doing a lot of patching of code into programs. I would write the code into W32Dasms patch window, test it copy it, and then go and insert all the bytes by hand. Pain! bigtime.

So why not add a button to W32Dasm which will automatically update the file with the patch.

Here we go..........


First add a button into the W32Dasm patch window using BRW. I am not going to tell you how to suck eggs.
Load W32Dasm into W32Dasm and locate the dialog handling routine for the patch dialog.

 

Routine: 470003h
Button Values:
Apply - 5682h
close - 5685h
clear - 5684h
copy - 5687h
remlst - 5688h
Mine - 5683h

Now we need to check to see if our button was pressed. There is no free space for this so we will have to make a hole. I decide to use the close button. Everytime you click close you are asked 'Are you sure?' (Of course I am sure I clicked dammn the thing) I decide to do away with this confidence check and insert my code here.

So.....

 

:004700F2 6681FB8556 cmp bx, 5685 -if close button
:004700F7 7575 jne 0047016E
:004700F9 C1EB10 shr ebx, 10
:004700FC 6681E3FFFF and bx, FFFF
:00470101 6683EB01 sub bx, 0001
:00470105 7360 jnb 00470167
:00470107 8B96BAEC0100 mov edx, dword ptr[esi+0001ECBA]
:0047010D 85D2 test edx, edx
:0047010F 743C je 0047014D -this jumps to the close routine

Then comes our 'Are you sure?' messagebox.

So we make sure it jumps everytime:

 
offset 6f70fh
:0047010F EB3C jmp 0047014D

Now we have made ourselves a little space (60 bytes) as the following are no longer needed:

 
offset 6f711h
:00470111 8B9EE4116F00 mov ebx, dword ptr [esi+006F11E4]
:00470117 6A00 push 00000000
:00470119 6A04 push 00000004
:0047011B 68E0534C00 push 004C53E0
:00470120 68CA534C00 push 004C53CA
:00470125 53 push ebx
:00470126 E85DF00300 Call 004AF188
:0047012B 83F807 cmp eax, 00000007
:0047012E 751D jne 0047014D
:00470130 687E560000 push 0000567E
:00470135 FFB6E4116F00 push dword ptr [esi+006F11E4]
:0047013B E80AEF0300 Call 004AF04A
:00470140 50 push eax
:00470141 E8BEEF0300 Call 004AF104
:00470146 B001 mov al, 01
:00470148 E9C9000000 jmp 00470216

So lets add a check to see if our button was pressed. At the momment if the Close button was not pressed then we jump to 0047016Eh but we want it to jump to our check in our new found space so:

 
offset 6f711h
From:
:004700F2 6681FB8556 cmp bx, 5685 -if close button
:004700F7 7575 jne 0047016E
To:
(00470111 - 004700F7) - 2 =18

:004700F2 6681FB8556 cmp bx, 5685 -if close button
:004700F7 7518 jne 00470111 -else jump to our gap
...........
:00470111 6681FB8356 cmp bx, 5683 our button
:00470116 7556 jne 0047016E if not then carry on as normal

So we have a button, now we need to make it do something useful.

The first thing I want to do is copy the patch data from the window to the clipboard so I can then use it from anywhere. There is already a function for doing this through the 'Copy' button so lets just use this little routine.

 
So this is the code from the copy button:

:004701AE 687F560000 push 0000567F
:004701B3 FFB6E4116F00 push dword ptr [esi+006F11E4]
:004701B9 6A01 push 00000001
:004701BB 56 push esi
:004701BC E81235FFFF call 004636D3
:004701C1 83C410 add esp, 00000010
:004701C4 B001 mov al, 01
:004701C6 EB4E jmp 00470216

We eventually want to do all of this but right now we are not quite ready for the last two lines. Patch the first six lines into our space after the button check. The call at :004701BC becomes:

 
E8a835ffff call 004636D3

Due to our calling it from a different offset I calculated this as follows:

 
New offset 6F726h = RVA: 470126h
So 4701BCh - 470126h = 96h
Therefore 3512h + 96h = 35a8h

Right we now have our data on the clipboard what do we want to do next?
Well we are running out of our space and we have a lot to do yet, so we need to find some more space.

The nearest free space is at offset AE8COh and this is not enough. So I have two choices here I can insert a new section of my own, (this would not really be ideal as I would like my final product to be a patch) or I will have to place the main body of my code in a dynamic link library and just load and call it from here. My other reason is that I only have W32Dasm (I rarely need Softice) installed on my machine and if you want to see a tangled nightmare try testing and debugging this from in W32Dasm. You don't know which window you are looking at half the time.
I haven't writen the Dll at this point but lets load it anyway.

Lets use the LoadLibrary API. But first of all I am going to need a data section in which to store my variables. At the begining of the data section we see the usual Borland junk so lets overwrite this and use this as our data storage.

Lets make AEA00hour data section.
At this address I hexedit in the name of my dll (no path required if the dll is placed in the same directory as W32Dasm)

Now we need to load it, first we need its RVA.

 
Our Code: AE8C0h RVA: 4AF2C0h
Our Data: AEA00h RVA: 4B0000h

My function:

:004AF2C0 60 pushad ;Save all registers
:004AF2C1 6800004B00 push 004B0000 ;Our dll name
:004AF2C6 E827F8FFFF call 004AEAF2 ;LoadLibrary
:004AF2CB 89C3 mov ebx, eax ;Save the library handle
:004AF2CD 6810004B00 push 004B0010 ;Our Function name
:004AF2D2 50 push eax ;Library handle
:004AF2D3 E8FCF7FFFF call 004AEAD4 ;GetProcAddress
:004AF2D8 85C0 test eax, eax ;If not loaded
:004AF2DA 741A je 004AF2F6 ;Leave
:004AF2DC 89F1 mov ecx, esi ;Base address
:004AF2DE 81C131016F00 add ecx, 006F0131 ;offset to File name
:004AF2E4 51 push ecx ;onto stack
:004AF2E5 89F1 mov ecx, esi ;Base address again
:004AF2E7 81C14F066400 add ecx, 0064064F ;Offset to File Dir
:004AF2ED 51 push ecx ;Onto stack
:004AF2EE FFD0 call eax ;Call our function
:004AF2F0 53 push ebx ;Library handle
:004AF2F1 E8E8F9FFFF call 004AECDE ;FreeLibrary
:004AF2F6 61 popad ;Restore all
:004AF2F7 C3 ret ;Go home (or the pub whichever you prefer)

As you can see I saved the name of my dll function at 4B0010h.

Now all we need to do is call our function from our button code so:

 
:0047012E E88DF10300 call 004AF2C0
:00470133 B001 mov al, 01 ;The two lines left over from
:00470135 E9DC000000 jmp 00470216 ;the copy function

And that's all there is to it.
Here endeth the Reverse Engineering section of this essay. We have added our button, created a check for it, added an action. We have copied our text into the clipboard for all programs to use. We have loaded our dynamic link library and our function within it. All that remains now is to write the dll.

I include at the end in order to keep all together the source for my dll.
 


My thanks go to Sepulcrum and Kaai for the inspiration.

Thanks to everybody who takes the time to write essays and/or help others.

Mail to: Harlequin


;                 Writen By Harlequin   7/2000
;
.486p
.MODEL FLAT,STDcall

include W32patch.inc

;Local Function prototypes
Patchit PROTO :DWORD, :DWORD
Convertit PROTO :DWORD, :DWORD, :DWORD

.DATA

Err db "!!Error!!",0
Errtxt db "Cannot process patch data!",0

Succ db "Success",0
Succtxt db "The file has been patched and saved as: ",0

Backslsh db "\",0
Ptch db "P",0

RVA db 0Fh DUP (?)
Pdata db 500h DUP (?)
Path db 80h DUP (?)



hinst dd 0
Clip dd 0
GClip dd 0
numb dd 0
Fhand dd 0
Glob dd 0
Readcnt dd 0
Writecnt dd 0
Realoff dd 0
temp dd 0

.CODE

EntryPoint proc DLLinst:DWORD, Reason:DWORD, Reserved1:DWORD
mov eax,1
ret
EntryPoint endp

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
; Patchit Exported function
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Patchit proc Fname:DWORD, Fdir:DWORD

pushad
invoke GetModuleHandleA, 0
mov hinst,eax

invoke OpenClipboard,hinst
invoke GetClipboardData,1 ;Get handle to clipboard in text format
mov GClip,eax
invoke GlobalLock,eax ;Get pointer to first byte
mov Clip,eax ;Save into our variable
inc eax ;Point to second byte
invoke Convertit,eax,8,ADDR RVA ;Convert string to number
test eax,eax
jne exitdll ;If there was an error then leave now
mov edx,Clip ;Point to the clipboard patch data
mov esi,offset Pdata
xor ecx,ecx
xor ebx,ebx ;Character counter
Processit:
.WHILE byte ptr[edx+ecx] != 20h ;While char is not a space
inc ecx ;ignore it
.ENDW

inc ecx ;When = space point to next

.WHILE byte ptr[edx+ecx] != 20h ;While char is not a space
mov al,byte ptr[edx+ecx] ;Add it to our Patch string
mov byte ptr[esi],al
inc ebx
inc esi
inc ecx
.ENDW

.WHILE byte ptr[edx+ecx] != 00h && byte ptr[edx+ecx] != 0Ah
inc ecx ;While not EOL and not EOF ignore it
.ENDW

.IF byte ptr[edx+ecx] != 00h && byte ptr[edx+ecx+1] != 00h
jmp Processit ;Do next line
.ENDIF

mov numb,ebx
mov byte ptr[esi],00h ;Terminate our Patch string
invoke Convertit,ADDR Pdata,ebx,ADDR Pdata;Convert string to number
test eax,eax
jne exitdll ;If there was an error then leave now
invoke GlobalUnlock,GClip ;Close the clipboard and make it
invoke CloseClipboard ;available for other apps

mov edx,offset Path ;File path
xor ecx,ecx
.WHILE ecx != 14h
mov dword ptr[edx+ 4*ecx],00000000h
inc ecx
.ENDW
invoke lstrcpyA,edx,[Fdir]
mov ecx,offset Backslsh
invoke lstrcatA,edx,ecx ;Put them together
mov ecx,offset Ptch
invoke lstrcatA,eax,ecx ;Put them together
mov ecx,dword ptr[Fname] ;File directory
invoke lstrcatA,eax,ecx ;Put them together
mov temp,eax
invoke CreateFileA,eax,GENERIC_READ,3,0,3,NORMAL,0 ;Open the file
.IF eax != 0ffffffffh
jmp exists
.ENDIF


mov edx,offset Path ;File path
xor ecx,ecx
.WHILE ecx != 14h
mov dword ptr[edx+ 4*ecx],00000000h
inc ecx
.ENDW
invoke lstrcpyA,edx,[Fdir]
mov ecx,offset Backslsh
invoke lstrcatA,edx,ecx ;Put them together
mov ecx,dword ptr[Fname] ;File directory
invoke lstrcatA,eax,ecx ;Put them together
mov temp,eax
invoke CreateFileA,eax,GENERIC_READ,3,0,3,NORMAL,0 ;Open the file
exists:
mov Fhand,eax
invoke GlobalAlloc,42h,4c4b40h ;Get some memory
invoke GlobalLock,eax ;Get the handle to it
mov Glob,eax ;Save the handle
invoke ReadFile,Fhand,Glob,4c4b3fh,ADDR Readcnt,0 ;read file into allocated memory
invoke CloseHandle,Fhand
mov esi,Glob ;Point esi to begining of file
xor eax,eax
mov eax,dword ptr[esi+3Ch] ;Read offset for PE header
add esi,eax ;Point esi to PE header
mov dx,word ptr[RVA] ;This just rearranges the RVA into the correct order
ror dx,8
shl edx,16
mov dh,byte ptr[RVA+2]
mov dl,byte ptr[RVA+3]
sub edx,[esi+34h] ;Subtract the image base from the RVA
mov bl,byte ptr[esi+6] ;Read how many sections there are
add esi,104h ;Point to Virtual offset of 1st section
Search:
test bl,bl ;Check if we have done all sections
je errorm ;If so then we cannot process
mov eax,dword ptr[esi] ;Virtual offset into eax
cmp eax,edx ;Check if > than RVA if so just do all sections then error
ja NxtSect
add eax,dword ptr[esi+4h] ;Add raw offset to Virtual offset
cmp eax,edx ;Check if RVA is in this section
ja Found
NxtSect:
add esi,28h ;If not move to next section
dec bl ;Decrement section count
jmp Search

Found:
mov eax,dword ptr[esi+8] ;Raw offset to eax
sub edx,dword ptr[esi] ;Subtract the Virtual offset
add edx,eax ;Add raw offset
mov Realoff,edx ;This is our actual offset
mov esi,Glob
add esi,Realoff
mov edi,offset Pdata
mov ecx,numb

.WHILE ecx != 0
mov al,byte ptr[edi]
mov byte ptr[esi],al
inc esi
inc edi
dec ecx
dec ecx
.ENDW



mov edx,offset Path ;File path
xor ecx,ecx
.WHILE ecx != 14h
mov dword ptr[edx+ 4*ecx],00000000h
inc ecx
.ENDW
invoke lstrcpyA,edx,[Fdir]
mov ecx,offset Backslsh
invoke lstrcatA,edx,ecx ;Put them together
mov ecx,offset Ptch
invoke lstrcatA,eax,ecx ;Put them together
mov ecx,dword ptr[Fname] ;File directory
invoke lstrcatA,eax,ecx ;Put them together
mov temp,eax


invoke CreateFileA,temp,GENERIC_WRITE,2,0,2,NORMAL,0 ;Open the file
invoke WriteFile,Fhand,Glob,[Readcnt],ADDR Writecnt,0 ;Write the patch
invoke CloseHandle,Fhand
mov edx,offset Succtxt
invoke lstrcatA,edx,offset Ptch
invoke lstrcatA,eax,[Fname]
invoke MessageBoxA,hinst,eax,ADDR Succ,0
test eax,eax
jmp exitdll

errorm:

invoke MessageBoxA,hinst,ADDR Errtxt,ADDR Err,0



exitdll:

popad
RET
Patchit Endp
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
; End Patchit exported function
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
; Convertit Local function
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Convertit proc string:DWORD, StLen:DWORD, Output:DWORD

push ecx
push edx
push ebx
mov edx,[string]
mov ebx,[Output]
xor ecx,ecx

convloop:
xor eax,eax ;Clear eax
cmp ecx,StLen ;Check if we are done
jge endcon
mov al,byte ptr[edx + ecx] ;Move char into al
.IF al <3Ah && al > 2Fh ;Convert it to number
sub al,'0'
.ELSEIF al < 47h && al > 40h
sub al,'A'
add al,0Ah
.ELSEIF al < 67h && al >60h
sub al,'a'
add al,0Ah
.ELSEIF al == ':' || al == ',' || al == '[' || al == ']'
.ELSE
jmp error
.ENDIF

shl eax,8 ;Move result into ah
inc ecx

mov al,byte ptr[edx + ecx] ;Move next char into al

.IF al <3Ah && al > 2Fh ;Convert it to number
sub al,'0'
.ELSEIF al < 47h && al > 40h
sub al,'A'
add al,0Ah
.ELSEIF al < 67h && al >60h
sub al,'a'
add al,0Ah
.ELSEIF al == 00h
.ELSE
jmp error
.ENDIF

shl al,4
shr eax,4 ;Place both results in al
mov byte ptr[ebx],al ;Store result in Output
inc ebx ;Point Output to next byte
inc ecx
jmp convloop ;Go again

error:
invoke MessageBoxA,hinst,ADDR Errtxt,ADDR Err,0
mov eax,00000001

endcon:
mov byte ptr[ebx],00h
pop ebx
pop edx
pop ecx


RET
Convertit Endp
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
; End Convertit Local function
;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

End Entrypoint