代码注入是一种向目标进程插入独立运行代码并使之运行的技术,一般调用CreateRemoteThread()API以远程线程形式运行插入的代码,所以也被称为线程注入。
首先向目标进程插入代码和数据,在此过程中,代码以线程过程形式插入,而代码中使用的数据则以线程参数的形式传入,也就是说代码与数据是分别注入的。
// CodeInjection.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "windows.h"
#include "stdio.h"
#include "windef.h"
typedef struct _THREAD_PARAM
{
//FARPROC是一个(int FAR WINAPI*)()类型的指针
FARPROC pFunc[2]; // LoadLibraryA(), GetProcAddress()
char szBuf[4][128]; // "user32.dll", "MessageBoxA",
// "www.reversecore.com", "ReverseCore"
} THREAD_PARAM, *PTHREAF_PARAM;
// LoadLibraryA() 函数指针PFLOADLIBRARYA
typedef HMODULE (WINAPI *PFLOADLIBRARYA)(LPCSTR lpLibFileName);
// GetProcAddress()
typedef FARPROC (WINAPI *PFGETPROCADDRESS)
(
HMODULE hModule,
LPCSTR lpProcName
);
// MessageBoxA()
typedef int (WINAPI *PFMESSAGEBOXA)
(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType
);
// Thread Procedure
DWORD WINAPI ThreadProc(LPVOID lParam)
{
PTHREAF_PARAM pParam = (PTHREAF_PARAM)lParam;
HMODULE hMod = NULL;
FARPROC pFunc = NULL;
// LoadLibraryA("user32.dll")
// pParam->pFunc[0] -> kernel32!LoadLibraryA()
// pParam->szBuf[0] -> "user32.dll"
hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]);
// GetProcAddress("MessageBoxA")
// pParam->pFunc[1] -> kernel32!GetProcAddress()
// pParam->szBuf[1] -> "MessageBoxA"
pFunc = (FARPROC)((PFGETPROCADDRESS)pParam->pFunc[1])(hMod,
pParam->szBuf[1]);
// MessageBoxA(NULL, "www...", "ReverseCore", MB_OK)
// pParam->szBuf[2] = "www..."
// pParam->szBuf[3] = "ReverseCore"
((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], MB_OK);
return 0;
}
BOOL InjectCode(DWORD dwPID)
{
HMODULE hMod = NULL;
THREAD_PARAM param = { 0, };
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
LPVOID pRemoteBuf[2] = { 0, };
DWORD dwSize = 0;
hMod = GetModuleHandleA("kernel32.dll");
param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");
strcpy_s(param.szBuf[0], "user32.dll");
strcpy_s(param.szBuf[1], "MessageBoxA");
strcpy_s(param.szBuf[2], "www.reversecore.com");
strcpy_s(param.szBuf[3], "ReverseCore");
// OpenProcess
hProcess = OpenProcess(PROCESS_ALL_ACCESS,
FALSE,
dwPID);
// Allocation for THREAD_PRARM
dwSize = sizeof(THREAD_PARAM);
pRemoteBuf[0] = VirtualAllocEx(hProcess,
NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
if (pRemoteBuf[0] == NULL)
{
printf("VirtualAllocEx failed\n");
return FALSE;
}
if (!WriteProcessMemory(hProcess,
pRemoteBuf[0], (LPVOID)¶m, dwSize, NULL))
{
printf("WriteProcessMemory failed\n");
return FALSE;
}
// Allocation for ThreadProc
dwSize = (DWORD)InjectCode - (DWORD)ThreadProc;
printf("dwSize: %d\n", dwSize);
pRemoteBuf[1] = VirtualAllocEx(hProcess, NULL, dwSize,
MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 这里注意要有可执行权限
if (pRemoteBuf[1] == NULL)
{
printf("VirtualAllocEx failed\n");
return FALSE;
}
if (!WriteProcessMemory(hProcess, pRemoteBuf[1],
(LPVOID)ThreadProc, dwSize, NULL))
{
printf("WriteProcessMemory failed\n");
return FALSE;
}
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)pRemoteBuf[1],
pRemoteBuf[0],
0,
NULL);
if (hThread == NULL)
{
printf("CreateRemoteThread failed\n");
return FALSE;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
int main(int argc, char *argv[])
{
DWORD dwPID = 0;
if (argc != 2)
{
printf("\n usage: %s PID\n", argv[0]);
return 1;
}
dwPID = (DWORD)atol(argv[1]);
InjectCode(dwPID);
return 0;
}
执行的时候注意要生成release
版本,因为MS Virual C++中使用Release模式编译程序代码后,源代码中函数顺序与二进制代码中的顺序是一致的,所以代码中的InjectCode-ThreadProc
才可以表示ThreadProc函数的大小。
将PID设置成notepad.exe的PID时,结果如下:
网友评论