DLL注入总体介绍
一.DLL注入应用:
-
改善功能与修复Bug:可以使用DLL注入技术为程序添加新功能(类似于插件),或者修改有问题的代码、数据等。
-
消息钩取:windows os自带的消息钩取功能就是一种dll注入技术,它自带了一些dll文件,我们只需要编写函数将其注入就可以。比如说后面会提到的键盘消息钩取。
-
监视、管理应用程序的使用:类似手机中常见的青少年模式,比如,用来阻止特定程序(像游戏、股票交易等)运行、禁止访问有害网站,以及监视PC的使用等。
-
恶意代码:不法分子通过把自己编写的恶意代码隐藏到正常进程中,施放dll文件,开启后门端口,进行窃取用户信息、篡改注册表,强制安装病毒等恶意操作。
二.DLL注入手法:
- APC注入
- message注入
- 注册表注入
- 远程线程注入
- 输入法注入
- LSP注入
三.常用API函数和结构体
-
OpenProcess函数:
用于打开进程
HANDLE OpenProcess( DWORD dwDesiredAccess,//访问权限 BOOL bInheritHandle,//是否继承句柄 DWORD dwProcessId//打开进程的id ); //例如: HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); if (NULL == hProcess) { OutputDebugString("Cannot open this process.\n"); return -1; }
-
CreateToolhelp32Snapshot函数:
创建一个进程快照,获得当前运行的进程列表,这个函数通常用于获得进程PId。
HANDLE CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID); /* 参数说明: dwFlags:指定要创建的快照类型。可以是以下值的组合: THCS_SNAPALL:获取所有进程和线程的信息。 进程信息。 TH32CS_SNAPTHREAD:仅获取线程信息。 TH32CS_SNAPMODULE:仅获取模块信息。 th32ProcessID:可选参数,指定要获取信息的进程ID。如果不指定,将获取所有进程的信息。 返回值: 如果成功,返回一个句柄,表示创建的快照。 如果失败,返回NULL。 /*
-
Process32Next函数:
Process32Next
是一个 Windows API 函数,用于遍历系统中所有运行的进程。它需要两个参数:一个进程快照句柄和一个指向PROCESSENTRY32
结构体的指针。当函数成功时,它会更新结构体中的字段以反映下一个进程的信息,并返回非零值;如果已经到达快照的末尾,则返回零。int GetPidByProcessName(const char* ProcessName) { HANDLE Processes = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,NULL); PROCESSENTRY32 ProcessInfo = { 0 }; ProcessInfo.dwSize = sizeof(PROCESSENTRY32); while (Process32Next(Processes, &ProcessInfo)) { if (strcmp(ProcessInfo.swExeFile, ProcessName) == 0) { return ProcessInfo.th32ProcessID; } } return -1; } //使用进程快照和进程遍历函数,得到已知名称进程的PID。
-
VirtualAllocEx函数:
该函数可以在目标进程空间申请一块内存空间
LPVOID VirtualAllocEx( HANDLE hProcess,//要申请的进程 LPVOID lpAddress,//申请内存的所在地址,传入null可以自动寻址 SIZE_T dwSize,//申请内存的大小 DWORD flAllocationType,//申请的内存空间类型 DWORD flProtect//内存保护量 );
-
WriteProcessMemory函数:
WriteProcessMemory可以向指定的内存地址中写入数据
BOOL WriteProcessMemory( HANDLE hProcess,//进程句柄 LPVOID lpBaseAddress,//要写入的目标地址 LPCVOID lpBuffer,//待写入数据 SIZE_T nSize,//写入数据的大小 SIZE_T *lpNumberOfBytesWritten );
-
GetModuleHandleA函数:
GetModuleHandle函数根据模块名称得到模块的句柄
HMODULE GetModuleHandleA( LPCSTR lpModuleName//模块名 );
-
GerProcAddress函数:
GetProcAddress函数可以根据函数名来得到模块中的一个导出函数的地址
FARPROC GetProcAddress( HMODULE hModule,//模块句柄 LPCSTR lpProcName//导出函数名 ); //返回值:导出函数的地址
-
CreateRemoteThread函数:
CreateRemoteThread用于在指定进程的虚拟空间中开启一个线程
注意:CreateRemoteThread可以在指定的外部进程中创建并启动新的线程,而CreateThread只能在当前进程中创建新的线程
HANDLE CreateRemoteThread( HANDLE hProcess,//目标进程句柄 LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,//线程执行函数地址 LPVOID lpParameter,//线程函数的参数 DWORD dwCreationFlags, LPDWORD lpThreadId );
-
LoadLibrary函数:
HMODULE WINAPI LoadLibraryW (LPCWSTR lpLibFileName)//参数lpFileName是模块的名称
-
PROCESSENTRY32
typedef struct tagPROCESSENTRY32 { DWORD dwSize;//表示结构体的大小,单位为字节 DWORD cntUsage;//表示进程的使用计数 DWORD th32ProcessID;//表示进程的标识符(PID) ULONG_PTR th32DefaultHeapID;//表示进程使用的默认堆的标识符 DWORD th32ModuleID;//表示进程加载的第一个模块的标识符 DWORD cntThreads;//表示进程中线程的数量 DWORD th32ParentProcessID;//表示进程中线程的数量 LONG pcPriClassBase;//表示进程的优先级基址 DWORD dwFlags;//表示进程的标志位 CHAR szExeFile[MAX_PATH];//表示进程可执行文件的完整路径,最大长度为MAX_PATH } PROCESSENTRY32; typedef PROCESSENTRY32 *PPROCESSENTRY32; typedef PROCESSENTRY32 *LPPROCESSENTRY32;