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:
http://blog.rewolf.pl/blog/
https://github.com/rwfpl/rewolf-wow64ext
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
1、将程序编译成32位,打开64位calc.exe
2、运行测试程序
命令行输出如图
成功执行payload:”cmd /c start calc.exe”,弹出计算器
0x05 小结
本文介绍了32位程序对64位进程远程注入的实现方法,参照以上代码可实现Windows 32位/64位系统下进程注入的通用模板。