第24章:DLL卸载
DLL卸载是通过调用 FreeLibrary() API.
每个内核对象( Kernel Object )都拥有一个引用计数( Reference Count ),代表对象的被使用的次数.
使用LoadLibrary() 会 +1, FreeLibrary() 会 -1.FreeLibrary() 仅适用于卸载自己强制注入的DLL文件,PE文件导入的无法在进程运行过程中卸载的.
// EjectDll.exe #include "windows.h" #include "tlhelp32.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; // Get the snapshot of the system pe.dwSize = sizeof( PROCESSENTRY32 ); hSnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPALL, NULL ); // find process Process32First(hSnapShot, &pe); do { if(!_tcsicmp(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; 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; } } 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; } hModule = GetModuleHandle(L"kernel32.dll"); pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary"); hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, me.modBaseAddr, 0, NULL); WaitForSingleObject(hThread, INFINITE); //与前面加载DLL是一样的操作 CloseHandle(hThread); CloseHandle(hProcess); CloseHandle(hSnapshot); return TRUE; } int _tmain(int argc, TCHAR* argv[]) { DWORD dwPID = 0xFFFFFFFF; // find 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); // change 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\") failed!!!\n", dwPID, DEF_DLL_NAME); return 0; }
大致看看,知道流程就行.