发布时间:2025-12-09 13:42:05 浏览次数:4
CreateRemoteThread和WriteProcessMemory技术
示例程序:WinSpy
另一种注入代码到其他进程地址空间的方法是使用WriteProcessMemory API。这次你不用编写一个独立的DLL而是直接复制你的代码到远程进程(WriteProcessMemory)并用CreateRemoteThread执行之。
让我们看一下CreateRemoteThread的声明:
HANDLECreateRemoteThread(和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例程-初学者必看
//
//
==========定义一个代码结构,本例为一个对话框============
struct
MyData
{
char
sz[
64
];
//
对话框显示内容
DWORDdwMessageBox;
//
对话框的地址
};
//
==========远程线程的函数==============================
DWORD__stdcallRMTFunc(MyData
*
pData)
{
typedef
int
(__stdcall
*
MMessageBox)(HWND,LPCTSTR,LPCTSTR,UINT);
MMessageBoxMsgBox
=
(MMessageBox)pData
->
dwMessageBox;
MsgBox(NULL,pData
->
sz,NULL,MB_OK);
return
0
;
}
int
main(
int
argc,
char
*
argv[])
{
//
=====获得需要创建REMOTETHREAD的进程句柄===============================
HWNDhWnd
=
FindWindow(
“
notepad
“
,NULL);
//
以NOTEPAD为例
DWORDdwProcessId;
::GetWindowThreadProcessId(hWnd,
&
dwProcessId);
HANDLEhProcess
=
OpenProcess(
PROCESS_ALL_ACCESS,
FALSE,
dwProcessId);
//
=========代码结构================================================
MyDatadata;
ZeroMemory(
&
data,
sizeof
(MyData));
strcat(data.sz,
“
对话框的内容.
“
);
HINSTANCEhUser
=
LoadLibrary(
“
user32.dll
“
);
if
(
!
hUser)
{
printf(
“
Cannotloadlibrary.
“
);
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
;
//
===========创建远程线程===========================================
HANDLEhThread
=
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(
“
HelloWorld!
“
);
return
0
;
}
zhuangyu1982@hotmail.com:我用你的程序在windowsxp下运行,弹出messagebox之后,只要点击确定宿主进程就会崩溃。
而且不止是messagebox,调用其它的api函数也是一样,请问这是什么原因?有什么办法可以解决吗?
——————————————————–
编译成RELEASE版本就不会出错了,主要是DEBUG版本加了一个__chkesp的函数导致调用了非法地址