A brief on using CreateRemoteThread

本文介绍了在Windows编程中,Jeffery Richter使用远程线程将DLL注入另一进程地址空间的方法,探讨了获取函数地址及确保其在本地和远程进程中一致的问题,还分析了病毒相关情况,并给出了创建远程线程定期弹出消息框的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2004-12-14   gr1x(c)


In "Programming Applications for Microsoft Windows 4th", Jeffery Richter used Remote Threads to inject a dll into another process's address space. He tansfered LoadLibrary's address into remote thread and let remote thread to load a dll we wrote(may be a trojan dll :-) ), As we create that thread ourselves, we cann't count on the compiler&linker has prepared the referenced functions' addresses well in the remote process's import section's thunk area(refer PE format specification), which means we have to get every function address we'll use in remote thread within the injected process address space,  Jeffery told us to use GetProcAddress, howerver what GetProcAddress returns is just the address of function within our own process address space, how can we make sure that address will stay the same with remote process? Jeffery said that “Kernel32.dll is mapped to the same memory location in both the local and the remote processes' address spaces”,why same? I think as for efficiency consideration(relocation is a horrible process), Microsoft may has ran Rebase on all the operating system-supplied files before shipping Windows or has allocated a non-overlapped prefered address for these system-supplied fils so that none of the operating system modules overlap once mapping them all into a single address space, so now we can count on that majority of system functions' memory location would be the same. 


To make this explaination simple, think that if we've wrote a dll, and we're sure the remote process and our own process all have loaded that dll in same memory location, surely we  can play this magic trick. Luckily , nearly every process will load kernle32.dll and user32.dll,isn't it a great relief:) Just think about the tedious work in virous for searching the base address of kernel32.dll  and its export section for function GetProcAddress's address. A interesting question arises, why does virous have to do that awful work,why don't use the above talking attribute? Personally, I think firstly Windows version varries so function memory location varies; Second,Virus code are normally injected into EXE files and changes the entry point to point to itself so virus can start running before original EXE's code, it doesn't have the  luxurios environment as we are now: tow running process in the same host, one for injecting and one being injected, as it doesn't know anything about the infected host. Anyway, some early virus just hardcoded the function address in code so they are not portable accross different platform.(Here, I must declare I know little about virus, just correct me if I'm wrong). 


Sorry, just run such far away from the topic, following is the code snippet which create a remote thread to pop a messagebox periodlly:

  1. // zombie.cpp :
  2. // Usage: Zombie(szMessage,szTitle);
  3. #include "zombie.h"
  4. #pragma comment(lib, "Psapi.lib")
  5. #define UNICODE
  6. #define _UNICODE
  7. #define _RemoteProcess                   
  8. typedef struct _remoteparameter
  9. {
  10.  DWORD       _OututDebugstring;
  11.  DWORD       _Sleep;
  12.  DWORD       _MessageBox;
  13.  TCHAR       szMessage[100];
  14.  TCHAR       szTitle[20];
  15.  TCHAR       szMessageBoxError[30];
  16.  TCHAR       szDebugEnterRemote[30];
  17.  TCHAR       szDebugExitRemote[30];  
  18. }REMOTEPARAMETER, *PREMOTEPARAMETER;
  19. TCHAR szModuleName[MAX_PATH];
  20. DWORD Process2ID(TCHAR *);
  21. DWORD WINAPI RemoteThread(LPVOID);
  22. BOOL   Zombie(TCHAR * szMessage,TCHAR * szTitle)
  23. {
  24.  MessageBox(NULL,szMessage,szTitle,MB_OK);
  25.  GetModuleFileName(NULL,szModuleName,MAX_PATH);
  26.  MessageBox(NULL,szModuleName,"Module",MB_OK);
  27.  HANDLE            RThread;
  28.  HANDLE            RemoteModuleHandle;
  29.  TCHAR             RemoteModuleName[2][15];
  30.  TCHAR             *RemotePageBaseAddr;
  31.  TCHAR             *RemoteParaBaseAddr;
  32.  DWORD             RemotePID;
  33.  int               nPageSize;
  34.  int               signal;
  35.  HINSTANCE         hKernel32,hUser32;
  36.  REMOTEPARAMETER   remotepara;
  37.  _tcscpy(RemoteModuleName[0],_T("Explorer.exe"));
  38.  _tcscpy(RemoteModuleName[1],_T("Taskmgr.exe"));
  39.  signal=1;
  40.  while(1)
  41.  {
  42.   RemotePID=Process2ID(RemoteModuleName[(++signal)%2]);
  43.   if(RemotePID==-1)
  44.   {
  45.    return NULL;
  46.   }
  47.   else if(RemotePID==0)
  48.   {
  49.    if(signal%2==0)
  50.    {
  51.     OutputDebugString(_T("Remote Process Explorer isn't running/n"));
  52.    }
  53.    else
  54.    {
  55.     OutputDebugString(_T("Remote Process Taskmgr isn't running/n"));
  56.    }
  57.    Sleep(1000);
  58.    continue;
  59.   }
  60.   RemoteModuleHandle=OpenProcess(PROCESS_CREATE_THREAD |    
  61.    PROCESS_VM_OPERATION  |    
  62.    PROCESS_VM_WRITE,          
  63.    FALSE,RemotePID);
  64.   if(RemoteModuleHandle==NULL)
  65.   {
  66.    Sleep(1000);
  67.    continue;
  68.   }
  69.   else
  70.   {
  71.    break;
  72.   }
  73.  }
  74.  nPageSize=sizeof(TCHAR)*4*1024;
  75.  RemotePageBaseAddr=(PTSTR)VirtualAllocEx(RemoteModuleHandle,NULL,nPageSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
  76.  if(RemotePageBaseAddr==NULL)
  77.  {
  78.   OutputDebugString(_T("VirtualAllocEx for Thread Error/n"));
  79.   CloseHandle(RemoteModuleHandle);      
  80.   return NULL;
  81.  }
  82.  if(WriteProcessMemory(RemoteModuleHandle,RemotePageBaseAddr,(LPVOID)RemoteThread,nPageSize,NULL)==FALSE)
  83.  {
  84.   OutputDebugString(_T("WriteProcessMemory for Thread Error/n"));
  85.   CloseHandle(RemoteModuleHandle);
  86.   return NULL;
  87.  }
  88.  memset(&remotepara,0,sizeof(remotepara));
  89.  _tcscpy(remotepara.szDebugEnterRemote,_T("Hello,Magic World!/n"));
  90.  _tcscpy(remotepara.szMessageBoxError,_T("MessageBox() Error/n"));
  91.  _tcscpy(remotepara.szDebugExitRemote,_T("Bye,Cruel World!/n"));
  92.  _tcscpy(remotepara.szMessageBoxError,_T("Sleep() Error/n"));
  93.  _tcscpy(remotepara.szMessage,szMessage);
  94.  _tcscpy(remotepara.szTitle,szTitle);
  95.  hKernel32=GetModuleHandle(_T("kernel32.dll"));
  96.  hUser32=GetModuleHandle(_T("user32.dll"));
  97.  remotepara._OututDebugstring=(DWORD)GetProcAddress(hKernel32,"OutputDebugStringW");
  98.  remotepara._MessageBox=(DWORD)GetProcAddress(hUser32,"MessageBoxExA");
  99.  remotepara._Sleep=(DWORD)GetProcAddress(hKernel32,"Sleep");
  100.  nPageSize=sizeof(TCHAR)*sizeof(remotepara);
  101.  RemoteParaBaseAddr=(PTSTR)VirtualAllocEx(RemoteModuleHandle,NULL,nPageSize,MEM_COMMIT,PAGE_READWRITE);
  102.  if(RemoteParaBaseAddr==NULL)
  103.  {
  104.   OutputDebugString(_T("VirtualAllocEx for Parameter Error/n"));
  105.   CloseHandle(RemoteModuleHandle);
  106.   return NULL;
  107.  }
  108.  if(WriteProcessMemory(RemoteModuleHandle,RemoteParaBaseAddr,(LPVOID)&remotepara,nPageSize,NULL)==FALSE)
  109.  {
  110.   OutputDebugString(_T("WriteProcessMemory for Parameter Error:"));
  111.   CHAR szBuf[80];
  112.   DWORD dw = GetLastError();
  113.      sprintf(szBuf, "WriteProcessMemory failed: GetLastError returned %u/n", dw);
  114.      MessageBox(NULL, szBuf, "Error", MB_OK);
  115.   CloseHandle(RemoteModuleHandle);
  116.   return NULL;
  117.  }
  118.  RThread=CreateRemoteThread(RemoteModuleHandle,NULL,0,(LPTHREAD_START_ROUTINE)RemotePageBaseAddr,(LPVOID)RemoteParaBaseAddr,0,NULL);
  119.  if(RThread==NULL)
  120.  {
  121.   OutputDebugString(_T("CreateRemoteThread Error/n"));
  122.   CloseHandle(RemoteModuleHandle);
  123.   return NULL;
  124.  }
  125.  return true;
  126. }
  127. DWORD Process2ID(TCHAR *processname)
  128. {
  129.  DWORD    lpidprocesses[1024],cbneeded,cprocesses;
  130.  HANDLE   hprocess;
  131.  HMODULE  hmodule;
  132.  UINT     i;
  133.  TCHAR    normalname[MAX_PATH]=_T("UnknownProcess");
  134.  if(!EnumProcesses(lpidprocesses,sizeof(lpidprocesses),&cbneeded))
  135.  {
  136.   OutputDebugString(_T("EnumProcesses Error/n"));
  137.   return -1; 
  138.  }
  139.  cprocesses=cbneeded/sizeof(DWORD);
  140.  for(i=0;i<cprocesses;i++)
  141.  {
  142.   hprocess=OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,lpidprocesses[i]);
  143.   if(hprocess)
  144.   {
  145.    if(EnumProcessModules(hprocess,&hmodule,sizeof(hmodule),&cbneeded))
  146.    {
  147.     GetModuleBaseName(hprocess,hmodule,normalname,sizeof(normalname));
  148.     if(!_tcsicmp(normalname,processname)) 
  149.     {
  150.      CloseHandle(hprocess);
  151.      return (lpidprocesses[i]);
  152.     }
  153.    }
  154.   }
  155.  }
  156.  CloseHandle(hprocess);
  157.  return 0;
  158. }
  159. DWORD WINAPI RemoteThread(LPVOID pvparam)
  160. {
  161.  PREMOTEPARAMETER pRemotePara=(PREMOTEPARAMETER)pvparam;
  162.  int errorcode;
  163.  typedef VOID   (WINAPI *OUTPUTDEBUGSTRING)(LPCTSTR);
  164.  typedef VOID (WINAPI *SLEEP)(DWORD);
  165.  typedef int (WINAPI *MESSAGEBOX)(HWND,LPCTSTR,LPCTSTR,UINT,WORD);
  166.  OUTPUTDEBUGSTRING   _OutputDebugString;
  167.  SLEEP         _Sleep;
  168.  MESSAGEBOX _MessageBox;
  169.  _OutputDebugString=(OUTPUTDEBUGSTRING)pRemotePara->_OututDebugstring;
  170.  _Sleep=(SLEEP)pRemotePara->_Sleep;
  171.  _MessageBox=(MESSAGEBOX)pRemotePara->_MessageBox;
  172.  _OutputDebugString(pRemotePara->szDebugEnterRemote);
  173.  while(1)
  174.  {
  175.   errorcode=_MessageBox(NULL,pRemotePara->szMessage,pRemotePara->szTitle,MB_ICONWARNING,0);
  176.   if(errorcode==0)
  177.   {
  178.    _OutputDebugString(pRemotePara->szMessageBoxError);
  179.    return -1;
  180.   }
  181.   _Sleep(1000*10);
  182.  }
  183.  return 0;
  184. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值