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时需要充分考虑好引用计数这个因素。

posted @ 2017-01-25 16:56  dlive  阅读(605)  评论(0编辑  收藏  举报