前段时间做了一个东西,在所有进程中都挂接了自己的DLL,结果每次要重新编译DLL让其运行都需要重启计算机,这下可有点郁闷, 得想想办法手动卸载了这些DLL,因此变有了这个程序
原理:
通过在指定的进程中创建远程线程,然后在线程中调用FreeLibrary把相应的模块卸载就OK了,就这么简单,废话就不多说了,代码中我已经给出详尽的注释了
// FreeModule.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

#define MAX_MODULE_NAME_LEN 16

// 传入到远程线程中的参数结构定义
typedef struct tagThreadParam

...{
DWORD dwFreeLibrary; // FreeLibrary 地址
DWORD dwGetModuleHandle; // GetModuleHandle 地址
TCHAR szModuleName[MAX_MODULE_NAME_LEN];// 需要卸载的模块的名称
}ThreadParam,*PThreadParam;



/**//*
远程线程函数
*/
void RemoteThreadFun(PThreadParam PParam)

...{
DWORD dwFreeLibrary;
DWORD dwGetModuleHandle;
DWORD dwModuleName;

dwFreeLibrary = PParam->dwFreeLibrary;
dwGetModuleHandle = PParam->dwGetModuleHandle;
dwModuleName = (DWORD)PParam->szModuleName;
// 释放的最高次数
DWORD dwCount = 100;

// 循环寻找指定模块的句柄,如果找到,那么调用FreeLibrary释放,
// 直到该模块被释放
__asm

...{
START:
push dwModuleName; // 模块名称压栈
call dwGetModuleHandle; // 调用GetModuleHandle
test eax,eax; //
jz OVER; // 没有找到模块返回
dec dwCount;
jz OVER; // 达到最高次数
push eax; // 模块句柄压栈
call dwFreeLibrary; // 调用FreeLibrary
test eax,eax;
jnz START;
OVER:
}
return;
}


/**//*
调整权限
*/
bool AdjustPurview()

...{
TOKEN_PRIVILEGES TokenPrivileges;
bool bRet;
HANDLE hToken;

LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &TokenPrivileges.Privileges[0].Luid);
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
TokenPrivileges.PrivilegeCount = 1;
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bRet = !!AdjustTokenPrivileges(hToken, FALSE, &TokenPrivileges, 0, NULL, NULL);

CloseHandle(hToken);
return bRet ;
}

BOOL FreeModuleByPid(TCHAR * szModuleName,DWORD dwPid)

...{
// 参数构造

ThreadParam Param = ...{0};
Param.dwFreeLibrary = (DWORD)FreeLibrary;
Param.dwGetModuleHandle = (DWORD)GetModuleHandleA;
MoveMemory(Param.szModuleName,szModuleName,MAX_MODULE_NAME_LEN);

// 打开指定的进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwPid);
if(hProcess==NULL)

...{
OutputDebugString(_T("OpenProcess failed!!"));
return FALSE;
}

// 参数写入
LPVOID lpParam = NULL;
lpParam = VirtualAllocEx(hProcess,NULL,sizeof(Param),MEM_COMMIT,PAGE_READWRITE);
if (lpParam == NULL)

...{
return FALSE;
}
if (!WriteProcessMemory(hProcess,lpParam,&Param,sizeof(Param),0))

...{
VirtualFreeEx(hProcess,lpParam,0,MEM_RELEASE);
return FALSE;
}

// 函数写入
LPVOID lpThread = NULL;
lpThread = VirtualAllocEx(hProcess,NULL,0x100,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if (lpThread == NULL)

...{
return FALSE;
}
if (!WriteProcessMemory(hProcess,lpThread,RemoteThreadFun,0x100,0))

...{
VirtualFreeEx(hProcess,lpThread,0,MEM_RELEASE);
return FALSE;
}
// 创建线程
HANDLE hThread = NULL;
hThread = CreateRemoteThread(hProcess,0,0,(LPTHREAD_START_ROUTINE)lpThread,lpParam,0,NULL);
if(hThread == NULL)

...{
return FALSE;
}

// 等待线程结束
WaitForSingleObject(hThread,INFINITE);

// 清理工作
VirtualFreeEx(hProcess,lpThread,0,MEM_RELEASE);
VirtualFreeEx(hProcess,lpParam,0,MEM_RELEASE);
CloseHandle(hProcess);

return TRUE;
}

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)

...{
AdjustPurview();
TCHAR * szModuleName = _T("AcroIEHelper.dll");
DWORD dwPid = 1128;
FreeModuleByPid(szModuleName,dwPid);
return 0;
}

我只是演示了向某一个进程(pid为1128)卸载
AcroIEHelper.dll,还有一个值得注意的地方,我在函数写入的地方,在WriteProcessMemory的最后一个参数给的是PAGE_EXECUTE_READWRITE,必须有EXECUTE的权限,不然在一些升级之后的XP SP2会执行失败,导致被注入的进程崩溃