卸载其他进程中的模块/dll

本文介绍了一种在不重启计算机的情况下从指定进程中卸载DLL的方法。通过创建远程线程并调用FreeLibrary来实现,避免了因挂接DLL而频繁重启的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       前段时间做了一个东西,在所有进程中都挂接了自己的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会执行失败,导致被注入的进程崩溃
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值