如何訪問一個程式中的記憶體 (譯文二) (34千字)
原標題:HOW TO ACCESS THE MEMORY OF A PROCESS
(i.e. Game Trainer,Process Patcher etc.)
Deep into window
如何訪問一個程式中的記憶體(比如遊戲補丁、程式補丁等)
深入window
作者: NaTzGUL a great cracker (as Quine pointed out long ago)
Email: natzgul@hotmail.com
譯者: DDXia[CCG]
英文聯接:http://gadget.lansg.com/fravia/natz_mp2.htm
丁丁蝦前言:
在Crack工具八寶箱中有一種武器為記憶體動態補丁製作軟體,如果不懂它們的原理,會覺得非常的不
可思義,於是在網上無意中看到了這篇教程,揭示了記憶體動態補丁的原理,以及帶有一個簡單範例。寫的太
精彩了。希望大家看了,能有一些啟發和想法,俺丁丁蝦也知足了 :D 。
在文章中對API的詳細解釋,因為隨便找一本中文的API大全,就可以看個明白了,何況通曉API
也是CrAcKer基本功哦!所以就沒有翻譯。
順便說一聲,英語不是俺的母語(好象tKC也說過),也比較菜,翻譯內容大概的意思應該都對吧!
哈哈~~~~ :) 如有誤人子第的地方請指出。謝謝!
介紹:
是的!我又勤奮了=)
歡迎看我的新的教學篇。
這次的熱點:如何訪問程式中的記憶體,比如寫 和讀
其實也沒有什麼新意,但問題是在WIN95中,一個程式是不能訪問另一個程式的記憶體的。
在這個教程中,我將演示一種方法如何繞過這個問題。
雖然許多人都在談論這個問題,但是至今還是沒有人能解決,無論如何,都是我填補這個問題做一些貢獻
當然也包括一些例子,就是如何使用它去破解。
目標的 URL/FTP
目標:任何的EXE (FLAT MODEL !)
教學:
首先列出了我們將要用到的API
(實際上這些API是用於除錯)
KERNEL32!ReadProcessMemory
KERNEL32!WriteProcessMemory
下面是 win32.hlp中的描述:
--------------------------------------------------------------------------------
ReadProcessMemory功能是讀取指定程式的記憶體。但是被讀的區域必須是可以訪問的,要不就操
作失敗。
BOOL ReadProcessMemory(
HANDLE hProcess,
// 被讀記憶體的程式控制程式碼
LPCVOID lpBaseAddress,
// 開始讀的地址
LPVOID lpBuffer,
// 用於放資料的快取地址
DWORD cbRead,
//讀取的位元組數
LPDWORD lpNumberOfBytesRead // 從檔案中實際讀入的字元數
);
引數
hProcess
hProcess
Identifies an open handle of a process whose memory is read.
The handle must have PROCESS_VM_READ access to the process.
lpBaseAddress
Points to the base address in the specified process to be
read.
Before any data transfer occurs, the system verifies that
all data in the
base address and memory of the specified size is
accessible for read access.
If this is the case, the function proceeds; otherwise, the
function fails.
lpBuffer
Points to a buffer that receives the contents from the address
space of
the specified process.
cbRead
Specifies the requested number of bytes to read from the
specified process.
lpNumberOfBytesRead
Points to the actual number of bytes transferred into the
specified buffer.
If lpNumberOfBytesRead is NULL, the parameter is ignored.
Return Value
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE.
To get extended error information, call GetLastError.
The function fails if the requested read operation crosses
into an area of
the process that is inaccessible.
Remarks
ReadProcessMemory copies the data in the specified address
range from the
address space of the specified process into the
specified buffer of the
current process.
Any process that has a handle with PROCESS_VM_READ access
can call the function.
The process whose address space is read is typically, but
not necessarily,
being debugged.
The entire area to be read must be accessible.
If it is not, the function fails as noted previously.
--------------------------------------------------------------------------------
The WriteProcessMemory function writes memory in a specified
process.
The entire area to be written to must be accessible, or the
operation fails.
BOOL WriteProcessMemory(
HANDLE hProcess,
// handle of process whose memory is written to
LPVOID lpBaseAddress, //
address to start writing to
LPVOID lpBuffer,
// address of buffer to write data to
DWORD cbWrite,
// number of bytes to write
LPDWORD lpNumberOfBytesWritten // actual number of bytes written
);
Parameters
hProcess
Identifies an open handle of a process whose memory is to be written to.
The handle must have PROCESS_VM_WRITE and PROCESS_VM_OPERATION access to the
process.
lpBaseAddress
Points to the base address in the specified process to be written to.
Before any data transfer occurs, the system verifies that all data in the base
address
and memory of the specified size is accessible for write access.
If this is the case, the function proceeds; otherwise, the function fails.
lpBuffer
Points to the buffer that supplies data to be written into the address space
of the
specified process.
cbWrite
Specifies the requested number of bytes to write into the specified process.
lpNumberOfBytesWritten
Points to the actual number of bytes transferred into the specified process.
This parameter is optional. If lpNumberOfBytesWritten is NULL, the parameter
is ignored.
Return Value
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE.
To get extended error information, call GetLastError.
The function will fail if the requested write operation crosses into an area
of the process that is inaccessible.
Remarks
WriteProcessMemory copies the data from the specified buffer in the current
process
to the address range of the specified process.
Any process that has a handle with PROCESS_VM_WRITE and PROCESS_VM_OPERATION
access
to the process to be written to can call the function.
The process whose address space is being written to is typically, but not necessarily,
being debugged.
The entire area to be written to must be accessible.
If it is not, the function fails as noted previously.
--------------------------------------------------------------------------------
教程: 呼叫它用到的引數
HANDLE hProcess = ?
// 程式的控制程式碼
LPVOID lpBaseAddress, =自己指定
// 開始讀寫的地址
LPVOID lpBuffer, =自己指定
//讀寫資料的緩衝地址
DWORD cbWrite, =自己指定
// 需要讀寫的位元組
LPDWORD lpNumberOfBytesWritten = NULL
// 實際上讀寫的位元組
現在看起來已經很有希望了 呵呵~~~~;)
關鍵是需要得到我們想訪問的程式控制程式碼。
一個程式可以透過呼叫"KERNEL32!GetCurrentProcess"
獲得自己的 pseudo-handle (假控制程式碼)
透過這個 pseudo-handle(控制程式碼)可以獲得最大的訪問許可權。
如果我們想訪問,我們必須開啟另一個不同的程式。
我知道有兩種方法可以獲得另一個程式的控制程式碼:
1、使用 USER32!FindWindowA,USER32!GetWindowThreadProcessId and KERNEL32!OpenProcess
2、使用KERNEL32!CreateProcess
方法一:
Game Trainer就是透過這種方法(DDXia:可能是一個遊戲修改器)
在WIN95中程式也象其他東東一樣是一個物件,這就意味著我們可以透過
"KERNEL32!OpenProcess"得到控制程式碼,最後,不要忘記使用 "BOOL KERNEL32!CloseHandle
(hProcess)" Close。否則當程式中斷時程式的映象會留在記憶體中浪費空間。
下面是 win32.hlp中的描述:
--------------------------------------------------------------------------------
功能:返回現有程式物件的控制程式碼
HANDLE OpenProcess(
DWORD fdwAccess, // access
flag
BOOL fInherit, // handle
inheritance flag
DWORD IDProcess // process
identifier
);
Parameters
fdwAccess
Specifies the access to the process object. For operating systems that support
security
checking, this access is checked against any security descriptor for the target
process.
Any combination of the following access flags can be specified in addition to
the STANDARD_RIGHTS_REQUIRED access flags:
Access Description
PROCESS_ALL_ACCESS Specifies all possible
access flags for the process object.
PROCESS_CREATE_PROCESS Used internally.
PROCESS_CREATE_THREAD Enables using the
process handle in the
CreateRemoteThread
function to create a thread in the process.
PROCESS_DUP_HANDLE Enables using the process
handle as either the source
or
target process in the DuplicateHandle function to
duplicate
a handle.
PROCESS_QUERY_INFORMATION Enables using the process handle
in the
GetExitCodeProcess
and GetPriorityClass functions
to
read information from the process object.
PROCESS_SET_INFORMATION Enables using the
process handle in the SetPriorityClass
function
to set the priority class of the process.
PROCESS_TERMINATE Enables using the process
handle in the TerminateProcess
function
to terminate the process.
PROCESS_VM_OPERATION Enables using the
process handle in the VirtualProtectEx
and
WriteProcessMemory functions to modify the virtual
memory
of the process.
PROCESS_VM_READ Enables
using the process handle in the ReadProcessMemory
function
to read from the virtual memory of the process.
PROCESS_VM_WRITE Enables using the process
handle in the
WriteProcessMemory
function to write to the virtual
memory
of the process.
SYNCHRONIZE Windows
NT: Enables using the process handle in any of
the
wait functions to wait for the process to terminate.
fInherit
Specifies whether the returned handle can be inherited by a new process created
by
the current process. If TRUE, the handle is inheritable.
IDProcess
Specifies the process identifier of the process to open.
Return Value
If the function succeeds, the return value is an open handle of the specified
process.
If the function fails, the return value is NULL. To get extended error information,
call GetLastError.
Remarks
The handle returned by the OpenProcess function can be used in any function
that requires a handle to a process, provided the appropriate access rights
were requested.
--------------------------------------------------------------------------------
教程: 呼叫它用到的引數
DWORD fdwAccess = PROCESS_ALL_ACCESS (Thx
to Micro$oft ;) // 訪問標誌
BOOL fInherit = FALSE
// 控制程式碼繼承標誌
DWORD IDProcess = ?
// 程式標誌
使用 "KERNEL32!GetCurrentProcessId"得到當前程式的ID號
為了得到另一個程式的ID號,我們必須再次執行它。
為了找出現有的某個程式,我們得呼叫USER32!FindWindowA,它能夠透過查詢視窗的標題,
然後返回該視窗的控制程式碼。利用這個視窗控制程式碼,我們再呼叫GetWindowThreadProcessId去獲得
該程式的ID。
下面是 win32.hlp中兩個API的描述:
--------------------------------------------------------------------------------
The FindWindowA function retrieves the handle of the top-level window whose
class name
and window name match the specified strings. This function does not search child
windows.
HWND FindWindowA(
LPCTSTR lpClassName, // address of
class name
LPCTSTR lpWindowName // address
of window name
);
Parameters
lpClassName
Points to a null-terminated string that specifies the class name or is an atom
that
identifies the class-name string. If this parameter is an atom, it must be a
global
atom created by a previous call to the GlobalAddAtom function.
The atom, a 16-bit value, must be placed in the low-order word of lpClassName;
the high-order word must be zero.
lpWindowName
Points to a null-terminated string that specifies the window name (the window's
title).
If this parameter is NULL, all window names match.
Return Value
If the function succeeds, the return value is the handle of the window that
has the
specified class name and window name.
If the function fails, the return value is NULL. To get extended error information,
call GetLastError.
--------------------------------------------------------------------------------
教程: 呼叫它用到的引數
LPCTSTR lpClassName = NIL
//類名的指標
LPCTSTR lpWindowName = 自己指定
// 視窗名的指標
--------------------------------------------------------------------------------
The GetWindowThreadProcessId function retrieves the identifier of the thread
that
created the specified window and, optionally, the identifier of the process
that
created the window. This function supersedes the GetWindowTask function.
DWORD GetWindowThreadProcessId(
HWND hWnd, //
handle of window
LPDWORD lpdwProcessId // address of variable
for process identifier
);
Parameters
hWnd
Identifies the window.
lpdwProcessId
Points to a 32-bit value that receives the process identifier.
If this parameter is not NULL, GetWindowThreadProcessId copies the identifier
of the
process to the 32-bit value; otherwise, it does not.
Return Value
The return value is the identifier of the thread that created the window.
--------------------------------------------------------------------------------
教程: 呼叫它用到的引數
HWND hWnd = 從 FindWindowA返回的結果
//視窗的控制程式碼
LPDWORD lpdwProcessId = 自己指定
// 儲存程式ID變數的地址
現在我們有能力可以寫一個函式,使用它來訪問程式。這個函式我用Delphi3寫的。如果某人問我要彙編或者是
C版本的,我也會寫一個給你的,但這次我實在是太懶了;) 總之,不是很難寫的。
以下為Delphi寫的函式:
--------------------------------------------------------------------------------
(This function will in most cases find its use in a trainer i think)
type access_info = record
error :integer;
hwindow :integer;
thread_id :integer;
process_id :integer;
hprocess :integer;
end;
function AccessProcess ( access_type :integer;
wtitle :string;
address :integer;
buffer :PByteArray;
b_count :integer
):access_info;
var temp :integer;
begin result.error:=0;
if wtitle'' then
begin result.hwindow:=FindWindowA (nil,pchar(wtitle));
if result.hwindow0 then
begin result.thread_id:=GetWindowThreadProcessId (result.hwindow,@result.process_id);
result.hprocess:=OpenProcess (PROCESS_ALL_ACCESS,false,result.process_id);
if result.hprocess0 then
begin temp:=0;
case access_type of
0 : ;
1 : if not(ReadProcessMemory (result.hprocess,pointer(address),buffer,b_count,temp))
then
result.error:=4;
2 : if not(WriteProcessMemory (result.hprocess,pointer(address),buffer,b_count,temp))
then
result.error:=5;
else result.error:=6;
end;
CloseHandle (result.hprocess);
end
else result.error:=3;
end
else result.error:=2;
end
else result.error:=1;
end;
函式的訪問型別:
0 = 僅僅是獲得資訊
1 = 讀
2 = 寫
出錯資訊程式碼:
0 = 正確
1 = 視窗標題是空的。
2 = 不能找到指定標題的視窗
3 = 不能開啟程式
4 = 讀錯誤
5 = 寫錯誤
6 = 不支援寫型別
--------------------------------------------------------------------------------
方法2:
在這一節中我們將去寫一個程式補丁( Process Patcher)。
以下是需要實行的步驟:
- 得到命令列
- 建立新的程式和處理命令列
- 等待 直到程式初始化完成
- 補丁程式
- 最後終止並單獨留下新的程式
程式補丁將非常有用,如果。。。。。
1、程式是被壓縮的 (如 Shrinker)
2、程式是被加密的(如 PE-Crypt)
3、在程式執行過程中有 CRC-Check
4、不在乎用其他的方式修改程式
使用程式補丁工具你不用關心程式本身,因為它會象這個教程中的第一種方法,進行修改程式。不
同的是我們不需要再指定視窗的標題,因為我們將透過使用KERNEL32!CreateProcess (with PROCESS_ALL_ACCESS),從被返回的結果中
獲得程式的控制程式碼。
現在讓我們實現每一步:
得到命令列:
-----------------------------
如果你已經把patcher.exe重新命名為 app.exe,也許會有些幫助。
這種方法 app將會從補丁程式中接收到命令列,從而補丁程式對這個子程式是完全透明。
備註: 如果在exe中app執行CRC-Check,就不需要更改名字!!!!!
否則它會在補丁程式中進行檢測,那也是符合邏輯的;) (DDXia:也有點糊塗,於是搬出原文
相關文章
- 一個SMMU記憶體訪問異常的問題2024-08-10記憶體
- 排查一個潛在的記憶體訪問問題 — 用 C 寫程式碼的日常2019-05-14記憶體
- [譯] JavaScript是如何工作的:記憶體管理 + 如何處理4個常見的記憶體洩漏(譯)2017-09-26JavaScript記憶體
- RAC一個節點記憶體故障當機,無法訪問2014-08-26記憶體
- C語言訪問資料物件在記憶體中真實位模式的一個方法2023-05-19C語言物件記憶體模式
- 請教一個java程式記憶體釋放的問題2006-04-21Java記憶體
- 記憶體訪問全過程2020-05-10記憶體
- 一個記憶體不能被written的問題2017-01-07記憶體
- [譯] Swift 中的記憶體洩漏2018-05-27Swift記憶體
- 一個由程式記憶體佈局異常引起的問題2017-02-16記憶體
- VB也能訪問記憶體 (轉)2007-12-12記憶體
- Go記憶體架構,一個有趣的問題2022-05-22Go記憶體架構
- 關於在 Linux 下多個不相干的程式互斥訪問同一片共享記憶體的問題2019-05-13Linux記憶體
- 如何在windows程式中讀取bios內容(實體記憶體內容) (5千字)2003-03-02WindowsiOS記憶體
- VCL 中的一個記憶體洩漏 Bug (轉)2007-12-14記憶體
- 【翻譯】記憶體結構 (一)2009-08-14記憶體
- 關於java記憶體訪問重排序的思考2018-03-30Java記憶體排序
- 跨工程編譯orbslam3記憶體中斷問題2020-10-27編譯ORBSLAM記憶體
- 【譯】Ringbahn的兩個記憶體Bug2020-11-03記憶體
- [譯]理解閉包中的記憶體洩漏2019-03-01記憶體
- 翻譯 | 理解Java中的記憶體洩漏2019-02-11Java記憶體
- ReFlex:讓遠端快閃記憶體訪問擁有本地訪問的效能2018-05-07Flex記憶體
- 如何在 Linux 中找出記憶體消耗最大的程式2019-11-06Linux記憶體
- Go記憶體管理一文足矣2022-05-19Go記憶體
- 一文解決記憶體屏障2018-01-08記憶體
- 如何設計一個記憶體分配器?2015-07-30記憶體
- Keep小表到記憶體,提高訪問速度2010-09-08記憶體
- 除錯應用程式記憶體中的神祕問題2013-08-09除錯記憶體
- 我寫的一個記憶體補丁,很基本。。高手莫入。。
(5千字)2015-11-15記憶體
- Java應用程式中的記憶體洩漏及記憶體管理2019-08-29Java記憶體
- 【譯】JavaScript 的記憶體模型2019-04-15JavaScript記憶體模型
- 剖析記憶體中的程式之祕2018-03-04記憶體
- JavaScript 工作原理之三-記憶體管理及如何處理 4 類常見的記憶體洩漏問題(譯)2019-03-04JavaScript記憶體
- JS中的棧記憶體、堆記憶體2019-02-23JS記憶體
- project中的堆疊記憶體,記憶體地址引用,gc相關問題2018-10-31Project記憶體GC
- (四) 一文搞懂 JMM - 記憶體模型2022-12-05記憶體模型
- [MetalKit]34-Working-with-memory-in-Metal記憶體管理2017-12-14記憶體
- 如何避免JavaScript中的記憶體洩漏?2023-10-30JavaScript記憶體