远程注入DLL并自动显示DLL的窗口

来源:互联网 发布:易烊千玺长相知乎 编辑:程序博客网 时间:2024/06/14 18:37

以前也可以注入并显示窗口,但是一旦卸载则会导致宿主进程也被关闭,今天终于搞定卸载注入的DLL后不影响宿主进程。

源码在http://wooddoor.ys168.com的VC目录下的“远程注入、卸载.rar”【VC2008的工程】

注入器源码部分:

#include <tlhelp32.h>

namespace pathfileFun
{
    //**************************************************************  
    //*  GetCurrentDirectory得到的不一定是应用程序所在的目录!要得到应用程序所在的目录,这里有一个函数:
    //*函数名:     GetAppPath()  
    //*  
    //*  
    //*返回值         CString                     -   返回路径的形式是   C:/temp/      
    //功能               -   得到应用程序所在的路径,保存到strPathBuffer中  
    //*  
    //**************************************************************  
    inline CString WINAPI GetAppPath()
    {
        CString strPathBuffer;
        TCHAR PathBuffer[MAX_PATH];
        GetModuleFileName(AfxGetInstanceHandle(), PathBuffer, MAX_PATH);
        strPathBuffer.Format(_T("%s"),PathBuffer);
        CString strAppPath=strPathBuffer.Mid(0,strPathBuffer.ReverseFind(_T('//'))+1);
        return strAppPath;
    };
    //格式化路径,使得路径统一成以“/”结尾
    inline CString FormatPath(CString strPath)
    {
        if ( strPath.Right(1) != _T("//") )
            strPath += _T("//");
        return strPath;
    };
    //从文件的全路径中获取文件所在的文件夹路径,返回的路径以“/”结尾
    inline CString GetPathFromFile(CString FilePath)
    {
        return FilePath.Mid(0,FilePath.ReverseFind(_T('//'))+1);
    };
    //从文件的全路径中获取文件名(含后缀)
    inline CString GetFileNameFromFilePath(CString FilePath)
    {
        return FilePath.Right(FilePath.GetLength() - FilePath.ReverseFind(_T('//'))+1);
    };
}

 

//===========================================


//调整进程权限
bool EnablePrivilege(TCHAR* PrivilegeName,BOOL IsEnable)
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ,&hToken))
    {
        return false;
    }
    if(!LookupPrivilegeValue(NULL, PrivilegeName, &luid))
    {
        return false;
    }
    tp.PrivilegeCount           = 1;
    tp.Privileges[0].Luid       = luid;
    tp.Privileges[0].Attributes = (IsEnable) ? SE_PRIVILEGE_ENABLED : 0;
    BOOL bSucc = AdjustTokenPrivileges(hToken,FALSE,&tp,NULL,NULL,NULL);
    CloseHandle(hToken);
    return (GetLastError() == ERROR_SUCCESS);
}
//将指定dll注入指定进程
bool HookProcess(DWORD dwProcessId,CStringA szDllPath)
{

    HANDLE hRemoteProcess    = NULL;
    HANDLE hRemoteThread     = NULL;
    HANDLE hRemoteFunc        = NULL;
    PVOID  pRemoteParam              = NULL;
    DWORD  dwWriten                   = 0;
    BOOL   bRet                      = FALSE;

    char   szDllPathCopy[256] = {0};
    lstrcpyA(szDllPathCopy,szDllPath);

    EnablePrivilege(SE_DEBUG_NAME,true);
    hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessId);

    if(hRemoteProcess == NULL)
    {
        EnablePrivilege(SE_DEBUG_NAME,false);
        return false;
    }
    int iSize = (int)strlen(szDllPath);
    pRemoteParam = VirtualAllocEx(hRemoteProcess,NULL,iSize,MEM_COMMIT,PAGE_READWRITE);
    if(pRemoteParam == NULL)
    {
        EnablePrivilege(SE_DEBUG_NAME,false);
        return false;
    }
    bRet = WriteProcessMemory(hRemoteProcess,pRemoteParam,(LPVOID)szDllPathCopy,iSize,&dwWriten);
    if(!bRet)
    {
        if (pRemoteParam)
            VirtualFreeEx(hRemoteProcess,pRemoteParam,0,MEM_RELEASE);
        EnablePrivilege(SE_DEBUG_NAME,false);
        return false;
    }
    hRemoteFunc = GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "LoadLibraryA");
    // #ifdef UNICODE
    //     hRemoteFunc = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryW");
    // #else
    //     hRemoteFunc = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
    // #endif
    hRemoteThread = CreateRemoteThread(hRemoteProcess,0,0,(LPTHREAD_START_ROUTINE)hRemoteFunc,pRemoteParam,0,&dwWriten);

    EnablePrivilege(SE_DEBUG_NAME,false);
    // 等待线程结束
    if (hRemoteThread)
    {
        WaitForSingleObject(hRemoteThread,INFINITE);
        HMODULE g_hRemoteHandle;
        GetExitCodeThread(hRemoteThread,(DWORD*)&g_hRemoteHandle);
    }

    // 清理工作
    if(pRemoteParam)
        VirtualFreeEx(hRemoteProcess, pRemoteParam,0,MEM_RELEASE);
    CloseHandle(hRemoteProcess);
    return true;
}
//查找dll实例句柄
HMODULE GetProcessModuleByName(DWORD dwProcessId,CString lpStrName)
{
    HANDLE hModuleSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,dwProcessId);

    //查找相关的DLL
    MODULEENTRY32 me32 = {sizeof(MODULEENTRY32)};
    for(BOOL fok=::Module32First(hModuleSnap,&me32); fok ;fok=::Module32Next(hModuleSnap,&me32))
    {
        if(lstrcmpi(me32.szExePath , lpStrName) == 0 || lstrcmpi(me32.szModule , lpStrName) == 0)
        {
            return me32.hModule;
        }
    }
    return 0;
}
//卸载注入的DLL
bool UnhookProcess(DWORD dwProcessId,CString szDllPath)
{
    HANDLE hRemoteProcess = NULL;
    HANDLE hRemoteThread  = NULL;
    HANDLE hRemoteFunc    = NULL;
    PVOID  pRemoteParam      = NULL;
    DWORD  dwWriten       = 0;
    BOOL   bRet           = FALSE;
    //char   szDllPathCopy[256] = {0};
    //lstrcpyA(szDllPathCopy,szDllPath);
    EnablePrivilege(SE_DEBUG_NAME,true);
    hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessId);
    if(hRemoteProcess == NULL)
    {
        EnablePrivilege(SE_DEBUG_NAME,false);
        return false;
    }
    //此dll句柄地址就已经是dwProcessId中的地址,所有不需要写入
    HMODULE hDllModule = GetProcessModuleByName(dwProcessId,szDllPath);
    if (!hDllModule)
    {
        EnablePrivilege(SE_DEBUG_NAME,false);
        return false;
    }
    pRemoteParam = hDllModule;
    hRemoteFunc = GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "FreeLibrary");
    hRemoteThread = CreateRemoteThread(hRemoteProcess,0,0,(LPTHREAD_START_ROUTINE)hRemoteFunc,pRemoteParam,0,&dwWriten);
    EnablePrivilege(SE_DEBUG_NAME,false);
    // 等待线程结束
    if (hRemoteThread)
    {
        WaitForSingleObject(hRemoteThread,INFINITE);
    }
    CloseHandle(hRemoteProcess);
    return true;
}
//获取进程列表
void GetProcessList(CArray<PROCESSENTRY32>& arrProcess)
{
    arrProcess.RemoveAll();
    PROCESSENTRY32    stProcess;
    HANDLE     hSnapShot;
    BOOL b;

    RtlZeroMemory(&stProcess, sizeof(stProcess));
    stProcess.dwSize = sizeof(stProcess);
    hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    b = Process32First(hSnapShot, &stProcess);
    while ( b )
    {
        arrProcess.Add(stProcess);

        b = Process32Next(hSnapShot, &stProcess);
    }        
    CloseHandle(hSnapShot);
}

 

//======================================================

 

//点击“注入”按钮
void CwooddoorDlg::OnBnClickedButtonHook()
{
    // TODO: 在此添加控件通知处理程序代码
    if (m_ProcessList.GetCurSel() == -1)
    {
        AfxMessageBox(_T("请先选择目标进程!"));
    }
    else
    {
        CString strDllFile = pathfileFun::GetAppPath() + _T("HookRXJH.dll");
        if ( HookProcess( m_ProcessList.GetItemData(m_ProcessList.GetCurSel()), CStringA(strDllFile.LockBuffer()) ) == false )
        {
            AfxMessageBox(_T("注入失败!"));
        }
        strDllFile.UnlockBuffer();
    }
}
//点击“卸载”按钮
void CwooddoorDlg::OnBnClickedButtonUnhook()
{
    // TODO: 在此添加控件通知处理程序代码
    if (m_ProcessList.GetCurSel() == -1)
    {
        AfxMessageBox(_T("请先选择目标进程!"));
    }
    else
    {
        CString strDllFile = pathfileFun::GetAppPath() + _T("HookRXJH.dll");
        if ( UnhookProcess( m_ProcessList.GetItemData(m_ProcessList.GetCurSel()), strDllFile ) == false )
        {
            AfxMessageBox(_T("卸载失败!"));
        }
    }
}
//在组合框内显示进程列表
void CwooddoorDlg::OnCbnDropdownComboProcesslist()
{
    // TODO: 在此添加控件通知处理程序代码
    m_ProcessList.ResetContent();//清空列表
    CArray<PROCESSENTRY32> arrProcess;
    GetProcessList(arrProcess);
    CString strProcessInfo;
    for (int i=arrProcess.GetCount()-1; i>=0; i--)
    //for (int i=0; i<arrProcess.GetCount(); i++)
    {
        strProcessInfo=_T("");
        strProcessInfo.Format( _T("[%d]%s"),arrProcess[i].th32ProcessID,pathfileFun::GetFileNameFromFilePath(arrProcess[i].szExeFile) );
        //m_ProcessList.AddString(pathfileFun::GetFileNameFromFilePath(arrProcess[i].szExeFile));
        m_ProcessList.SetItemData( m_ProcessList.AddString(strProcessInfo), arrProcess[i].th32ProcessID );
    }
}

 

DLL部分:

创建MFC DLL,名为HookRXJH。

在DLL中插入一个对话框,并给该对话框创建一个类如:

class CMainDialog : public CDialog

在DLL的CHookRXJHApp内创建一个成员变量:

public:
    CMainDialog *m_pMainDialog;
    CFrameWnd *m_pFrame;

给CHookRXJHApp添加成员函数:virtual int ExitInstance();

然后在InitInstance内添加代码:

BOOL CHookRXJHApp::InitInstance()
{
    CWinApp::InitInstance();

    //在dll注入之后显示主对话框:
    m_pMainDialog = new CMainDialog;
    m_pFrame = new CFrameWnd();
    m_pMainWnd = m_pFrame;//用于自动处理消息,省去手动写消息循环,从而不至于对话框刚出现就关闭
    m_pMainWnd = m_pMainDialog;
    ::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ShowDialog,(LPVOID)m_pMainDialog,NULL,NULL);

    return TRUE;
}

在ExitInstance内添加代码:

int CHookRXJHApp::ExitInstance()
{
    SendMessage(m_pMainDialog->m_hWnd, WM_CLOSE, NULL, NULL);

    return CWinApp::ExitInstance();
}

另外定义一个函数用于显示窗口:

void ShowDialog(CMainDialog *pMainDialog)
{
    pMainDialog->DoModal(); //显示对话框
}