DLL卸载
@author: dlive
EjectDll.cpp
主要看一下EjectDll这个函数
//dwPID是notepad.exe的PID
//szDllName是dll的名称
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;
// 使用TH32CS_SNAPMOUDLE参数,获取加载到notepad进程的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;
}
}
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");
//使用FreeLibrary卸载DLL仅适用于使用CreateRemoteThread注入的DLL文件
//PE文件直接导入的DLL文件是无法在进程运行过程中卸载的
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary");
hThread = CreateRemoteThread(hProcess, NULL, 0,
pThreadProc, me.modBaseAddr,
0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
CloseHandle(hSnapshot);
return TRUE;
}
MOUDLEENTRY32结构体
typedef struct tagMODULEENTRY32 {
DWORD dwSize;
DWORD th32ModuleID;
DWORD th32ProcessID;
DWORD GlblcntUsage;
DWORD ProccntUsage;
BYTE *modBaseAddr; //DLL被加载的地址(虚拟内存),即dll的句柄
DWORD modBaseSize;
HMODULE hModule;
TCHAR szModule[MAX_MODULE_NAME32 + 1]; //DLL的名称
TCHAR szExePath[MAX_PATH];
} MODULEENTRY32, *PMODULEENTRY32;
FindProcessID函数
以后用到类似功能的时候可以直接粘贴过去用XD
//参数为进程名,如L"notepad.exe"
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;
}
卸载DLL需要注意的一点:DLL引用计数
每个Windows内核对象都有一个引用计数(Reference Count),代表对象被使用的次数。
调用10次LoadLibrary("a.dll"),a.dll的引用计数就变为10,卸载a.dll时同样需要调用10次FreeLibrary,每次调用FreeLibrary引用计数都会减1。
卸载DLL时需要充分考虑好引用计数这个因素。
注:本博客文章转载需带上原文链接