如何卸載其他進程中的DLL。
要卸載其他進程中的DLL一般都要首先提升本進程的權限。相關的操作也很簡單,我已經將其封裝為一個函數

/** *//*********************************************************************/
BOOL BDebugProcess2(HANDLE hProcess, LPCTSTR PrivilegeName)


{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;

if (!OpenProcessToken(hProcess,
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return( FALSE );
LookupPrivilegeValue(NULL,PrivilegeName,
&tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES)NULL, 0);


if(GetLastError()=!ERROR_SUCCESS)


{
::MessageBox(NULL,"所申請的權限全部成功","成功",MB_OK);
return FALSE;
}
return TRUE;
}
*參數說明:hProcess為你想要提升權限的進程句柄,如果要提升本進程的權限只要傳遞GetCurrentProcess()函數即可。
PrivilegeName為你想要申請的權限,一般傳遞SE_DEBUG_NAME參數,說明你要對其他進程的內存空間進行操作。

再提升了自己的進程權限之后就要開始我們的主要操作了,操作分這麼幾步:
1.首先要通過調用 OpenProcess函數獲得宿主進程的句柄,注意給這個函數傳遞的第一個參數要包括PROCESS_CREATE_THREAD,PROCESS_VM_OPERATION,PROCESS_VM_WRITE
。在這說明一下,因為我們要在其他進程進程中創建線程即所謂的遠程線程,所以我們要申請PROCESS_CREATE_THREAD權限。再就是我們要對遠程進程的地址空間進行操作
所以我們要申請PROCESS_VM_OPERATION權限,PROCESS_VM_WRITE申請對進程的地址空間的寫操作權限。
2.我們要將DLL的路徑名寫到遠程線程的地址空間中去。首先要先計算一下DLL路徑名的長路,以確定我們再地址空間中申請多大的空間,
這步操作用strlen,lstrlen等函數都行。知道了DLL路徑名長度以后我們就開始申請空間,調用函數VirtualAllocEx提交一塊指定大小的空間
,然后調用WriteProcessMemory函數將DLL名寫進剛才提交的空間中。以上操作完成以后再遠程線程的地址空間中就存在了DLL名。
3.正式開始創建遠程線程卸載DLL。卸載DLL可以調用FreeLibraryAndExitThread或FreeLibrary函數,這兩個函數都需要一個參數就是DLL模塊的
句柄。而要得到DLL模塊而句柄就需要調用GetModuleHandle函數,所以首先要確定GetModuleHandle的函數指針,然后再遠程進程中創建一個遠程線程
進行GetModuleHandle的調用得到DLL的句柄。之后我們就可以再次創建一個遠程線程調用FreeLibraryAndExitThread或FreeLibrary將DLL卸載掉
,這樣我們就完工了。

完整的操作代碼如下(注:自己實在不想寫,偷懶再網上找的,看完絕的還不錯)

/** *//******************************************************************************/
BOOL UnloadDll(DWORD dwPid, char *strDllName)


{
//獲取宿主進程的句柄,注意那幾個參數,不然會出錯
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,
FALSE, dwPid);

if(hProcess == NULL)
{
::MessageBox(NULL, "無法獲取進程句柄", "錯誤", MB_OK | MB_ICONERROR);
return FALSE;
}

DWORD dwSize = 0;
DWORD dwWritten = 0;
DWORD dwHandle = 0;
dwSize = strlen(strDllName)+ 1;//dll的全路徑名的長度,待會分配內存要用到的

//向宿主進程分配內存,返回一個指針
LPVOID lpBuf = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);

//如果在宿主進程空間寫失敗就直接報錯閃人

if( !WriteProcessMemory(hProcess, lpBuf, (LPVOID)strDllName.GetBuffer(dwSize), dwSize, &dwWritten))
{
VirtualFreeEx(hProcess, lpBuf, dwSize, MEM_DECOMMIT);
CloseHandle(hProcess);
MessageBox(NULL, "在目標進程中寫入失敗", "錯誤", MB_OK | MB_ICONERROR);
return FALSE;
}

//獲取GetModuleHandleA函數地址
LPVOID pFun = GetProcAddress(GetModuleHandle("Kernel32"), "GetModuleHandleA");

//在宿主進程中創建一個遠程線程,線程函數為上面導出的GetModuleHandleA,參數為lpBuf指針,還
//記得我們獲取的dll全路徑不
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFun,
lpBuf, 0, NULL);
//如果創建線程失敗,直接報錯退出

if(hThread == NULL)
{
CloseHandle(hProcess);
::MessageBox(NULL, "在目標進程創建遠程線程失敗", "錯誤", MB_OK | MB_ICONERROR);
return FALSE;
}

// 等待GetModuleHandle運行完畢
WaitForSingleObject(hThread, INFINITE);
// 獲得GetModuleHandle的返回值
GetExitCodeThread(hThread, &dwHandle);

// 釋放目標進程中申請的空間
VirtualFreeEx(hProcess, lpBuf, dwSize, MEM_DECOMMIT);
CloseHandle(hThread);

// 使目標進程調用FreeLibraryAndExit,卸載DLL,實際也可以用FreeLibrary,但是我發現前者好一點
pFun = GetProcAddress(GetModuleHandle("Kernel32"), "FreeLibraryAndExitThread");
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFun,
(LPVOID)dwHandle, 0, NULL);
// 等待FreeLibraryAndExitThread執行完畢
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);

return TRUE; //操作成功

}

/** *//*******************************************************************************************/

再就補充一點,上面的那個函數要求傳遞的參數為進程的ID號,但大多數情況下我們只知道進程的進程名,由進程名得到進程ID號我自己寫了一個
函數如下(注:使用此函數需要包含頭文件<Tlhelp32.h>):
DWORD GetProcessIdFromName(LPCTSTR name,PROCESSENTRY32 * BPE)


{
PROCESSENTRY32 pe;
DWORD id = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
pe.dwSize = sizeof(PROCESSENTRY32);
BOOL PF=FALSE;
for(PF=Process32First(hSnapshot,&pe);PF;PF=Process32Next(hSnapshot,&pe))


{
if(strcmp(pe.szExeFile,name) == 0)

{
id = pe.th32ProcessID;
*BPE=pe;
break;
}
}
CloseHandle(hSnapshot);
return id;
}

好了到這里我們就完全可以使用這些函數寫出一個專門卸載其他進程DLL的小工具了。


posted on 2008-06-14 09:44
楊彬彬 閱讀(2497)
評論(2) 編輯 收藏 引用 所屬分類:
Windows編程