Aprire File e Cercare Byte
From UIC
Modifica di Aprire File e Cercare Byte
Contents |
| Infos | |
|---|---|
| Author: | Masta |
| Email: | |
| Website: | |
| Date: | 07/04/2007 (dd/mm/yyyy) |
| Level: |
|
| Language: | English |
| Comments: | |
Introduzione
After the part 0 I got some mail saying that it was a good idea to do a windows-based revival of the "old art" of assembly language programming. We all know that DOS is about to die (not many (if any) of us are happy about that), but unfortunately we can't change this fact.
Tools
- a texteditor
- TASM 5.0, complete with libs, etc.
- Win32-API-Reference (Win32.hlp)
Notizie sul programma
We want to code a "generic patcher" which is also known as a "Search-and-Destroy-Patcher". Since many people may not know what to expect from a Generic-Patcher,I want to explain it shortly. It is a patcher, which is not only able to patch a certain version of a program, but future versions also, if they are nearly the same. This is done by searching for a certain byte-pattern (and writing a new one) and not by patching some offset, which makes this kind more universal to use. Since most likely the protection-scheme is not changed by the coder,this bytes of this routine may have another offset-address in the newer (older) version, but the bytes will be the same. That's the trick =).
Essay
OK, first we think about the main structure of our program, then we think about which functions we use and last but not least, we write the program.
- Intro - Little intro, presented in a MessageBox
- Open File - Set file-handle. If file not exist -> MessageBox
- Get Filesize
- Allocate memory - Allocate memory equal to the filesize.
If error -> MessageBox - Read File - copy complete file into allocated memory
- Search Bytes - Determination of the offset of the bytepattern.
If errors -> MessageBox - Set Filepointer to offset
- Overwrite File - Patch of the file. Success -> MessageBox with new bytes
- Close File - Cleanup!
Deallocate Mem
Quit
- All messages will be presented by a messagebox, i.e. 'MessageBoxA'.
- For opening the file we will use the CreateFileA-function, which is more complex than the OpenFile, but also more flexible to use.
- To close we will use CloseHandle.
- The filesize we get via GetFileSize
- We allocate the mem with the help of GlobalAlloc; set it free again with GlobalFree
- Logically we read the file with ReadFile and write it with WriteFile
- The Filepointer can be set with SetFilePointer
- To quit we use ExitProcess
This is the heart of our patcher. With the help of this little routine the target-file is searched for a byte pattern, which will be changed later. I will just explain it shortly, because the most you can get out of the code. OK, we first load the size of the file (the alloc. memory) into ECX to set a value for the "REPNZ"-command; also the first byte of the search- pattern is written into AL and ESI is set to the address of the original values. With 'REPNZ SCASB' the value of AL is compared to the value of the memory address, which EDI points to (EDI is incremented by 1). The 'REPNZ'-command repeats the following 'SCASB' as long as either ECX=0 or the compared values are equal (FL Z=1). If the values are equal ECX is loaded with the length of the patch, EDI is ecremented by 1, because the 'SCASB' already counted one byte ahead. The following 'REPZ CMPSB' repeats 'CMPSB' (compares the address of [ESI] with the one of [EDI]) as long as either ECX=0 or the value differs.
Now quickly some stuff about the patch routine itself.
First the offset is calculated by incrementing ECX (byte-counter) by 1
and this value we subtract from the total filesize:
- (FILESIZE) - (BYTES UNTIL THE END OF FILE) = ACTUAL OFFSET
This value is put on the stack, as well as the file-handle to later CALL the function 'SetFilePointer' to set the filepointer to our offset. After that the buffer for the written bytes (bwrite), the length of the patch, the offset of the new bytes and the file-handle is PUSHed and the API-function 'WriteFile' is CALLed.
Maybe a bit complex, but I guess still easy to understand =) ...
; set a couple of options for the assembler
.386P
Locals
jumps
.Model Flat ,StdCall
mb_ok equ 0
hWnd equ 0
FILE_ATTRIBUTE_NORMAL equ 080h
OPEN_EXISTING equ 3
GENERIC_READ equ 80000000h
GENERIC_WRITE equ 40000000h
--==declaration of all used API-functions==--
extrn ExitProcess : PROC ;procedure to end the program
extrn MessageBoxA : PROC ;procedure to show a MessageBox
extrn CreateFileA : PROC ; " ... to open a file
extrn ReadFile : PROC ;read a block of a file
extrn WriteFile : PROC ;write a block into a file
extrn CloseHandle : PROC ;close file
extrn GetFileSize : PROC ;get the filesize
extrn GlobalAlloc : PROC ;allocate memory
extrn GlobalFree : PROC ;set (free) memory
extrn SetFilePointer : PROC ;set the filepointer
--==here begins our Data==--
.Data
caption db "_masta_'s essay on Win32-ASM-Coding, part 1",0
;captionstring, 0-terminated
text db "Hi, nice to CU again",13,10
db "This tut will describe you how to make",13,10
db "Win32-ASM Search and Destroy patchers",0
;introtext, 0-terminated
err_cap db "ERROR",0 ;caption for errormessage
openerr db "Error on opening File",0 ;errortext opening file
memerr db "Error on allocating memory",0 ;errortext alloc. memory
byterr db "File is here, but i can't find the original bytes",0
;error while bytesearch
readycap db "Ready",0 ;caption for 'done'
readytxt db "Ok, file is patched",0 ;text for 'done'
file db "make.old",0 ;what file we want to patch?
org_val db "Xmas'97" ;original values
new_val db "_masta_" ;new values
len equ $-new_val ;how many values (length)
;org_val and new_val must be equal
fhandle dd ? ;variable for the filehandle
fsize dd ? ;variable for the filesize
memptr dd ? ;pointer to allocated memory
bread dd ? ;number of read bytes
bwrite dd ? ;number of written bytes
--==and here we start with our code==--
.Code
Main:
push mb_ok ;PUSH value for 'uType'
push offset caption ;PUSH pointer to caption
push offset text ;PUSH pointer to Text
push hWnd ;PUSH Masterhandle
call MessageBoxA ;CALL MessageBoxA
push 0 ;for Win95 always 0
push FILE_ATTRIBUTE_NORMAL ;standard Fileattributes
push OPEN_EXISTING ;open existing file
push 0 ;no Security-attributes
push 0 ;disable Share-Mode
push GENERIC_READ + GENERIC_WRITE ;read- and writeaccess
push offset file ;offset of the filename
Call CreateFileA ;open file
mov fhandle,eax ;save filehandle
cmp eax,0FFFFFFFFh ;if eax=FFFFFFFF then
; error
jnz file_is_here
push mb_ok
push offset err_cap
push offset openerr
push hWnd
call MessageBoxA ; showerrormessage
jmp end_ ; jump to end
file_is_here: ;file is there, so go on
push 0 ;can be 0, if the filesize is less
; then 4,3 GB :)
push fhandle ;PUSH filehandle
Call GetFileSize ;get the filesize
mov fsize,eax ;save the filesize
push fsize ;PUSH filesize=size of the buffer
push 0 ;0=GMEM_FIXED -> fixed memory-area
Call GlobalAlloc ;allocate as much as memory as filesize
mov memptr,eax ;save pointer to memory-area
cmp eax,0 ;if eax=0, then there were errors
jnz mem_ok
push mb_ok
push offset err_cap
push offset memerr
push hWnd
call MessageBoxA
jmp end_kill_handle ;end program, close file b4
mem_ok: ;memory is allocated -> next step
push 0 ;set to 0 in most cases
push offset bread ;pointer to number of read bytes
push fsize ;read how many bytes?,
; fsize=whole file
push memptr ;save where? ->allocated memory
push fhandle ;filehandle
Call ReadFile ;read file!
read_ok:
mov edi,memptr ;set EDI to memory-area
mov ecx,fsize ;set ECX (for repnz) to filesize
mov esi,offset org_val ;set ESI to the string to find
mov al, byte ptr [esi] ;load AL with the first byte
loop_:
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, nothing is found
jz not_found
here_is_something: ;found matching byte
push ecx ;save register
push edi
push esi
dec edi ;EDI-1, cos REPNZ SCASB is one step too far
mov ecx,len ;ECX=length of the patch
repz cmpsb ;repeat until the values in the memory of
;[EDI] and [ESI] are different,
;or ecx=0
cmp ecx,0 ;If ecx=0, then the org_val is in memory
jz patch ;->jump to patcher
not_that: ;it is not yet here
pop esi ;POP ESI
pop edi
pop ecx
jmp loop_ ;search next byte
patch: ;start of the patcher
pop esi ;POP registers
pop edi
pop ecx
dec edi ;EDI-1
inc ecx ;ECX+1
mov eax,fsize
sub eax,ecx ;compute Offset
push 0 ;offset from the beginning of the file
push 0 ;is 0, if file < 4,3GB
push eax ;offset
push fhandle ;filehandle
call SetFilePointer ;set FilePointer
push 0 ;normally 0
push offset bwrite ;how many bytes where written?
push len ;length of the bytes to write
push offset new_val ;offset to new values
push fhandle ;filehandle
Call WriteFile ;write block to file
push mb_ok
push offset readycap
push offset readytxt
push hwnd
call MessageBoxA ;OK, patch is done!
jmp end_kill_all ;END! Cleanup!
not_found:
push mb_ok
push offset err_cap
push offset byterr
push hWnd
call MessageBoxA ;the bytes where not in the file
end_kill_all:
push memptr ;pointer to Memoryarea
call GlobalFree ;enable (free) memory
end_kill_handle:
push fhandle ;PUSH filehandle
call CloseHandle ;CloseHandle
end_:
CALL ExitProcess ;Quit program
End Main ;end of code, JUMP-spot (main)
-----------------------==END OF SOURCE==----------------------------
tasm32 /mx /m3 /z /q tut
tlink32 -x /Tpe /aa /c tut,tut,, import32.lib
--------------END--------------make.bat
Until now I didn't see a reason to use include-files and well, the INC-files coming with TASM are not very complete, BUT if there is anybody out there possessing complete *.incs then don't hesitate to send'em to me!
OK, I think this time we did something really useful, not just a MessageBox like in my first essay, but a real every-day-tool of a cracker. The source can be freely used naturally and maybe there are some things you can optimize, especially concerning the search-routine (Hi Fungus ;)), but I think for learning-purpose it is OK. For a little challenge:
--> You could search for the first 4 bytes from the start
OK, I hope that my mailbox (masta_t@USA.NET) will explode soon
(CRITICS ARE WELCOME) and I will see ya all next time ... =)
By the way I am trying to establish an IRC-channel about these facts ...
Note Finali
I just hope there are enough people interested in this stuff and also in giving there knowledge to others.
VucoeT (Translator and Designer(:])), scut (Idea is from your DSP), |caligo| (bad news about you :(), fravia+ (best on the web), +Aescalapius (nice Bytepatcher) not4you (we Ossis must stick together ;)), fungus (something to optimze), Quest, Silvio, TheDoctor, everyone on #LAC and #cracking4newbies and to every cracker around the world.
Disclaimer
I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.
Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevoli e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.
Categories: Assembly | Masta | 2007