DLL卸载
DLL卸载(DLL Ejection)是将强制插入进程的DLL弹出的一种技术,原理是驱使目标进程调用FreeLibrary() API,即将FreeLibrary() API的地址传递给CreateRemoteThread()的lpStartAddress参数并把要卸载的DLL的句柄传递给lpParameter参数。
注意:使用FreeLibrary() API实现DLL卸载,仅适用于卸载自己强制注入的DLL文件。PE文件直接导入的DLL文件是无法在进程运行过程中卸载的。
编写DLL卸载程序
下面编写针对之前DLL注入编写的InjectDll.exe和myhack.dll的DLL卸载程序EjectDll.exe程序。当然想卸载指定进程的指定DLL文件时只需修改代码中常量定义部分即可。
//EjectDll.cpp #include "windows.h" #include "tchar.h" #include "tlhelp32.h" //定义目标进程名和目标DLL文件名常量 #define DEF_PROC_NAME (L"notepad.exe") #define DEF_DLL_NAME (L"myhack.dll") //查看设置权限 BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege){ TOKEN_PRIVILEGES tp; HANDLE hToken; LUID luid; //获取进程Token if( !OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken) ){ _tprintf(L"[-]OpenProcessToken error: %u\n", GetLastError()); return FALSE; } //查看本地系统的权限值 if ( !LookupPrivilegeValue(NULL, lpszPrivilege, &luid) ){ _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; } //启用特权或禁用所有特权 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; } //查找目标进程ID DWORD FindProcessID(LPCTSTR szProcessName){ DWORD dwPID = 0xFFFFFFFF; HANDLE hSnapShot = INVALID_HANDLE_VALUE; PROCESSENTRY32 pe; //获取系统快照 pe.dwSize = sizeof( PROCESSENTRY32 ); hSnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPALL, NULL ); //遍历查找目标进程 Process32First(hSnapShot, &pe); do{ if( !_tcsicmp(szProcessName, (LPCTSTR)pe.szExeFile) ){ dwPID = pe.th32ProcessID; break; } }while( Process32Next(hSnapShot, &pe) ); CloseHandle(hSnapShot); return dwPID; } //卸载DLL BOOL EjectDll(DWORD dwPID, LPCTSTR szDllName){ BOOL bMore = FALSE; BOOL bFound = FALSE; HANDLE hSnapshot; HANDLE hProcess; HANDLE hThread; HMODULE hModule = NULL; MODULEENTRY32 me = { sizeof(me) }; LPTHREAD_START_ROUTINE pThreadProc; //获取加载到进程的所有模块(DLL)信息 hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID); //循环遍历所有模块信息,查找是否存在目标DLL文件 bMore = Module32First(hSnapshot, &me); for( ; bMore; bMore = Module32Next(hSnapshot, &me) ){ if( !_tcsicmp((LPCTSTR)me.szModule, szDllName) || !_tcsicmp((LPCTSTR)me.szExePath, szDllName) ){ bFound = TRUE; break; } } //查找不到指定进程中的指定的DLL文件时,退出程序 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"); //在目标进程中创建远程线程并运行线程函数 //me.modBaseAddr参数是要卸载的DLL的加载地址 hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL); WaitForSingleObject(hThread, INFINITE); //关闭句柄 CloseHandle(hThread); CloseHandle(hProcess); CloseHandle(hSnapshot); return TRUE; } int _tmain(int argc, TCHAR* argv[]){ DWORD dwPID = 0xFFFFFFFF; //寻找目标进程ID dwPID = FindProcessID(DEF_PROC_NAME); if( dwPID == 0xFFFFFFFF ){ _tprintf(L"[-]Can't find the process <%s>.\n", DEF_PROC_NAME); return 1; } _tprintf(L"[*]The PID of <\"%s\"> is %d\n", DEF_PROC_NAME, dwPID); //设置权限 if( !SetPrivilege(SE_DEBUG_NAME, TRUE) ){ return 1; } //卸载DLL if( EjectDll(dwPID, DEF_DLL_NAME) ){ _tprintf(L"[+]Eject DLL(%d, \"%s\") success!!!\n", dwPID, DEF_DLL_NAME); }else{ _tprintf(L"[-]Eject DLL(%d, \"%s\") failed!!!\n", dwPID, DEF_DLL_NAME); } return 0; }
先打开notepad.exe程序,打开Process Explorer查看notepad.exe程序的PID,然后运行InjectDll.exe向notepad.exe进程注入myhack.dll:
接着运行EjectDll.exe卸载myhack.dll,再到Process Explorer查看:
可以看到,notepad.exe进程的myhack.dll已经被卸载成功。
文章来源: DLL卸载