如何編寫Loader[翻譯]

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

感謝大家支援.有翻譯一篇.有些地方翻的不好.以前看雪精華里面也有相關文章,不過感覺這個說的更淺顯易懂一些.
              
          如何編寫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技術。比如讀取和修改程式環境(所有的暫存器和標記)

相關文章