32 位程序对 64 位进程的远程注入实现

发布于 2024-10-13 17:50:41 字数 8536 浏览 7 评论 0

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:

  1. http://blog.rewolf.pl/blog/
  2. 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,接着尝试远程注入,弹出对话框,如图

Alt text

  • 将程序编译成 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 进行注入

回显如图

Alt text

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. 运行测试程序

命令行输出如图

Alt text

成功执行 payload:"cmd /c start calc.exe",弹出计算器

0x05 小结

本文介绍了 32 位程序对 64 位进程远程注入的实现方法,参照以上代码可实现 Windows 32 位/64 位系统下进程注入的通用模板。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

旧伤慢歌

暂无简介

0 文章
0 评论
529 人气
更多

推荐作者

安静被遗忘

文章 0 评论 0

喔爱吃橙子

文章 0 评论 0

草莓味的萝莉

文章 0 评论 0

梦里兽

文章 0 评论 0

mb_83J3Cyxa

文章 0 评论 0

时间海

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文