Log in

View Full Version : Help with addition to a program


mint77
December 14th, 2012, 11:46
I am new here and am looking for some help.

Does someone have some code they might wish to share that searches for a string in an executable ?

I would like to add it to another program I wrote to give it the ability to change something in my data section and the code section either while it's running and save to disk or create a "clone" and patch it.

I hope that made sense.

I thought about putting markers around the area that I would want to change.

Thanks.

Kayaker
December 14th, 2012, 22:58
Why don't you google for boyer-moore or rabin-karp or similar string search algorithm and see if you can dig up a suitable code snippet, as a start?

OfMonsterAndMen
December 14th, 2012, 23:14
Hello,

This can be accomplished at run-time by suspending all the threads and mapping the image, and then searching for the string with a String Comparison function that isn't type safe,one that just uses byte pointers.There are some prerequisites to accomplishing this: ie memory protection ,offset recalculation,and researching StrCmp(byte*,byte*). But I hope that this will put you on the path to writing your own code or finding what you are searching for.

cheers

mint77
December 15th, 2012, 00:43
Quote:
[Originally Posted by Kayaker;93839]Why don't you google for boyer-moore or rabin-karp or similar string search algorithm and see if you can dig up a suitable code snippet, as a start?


I have some code snippets in assembly.

There was some things missing and I had a problem understanding the patching part of it.

I thought someone had some code so I don't reinvent the wheel.

bilbo
December 15th, 2012, 06:50
Maybe you didn't understand Kayaker's hint??????
www.google.com/#q=boyer-moore+or+rabin-karp+codeproject

"ALL KNOWLEDGE is on the Web, for free, for you to discover and enjoy!
If you don't believe it, just learn how to search!" (Fravia+)

Best regards, bilbo

mint77
December 15th, 2012, 13:12
I am sorry that this is butchered up.

My experience is limited but I am trying.

It used to not even compile.

It opens a file O.K.but there is a lot missing.

What I would like is to add a box to add the string to search for.

Code:
; Find a string in a file and replace it
;
; REPARIEREN.ASM Help from Fetten,Dave,Frank K.,Qword,TightCoderEx,Gunther,
;
INCLUDE \masm32\include\masm32rt.inc

WinMain proto WORD,WORD,WORD,WORD
Convert proto WORD,WORD

.const

MAXSTR equ 100
MAXSIZE equ 260
ButtonOpenID equ 100
ButtonPatchID equ 101
StringID equ 200
NStringID equ 201

.data

ClassName db "WinClass",0

NotEqual db "Length of strings must be equal",0
Error db "Error!",0
NoMem db "Error allocating memory",0
FilterString db "All Files",0,"*.*",0

; in other source, looks incomplete ??
;db "Executable Files",0,"*.exe",0,0

FilePath db 260 dup (0)

Caption db "Choose the file to fix :",0
AppName db "REPARIEREN",0
Done db "File fixed succesfully !",0

NoFile db "Can't find the file !",0
WrFile db "Error writing to file !",0

ofn OPENFILENAME <>

FSize dd 0
NString db 50 dup (0)
OString db 50 dup (0)
StrLenA dd 0
StrLen2 dd 0

ButtonOpen db "Open item to be fixed.",0
ButtonPatch db "Repair Item",0
EditClassName db "edit",0
ButtonClassName db "button",0
WinName db " ",0

StringBuf db MAXSTR dup (0)
NStringBuf db MAXSTR dup (0)
NotFound db "The string can not be found !",0

.data?

hwndOpen HWND ?
hwndPatch HWND ?
hwndString HWND ?
hwndNString HWND ?
hInstance HINSTANCE ?
hwndname HWND ?
hFile HANDLE ?
Numb dd ?
FPointer dd ?

.code

start:

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShowWORD

LOCAL wc:WNDCLASSEX ; create local variables on stack
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX ; fill values in members of wc
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax

invoke RegisterClassEx, addr wc ; register our window class

;invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,

; width height
invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,WS_OVERLAPPEDWINDOW or WS_VISIBLE,3,3, 400, 280,NULL,NULL,hInstance,NULL ; Create the window
mov hwnd,eax

invoke ShowWindow, hwnd,CmdShow ; show our window
invoke UpdateWindow, hwnd

.WHILE TRUE ; The MessageLoop use of register assumed to ERROR <error FIXED Friday, December 07, 2012>

invoke GetMessage, ADDR msg,NULL,0,0

.BREAK .IF (!eax)

invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg

.ENDW

mov eax,msg.wParam
ret

WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL Fpointer

.IF uMsg==WM_CREATE

; Create 2 buttons and 2 edit boxes

invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,ADDR WinName,WS_CHILD,30,15,210,20,hWnd,StringID,hInstance,NULL

; CreateWindowEx(
;
; DWORD dwExStyle, // extended window style
; LPCTSTR lpClassName, // pointer to registered class name
; LPCTSTR lpWindowName, // pointer to window name
; DWORD dwStyle, // window style
; int x, // horizontal position of window
; int y, // vertical position of window
; int nWidth, // window width
; int nHeight, // window height
; HWND hWndParent, // handle to parent or owner window
; HMENU hMenu, // handle to menu, or child-window identifier
; HINSTANCE hInstance, // handle to application instance
; LPVOID lpParam // pointer to window-creation data

mov hwndString,eax

; Window where input is made 3rd number is width
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or ES_AUTOHSCROLL,30,40,310,20,hWnd,NStringID,hInstance,NULL

mov hwndNString,eax

invoke SetFocus, hwndString
; open item
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonOpen,WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,10,70,200,20,hWnd,ButtonOpenID,hInstance,NULL

mov hwndOpen,eax
; repair window ; horiz and vertical position
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonPatch,WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,250,70,100,20,hWnd,ButtonPatchID,hInstance,NULL

mov hwndPatch,eax

.ELSEIF uMsg==WM_COMMAND

mov eax,wParam
mov edx,wParam
shr edx,16

.IF dx==BN_CLICKED

.IF ax==ButtonOpenID ; Open button clicked?

mov ofn.lStructSize,SIZEOF ofn
mov ofn.lpstrFile, OFFSET FilePath
mov ofn.lpstrFilter, OFFSET FilterString
mov ofn.nMaxFile,MAXSIZE
mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY
mov ofn.lpstrTitle, OFFSET Caption

invoke GetOpenFileName, ADDR ofn

.IF eax == TRUE

; Open file to be repaired

invoke CreateFile, ofn.lpstrFile, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL

.IF eax!=INVALID_HANDLE_VALUE

; Code does open the file properly, code looks good up to here


jmp next

place db "Open Sesamee",0

next:


mov hFile, eax
Invoke GetFileSize, hFile, NULL

mov FSize, eax ; Save FileSize
Invoke GlobalAlloc, GMEM_FIXED, FSize
mov FPointer, eax

.IF eax == NULL ; If no pointer, error message

push MB_OK OR MB_ICONINFORMATION
push OFFSET NoMem
push OFFSET Error

JMP MESSAGE

.ENDIF

Invoke ReadFile, hFile,FPointer,FSize, ADDR Numb, NULL

.ELSE ; error message if no valid handle

push MB_OK OR MB_ICONINFORMATION
push OFFSET NoFile
push OFFSET Error

jmp MESSAGE

.ENDIF

.ENDIF

.ELSEIF ax == ButtonPatchID ; See if Fix Button has been hit

Invoke GetDlgItemText,hWnd,StringID,ADDR StringBuf,MAXSTR ; Get first string
mov StrLenA, eax ; Save string length

Invoke Convert,ADDR StringBuf, ADDR OString ; Convert to bytes
; NString = 201

Invoke GetDlgItemText,hWnd,NStringID,ADDR NStringBuf,MAXSTR ;Get 2nd string

.IF eax != StrLenA ; both strings equal?

push MB_OK OR MB_ICONINFORMATION ; If not, error message
push OFFSET Error
push OFFSET NotEqual
JMP MESSAGE

.ENDIF

Invoke Convert,ADDR NStringBuf, ADDR NString ; Convert to bytes

mov edi,FPointer ;move pointer to memory to edi
mov ecx,FSize ;move Filesize to ecx
mov esi,offset OString ;set ESI to the Opcode string we search
mov al, byte ptr [esi] ;move the first byte of the string to AL

SEARCH :

repnz scasb ;repeat until ECX=0 or AL equals the value of the byte [EDI], EDI is incremented by 1 every run

cmp ecx,0 ;If ECX=0, no matching string is found

jz NOT_FOUND

FOUND_A_MATCH : ;found matching byte
push ecx ;save registers
push edi
push esi
dec edi ;EDI-1 because REPZ added 1 byte to much
mov ecx,StrLen2 ;ECX = length of the string
repz cmpsb ;repeat until the values in the memory o ;[EDI] and [ESI] are not equal, or ecx=0
cmp ecx,0 ;If ecx = 0, we have found the correct string

jz FIX

pop esi ;Restore registers for continuing search
pop edi
pop ecx
jmp SEARCH ;go on with search

FIX :

pop esi
pop edi
pop ecx
dec edi ;EDI - 1
inc ecx ;ECX + 1
mov eax,FSize

sub eax,ecx ;compute the File Offset to repair FileSize - remaining bytes (ecx) = Offset to repair

Invoke SetFilePointer, hFile, eax, NULL, FILE_BEGIN

Invoke WriteFile, hFile,offset NString, StrLen2, ADDR Numb, NULL

mov eax, Numb
.IF eax == StrLen2 ; bytes written = Bytes to write ?

push MB_OK ; If so success-message
push OFFSET AppName
push OFFSET Done

JMP MESSAGE

.ELSE

push MB_OK OR MB_ICONINFORMATION ; If not, error message
push OFFSET Error
push OFFSET WrFile

.ENDIF

NOT_FOUND :

push MB_OK OR MB_ICONINFORMATION ; If no handle, error message
push OFFSET Error
push OFFSET NotFound

MESSAGE :

push NULL
Call MessageBox

.ENDIF

.ENDIF


.ELSEIF uMsg==WM_DESTROY ; Close program

invoke CloseHandle, hFile ; Release handle
invoke GlobalFree,Fpointer ; Release memory block
invoke ExitProcess,eax ; Exit
invoke PostQuitMessage,NULL

.ELSE

invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret

WndProc endp

; This routine converts the ascii strings to their byte equivalent. eg
; string 7415FF -> 74h,15h,FFh
; Use only numbers, and uppercase letters (A,B,C,D,E,F)

; Change a string to its byte equivalent.
; Use only numbers, and uppercase letters

Convert proc LpBufferWORD,LpStringWORD

push eax
push esi
push ecx
push edx
mov esi, LpBuffer
mov edx, LpString
xor ecx, ecx

MORE :

MOV al, [esi]

.IF al > 29h

.if al&0Fh

IMUL eax, 10h

.ELSE

.IF al>64

.IF al

SUB al, 55

IMUL eax, 10h

.ENDIF

.ENDIF

.ENDIF

.ENDIF

MOV byte ptr [edx+ecx], al
INC esi
mov al, [esi]

.IF al >29h

.if al&0Fh

ADD byte ptr [edx+ecx], al

.ELSE

.IF al > 64

sub al,55

.if !ZERO?

ADD byte ptr [edx+ecx], al

.ENDIF

.ENDIF

.ENDIF

.ENDIF

.IF byte ptr [edx+ecx] != NULL

INC esi
INC ecx
JMP MORE

.ENDIF
mov StrLen2, ecx

pop edx
pop ecx
pop esi
pop eax

ret

Convert endp

end start

blabberer
December 15th, 2012, 16:43
iam not sure if i should jump in bayer-mooring you in a rabin-karpet your question in the last post seems to be way way off from your original question

if you are struggling to add an edit box refer to iczelions tut 10 for a dialog based approach to adding edit boxes

or better still stop doing what you are doing now and study iczelions tuts from 2 to about 15 before attempting to do anything else

if bayor mooring is the problem as you posted in your first question masm has a builtin support for it

just stick BMBinSearch (BayerMoore Binary Search) and you are ready to search any string in any stream

you have to implement your own file open. read .map , search unmap close exit routines


here is a sample code that searches for a given pattern in a predefined source string (oh yeah we are bayer mooring here )

Code:


.386
.model flat, stdcall
option casemap:none
include \masm32\include\masm32.inc
include \masm32\include\USER32.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\USER32.lib

.data
SourceStr db "Iczelion's tutorial no.2 instead of this string you can use file open mint77 and use the stream",0
SearchStr db "mint77",0

.code
start:
;we are suing boyer moore binary search algo available in masm32 just include masm32.inc / masm32.lib and we are go
;for string searching in this example we are searching for mint77 in the source string and display both
;source string as MsgBoxCaption and result as message box text
invoke BMBinSearch,0,ADDR SourceStr,200,ADDR SearchStr,6
add eax,OFFSET SourceStr ; result in eax is the offset where pattern was found this can be -1 if no pattern found/blah blah and crash
invoke MessageBox, 0,eax,addr SourceStr, 1
retn
end start

bilbo
December 15th, 2012, 17:07
Great answer, blabberer!

Anyway, the reasons for which mint77 code will not run are:

(1) some code is missing between "start:" and WinMain definition. Add this:
Code:

start:
invoke GetModuleHandle, NULL ; provides the instance handle
mov hInstance, eax
invoke GetCommandLine ; provides the command line address
mov CommandLine, eax
invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
invoke ExitProcess,eax ; cleanup & return to operating system

defining
Code:

CommandLine LPSTR ?

in ".data" section

(2) first edit box (the one for the string to replace) is not visible, so replace
Code:

invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,ADDR WinName,WS_CHILD,30,15,210,20,hWnd,StringID,hInstance,NULL

with
Code:

invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,ADDR WinName,WS_CHILD or WS_VISIBLE,30,15,210,20,hWnd,StringID,hInstance,NULL


(3)
Convert is buggied...
replace in both places
Code:

.if al&0Fh

with
Code:

.if (al>=30h) && (al<=39h)

and in the second place, before first occurrence of
Code:

ADD byte ptr [edx+ecx], al

do not forget
Code:

sub al, 30h ; to remove the high nibble in case of digit 0-9

and before second occurrence
Code:

sub al, 40h ; to remove the high nibble in case of letter A-F


Best regards, bilbo

mint77
December 15th, 2012, 19:12
Thanks blabberer.

Short code as well.

mint77
December 15th, 2012, 19:16
bilbo,

I have attached the .exe and source.
.
I didn't find the last code change that you suggested.

I still have some work and I attached the source and .exe.

Andy

bilbo
December 16th, 2012, 01:14
Yes, you did not apply the last two changes (SUB...)!

It seems like you did not understand the Convert way of working.

Ok Ok Ok, let see...

For every loop (between MORE: and JMP MORE) two ascii characters are taken and converted into a single byte: the first character will go in the high nibble, the second character into the second nibble (e.g "41" represented as 34 31 must be converted as one byte 0x41 into AL.

First character:
(a) if it is a digit (.if (al>=30h) && (al<=39h)) we shift it by 4 bits (IMUL eax, 10h) to bring it in the high nibble, e.g. 34 -> 340, the 3 is lost -> resulting AL will hold 4x (where x will be the result of the conversion of the second character)
(b) if it is a letter (.IF al>64) A-F = 41-46 it will be subtracted by 37 before the shift, becoming 0A-0F -> Ax-Fx after the shift (x as above)

Second character:
In order to replace the 'x' we saw above we do not shift anymore but we ADD.
(a) if it is a digit (.if (al>=30h) && (al<=39h)) we first remove the '3' in the high nibble position (SUB AL,30h) - this is the correction you didn't apply - then ADD what remains to replace the 'x' (ADD byte ptr [edx+ecx], al)
E.g. 31 -> 01 after the sub, 4x(resulted from first character conversion) -> 41 after the ADD
(b) if it is a letter 41-46 (.IF al>64) we first remove the '4' in the high nibble position (SUB AL,40h) - this is the correction you didn't apply - then ADD what remains to replace the 'x' (ADD byte ptr [edx+ecx], al)

Obviously this algorithm can be highly optimized but I think it is better to fully understand it before modifying it.

Use a debugger if you have yet some questions: Google and a debugger are your best friends.
Best regards, bilbo

mint77
December 16th, 2012, 08:57
I see the original code was using the hex value of 37h instead of 40h.

.IF al > 64
SUB AL,40h
;sub al,55 55 decimal = 37h

mint77
December 16th, 2012, 09:04
I ran my prog under Olly but I can't see anything happening in Olly because of the open windows etc.

Is there some debug code I can put in to see if it's opening up the file correctly and then what it does when I hit the repair button ?

Andy

I will put in some int 3s in the meantime.

bilbo
December 16th, 2012, 10:39
>>I see the original code was using the hex value of 37h instead of 40h.
Correct! That was a mistake of mine!
Here is the Convert code:

Code:

Convert proc LpBufferWORD,LpStringWORD

push eax
push esi
push ecx
push edx

mov esi, LpBuffer ; IN
mov edx, LpString ; OUT
xor ecx, ecx

MORE:
; code to obtain high nibble
MOV al, [esi]
.IF al > 29h
.if (al>=30h) && (al<=39h)
IMUL eax, 10h ; is a digit
.ELSE
.IF al>64 ; 41,...
.IF al
SUB al, 37h ; is a letter 41 -> 0A,...
IMUL eax, 10h
.ENDIF
.ENDIF
.ENDIF
.ENDIF
MOV byte ptr [edx+ecx], al

INC esi

; code to obtain low nibble
mov al, [esi]
.IF al >29h
.if (al>=30h) && (al<=39h)
sub al, 30h ; is a digit: 31->01
ADD byte ptr [edx+ecx], al
.ELSE
.IF al > 64
sub al, 37h ; is a letter 41 -> 0A,...
.if !ZERO?
ADD byte ptr [edx+ecx], al
.ENDIF
.ENDIF
.ENDIF
.ENDIF

; continue with next loop
.IF byte ptr [edx+ecx] != NULL
INC esi
INC ecx
JMP MORE
.ENDIF

mov StrLen2, ecx

pop edx
pop ecx
pop esi
pop eax

ret

Convert endp


>> I will put in some int 3s in the meantime.
No need to put in INT3's: you can put breakpoints or you can single-step

Best regards, bilbo

mint77
December 17th, 2012, 08:25
Thanks. Bilbo should be sufficient

do not quote the whole post without necessity

I made changes.

enclose code in code tags it makes reading easier

Code:


; Find a string in a file and replace it
;
; REPAIR.ASM Help from Fetten,Dave,Frank K.,Qword,TightCoderEx,Gunther,bilbo,blabberer,
;
INCLUDE \masm32\include\masm32rt.inc

WinMain proto WORD,WORD,WORD,WORD
Convert proto WORD,WORD

.const

MAXSTR equ 100
MAXSIZE equ 260
ButtonOpenID equ 100
ButtonPatchID equ 101
StringID equ 200
NStringID equ 201

.data

ClassName db "WinClass",0

NotEqual db "Length of strings must be equal",0
Error db "Error!",0
NoMem db "Error allocating memory",0
FilterString db "All Files",0,"*.*",0

; in other source, looks incomplete ??
;db "Executable Files",0,"*.exe",0,0

FilePath db 260 dup (0)

Caption db "Choose the file to fix :",0
AppName db "REPARIEREN",0
Done db "File fixed succesfully !",0

NoFile db "Can't find the file !",0
WrFile db "Error writing to file !",0

ofn OPENFILENAME <>

FSize dd 0
NString db 50 dup (0)
OString db 50 dup (0)
StrLenA dd 0
StrLen2 dd 0

ButtonOpen db "Open item to be fixed.",0
ButtonPatch db "Repair Item",0
EditClassName db "edit",0
ButtonClassName db "button",0
WinName db " ",0

StringBuf db MAXSTR dup (0)
NStringBuf db MAXSTR dup (0)
NotFound db "The string can not be found !",0

.data?

hwndOpen HWND ?
hwndPatch HWND ?
hwndString HWND ?
hwndNString HWND ?
hInstance HINSTANCE ?
hwndname HWND ?
hFile HANDLE ?
Numb dd ?
FPointer dd ?
CommandLine LPSTR ?

.code

start:

invoke GetModuleHandle, NULL ; provides the instance handle
mov hInstance, eax
invoke GetCommandLine ; provides the command line address
mov CommandLine, eax
invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
invoke ExitProcess,eax ; cleanup & return to operating system

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShowWORD

LOCAL wc:WNDCLASSEX ; create local variables on stack
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX ; fill values in members of wc
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax

invoke RegisterClassEx, addr wc ; register our window class

;invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,

; width height
invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,WS_OVERLAPPEDWINDOW or WS_VISIBLE,3,3, 400, 280,NULL,NULL,hInstance,NULL ; Create the window
mov hwnd,eax

invoke ShowWindow, hwnd,CmdShow ; show our window
invoke UpdateWindow, hwnd

.WHILE TRUE ; The MessageLoop use of register assumed to ERROR <error FIXED Friday, December 07, 2012>

invoke GetMessage, ADDR msg,NULL,0,0

.BREAK .IF (!eax)

invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg

.ENDW

mov eax,msg.wParam
ret

WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL Fpointer

.IF uMsg==WM_CREATE

; Create 2 buttons and 2 edit boxes

;invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,ADDR WinName,WS_CHILD,30,15,210,20,hWnd,StringID,hInstance,NULL
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,ADDR WinName,WS_CHILD or WS_VISIBLE,30,15,210,20,hWnd,StringID,hInstance,NULL

; CreateWindowEx(
;
; DWORD dwExStyle, // extended window style
; LPCTSTR lpClassName, // pointer to registered class name
; LPCTSTR lpWindowName, // pointer to window name
; DWORD dwStyle, // window style
; int x, // horizontal position of window
; int y, // vertical position of window
; int nWidth, // window width
; int nHeight, // window height
; HWND hWndParent, // handle to parent or owner window
; HMENU hMenu, // handle to menu, or child-window identifier
; HINSTANCE hInstance, // handle to application instance
; LPVOID lpParam // pointer to window-creation data

mov hwndString,eax

; Window where input is made 3rd number is width
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or ES_AUTOHSCROLL,30,40,310,20,hWnd,NStringID,hInstance,NULL

mov hwndNString,eax

invoke SetFocus, hwndString
; open item
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonOpen,WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,10,70,200,20,hWnd,ButtonOpenID,hInstance,NULL

mov hwndOpen,eax
; repair window ; horiz and vertical position
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonPatch,WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,250,70,100,20,hWnd,ButtonPatchID,hInstance,NULL

mov hwndPatch,eax

.ELSEIF uMsg==WM_COMMAND

mov eax,wParam
mov edx,wParam
shr edx,16

.IF dx==BN_CLICKED

.IF ax==ButtonOpenID ; Open button clicked?

mov ofn.lStructSize,SIZEOF ofn
mov ofn.lpstrFile, OFFSET FilePath
mov ofn.lpstrFilter, OFFSET FilterString
mov ofn.nMaxFile,MAXSIZE
mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY
mov ofn.lpstrTitle, OFFSET Caption

invoke GetOpenFileName, ADDR ofn

.IF eax == TRUE

; Open file to be repaired

invoke CreateFile, ofn.lpstrFile, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL

.IF eax!=INVALID_HANDLE_VALUE

jmp next

mark db "After CreateFile",0

next:

mov hFile, eax
Invoke GetFileSize, hFile, NULL ; program is opening file and getting size sucessfully

mov FSize, eax ; Save FileSize
Invoke GlobalAlloc, GMEM_FIXED, FSize
mov FPointer, eax

.IF eax == NULL ; If no pointer, error message

push MB_OK OR MB_ICONINFORMATION
push OFFSET NoMem
push OFFSET Error

JMP MESSAGE

.ENDIF

Invoke ReadFile, hFile,FPointer,FSize, ADDR Numb, NULL

.ELSE ; error message if no valid handle

push MB_OK OR MB_ICONINFORMATION
push OFFSET NoFile
push OFFSET Error

jmp MESSAGE

.ENDIF

.ENDIF

.ELSEIF ax == ButtonPatchID ; See if Fix Button has been hit

Invoke GetDlgItemText,hWnd,StringID,ADDR StringBuf,MAXSTR ; Get first string
mov StrLenA, eax ; Save string length

Invoke Convert,ADDR StringBuf, ADDR OString ; Convert to bytes
; NString = 201

Invoke GetDlgItemText,hWnd,NStringID,ADDR NStringBuf,MAXSTR ;Get 2nd string

.IF eax != StrLenA ; both strings equal?

push MB_OK OR MB_ICONINFORMATION ; If not, error message
push OFFSET Error
push OFFSET NotEqual
JMP MESSAGE

.ENDIF

Invoke Convert,ADDR NStringBuf, ADDR NString ; Convert to bytes

mov edi,FPointer ;move pointer to memory to edi
mov ecx,FSize ;move Filesize to ecx
mov esi,offset OString ;set ESI to the Opcode string we search
mov al, byte ptr [esi] ;move the first byte of the string to AL

SEARCH :

repnz scasb ;repeat until ECX=0 or AL equals the value of the byte [EDI], EDI is incremented by 1 every run

cmp ecx,0 ;If ECX=0, no matching string is found

jz NOT_FOUND

FOUND_A_MATCH : ;found matching byte
push ecx ;save registers
push edi
push esi
dec edi ;EDI-1 because REPZ added 1 byte to much
mov ecx,StrLen2 ;ECX = length of the string
repz cmpsb ;repeat until the values in the memory o ;[EDI] and [ESI] are not equal, or ecx=0
cmp ecx,0 ;If ecx = 0, we have found the correct string

jz FIX

pop esi ;Restore registers for continuing search
pop edi
pop ecx
jmp SEARCH ;go on with search

FIX :

pop esi
pop edi
pop ecx
dec edi ;EDI - 1
inc ecx ;ECX + 1
mov eax,FSize

sub eax,ecx ;compute the File Offset to repair FileSize - remaining bytes (ecx) = Offset to repair

Invoke SetFilePointer, hFile, eax, NULL, FILE_BEGIN

Invoke WriteFile, hFile,offset NString, StrLen2, ADDR Numb, NULL

mov eax, Numb
.IF eax == StrLen2 ; bytes written = Bytes to write ?

push MB_OK ; If so success-message
push OFFSET AppName
push OFFSET Done

JMP MESSAGE

.ELSE

push MB_OK OR MB_ICONINFORMATION ; If not, error message
push OFFSET Error
push OFFSET WrFile

.ENDIF

NOT_FOUND :

push MB_OK OR MB_ICONINFORMATION ; If no handle, error message
push OFFSET Error
push OFFSET NotFound

MESSAGE :

push NULL
Call MessageBox

.ENDIF

.ENDIF

.ELSEIF uMsg==WM_DESTROY ; Close program

invoke CloseHandle, hFile ; Release handle
invoke GlobalFree,Fpointer ; Release memory block
invoke ExitProcess,eax ; Exit
invoke PostQuitMessage,NULL

.ELSE

invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret

WndProc endp

; This routine converts the ascii strings to their byte equivalent. eg
; string 7415FF -> 74h,15h,FFh
; Use only numbers, and uppercase letters (A,B,C,D,E,F)

; Change a string to its byte equivalent.
; Use only numbers, and uppercase letters

; For every loop (between MORE: and JMP MORE) two ascii characters are taken and converted into a single byte: the first character will go in the high
; nibble, the second character into the second nibble (e.g "41" represented as 34 31 must be converted as one byte 0x41 into AL.
;
; First character:
; (a) if it is a digit (.if (al>=30h) && (al<=39h)) we shift it by 4 bits (IMUL eax, 10h) to bring it in the high nibble, e.g. 34 -> 340,
; the 3 is lost -> resulting AL will hold 4x (where x will be the result of the conversion of the second character)
; (b) if it is a letter (.IF al>64) A-F = 41-46 it will be subtracted by 37 before the shift, becoming 0A-0F -> Ax-Fx after the shift (x as above)
;
; Second character:
; In order to replace the 'x' we saw above we do not shift anymore but we ADD.
; (a) if it is a digit (.if (al>=30h) && (al<=39h)) we first remove the '3' in the high nibble position (SUB AL,30h) - this is the correction you
; didn't apply - then ADD what remains to replace the 'x' (ADD byte ptr [edx+ecx], al)
; E.g. 31 -> 01 after the sub, 4x(resulted from first character conversion) -> 41 after the ADD
; (b) if it is a letter 41-46 (.IF al>64) we first remove the '4' in the high nibble position (SUB AL,40h) - this is the correction you didn't apply
; - then ADD what remains to replace the 'x' (ADD byte ptr [edx+ecx], al)
;
; Obviously this algorithm can be highly optimized but I think it is better to fully understand it before modifying it.

Convert proc LpBufferWORD,LpStringWORD

push eax
push esi
push ecx
push edx

mov esi, LpBuffer ; IN
mov edx, LpString ; OUT
xor ecx, ecx

MORE:
; code to obtain high nibble
MOV al, [esi]
.IF al > 29h
.if (al>=30h) && (al<=39h)
IMUL eax, 10h ; is a digit
.ELSE
.IF al>64 ; 41,...
.IF al
SUB al, 37h ; is a letter 41 -> 0A,...
IMUL eax, 10h
.ENDIF
.ENDIF
.ENDIF
.ENDIF
MOV byte ptr [edx+ecx], al

INC esi

; code to obtain low nibble
mov al, [esi]
.IF al >29h
.if (al>=30h) && (al<=39h)
sub al, 30h ; is a digit: 31->01
ADD byte ptr [edx+ecx], al
.ELSE
.IF al > 64
sub al, 37h ; is a letter 41 -> 0A,...
.if !ZERO?
ADD byte ptr [edx+ecx], al
.ENDIF
.ENDIF
.ENDIF
.ENDIF

; continue with next loop
.IF byte ptr [edx+ecx] != NULL
INC esi
INC ecx
JMP MORE
.ENDIF

mov StrLen2, ecx

pop edx
pop ecx
pop esi
pop eax

ret

Convert endp
end start



what is your question do you have one ?

mint77
December 18th, 2012, 09:15
Sorry I forgot to enclose my code in tags.

Thanks for everyone's help and patience. I am learning a lot so I can do more coding by myself.

My code needs some additions.

Right now it opens the file fine and stores it's file size ok.

I need it to :

1. prompt for a string to search for ( I can add error checking myself)
2. Prompt for a string to replace it
3. And write it to disk (as it does now.)

Thanks.

blabberer
December 18th, 2012, 19:02
well from a reversing point of view assembly is a must and to learn assembly coding a few apps in assembly is required
but once you get a bit of hang i would suggest you to drop coding .if eax = 123 .elseif blah and switch to a higher level language
and in higher level languages too dont go for win32 gui and crap
code console apps till you can express yourself fluently

a few lines is all it takes in c to open a file , prompt for a search string , prompt for a replacement string , write the replacement string close and exit


Code:


#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
FILE *infile;
char somestr[20];
fopen_s(&infile,argv[1],"rb+"; // opens a file in binary mode for editing file name is given as first argument from a console
do
{
do
{
fgets(somestr,2,infile); // reads each character from the file
}while( (_strnicmp(somestr,argv[2],1) != 0) && ( feof(infile) == 0)); // compares it to the first letter in search str or end of file
if( (feof(infile) !=0))
{
return 0; // if end of file exit without changing the file
}
fseek(infile,-1,SEEK_CUR);
fgets(somestr,strlen(argv[2])+1,infile); // reads the string at match and
}while( (_strnicmp(somestr,argv[2],strlen(argv[2])) != 0) && ( feof(infile) == 0) ); // does a full word comparison
fseek(infile,~(strlen(argv[2])-1),SEEK_CUR);
fputs(argv[3],infile); if match with search str replacement string is put in place
fclose(infile); // close file
return 1; // exit
}



compile and run this like

foo.exe c:\blah\.....\meow.exe cat dog

meow.exe is the file to open cat is search str dog is replacement string

lets check

Code:



mint77:\>fc f:\masm32\icztutes\tute02\msgbox.exe "f:\masm32\icztutes\tute02\Copy
of msgbox.exe"
Comparing files F:\MASM32\ICZTUTES\TUTE02\msgbox.exe and F:\MASM32\ICZTUTES\TUTE
02\COPY OF MSGBOX.EXE
FC: no differences encountered


mint77:\>edit.exe f:\masm32\icztutes\tute02\msgbox.exe win32 c++

mint77:\>fc f:\masm32\icztutes\tute02\msgbox.exe "f:\masm32\icztutes\tute02\Copy
of msgbox.exe"
Comparing files F:\MASM32\ICZTUTES\TUTE02\msgbox.exe and F:\MASM32\ICZTUTES\TUTE
02\COPY OF MSGBOX.EXE
00000819: 63 c 57 W
0000081A: 2B + 69 i
0000081B: 2B + 6E n



mint77
December 18th, 2012, 19:17

do not quote full posts without any necessity use reply to thread do not use reply with quote
if using reply with quote quote only the necessary lines and not the full post


I appreciate your help.

I like assembly, even if it's harder.

I like the ability to make programs smaller and faster.
I have seen C code producing .exes that are 10 times larger than an equivalent assembly program.

blabberer
December 18th, 2012, 19:45
with compilers aggressive optimization
with processors speed and
with availability of memory
there doesn't exist a scenario where hand assembly is required in generic coding

as far as size is concerned with a bit of careful usage of compiler and linker switches
you can make the output of equal size and actually performing better than some ill thought
out hand assembly (look for asotirov / gil dabah tiny pe projects or rather maximus on code breaker journal)

assembly has its uses and coding a generic file editor / patcher is absolutely not one of them
unless you are into it for the pain and perspiration

Kayaker
December 19th, 2012, 00:30
Don't worry, the assembly worship will fade over time. I'd wager a majority of reversers felt the same way, started the same way. Certainly, learn to program in ASM - console, GUI, even drivers, it will only do you good. But at some point you'll realize that coding in assembly simply to save microcycles and bytes has little practical value other than for idealistic fun. What, still executing programs from the A: drive?

Ultimately, trying to learn to code efficiently (c'mon, tighten up that loop) in a high level language (and I don't mean VB or Delphi, shudder) is a much more practical way to spend your time.