編寫一個檔案補丁

看雪資料發表於2004-08-27

本來應該發在翻譯區,但考慮到這裡不少朋友都問補丁的情況,我看還是自己寫補丁來的爽快.這個程式碼編譯後才2.5K.小的很.
第一次翻譯東西,不足之處請原諒!



            編寫一個檔案補丁(Make a standalone patch)

作者 : Detten    Detten@tiscali.be 
來源 : http://biw.rult.at/

翻譯 : nbw       www.vxer.com

1、前言
  一但破解了一個程式,你就想把成果共享給別人。為了不用把整個破解後的程式上傳,你可以製作一個小補丁來修改程式中必要的位元組。
  那如何來寫呢?
===〉首先找到需要打補丁的檔案。大多數補丁認為該檔案處在自己當前目錄下。

===〉如果找到,開啟該檔案。

===〉然後檢查開啟的檔案是不是和所破解的檔案。比如我們可以檢查檔案大小,或者隨機檢查一些位元組,或者最好檢查將要被修改的位元組。

===〉如果以上都無誤,我們可以做需要調整:)
    把檔案指標移動到指定位置,然後寫入新的操作碼。

===〉關閉檔案,給出提示結果。

下面找一個你破解的檔案,然後開始....

2、必要的API
   做這個程式需要用到什麼API呢?

HANDLE CreateFile( 

LPCTSTR lpFileName, // pointer to name of the file 
DWORD dwDesiredAccess, // access (read-write) mode 
DWORD dwShareMode, // share mode 
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes 
DWORD dwCreationDistribution, // how to create 
DWORD dwFlagsAndAttributes, // file attributes 
HANDLE hTemplateFile // handle to file with attributes to copy 
);

   這個API函式用來開啟或者建立檔案。
dwDesiredAccess 應該設定為: 'GENERIC_WRITE OR GENERIC_READ' ,因為需要讀寫檔案;
dwShareMode = 'FILE_SHARE_WRITE OR FILE_SHARE_READ'
dwCreationDistribution = 'OPEN_EXISTING'  我們只需要開啟檔案,如果檔案不存在函式將返回失敗,然後我們給出提示資訊。
   可以察看WIN32.HLP獲取詳細資訊,如果你沒有這個API庫,可以找相關資料。
   如你所見,這個API函式返回我們需要檔案控制程式碼。我們可以利用這個控制程式碼做下一步:寫檔案。

BOOL WriteFile( 
HANDLE hFile, // handle to file to write to 
LPCVOID lpBuffer, // pointer to data to write to file 
DWORD nNumberOfBytesToWrite, // number of bytes to write 
LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written 
LPOVERLAPPED lpOverlapped // pointer to structure needed for overlapped I/O
);

   我們用這個函式把2個位元組寫入需要打補丁的檔案(當然是在正確的位置)[譯者:作者的例子是寫2個位元組,我們做的時候根據需要]
   涉及到的hFile控制程式碼就是CreateFile函式的返回值。

lpOverlapped應該指向一個 OVERLAPPED 結構,我們需要用它設定正確的檔案指標。

typedef struct _OVERLAPPED { // o 
DWORD Internal; 
DWORD InternalHigh; 
DWORD Offset; 
DWORD OffsetHigh; 
HANDLE hEvent; 
} OVERLAPPED; 
Offset的內容是需要寫入的地址。(譯者:注意不是記憶體中的虛擬地址)

3、目標
   目標程式是Crackme5.exe,假定我們現在獲取不到正確的序列號,而需要對他打補丁(譯者:這個程式我也沒有,大家知道意思就行) 
   當然你肯定是不錯的Cracker:) 並且很快找出來了需要修補的地方:

Offset 53Fh : 74h, 15h -> 90h, 90h

   以上就是我們所需要的所有資訊。

4、程式碼

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

.data 
FileName db "Crackme5.exe",0
AppName db "Crackme 5 Patch",0
Done db "File patched succesfully !",0
NoFile db "Can't find crackme5.exe !",0
ReFile db "Wrong version of crackme5.exe !",0
WrFile db "Error writing to crackme5.exe !",0
RBuffer db 75h, 15h
WBuffer db 90h,90h
OffsetPos OVERLAPPED <NULL,NULL,53Fh,NULL,NULL> 
 
.data?

hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndname HWND ?
hFile HANDLE ?
Numb dd ?
Buffer db 2 dup(?) 


.const
 
.code
start:

invoke GetModuleHandleA, NULL
mov hInstance,eax 

invoke CreateFile,ADDR FileName, GENERIC_READ OR GENERIC_WRITE, FILE_SHARE_READ OR FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL 

.IF eax!=INVALID_HANDLE_VALUE

mov hFile, eax ; 儲存檔案控制程式碼
Invoke ReadFile, hFile, ADDR Buffer, 2, ADDR Numb, ADDR OffsetPos ; 讀取要修改的2個位元組
mov ax, word ptr [Buffer] 
.IF ax == word ptr [RBuffer] ; 如果判斷正確 (75h,15h) 就覆蓋他們 :-)
Invoke WriteFile, hFile, ADDR WBuffer, 2, ADDR Numb, ADDR OffsetPos ;寫入新的程式碼(90h 90h)
.IF Numb == 2 ; 如果返回值為 2, 彈出成功資訊
push MB_OK 
push OFFSET AppName
push OFFSET Done ; 彈出資訊地址入棧
.ELSE ;如果返回值不是2,那麼彈出錯誤資訊
push MB_OK OR MB_ICONINFORMATION
push OFFSET AppName
push OFFSET WrFile
.ENDIF 
.ELSE ; 如果讀取的2個位元組不正確,彈出檔案選擇錯誤資訊
push MB_OK OR MB_ICONINFORMATION
push OFFSET AppName
push OFFSET ReFile 
.ENDIF 

.ELSE ; 如果未獲得檔案控制程式碼,彈出檔案不存在資訊
push MB_OK OR MB_ICONINFORMATION
push OFFSET AppName
push OFFSET NoFile 
.ENDIF

push NULL
Call MessageBox
invoke CloseHandle, hFile ; 關閉檔案
invoke ExitProcess,eax ; 退出

end start
 
   如果你看懂了上面的程式碼,就可以製作自己的檔案補丁。當然也可以編寫的更人性化一些,比如新增上選擇檔案路徑的對話方塊,但那就是另外一個題目了。

相關文章