DLL卸载的工作原理
主要来说与DLL注入类似,DLL注入是驱使目标进程调用LoadLibrary() API,DLL卸载则是驱动目标进程调用FreeLibrary() API:
- 将FreeLibrary() API的地址传递给CreatRemoteThread()的lpStartAddress参数
- 将要卸载的DLL的句柄传递给lpParameter参数
引用指数:记录DLL被调用的次数,卸载时也要卸载相同的次数。
实现DLL卸载
- EjectDll.exe
#include "windows.h"
#include "tjhelp32.h"
#include "tchar.h"
#define DEF_PROC_NAME(L"notepad.exe")
#define DEF_DLL_NAME (L"myhack.dll")
DWORD FindProcessID(LPCTSTR szProcessName){
DWORD dwPID=0xFFFFFFFF;
HANDLE hSnapShot=INVALID_HANDLE_VALUE;
PROCESSENTRY32 pe;
//获取系统快照(Snapshot)
pe.dwSize=sizeof(PROCESSENTRY32);
hSnapShot=CreateToolhelp32Snapshot(TH32CS_SNAPALL,NULL);
//查找进程
Process32First(hSnapShot, &pe);
do{
if(!_tcs/Picmp(szProcessName, (LPCTSTR)pe.szExeFile)){
dwPID=pe.th32ProcessID;
break;
}
}
while(Process32Next(hSnapShot, &pe));
CloseHandle(hSnapShot);
return dwPID;
}
BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege){
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)){
_tprintf(L"OpenProcessToken error: %u\n", GetLastError());
return FALSE;
}
if(!LookupPrivilegeValue(NULL, //lookup privilege on local system
lpszPrivilege, //privilege to lookup
&luid)){ //receives LUID of privilege
_tprintf(L"LookupPrivilegeValue error: %u\n", GetLastError());
return FALSE;
}
tp.PrivilegeCount=1;
tp.Privileges[0].Luid=luid;
if(bEnablePrivilege)
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes=0;
//Enable the privilege or disable all privileges
if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL)){
_tprintf(L"AdjustTokenPrivileges error: %u\n", GetLastError());
return FALSE;
}
if(GetLastError()==ERROR_NOT_ALL_ASSIGNED){
_tprintf(L"The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
BOOL EjectDll(DWORD dwPID, LPCTSTR szDllName){
BOOL bMore=FALSE, bFound=FALSE;
HANDLE hSnapshot,hProcess, hThread;
HMODULE hModule=NULL;
MODULEENTRY32 me={sizeof(me)};
LPTHREAD_START_ROUTINE pThreadProc;
//dwPID=notepad进程ID
//使用TH32CS_SNAPMODULE参数,获取加载到notepad进程的DLL名称
hSnapshot=CreateToolhelp32Snapshot(TH32CS-SNAPMODULE, dwPID);
bMore=Module32First(hSnopshot, &me);
for(; bMore; bMore=Module32Next(hSnapshot, &me)){ //对dll进行比较
if(!_tcsicmp((LPCTSTR)me.szModule, szDllName) || !_tcsicmp((LPCTSTR)me.szExePath, szDllName)){ //szModule代表DLL的名称
bFound=TRUE;
break;
}
}
if(!bFound){
CloseHandle(hSnapshot);
return FALSE;
}
//获取目标进程的句柄
if(!(hProcess=OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID))){
_tprintf(L"OpenProcess(%d) failed !!! [%d]\n", dwPID, GetLastError());
return FALSE;
}
//获取FreeLibrary() API地址
hModule=GetModuleHandle(L"kernel32.dll");
pThreadProc=(LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary");
//在目标进程中运行线程
hThread=CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL); //pThreadProc为FreeLibrary() API的地址,me.modBaseAddr是要卸载的DLL的加载地址
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
CloseHandle(hSnapshot);
return TRUE;
}
int _tmain(int argc, TCHAR* argv[]){
DWORD dwPID=0xFFFFFFFF;
//查找process
dwPID=FindProcessID(DEF_PROC_NAME);
if(dwPID==0xFFFFFFFF){
_tprintf(L"There is no %s process!\n", DEF_PROC_NAME);
return 1;
}
_tprintf(L"PID of \"%s\" is %d\n", DEF_PROC_NAME, dwPID);
//更改privilege
if(!SetPrivilege(SE_DEBUG_NAME, TRUE))
return 1;
//eject dll
if(EjectDll(dwPID, DEF_DLL_NAME))
_tprintf(L"EjectDll(%d, \"%s\") success!!!\n", dwPID, DEF_DLL_NAME);
else
_tprintf(L"EjectDll(%d, \"%s\") gailed!!!\n", dwPID, DEF_DLL_NAME);
return 0;
}
使用FreeLibrary()的方法仅适用于卸载自己强制注入的DLL文件,PE文件直接导入的DLL文件是无法在进程运行过程中卸载的。
参考文献
《逆向工程核心原理》
来源:CSDN
作者:你的名字5686
链接:https://blog.csdn.net/wk19951125/article/details/104358646