利用createRemoteThread远程注入(非DLL插入)
作者:d99 日期:2005-12-12
DELPHI代码,直截注入别的进程,之后直截运行在别的进程中的代码!
效果是弹出一个确认框!
本方法不能在98系统下使用!
function createRemoteThread(hProcess: THandle; lpThreadAttributes: Pointer;
dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer;
dwCreationFlags: DWORD; var lpThreadId: DWORD): THandle; stdcall;
第一個參數:目標行程 ID
第二個參數:指定 SD (security descriptor), nil 表示使用預設 SD
第三個參數:堆疊大小, 0 表示使用目標行程預設堆疊大小
第四個參數:開始執行函數的位址
第五個參數:餵進上面函數參數的位址
第六個參數:旗標設定
第七個參數:回傳成功後產生的 Thread ID
接著來說明一下,使用流程吧..
1. 取得目標 Process ID (用 FindWindow+GetWindowProcessID or createToolhelp32Snapshot)
2. OpenProcess 並設定 PROCESS_ALL_ACCESS (懶,用這最方便)
3. 使用 VirtualAllocEx 在目標行程內要求兩塊可執行可讀寫的空間,一塊放函數,另一塊放參數
4. 使用 WriteProcessMemory 將函數和參數寫進剛剛要求的兩塊空間
5. 準備完畢,createRemoteThread
6. WaitForSingleObject (等待 Thread 結束)
7. VirtualFreeEx 釋放剛剛要求的兩塊位址
需小心的地方:
1. 別使用 VCL, 連 string 也不能用.
2. 在目標行程執行的程式,無法直接使用 API, 需由 LoadLibraryA & GetProcAddress 來動態載入 dll 來使用 API。但是所有 kernel32.dll 的函數可直接使用, 因為每個行程必定會載入這個 dll, 所以可由本地行程先找好 LoadLibraryA & GetProcAddress 的函數位址,然後塞進參數內
3. 在目標行程執行的程式,如果用到字串的話,要小心! 不可直接用, 需將要使用的字串先寫入到參數中
4. 很想用 VCL 的話,目非行程執行的程式就直接載入一個用 delphi 寫的 dll 吧 XD
最後,以一個例子當結尾
簡單在指定的 Process 秀出一個 MessageBox..
使用了 FindWindow+GetWindowProcessId 取得目標 Process Id
1. 要在目標行程內執行的程式
procedure myMessageBegin(param: PParam); stdcall;
type
LoadLibraryFunc = function(lib: PChar): DWORD; stdcall;
GetProcAddressFunc = function(lib: DWORD; name: PChar): DWORD; stdcall;
MessageBoxFunc = function(handle: DWORD; msg, title: PChar; flag: DWORD): DWORD; stdcall;
var
myLoad: LoadLibraryFunc;
myGetProc: GetProcAddressFunc;
myMsg: MessageBoxFunc;
hlib: DWORD;
begin
myLoad := LoadLibraryFunc(param^.fLoadLibrary);
myGetProc := GetProcAddressFunc(param^.fGetProcAddress);
hlib := myLoad(@param^.sUser[0]);
myMsg := MessageBoxFunc(myGetProc(hlib, @param^.sMessage[0]));
myMsg(0, @param^.sUser[0], @param^.sMessage[0], MB_OK);
end;
看的出來,寫的相當迂迴 @@
2. 注入函數的參數型別定義
//要呼叫 MessageBox, 需先 LoadLibrary User32.dll
//然後再用 GetProcAddress 取得 MessageBox 位址
//所以需要以下欄位
// PS: 因為系統 DLL 函數位址在每個行程都一樣,
// 加上每個程行必定含入 kernel32.dll, 所以可以放心先取得
// LoadLibrary & GetProcAddress 的位址
PParam = ^TParam;
TParam = packed record
fLoadLibrary: DWORD;
fGetProcAddress: DWORD;
sUser: array[0..10] of Char;
sMessage: array[0..11] of Char;
end;
3. 注入的程式
procedure TForm1.btnInjectClick(Sender: TObject);
var
hwin, pid: DWORD;
hprocess: DWORD;
param: TParam;
pparam, pfunc: Pointer;
hlib: DWORD;
hthread: DWORD;
s: string;
v: DWORD;
iSize: DWORD;
begin
// 尋找指定視窗
hwin := FindWindow(nil, PChar(edtName.Text));
if hwin = 0 then begin
MessageBox(self.Handle, '找不到指定的視窗!', '訊息', MB_OK or MB_ICONWARNING);
Exit;
end;
// 取得該視窗所屬的 Process Id
GetWindowThreadProcessId(hwin, pid);
if pid = 0 then begin
MessageBox(self.Handle, '找不到行程ID', '訊息', MB_OK or MB_ICONWARNING);
Exit;
end;
// 開啟這個行程,權限設為 ALL
hprocess := OpenProcess(PROCESS_ALL_ACCESS, False, pid);
if hprocess = 0 then begin
MessageBox(self.Handle, '無法開啟行程', '訊息', MB_OK or MB_ICONWARNING);
Exit;
end;
// 在目標行程內要求參數記憶體
pparam := VirtualAllocEx(hprocess, nil, SizeOf(param), MEM_COMMIT, PAGE_READWRITE);
if pparam = nil then begin
MessageBox(self.Handle, '要求參數記憶體失敗', '訊息', MB_OK or MB_ICONWARNING);
CloseHandle(hprocess);
Exit;
end;
// 在目標行程內要求函數記憶體
// 這裡定義一個 myMessageEnd 空函數來判斷 myMessageBegin 大小
iSize := DWORD(@myMessageEnd)-DWORD(@myMessageBegin)+1;
pfunc := VirtualAllocEx(hprocess, nil, iSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if pfunc = nil then begin
MessageBox(self.Handle, '要求函數記憶體失敗', '訊息', MB_OK or MB_ICONWARNING);
CloseHandle(hprocess);
Exit;
end;
// 初始化參數
FillChar(param, SizeOf(param), 0);
hlib := GetModuleHandle('Kernel32.dll');
param.fLoadLibrary := DWORD(GetProcAddress(hlib, 'LoadLibraryA'));
param.fGetProcAddress := DWORD(GetProcAddress(hlib, 'GetProcAddress'));
s := 'user32.dll';
Move(s[1], param.sUser[0], Length(s));
s := 'MessageBoxA';
Move(s[1], param.sMessage[0], Length(s));
// 寫入參數
WriteProcessMemory(hprocess, pparam, @param, SizeOf(param), v);
// 寫入函數
WriteProcessMemory(hprocess, pfunc, @myMessageBegin, iSize, v);
// 準備完畢,跑吧!!
hthread := createRemoteThread(hprocess, nil, 0, pfunc, pparam, 0, v);
// 等!
WaitForSingleObject(hthread, INFINITE);
// 釋放剛剛要求的記憶體
VirtualFreeEx(hprocess, pfunc, iSize, MEM_DECOMMIT);
VirtualFreeEx(hprocess, pparam, SizeOf(param), MEM_DECOMMIT);
// 收尾
CloseHandle(hprocess);
end;