Win32编程之远程注入(十八)

一、VirtualAllocEx函数

VirtualAllocEx 用于在另一个进程的虚拟地址空间中分配内存。这个函数通常与其他进程间内存操作函数一起使用,允许一个进程分配内存并将其映射到另一个进程的地址空间中。

函数原型:

1
2
3
4
5
6
7
LPVOID VirtualAllocEx(
  HANDLE hProcess,
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD  flAllocationType,
  DWORD  flProtect
);

参数:

  • hProcess(HANDLE):

    描述:目标进程的句柄,用于指定在哪个进程中分配内存。
    注意事项:你需要有足够的权限来打开目标进程。

  • lpAddress(LPVOID,可选):

    描述:可选参数,用于指定分配内存的首选地址。如果为 NULL,则系统会选择一个合适的地址。

  • dwSize(SIZE_T):

    描述:要分配的内存大小,以字节为单位。

  • flAllocationType(DWORD):

    描述:内存分配类型,可以是以下值之一:
    MEM_COMMIT:分配内存并提交它,使其可用。
    MEM_RESERVE:仅保留内存地址空间,但不分配物理内存。
    MEM_RESET:重置已经提交的内存区域。

  • flProtect(DWORD):

    描述:内存保护标志,用于指定内存的访问权限,可以是以下值之一:
    PAGE_EXECUTE_READ:可执行代码。
    PAGE_EXECUTE_READWRITE:可读写的可执行代码。
    PAGE_READWRITE:可读写。
    等等,还有其他选项,用于控制内存的保护级别。
返回值:

  • 如果函数成功分配内存,它将返回一个指向分配内存区域的指针(LPVOID),通常是分配内存的起始地址。
  • 如果函数失败,它将返回 NULL。你可以使用 GetLastError 函数来获取详细的错误信息。

二、VirtualFreeEx函数

VirtualFreeEx用于释放在另一个进程的虚拟地址空间中分配的内存。这个函数通常与 VirtualAllocEx 函数一起使用,用于在另一个进程中分配内存并在不再需要时释放它。 

函数原型:

1
2
3
4
5
6
BOOL VirtualFreeEx(
  HANDLE hProcess,
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD  dwFreeType
);

 参数介绍:

  • hProcess:目标进程的句柄,用于指定在哪个进程中释放内存。
  • lpAddress:要释放的内存区域的起始地址。
  • dwSize:要释放的内存大小,以字节为单位。通常,这应该与之前使用 VirtualAllocEx 分配的内存大小相匹配。
  • dwFreeType:内存释放类型,可以是以下值之一:
    1. MEM_DECOMMIT:释放内存并标记为未提交。这个选项允许稍后重新提交。
    2. MEM_RELEASE:释放内存,并从进程的地址空间中删除。这个选项将释放内存并返回系统。

三、WriteProcessMemory函数

WriteProcessMemory用于在另一个进程的虚拟地址空间中写入数据。这个函数通常与 VirtualAllocExReadProcessMemoryCreateRemoteThread 等函数一起使用,允许一个进程向另一个进程写入数据,这在一些应用程序和系统工具中非常有用。 

函数原型:

1
2
3
4
5
6
7
BOOL WriteProcessMemory(
  HANDLE  hProcess,
  LPVOID  lpBaseAddress,
  LPCVOID lpBuffer,
  SIZE_T  nSize,
  SIZE_T  *lpNumberOfBytesWritten
);

参数介绍:

  • hProcess:目标进程的句柄,用于指定在哪个进程中写入数据。
  • lpBaseAddress:目标进程中的起始地址,指定要写入数据的位置。
  • lpBuffer:包含要写入目标进程的数据的缓冲区。
  • nSize:要写入的数据大小,以字节为单位。
  • lpNumberOfBytesWritten:一个指向 SIZE_T 类型的变量指针,用于接收成功写入的字节数。这是一个可选参数,可以为 NULL。

四、ReadProcessMemory函数

ReadProcessMemory 是 Windows 操作系统提供的函数,用于从另一个进程的虚拟地址空间中读取数据。这个函数通常与 WriteProcessMemoryVirtualAllocExCreateRemoteThread 等函数一起使用,允许一个进程从另一个进程读取数据。

函数原型:

1
2
3
4
5
6
7
BOOL ReadProcessMemory(
  HANDLE  hProcess,
  LPCVOID lpBaseAddress,
  LPVOID  lpBuffer,
  SIZE_T  nSize,
  SIZE_T  *lpNumberOfBytesRead
);

参数介绍:

  • hProcess:目标进程的句柄,用于指定从哪个进程中读取数据。
  • lpBaseAddress:目标进程中的起始地址,指定要读取数据的位置。
  • lpBuffer:用于接收从目标进程读取的数据的缓冲区。
  • nSize:要读取的数据大小,以字节为单位。
  • lpNumberOfBytesRead:一个指向 SIZE_T 类型的变量指针,用于接收成功读取的字节数。这是一个可选参数,可以为 NULL。

五、CreateRemoteThread函数

CreateRemoteThread用于在另一个进程的上下文中创建一个新的线程。这个函数通常与其他进程间通信函数如 VirtualAllocExWriteProcessMemoryReadProcessMemory 一起使用,允许一个进程在另一个进程中执行代码。

函数原型:

1
2
3
4
5
6
7
8
9
HANDLE CreateRemoteThread(
  HANDLE                 hProcess,
  LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  SIZE_T                 dwStackSize,
  LPTHREAD_START_ROUTINE lpStartAddress,
  LPVOID                 lpParameter,
  DWORD                  dwCreationFlags,
  LPDWORD                lpThreadId
);

参数介绍:

  • hProcess:目标进程的句柄,用于指定在哪个进程中创建线程。
  • lpThreadAttributes:一个指向 SECURITY_ATTRIBUTES 结构的指针,用于指定新线程的安全属性,通常可以设置为 NULL。
  • dwStackSize:新线程的堆栈大小,通常可以设置为 0。
  • lpStartAddress:新线程的起始地址,即要在目标进程中执行的函数指针。
  • lpParameter:传递给新线程的参数,通常可以设置为 NULL。
  • dwCreationFlags:线程创建标志,通常可以设置为 0。
  • lpThreadId:一个指向 DWORD 类型的变量指针,用于接收新线程的标识。这是一个可选参数,可以为 NULL。

六、OpenProcess函数  

OpenProcess用于打开一个已存在进程的句柄,以便后续进行与该进程相关的操作,如读取或写入其内存、查看其线程、以及执行其他与进程有关的任务。

函数原型:

1
2
3
4
5
HANDLE OpenProcess(
  DWORD dwDesiredAccess,
  BOOL  bInheritHandle,
  DWORD dwProcessId
);

参数介绍:

  • dwDesiredAccess:指定要打开的进程的访问权限。这是一个标志位,可以指定多个权限选项,如下所示的一些常见选项:

    1. PROCESS_ALL_ACCESS:具有对进程的完全访问权限,包括读取、写入、执行、终止等。
    2. PROCESS_VM_READ:允许读取进程的虚拟内存。
    3. PROCESS_VM_WRITE:允许写入进程的虚拟内存。
    4. PROCESS_QUERY_INFORMATION:允许获取进程信息。
  • bInheritHandle:一个布尔值,指定句柄是否可以被子进程继承。通常可以设置为 FALSE。

  • dwProcessId:目标进程的进程标识符(PID),用于指定要打开的进程。

七、远程注入

1.进程注入的示例源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <Windows.h>
#include <TlHelp32.h>
#include <stdio.h>
 
DWORD getMainThreadIdFormName(const WCHAR* szName) {
    DWORD idProcess = 0; //进程ID
 
    PROCESSENTRY32 pe; //进程信息
    pe.dwSize = sizeof(PROCESSENTRY32);
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //获取系统进程列表快照
    if (Process32First(hSnapshot, &pe)) {
        //返回系统中第一个进程的信息
        do {
            if (_wcsicmp(pe.szExeFile, szName) == 0) {
                idProcess = pe.th32ProcessID;
                break;
            }
        } while (Process32Next(hSnapshot, &pe)); //下一个进程
    }
    CloseHandle(hSnapshot); //删除快照
 
    return idProcess;
}
 
int main() {
    DWORD idProcess = getMainThreadIdFormName(TEXT("WinInjection.exe"));
    if (idProcess == 0) {
        return 0;
    }
 
    printf("Process id:%d\n", idProcess);
 
   HANDLE hProcess =  OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, idProcess);
   if (hProcess == NULL) {
       printf("OpenProcess failed...\n");
 
       return 0;
   }
 
   char dllName[] = "mydll.dll";
   DWORD dllSize = strlen(dllName) + 1;
   DWORD dwWritten = 0;
   LPVOID lpBuf = VirtualAllocEx(hProcess, NULL, strlen(dllName) + 1, MEM_COMMIT, PAGE_READWRITE);
   if (lpBuf == NULL) {
       CloseHandle(hProcess);
       printf("VirtualAllocEx failed...\n");
 
       return 0;
   }
 
   if (WriteProcessMemory(hProcess, lpBuf, (LPCVOID)dllName, dllSize, &dwWritten)) {
       if (dwWritten != dllSize) {
           VirtualFreeEx(hProcess, lpBuf, dllSize, MEM_DECOMMIT);
           CloseHandle(hProcess);
       }
   } else {
       printf("WriteProcessMemory failed..\n");
       CloseHandle(hProcess);
 
       return 0;
   }
 
   DWORD dwID;
   LPVOID pFunc = LoadLibraryA;
   HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &dwID);
   if (hThread == NULL) {
       printf("CreateRemoteThread failed\n");
       VirtualFreeEx(hProcess, lpBuf, dllSize, MEM_DECOMMIT);
       CloseHandle(hProcess);
 
       return 0;
   }
 
   WaitForSingleObject(hThread, INFINITE);
 
   VirtualFreeEx(hProcess, lpBuf, dllSize, MEM_DECOMMIT);
   CloseHandle(hThread);
   CloseHandle(hProcess);
 
   return 1;
}

2.dll测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
 
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        ::MessageBox(NULL, L"dll attach", L"dll", MB_OK);
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        ::MessageBox(NULL, L"dll detach", L"dll", MB_OK);
        break;
    }
    return TRUE;
}

3.创建一个Win32的桌面应用程序(WinInjection.exe)并运行,然后再运行远程注入的代码

其效果如下:

posted @   TechNomad  阅读(396)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示