線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:4962
推到 Plurk!
推到 Facebook!

CreateRemoteThread 教學 XD

 
Skyer
高階會員


發表:43
回覆:111
積分:120
註冊:2002-04-04

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-07-24 00:53:56 IP:61.219.xxx.xxx 未訂閱
CreateRemoteThread 是 For 2k 以上的 API, 功能是在別的行程執行一段程式.    他的宣告如下 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;
-- Regards, Skyer
------
--
Regards,
Skyer
n4chen
一般會員


發表:9
回覆:7
積分:3
註冊:2011-05-12

發送簡訊給我
#2 引用回覆 回覆 發表時間:2011-09-21 22:09:16 IP:203.70.xxx.xxx 訂閱
我用相同的程式碼用Delphi 2010 編譯 就會發生記憶體錯誤耶
用Delphi 7編譯 救不會發生錯誤.........
系統時間:2024-03-29 9:53:14
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!