您的位置:首页 > 其它

A brief on using CreateRemoteThread

2004-12-14 21:55 441 查看
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:

// zombie.cpp :
// Usage: Zombie(szMessage,szTitle);
#include "zombie.h"
#pragma comment(lib, "Psapi.lib")

#define UNICODE
#define _UNICODE
#define _RemoteProcess
typedef struct _remoteparameter
{
DWORD _OututDebugstring;
DWORD _Sleep;
DWORD _MessageBox;
TCHAR szMessage[100];
TCHAR szTitle[20];
TCHAR szMessageBoxError[30];
TCHAR szDebugEnterRemote[30];
TCHAR szDebugExitRemote[30];
}REMOTEPARAMETER, *PREMOTEPARAMETER;

TCHAR szModuleName[MAX_PATH];

DWORD Process2ID(TCHAR *);
DWORD WINAPI RemoteThread(LPVOID);
BOOL Zombie(TCHAR * szMessage,TCHAR * szTitle)
{
MessageBox(NULL,szMessage,szTitle,MB_OK);
GetModuleFileName(NULL,szModuleName,MAX_PATH);
MessageBox(NULL,szModuleName,"Module",MB_OK);
HANDLE RThread;
HANDLE RemoteModuleHandle;
TCHAR RemoteModuleName[2][15];
TCHAR *RemotePageBaseAddr;
TCHAR *RemoteParaBaseAddr;
DWORD RemotePID;
int nPageSize;
int signal;
HINSTANCE hKernel32,hUser32;
REMOTEPARAMETER remotepara;

_tcscpy(RemoteModuleName[0],_T("Explorer.exe"));
_tcscpy(RemoteModuleName[1],_T("Taskmgr.exe"));
signal=1;
while(1)
{
RemotePID=Process2ID(RemoteModuleName[(++signal)%2]);
if(RemotePID==-1)
{
return NULL;
}
else if(RemotePID==0)
{
if(signal%2==0)
{
OutputDebugString(_T("Remote Process Explorer isn't running/n"));
}
else
{
OutputDebugString(_T("Remote Process Taskmgr isn't running/n"));
}
Sleep(1000);
continue;
}
RemoteModuleHandle=OpenProcess(PROCESS_CREATE_THREAD |
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE,
FALSE,RemotePID);
if(RemoteModuleHandle==NULL)
{
Sleep(1000);
continue;
}
else
{
break;
}
}

nPageSize=sizeof(TCHAR)*4*1024;
RemotePageBaseAddr=(PTSTR)VirtualAllocEx(RemoteModuleHandle,NULL,nPageSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if(RemotePageBaseAddr==NULL)
{
OutputDebugString(_T("VirtualAllocEx for Thread Error/n"));
CloseHandle(RemoteModuleHandle);
return NULL;
}
if(WriteProcessMemory(RemoteModuleHandle,RemotePageBaseAddr,(LPVOID)RemoteThread,nPageSize,NULL)==FALSE)
{
OutputDebugString(_T("WriteProcessMemory for Thread Error/n"));
CloseHandle(RemoteModuleHandle);
return NULL;
}
memset(&remotepara,0,sizeof(remotepara));
_tcscpy(remotepara.szDebugEnterRemote,_T("Hello,Magic World!/n"));
_tcscpy(remotepara.szMessageBoxError,_T("MessageBox() Error/n"));
_tcscpy(remotepara.szDebugExitRemote,_T("Bye,Cruel World!/n"));
_tcscpy(remotepara.szMessageBoxError,_T("Sleep() Error/n"));
_tcscpy(remotepara.szMessage,szMessage);
_tcscpy(remotepara.szTitle,szTitle);
hKernel32=GetModuleHandle(_T("kernel32.dll"));
hUser32=GetModuleHandle(_T("user32.dll"));
remotepara._OututDebugstring=(DWORD)GetProcAddress(hKernel32,"OutputDebugStringW");
remotepara._MessageBox=(DWORD)GetProcAddress(hUser32,"MessageBoxExA");
remotepara._Sleep=(DWORD)GetProcAddress(hKernel32,"Sleep");

nPageSize=sizeof(TCHAR)*sizeof(remotepara);
RemoteParaBaseAddr=(PTSTR)VirtualAllocEx(RemoteModuleHandle,NULL,nPageSize,MEM_COMMIT,PAGE_READWRITE);
if(RemoteParaBaseAddr==NULL)
{
OutputDebugString(_T("VirtualAllocEx for Parameter Error/n"));
CloseHandle(RemoteModuleHandle);
return NULL;
}

if(WriteProcessMemory(RemoteModuleHandle,RemoteParaBaseAddr,(LPVOID)&remotepara,nPageSize,NULL)==FALSE)
{
OutputDebugString(_T("WriteProcessMemory for Parameter Error:"));
CHAR szBuf[80];
DWORD dw = GetLastError();
sprintf(szBuf, "WriteProcessMemory failed: GetLastError returned %u/n", dw);
MessageBox(NULL, szBuf, "Error", MB_OK);
CloseHandle(RemoteModuleHandle);
return NULL;
}

RThread=CreateRemoteThread(RemoteModuleHandle,NULL,0,(LPTHREAD_START_ROUTINE)RemotePageBaseAddr,(LPVOID)RemoteParaBaseAddr,0,NULL);
if(RThread==NULL)
{
OutputDebugString(_T("CreateRemoteThread Error/n"));
CloseHandle(RemoteModuleHandle);
return NULL;
}
return true;
}

DWORD Process2ID(TCHAR *processname)
{
DWORD lpidprocesses[1024],cbneeded,cprocesses;
HANDLE hprocess;
HMODULE hmodule;
UINT i;
TCHAR normalname[MAX_PATH]=_T("UnknownProcess");

if(!EnumProcesses(lpidprocesses,sizeof(lpidprocesses),&cbneeded))
{
OutputDebugString(_T("EnumProcesses Error/n"));
return -1;
}
cprocesses=cbneeded/sizeof(DWORD);
for(i=0;i<cprocesses;i++)
{
hprocess=OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,FALSE,lpidprocesses[i]);
if(hprocess)
{
if(EnumProcessModules(hprocess,&hmodule,sizeof(hmodule),&cbneeded))
{
GetModuleBaseName(hprocess,hmodule,normalname,sizeof(normalname));
if(!_tcsicmp(normalname,processname))
{
CloseHandle(hprocess);
return (lpidprocesses[i]);
}
}
}

}
CloseHandle(hprocess);
return 0;
}

DWORD WINAPI RemoteThread(LPVOID pvparam)
{
PREMOTEPARAMETER pRemotePara=(PREMOTEPARAMETER)pvparam;
int errorcode;
typedef VOID (WINAPI *OUTPUTDEBUGSTRING)(LPCTSTR);
typedef VOID (WINAPI *SLEEP)(DWORD);
typedef int (WINAPI *MESSAGEBOX)(HWND,LPCTSTR,LPCTSTR,UINT,WORD);
OUTPUTDEBUGSTRING _OutputDebugString;
SLEEP _Sleep;
MESSAGEBOX _MessageBox;

_OutputDebugString=(OUTPUTDEBUGSTRING)pRemotePara->_OututDebugstring;
_Sleep=(SLEEP)pRemotePara->_Sleep;
_MessageBox=(MESSAGEBOX)pRemotePara->_MessageBox;

_OutputDebugString(pRemotePara->szDebugEnterRemote);
while(1)
{
errorcode=_MessageBox(NULL,pRemotePara->szMessage,pRemotePara->szTitle,MB_ICONWARNING,0);
if(errorcode==0)
{
_OutputDebugString(pRemotePara->szMessageBoxError);
return -1;
}
_Sleep(1000*10);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: