0x01.前言
提到Dll的注入,立马能够想到的方法就有很多,比如利用远程线程、Apc等等,这里我对Ring3层的Dll注入学习做一个总结吧。
我把注入的方法分成六类,分别是:1.创建新线程、2.设置线程上下背景文,修改寄存器、3.插入Apc队列、4.修改注册表、5.挂钩窗口消息、6.远程手动实现LoadLibrary。
那么下面就开始学习之旅吧!
0x02.预备工作
在涉及到注入的程序中,提升程序的权限自然是必不可少的,这里我提供了两个封装的函数,都可以用于提权。第一个是通过权限令牌来调整权限;第二个是通过ntdll.dll的导出的未文档化函数RtlAdjustPrivilege来调整权限。
// 传入参数 SE_DEBUG_NAME,提升到调试权限BOOL GrantPriviledge(WCHAR* PriviledgeName){TOKEN_PRIVILEGES TokenPrivileges, OldPrivileges;DWORD dwReturnLength = sizeof(OldPrivileges);HANDLE TokenHandle = NULL;LUID uID;// 打开权限令牌if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &TokenHandle)){if (GetLastError() != ERROR_NO_TOKEN){return FALSE;}if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle)){return FALSE;}}if (!LookupPrivilegeValue(NULL, PriviledgeName, &uID)) // 通过权限名称查找uID{CloseHandle(TokenHandle);return FALSE;}TokenPrivileges.PrivilegeCount = 1; // 要提升的权限个数TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // 动态数组,数组大小根据Count的数目TokenPrivileges.Privileges[0].Luid = uID;// 在这里我们进行调整权限if (!AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), &OldPrivileges, &dwReturnLength)){CloseHandle(TokenHandle);return FALSE;}// 成功了CloseHandle(TokenHandle);return TRUE;}
紧接着,既然我们要对目标进程注入Dll,那么获得目标进程的Id是不可或缺的吧,因为OpenProcess是肯定会使用的,这里我也提供了两种通过目标进程映像名称获得进程Id的方法。第一种是最常见的使用TlHelp创建系统的进程快照;第二种是借助Psapi枚举系列函数,不过这个方法我实现的有缺憾,32位下不能得到64位进程的Id。
// 使用ToolHelp系列函数#include <TlHelp32.h>BOOL GetProcessIdByProcessImageName(IN PWCHAR wzProcessImageName, OUT PUINT32 ProcessId){HANDLE ProcessSnapshotHandle = INVALID_HANDLE_VALUE;PROCESSENTRY32 ProcessEntry32 = { 0 };ProcessEntry32.dwSize = sizeof(PROCESSENTRY32); // 初始化PROCESSENTRY32结构ProcessSnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // 给系统所有的进程快照if (ProcessSnapshotHandle == INVALID_HANDLE_VALUE){return FALSE;}if (Process32First(ProcessSnapshotHandle, &ProcessEntry32)) // 找到第一个{do{if (lstrcmpi(ProcessEntry32.szExeFile, wzProcessImageName) == 0) // 不区分大小写{*ProcessId = ProcessEntry32.th32ProcessID;break;}} while (Process32Next(ProcessSnapshotHandle, &ProcessEntry32));}CloseHandle(ProcessSnapshotHandle);ProcessSnapshotHandle = INVALID_HANDLE_VALUE;if (*ProcessId == 0){return FALSE;}return TRUE;}// 使用Psapi系列枚举函数#include <Psapi.h>BOOL GetProcessIdByProcessImageName(IN PWCHAR wzProcessImageName, OUT PUINT32 ProcessId){DWORD dwProcessesId[1024] = { 0 };DWORD BytesReturned = 0;UINT32 ProcessCount = 0;// 获得当前操作系统中的所有进程Id,保存在dwProcessesId数组里if (!EnumProcesses(dwProcessesId, sizeof(dwProcessesId), &BytesReturned)){return FALSE;}ProcessCount = BytesReturned / sizeof(DWORD);// 遍历for (INT i = 0; i < ProcessCount; i++){HMODULE ModuleBase = NULL;WCHAR wzModuleBaseName[MAX_PATH] = { 0 };HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessesId[i]);if (ProcessHandle == NULL){continue;}if (EnumProcessModulesEx(ProcessHandle, &ModuleBase, sizeof(HMODULE), &BytesReturned, LIST_MODULES_ALL)){// 获得进程第一模块名称GetModuleBaseName(ProcessHandle, ModuleBase, wzModuleBaseName, MAX_PATH * sizeof(WCHAR));}CloseHandle(ProcessHandle);ProcessHandle = NULL;if (lstrcmpi(wzModuleBaseName, wzProcessImageName) == 0) // 不区分大小写{*ProcessId = dwProcessesId[i];break;}}if (*ProcessId == 0){return FALSE;}return TRUE;}
新闻热点
疑难解答