DLL文件名注入进程
VirtualAllocEx函数 (processthreadsapi.h)
官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex?redirectedfrom=MSDN
保留、提交或更改指定进程的虚拟地址空间中内存区域的状态。该函数初始化它分配的内存。如果函数成功,则返回值是页面分配区域的基址。
LPVOID VirtualAllocEx(
[in] HANDLE hProcess,
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);
参数 | 作用 |
---|---|
[in] hProcess | 进程的句柄。该函数在进程的虚拟地址空间中分配内存。句柄必须具有 PROCESS_VM_OPERATION 访问权限。 |
[in, optional] lpAddress | 为要分配的页面区域指定所需起始地址的指针。如果要保留内存,该函数会将此地址舍入到分配粒度中最近的倍数。 |
[in] dwSize | 要分配的内存区域的大小(以字节为单位)。 |
[in] flAllocationType | 内存分配的类型。 |
[in] flProtect | 要分配的页面区域的内存保护。 |
mem = VirtualAllocEx(process, NULL, wcslen(dllPath) * sizeof(wchar_t), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
在这个程序中flAllocationType的取值为MEM_COMMIT、MEM_RESERVE,其含义主要是:
-
MEM_COMMIT:为指定的保留内存页分配内存费用(从内存的总体大小和磁盘上的分页文件);
-
MEM_RESERVE:保留进程的虚拟地址空间范围,而无需在内存或磁盘上的分页文件中分配任何实际物理存储。
注意:为 enclave 分配动态内存时,flProtect 参数必须 PAGE_READWRITE 或 PAGE_EXECUTE_READWRITE。
WriteProcessMemory 函数 (memoryapi.h)
官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory?redirectedfrom=MSDN
将数据写入到指定进程中的内存区域。要写入的整个区域必须可访问,否则操作将失败。
BOOL WriteProcessMemory(
[in] HANDLE hProcess,
[in] LPVOID lpBaseAddress,
[in] LPCVOID lpBuffer,
[in] SIZE_T nSize,
[out] SIZE_T *lpNumberOfBytesWritten
);
参数 | 含义 |
---|---|
[in] hProcess | 要修改的进程内存的句柄。句柄必须具有对进程的PROCESS_VM_WRITE和PROCESS_VM_OPERATION访问权限。 |
[in] lpBaseAddress | 指向将数据写入到的指定进程中基址的指针。在进行数据传输之前,系统会验证指定大小的基址和内存中的所有数据是否可供写入访问,如果无法访问,则函数将失败。 |
[in] lpBuffer | 指向缓冲区的指针,该缓冲区包含要写入指定进程的地址空间中的数据。 |
[in] nSize | 要写入指定进程的字节数。 |
[out] lpNumberOfBytesWritten | 指向变量的指针,该变量接收传输到指定进程的字节数。此参数是可选的。如果 lpNumberOfBytesWritten 为 NULL,则忽略参数。 |
根据dll名称远程加载DLL
createRemoteThread 函数 (processthreadsapi.h)
官方文档:https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread?redirectedfrom=MSDN
创建在另一个进程的虚拟地址空间中运行的线程。
HANDLE CreateRemoteThread(
[in] HANDLE hProcess,
[in] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] SIZE_T dwStackSize,
[in] LPTHREAD_START_ROUTINE lpStartAddress,
[in] LPVOID lpParameter,
[in] DWORD dwCreationFlags,
[out] LPDWORD lpThreadId
);
参数 | 含义 |
---|---|
[in] hProcess | 要在其中创建线程的进程句柄。句柄必须具有 PROCESS_CREATE_THREAD、 PROCESS_QUERY_INFORMATION、 PROCESS_VM_OPERATION、 PROCESS_VM_WRITE和 PROCESS_VM_READ 访问权限,并且在某些平台上没有这些权限可能会失败。 |
[in] lpThreadAttributes | 指向 SECURITY_ATTRIBUTES 结构的指针,该结构指定新线程的安全描述符,并确定子进程是否可以继承返回的句柄。如果 lpThreadAttributes 为 NULL,则线程将获取默认安全描述符,并且无法继承句柄。访问控制在来自创建者主令牌的线程的默认安全描述符中列出 (ACL) 。 |
[in] dwStackSize | 堆栈的初始大小(以字节为单位)。系统将此值舍入到最近的页。如果此参数为 0 (零) ,则新线程将使用可执行文件的默认大小。 |
[in] lpStartAddress | 指向 LPTHREAD_START_ROUTINE要由 线程执行的应用程序定义函数的指针,表示远程进程中线程的起始地址。函数必须存在于远程进程中。 |
[in] lpParameter | 指向要传递给线程函数的变量的指针. |
[in] dwCreationFlags | 控制线程创建的标志。 |
[out] lpThreadId | 指向接收线程标识符的变量的指针。 |
dwCreationFlags控制线程创建的标志选项:
值 | 含义 |
---|---|
0 | 线程在创建后立即运行。 |
CREATE_SUSPENDED0x00000004 | 线程以挂起状态创建,在调用ResumeThread 函数之前不会运行。 |
STACK_SIZE_PARAM_IS_A_RESERVATION0x00010000 | dwStackSize 参数指定堆栈的初始保留大小。如果未指定此标志, dwStackSize 将指定提交大小。 |
// 1. 使用 VirtualAllocEx 根据dllPath路径的大小申请空间
LPVOID mem = NULL;
mem = VirtualAllocEx(process, NULL, wcslen(dllPath) * sizeof(wchar_t), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!mem) {
_putts(TEXT("VirtualAllocEx error"));
return 0;
}
// 2. 使用 WriteProcessMemory 向申请的空间中写入dllpath的值
if (!WriteProcessMemory(process, mem, dllPath, wcslen(dllPath) * sizeof(wchar_t), NULL)) {
DisplayErrorMessage((LPTSTR)"WriteProcessMemory error: ", GetLastError());
return 0;
}
// 3. 调用CreateRemoteThread在process进程上执行加载dllpath上的dll
HANDLE thread = NULL;
thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, mem, 0, NULL);
if (!thread) {
_putts(TEXT("CreateRemoteThread error"));
return 0;
}
WaitForSingleObject(thread, INFINITE);
VirtualFreeEx(process, mem, 0, MEM_RELEASE);
CloseHandle(thread);
CloseHandle(process);
原文始发于微信公众号(蟹堡安全团队):通过远程线程注入DLL源码分析
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论