32 位程序对 64 位进程的远程注入实现
0x00 前言
要对指定进程进行远程注入,通常使用 Windows 提供的 API CreateRemoteThread 创建一个远程线程,进而注入 dll 或是执行 shellcode。
在 64 位系统下,该方法需要特别注意,注入的目标进程要同程序的结构保持一致,即 32 位程序只能对 32 进程作注入,64 位程序只能对 64 位进程作注入
32 位程序对 64 位程序进行注入时会失败(32 位和 64 位的结构不同)
然而,在某些特殊的环境下,无法提前预知目标进程的结构,准备两个不同版本的程序又不现实
所以只能重新思考这个问题:
32 位程序真的无法对 64 位程序进行远程注入吗?
0x01 简介
我在 odzhan 的博客里找到了解决思路,文章地址如下:https://modexp.wordpress.com/2015/11/19/dllpic-injection-on-windows-from-wow64-process/
本文将会介绍实现思路,参考 odzhan 的开源工程"pi",编写测试代码,生成 32 位程序,实现对 64 位进程 calc.exe 的进程注入,验证 32 位程序能够对 64 进程作注入的结论
0x02 实现思路
1、32 位程序支持对 64 位程序的读写
参考资料:
rgb/29a:http://www.vxheaven.org/lib/vrg02.html
ReWolf:
2、 利用 CreateRemoteThread 作进程注入的通用方法
进程注入流程:
- OpenProcess
- VirtualAllocEx
- WriteProcessMemory
- VirtualProtectEx
- CreateRemoteThread
- WaitForSingleObject
在具体的实现过程中,如果指定了进程名称,需要先将进程名称转换为进程 ID,参考代码如下:
DWORD processNameToId(LPCTSTR lpszProcessName)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnapshot, &pe)) {
MessageBox(NULL,"The frist entry of the process list has not been copyied to the buffer","Notice", MB_ICONINFORMATION | MB_OK);
return 0;
}
while (Process32Next(hSnapshot, &pe)) {
if (!strcmp(lpszProcessName, pe.szExeFile)) {
return pe.th32ProcessID;
}
}
return 0;
}
依次实现如下操作:
- 根据进程 ID 打开进程,获得进程句柄
- 申请内存空间
- 写入数据
- 将内存改为可读可执行(可选)
- 创建线程
- 等待线程退出(可选)
代码可参考:http://blog.csdn.net/g710710/article/details/7303081
对参考代码作细微修改,将注入进程名称指定为 calc.exe,完整代码已上传 github,地址如下:https://github.com/3gstudent/CreateRemoteThread/blob/master/CreateRemoteThreadTest.cpp
程序运行后,查找进程 calc.exe,接着尝试远程注入,弹出对话框,如图
- 将程序编译成 x86,对 32 位的进程 calc.exe 进行注入,成功
- 将程序编译成 x64,对 64 位的进程 calc.exe 进行注入,成功
- 将程序编译成 x86,对 64 位的进程 calc.exe 进行注入,OpenProcess、VirtualAllocEx、WriteProcessMemory、VirtualProtectEx 均正常,执行 CreateRemoteThread 时会报错
解决思路:
参考 rgb/29a 和 ReWolf 的思路,将此处的 CreateRemoteThread 切换为 64 位后再创建线程,完成后再切换回 32 位,即可实现 32 位程序对 64 位进程的远程注入
3、判断当前系统是 32 位还是 64 位
使用 API:
void WINAPI GetNativeSystemInfo(
_Out_ LPSYSTEM_INFO lpSystemInfo
);
查看结构体中的 wProcessorArchitecture 可获得 CPU 架构,进而判断操作系统
代码如下:
#include <windows.h>
BOOL Is64BitOS()
{
typedef VOID (WINAPI *LPFN_GetNativeSystemInfo)( __out LPSYSTEM_INFO lpSystemInfo );
LPFN_GetNativeSystemInfo fnGetNativeSystemInfo = (LPFN_GetNativeSystemInfo)GetProcAddress( GetModuleHandle("kernel32"),"GetNativeSystemInfo");
if(fnGetNativeSystemInfo)
{
SYSTEM_INFO stInfo = {0};
fnGetNativeSystemInfo( &stInfo);
if( stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64
|| stInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
{
return TRUE;
}
}
return FALSE;
}
int main()
{
if (Is64BitOS())
printf("x64\n");
else
printf("x86\n");
return 0;
}
4、判断注入的进程是 32 位还是 64 位
查找进程 ID,打开进程,获得句柄,使用 API,传入参数,进行判断
使用 API:
BOOL WINAPI IsWow64Process(
__in HANDLE hProcess,
__out PBOOL Wow64Process
);
返回 true, 代表进程是 32 位,否则是 64 位
完整代码如下:
#include <windows.h>
#include <TlHelp32.h>
BOOL IsWow64(HANDLE hProcess)
{
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;
BOOL bIsWow64 = FALSE;
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
GetModuleHandle("kernel32"),"IsWow64Process");
if (NULL != fnIsWow64Process)
{
fnIsWow64Process(hProcess, &bIsWow64);
}
return bIsWow64;
}
DWORD processNameToId(LPCTSTR lpszProcessName)
{
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe;
pe.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnapshot, &pe)) {
MessageBox(NULL,
"The frist entry of the process list has not been copyied to the buffer","Notice", MB_ICONINFORMATION | MB_OK);
return 0;
}
while (Process32Next(hSnapshot, &pe)) {
if (!strcmp(lpszProcessName, pe.szExeFile)) {
return pe.th32ProcessID;
}
}
return 0;
}
int main()
{
BOOL bWow64;
char *szExeName="calc.exe";
DWORD dwProcessId = processNameToId(szExeName);
if (dwProcessId == 0) {
MessageBox(NULL, "The target process have not been found !","Notice", MB_ICONINFORMATION | MB_OK);
return -1;
}
HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (!hTargetProcess) {
MessageBox(NULL, "Open target process failed !",
"Notice", MB_ICONINFORMATION | MB_OK);
return 0;
}
bWow64 = IsWow64(hTargetProcess);
if(bWow64)
printf("32-bit process\n");
else
printf("64-bit process\n");
}
5、开源工程 pi
下载地址:https://github.com/odzhan/shellcode/tree/master/win/pi
usage: pi [options] <proc name | proc id>
-d Wait after memory allocation before running thread
-e <cmd> Execute command in context of remote process (shows window)
-f <file> Load a PIC file into remote process
-l <dll> Load a DLL file into remote process
-p List available processes on system
-x <cpu> Exclude process running in cpu mode, 32 or 64
examples:
pi -e "cmd /c echo this is a test > test.txt & notepad test.txt" -x32 iexplore.exe
pi -l ws2_32.dll notepad.exe
pi -f reverse_shell.bin chrome.exe
测试系统:Win7x64
cmd 执行:pi32.exe -e "cmd /c start calc.exe" -x32 calc.exe
上述命令将对 64 位的 calc.exe 进行注入
回显如图
payload 没有成功执行
0x03 最终代码
虽然 pi 测试失败,但是代码值得参考,提取关键代码,开发测试程序
测试程序结构如下:
判断当前系统
- 如果为 32 位系统, 调用系统 api CreateRemoteThread,对目标进程尝试远程注入,弹出对话框
- 如果为 64 位系统,进入下一个分支,对进程判断
判断进程 calc.exe
- 如果为 32 位,调用系统 api CreateRemoteThread,对目标进程尝试远程注入,弹出对话框
- 如果为 64 位,调用自定义 api CreateRemoteThread64,对目标进程尝试远程注入,执行 payload:"cmd /c start calc.exe"
完整代码已上传 github,下载地址如下:https://github.com/3gstudent/CreateRemoteThread/blob/master/CreateRemoteThread32to64.cpp
0x04 实际测试
测试系统:
Win7 x64
- 将程序编译成 32 位,打开 64 位 calc.exe
- 运行测试程序
命令行输出如图
成功执行 payload:"cmd /c start calc.exe",弹出计算器
0x05 小结
本文介绍了 32 位程序对 64 位进程远程注入的实现方法,参照以上代码可实现 Windows 32 位/64 位系统下进程注入的通用模板。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 渗透技巧 —— 隐藏_注册表的更多测试
下一篇: Covenant 利用分析
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论