感謝大家支援.有翻譯一篇.有些地方翻的不好.以前看雪精華里面也有相關文章,不過感覺這個說的更淺顯易懂一些.
如何編寫Loader(How to code a loader)
作者 : Detten Detten@tiscali.be
來源 : http://biw.rult.at/
翻譯 : nbw www.vxer.com
例項下載:loader.zip(或滑鼠右鍵另存為)
1、什麼是Loader,為什麼需要它?
所謂的Loader是一個用來載入其他程式的小程式。當然,只有被載入的記憶體的程式需要改動的時候我們才採用Loader。(記憶體補丁)
Loader常用於讓遊戲玩家修改遊戲。
有很多原因導致我們選擇Loader而不是一般的補丁程式。我們或許需要在程式CRC校驗以後再進行修改,或者開始的時候修改記憶體資料,然後在程式中再恢復原來的資料.....
我肯定你還可以找到其他一些用途。
2、Loader是怎麼工作的?
OK,找到你的Win32.hlp然後坐下來:)
首先,Loader必須建立一個程式啟動目標程式。我們將用CreateProcess函式做這個(很明顯嘛)。當目標程式被載入到記憶體,我們需要中斷該程式,以便進行我們的修改。
讓我們檢視一下win32.hlp對這個API函式的講解:
BOOL CreateProcess(
LPCTSTR lpApplicationName, // 可執行模組名稱指標
LPTSTR lpCommandLine, // 命令列字串指標
LPSECURITY_ATTRIBUTES lpProcessAttributes, // 程式安全屬性指標
LPSECURITY_ATTRIBUTES lpThreadAttributes, // 執行緒安全屬性指標
BOOL bInheritHandles, // 控制程式碼繼承標記
DWORD dwCreationFlags, // 建立標記
LPVOID lpEnvironment, // 新環境塊指標
LPCTSTR lpCurrentDirectory, // 當前路徑指標
LPSTARTUPINFO lpStartupInfo, // STARTUPINFO指標
LPPROCESS_INFORMATION lpProcessInformation // PROCESS_INFORMATION指標
);
這裡涉及到的API函式請檢視win32.hlpl以瞭解詳細內容,因為這裡我只講解重要的一些關鍵的API。
lpApplicationName 使目標程式的路徑+名稱. (例如 c:\somedir\crackme.exe)
lpCommandLine 可以用來指定命令列引數,如果需要的話。
dwCreationFlags 也很重要,因為我們需要隨時中斷被載入的程式,所以這裡設定為CREATE_SUSPENDED lpStartupInfo 指向一個代表啟動資訊的結構(檢視win32.hlp看詳細資訊)。
lpProcessInformation 指向一個空結構,該結構在程式被載入的時候載記憶體中被填充。結構中包含有程式控制程式碼,執行緒控制程式碼和程式/執行緒ID。
注意:這裡建議採用程式控制程式碼而不是執行緒控制程式碼,因為如果採用程式控制程式碼,你對整個程式體擁有PROCESS_ALL_ACCESS的操作許可權。就是說你對整個程式擁有讀寫許可權,但是如果採用執行緒ID,就需要再設定寫許可權。
好了,現在目標程式被載入了。我們可以利用下面的API函式來執行或者停止程式:
DWORD ResumeThread(
HANDLE hThread // identifies thread to restart
); 恢復程式
DWORD SuspendThread(
HANDLE hThread // handle to the thread
); 掛起程式
hThread 可以從LPPROCESS_INFORMATION 結構獲得。
最後,可以利用下面的函式讀寫程式:
BOOL WriteProcessMemory(
HANDLE hProcess, // 需要修改的程式的控制程式碼
LPVOID lpBaseAddress, // 開始寫入的地址
LPVOID lpBuffer, // 指向被寫入的資料
DWORD nSize, // 寫入位元組數目
LPDWORD lpNumberOfBytesWritten // 返回寫入的資料長度
);
這是一個典型的資訊自我返回(self-explanatory)。hProcess可以從LPPROCESS_INFORMATION結構獲取。
從程式讀取資料:
BOOL ReadProcessMemory(
HANDLE hProcess, // handle of the process whose memory is read
LPCVOID lpBaseAddress, // address to start reading
LPVOID lpBuffer, // address of buffer to place read data
DWORD nSize, // number of bytes to read
LPDWORD lpNumberOfBytesRead // address of number of bytes read
);
看明白上面的資訊,就可以看下面的內容了。
3、Loader舉例
下面的事例我將啟動一個Crackme(譯者:我也沒有)並且把視窗標題改成“Detten's Caption”。我將把程式啟動5秒鐘,然後掛起之。
這裡我們修補的字串,當然用這種方法也可以修補位元組或者字:)。作為事情準備,我們需要指導字串在程式中的地址。所以,開啟你喜歡的反彙編軟體,找到地址為:004050FCh
<-------------Code Snippet----------------->
.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 "C:\somedir\crackme.exe",0
notloaded db "It did not work :-(",0
Letsgo db "The process is started",13,10,
"Let's change smthg and run it now :-)",0
NewText db "Dettens Caption",0
Startup STARTUPINFO <>
processinfo PROCESS_INFORMATION <>
.data?
hInstance HINSTANCE ?
byteswritten dd ?
uExitCode dd ?
.code
start:
invoke GetModuleHandleA, NULL
mov hInstance,eax
;建立新程式,載入crackme,並且迅速掛起該執行緒
invoke CreateProcess, ADDR FileName, NULL, NULL, NULL, NULL, CREATE_SUSPENDED,
NULL, NULL, ADDR Startup, ADDR processinfo
.IF eax == NULL ; 程式建立失敗?
invoke MessageBox, NULL, ADDR notloaded, NULL, MB_ICONEXCLAMATION
.ELSE
invoke MessageBox, NULL, ADDR Letsgo, NULL, MB_OK ; Display Message
;修改字串(004050FCh)
invoke WriteProcessMemory, processinfo.hProcess, 004050FCh, ADDR NewText,
13, byteswritten
; 恢復程式 ;)
invoke ResumeThread, processinfo.hThread
;讓程式執行5秒,然後殺掉它
invoke Sleep, 5000
invoke TerminateProcess, processinfo.hProcess, uExitCode
.ENDIF
invoke ExitProcess,eax
end start
<-------------End Code Snippet------------->
這就是寫Loader的整個步驟。
再下一篇中我將討論更多的Loader技術。比如讀取和修改程式環境(所有的暫存器和標記)