实验 4 代码注入技术
引言
1、实验说明
代码注入是将用户代码注入到其他进程或者可执行文件中,实现拦截目标进程运行过程的关键信息、改变目标进程或可执行文件原本执行流程等目的
2、实验目的
本实验通过远程线程和输入表注入,向目标进程注入代码、向目标 PE 文件注入 DLL,以加深对代码注入技术的理解。
3、实验原理
-
在目标进程中申请内存并写入待注入DLL的路径,然后调用
CreateRemoteThread,在目标中创建线程;线程函数地址为LoadLibrary(A/W),线程参数便是存放DLL路径的内存首地址 -
调用CreateRemoteThread需要目标进程句柄作刀梦数,此N而得到在目标进程中创建线程(PRoCES>CKEAlP_I11nEA)、r '存(PROCESS_VM_WRITE)等多项权限
-
“远程”线程是和CreateThread相对的,匹程纹任疋巧进性主利线程,创建的线程不属于当前进程
-
使用LoadLibrarv作为线程函数较为方便,因为不考虑返回值和参数类型的情况下,二者有相同的函数原型,如下所示:
HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName); DWORD WINAPI ThreadProc(LPVOID lpParameter);
-
远程线程注入过程需要在目标进程空间申请内存,存储线程执行时所需的参数等数据
-
VirtualAllocEx:在指定进程中申请内存空间
-
WriteProcessMemory:向指定进程的指定虚拟内存地址写入数据
//获取目标进程的句柄
HANDLE hProc =OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwTargetPid),
//在目标进程申请空间存储DLL完整路径
LPTSTR pDllFile =(LPTSTR)VirtualAllocEx(hProc, NULL, lstrlen(DllPath)+1,MEM_COMMIT, PAGE_READWRITE);
//将DLL路径写入目标进程申请的内存中
WriteProcessMemory(hProc, pDllFile, DllPath, lstrlen(DllPath)+1, NULL)
//获取LoadLibraryA的入口地址
HMODULE hKernel = GetModuleHandle("Kernel32");
PTHREAD_START_ROUTINE pfnStartAddr = GetProcAddress(hKernel,"LoadLibraryA");
//创建远程线程调用LoadLibrary
CreateRemoteThread(hProc, NULL,0, pfnStartAddr, pDllFile,0, NULL);
区别
原理和远程线程注入DLL原理相似,区别是:
-
线程执行对象不同:即线程函数不同,注入DLL时创建远程线程执行LoadLibrary(A/W)函数,而注入代码时执行用户实现的这部分代码
-
目标进程空间存储对象不同:注入DLL时在目标进程中申请的内存空间用于存储DLL路径,而注入代码存储的是作为线程函数的这部分代码,以及线程函数的参数
远程线程注入代码注意事项:
- 注入代码定位:包括如何确定代码的起始位置和代码的长度,这决定
了向目标进程写入什么内容、写入多少字节 - 注入代码实现:注入代码是要在目标进程中执行,因此创建该代码主体中的全局变量、堆内存、本地自定义函数等均无法使用,使用系统API则不受限制
4、实验环境
Windows 7 系统、Visual Studio 6.0 及以上版本
关于Windows 7 的选择,建议大家使用 带Service Pack1的X86系统,镜像下载网站.这样能够在使用WM ware时安装WMtools,实现内容文件的直接复制,方便快捷,是32位系统。
迅雷下载号:
ed2k://|file|hk_windows_7_home_premium_with_sp1_x86_dvd_620848.iso|2621298688|33CB0040A929656DC1BE176E3FF8F00E|/
5、实验内容
(1)远程线程注入
(2)利用 Detours 实现输入表注入
(3)DLL 劫持
远程线程注入
1创建 Win32 应用程序项目
打开 VS,选择空项目模板,创建 Win32 应用程序,然后向新建项目中添加源程序文件 InjectCode.cpp(附件已提供)。
源代码
#include <windows.h>
#include <stdio.h>
typedef struct _THREAD_PARAM
{
FARPROC pFunc[2]; // LoadLibraryA(), GetProcAddress()
char szBuf[4][128]; // "user32.dll", "MessageBoxA", "text", "caption"
} THREAD_PARAM, PTHREAD_PARAM;
typedef HMODULE(WINAPI pfnLoadLibrary)(LPCSTR lpLibFileName);
typedef xx(WINAPI pfnGetProcAddress)(xx, xx);
typedef xx (WINAPI pfnMsgBox)(xx, xx, xx, xx);
BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
printf("OpenProcessToken error:%d\n", GetLastError());
return FALSE;
}
LUID luid;
if (!LookupPrivilegeValue(NULL, lpszPrivilege, &luid))
{
printf("LookupPrivilegeValue error:%d\n", GetLastError());
return FALSE;
}
TOKEN_PRIVILEGES NewState;
NewState.PrivilegeCount = 1;
NewState.Privileges[0].Luid = luid;
if (bEnablePrivilege)
NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
NewState.Privileges[0].Attributes = 0;
if (!AdjustTokenPrivileges(hToken, FALSE, &NewState, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
{
printf("AdjustTokenPrivileges error:%d\n", GetLastError());
return FALSE;
}
return TRUE;
}
DWORD WINAPI ThreadProc(LPVOID lParam)
{
PTHREAD_PARAM pParam = (PTHREAD_PARAM)lParam;
// "user32.dll"
HMODULE hMod = ((pfnLoadLibrary)pParam->pFunc[0])(pParam->szBuf[0]);
if (!hMod)
return 1;
// "MessageBoxA"
pfnMsgBox pFunc = (pfnMsgBox)((pfnGetProcAddress)pParam->pFunc[1])(hMod, pParam->szBuf[1]);
if (!pFunc)
return 1;
pFunc(NULL, pParam->szBuf[2], pParam->szBuf[3], MB_OK);
return 0;
}
BOOL InjectCode(DWORD dwPID)
{
HANDLE hProcess = OpenProcess(xx, xx, xx);
if (!hProcess)
{
printf("OpneProcess Error:%d\n",