CreateRemoteThread和WriteProcessMemory技术

CreateRemoteThread和WriteProcessMemory技术

示例程序:WinSpy

另一种注入代码到其他进程地址空间的方法是使用WriteProcessMemory API。这次你不用编写一个独立的DLL而是直接复制你的代码到远程进程(WriteProcessMemory)并用CreateRemoteThread执行之。

让我们看一下CreateRemoteThread的声明:

HANDLE CreateRemoteThread( 
   HANDLE hProcess,         
//  handle to process to create thread in 
   LPSECURITY_ATTRIBUTES lpThreadAttributes,    //  pointer to security
                                              
//  attributes 
   DWORD dwStackSize,        //  initial thread stack size, in bytes 
   LPTHREAD_START_ROUTINE lpStartAddress,       //  pointer to thread 
                                              
//  function 
   LPVOID lpParameter,       //  argument for new thread 
   DWORD dwCreationFlags,    //  creation flags 
   LPDWORD lpThreadId        //  pointer to returned thread identifier 
);


和CreateThread相比,有一下不同:
●增加了hProcess参数。这是要在其中创建线程的进程的句柄。
●CreateRemoteThread的lpStartAddress参数必须指向远程进程的地址空间中的函数。这个函数必须存在于远程进程中,所以我们不能简单地传递一个本地ThreadFucn的地址,我们必须把代码复制到远程进程。
●同样,lpParameter参数指向的数据也必须存在于远程进程中,我们也必须复制它。


现在,我们总结一下使用该技术的步骤:
1.   得到远程进程的HANDLE(OpenProcess)。
2.   在远程进程中为要注入的数据分配内存(VirtualAllocEx)、
3.   把初始化后的INJDATA结构复制到分配的内存中(WriteProcessMemory)。
4.   在远程进程中为要注入的数据分配内存(VirtualAllocEx)。
5.   把ThreadFunc复制到分配的内存中(WriteProcessMemory)。
6.   用CreateRemoteThread启动远程的ThreadFunc。
7.   等待远程线程的结束(WaitForSingleObject)。
8.   从远程进程取回指执行结果(ReadProcessMemory 或 GetExitCodeThread)。
9.   释放第2、4步分配的内存(VirtualFreeEx)。
10.   关闭第6、1步打开打开的句柄。

另外,编写ThreadFunc时必须遵守以下规则:
1.   ThreadFunc不能调用除kernel32.dll和user32.dll之外动态库中的API函数。只有kernel32.dll和user32.dll(如果被加载)可以保证在本地和目的进程中的加载地址是一样的。(注意:user32并不一定被所有的Win32进程加载!)参考附录A。如果你需要调用其他库中的函数,在注入的代码中使用LoadLibrary和GetProcessAddress强制加载。如果由于某种原因,你需要的动态库已经被映射进了目的进程,你也可以使用GetMoudleHandle代替LoadLibrary。同样,如果你想在ThreadFunc中调用你自己的函数,那么就分别复制这些函数到远程进程并通过INJDATA把地址提供给ThreadFunc。

2.   不要使用static字符串。把所有的字符串提供INJDATA传递。为什么?编译器会把所有的静态字符串放在可执行文件的“.data”段,而仅仅在代码中保留它们的引用(即指针)。这样,远程进程中的ThreadFunc就会执行不存在的内存数据(至少没有在它自己的内存空间中)。

3.   去掉编译器的/GZ编译选项。这个选项是默认的(看附录B)。
4.   要么把ThreadFunc和AfterThreadFunc声明为static,要么关闭编译器的“增量连接(incremental linking)”(看附录C)。
5.   ThreadFunc中的局部变量总大小必须小于4k字节(看附录D)。注意,当degug编译时,这4k中大约有10个字节会被事先占用。
6.   如果有多于3tch分支的case语句,必须像下面这样分割开,或用if-else if代替.

     case constant1: statement1; goto END;
     case constant2: statement2; goto END;
     case constant3: statement2; goto END;
}

     case constant4: statement4; goto END;
     case constant5: statement5; goto END;
     case constant6: statement6; goto END;
}
END:

 

=====简单的CreateRemoteThread例程-初学者必看

 

//  _remotethreaddemo.cpp : Defines the entry point for the console application.
//  Author:秋镇菜

#include 
" stdafx.h "
#include 
" windows.h "


//  ========== 定义一个代码结构,本例为一个对话框============
struct  MyData
{
 
char  sz[ 64 ];  //  对话框显示内容
 DWORD dwMessageBox;  //  对话框的地址
};

//  ========== 远程线程的函数 ==============================
DWORD __stdcall RMTFunc(MyData  * pData)
{
 typedef 
int (__stdcall * MMessageBox)(HWND,LPCTSTR,LPCTSTR,UINT);
 MMessageBox MsgBox 
=  (MMessageBox)pData -> dwMessageBox;
 MsgBox(NULL, pData
-> sz, NULL, MB_OK);
 
return   0 ;
}
int  main( int  argc,  char *  argv[])
{
//  ===== 获得需要创建REMOTETHREAD的进程句柄 ===============================
 HWND hWnd  =  FindWindow( " notepad " , NULL);  //  以NOTEPAD为例
 DWORD dwProcessId;
 ::GetWindowThreadProcessId(hWnd, 
& dwProcessId);
 HANDLE hProcess 
=  OpenProcess(
        PROCESS_ALL_ACCESS,
        FALSE,
        dwProcessId);

//  ========= 代码结构 ================================================
 MyData data;
 ZeroMemory(
& data,  sizeof  (MyData));
 strcat(data.sz, 
" 对话框的内容. " );
 HINSTANCE hUser 
=  LoadLibrary( " user32.dll " );
 
if  ( !  hUser)
 {
  printf(
" Can not load library. " );
  
return   0 ;
 }
 data.dwMessageBox 
=  (DWORD)GetProcAddress(hUser,  " MessageBoxA " );
 FreeLibrary(hUser);
 
if  ( !  data.dwMessageBox)
  
return   0 ;

//  ======= 分配空间 ===================================================
  void   * pRemoteThread
  
=  VirtualAllocEx(hProcess,  0 ,
      
1024 * 4 , MEM_COMMIT | MEM_RESERVE,
      PAGE_EXECUTE_READWRITE);
 
if  ( !  pRemoteThread)
  
return   0 ;
 
if  ( !  WriteProcessMemory(hProcess, pRemoteThread,  & RMTFunc,  1024 * 4 0 ))
  
return   0 ;

 MyData 
* pData
  
=  (MyData * )VirtualAllocEx(hProcess,  0 ,
      
sizeof  (MyData), MEM_COMMIT,
      PAGE_READWRITE);
 
if  ( ! pData)
  
return   0 ;

 
if  ( !  WriteProcessMemory(hProcess, pData,  & data,  sizeof  (MyData),  0 ))
  
return   0 ;

//  =========== 创建远程线程 ===========================================
 HANDLE hThread
  
=  CreateRemoteThread(hProcess,  0 ,
       
0 , (LPTHREAD_START_ROUTINE)pRemoteThread,
       pData, 
0 0 );
 
if  ( !  hThread)
 {
  printf(
" 远程线程创建失败 " );
  
return   0 ;
 }
 CloseHandle(hThread);
 VirtualFreeEx(hProcess, pRemoteThread, 
1024 * 3 , MEM_RELEASE);
 VirtualFreeEx(hProcess, pData, 
sizeof  (MyData), MEM_RELEASE);
 CloseHandle(hProcess);
 printf(
" Hello World! " );
 
return   0 ;
}

zhuangyu1982@hotmail.com: 我用你的程序在windows xp下运行, 弹出messagebox之后, 只要点击确定宿主进程就会崩溃。 
而且不止是messagebox,调用其它的api函数也是一样,请问这是什么原因?有什么办法可以解决吗? 
--------------------------------------------------------  

编译成RELEASE版本就不会出错了,主要是DEBUG版本加了一个__chkesp的函数导致调用了非法地址 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值