让自己的dll注入到其他进程中运行

下面是一个简单的将mydll.dll注入到QQ中运行的例子:

#include 
#include 
#include 
#include 

DWORD dwProcessID=0;
HANDLE hProcessHandle=NULL;
LPVOID pAddrStart=NULL;
HANDLE hThreadHandle=NULL;
HANDLE hDllHandle=NULL;


/*****************************
*函数名:GetProcessIdByName
*功  能:根据进程名查找进程ID
*入  参:const char*ProcessName,进程名
*出  参:无
*返回值:进程ID,失败返回-1
*****************************/
DWORD GetProcessIdByName(const char*ProcessName)
{
    PROCESSENTRY32 stProcess;
    HWND hProcessShot;
    stProcess.dwSize=sizeof(PROCESSENTRY32);
    hProcessShot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    Process32First(hProcessShot,&stProcess);

    do
    {
        if(!strcmp(ProcessName,stProcess.szExeFile))
            return stProcess.th32ProcessID;
    }while(Process32Next(hProcessShot,&stProcess));

    CloseHandle(hProcessShot);
    return -1;
}

/*****************************
*函数名:dll_inject
*功  能:将dll注入到指定的进程中
*入  参:const char*ProcessName,进程名
        const char *pDllName,dll名
*出  参:无
*返回值:成功返回0,失败返回-1
*****************************/
int dll_inject(const char *pProcessName, const char *pDllName)
{
    //char *pProcessName="QQ.exe";
    BOOL bSuccess = FALSE;
    //根据进程名获取进程ID
    dwProcessID = GetProcessIdByName(pProcessName);
    if(dwProcessID == -1)
    {
        printf("%s未运行", pProcessName);
        return -1;
    }
    printf("%s进程ID为%d", pProcessName,dwProcessID);

    //根据进程ID获取进程句柄
    hProcessHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessID);
    if(hProcessHandle == NULL)
    {
        printf("OpenProcess获取进程句柄失败\n");
        return -1;
    }

    //用VirtualAllocEx在进程内申请内存
    pAddrStart = VirtualAllocEx(hProcessHandle,0,1024,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
    if (pAddrStart == NULL)
    {
        printf("进程内存申请失败!\n");
        return;
    }
    printf("申请进程内存的首地址为0x%x\n",pAddrStart);

    //将需要运行的dll名写入申请的内存地址
    bSuccess = WriteProcessMemory(hProcessHandle,pAddrStart,pDllName,1024,0);
    if(!bSuccess)
    {
        printf("WriteProcessMemory失败!\n");
        return -1;
    }
    //printf("memory of pAddrStart is:%s",pAddrStart);

    //注入,即"LoadLibraryA"函数加载mydll.dll
    hThreadHandle = CreateRemoteThread(hProcessHandle,
                                       0,
                                       0,
                                       GetProcAddress(GetModuleHandle("kernel32.dll"),"LoadLibraryA"),//函数LoadLibraryA的地址
                                       pAddrStart,//mydll.dll
                                       0,
                                       0);
    if(hThreadHandle == NULL)
    {
        printf("在进程%s中注入%s失败",pProcessName,pDllName);
        return -1;
    }
    WaitForSingleObject(hThreadHandle,INFINITE);
    //到这里已经完成dll的加载即注入了,通过dll函数执行我们要完成的任务


    //释放
    VirtualFreeEx(hProcessHandle,pAddrStart,0,MEM_RELEASE);
    CloseHandle(hThreadHandle);
    CloseHandle(hProcessHandle);

    printf("Hello world!\n");
    return 0;
}

/*****************************
*函数名:dll_free
*功  能:卸载注入到进程中的dll
*入  参:const char*ProcessName,进程名
        const char *pDllName,dll名
*出  参:无
*返回值:成功返回0,失败返回-1
*****************************/
int dll_free(const char *pProcessName, const char *pDllName)
{
    BOOL bSuccess = FALSE;
    //根据进程名获取进程ID
    dwProcessID = GetProcessIdByName(pProcessName);
    if(dwProcessID == -1)
    {
        printf("%s未运行", pProcessName);
        return -1;
    }
    printf("%s进程ID为%d", pProcessName,dwProcessID);

    //根据进程ID获取进程句柄
    hProcessHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessID);
    if(hProcessHandle == NULL)
    {
        printf("OpenProcess获取进程句柄失败\n");
        return -1;
    }

    //用VirtualAllocEx在进程内申请内存
    pAddrStart = VirtualAllocEx(hProcessHandle,0,1024,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
    if (pAddrStart == NULL)
    {
        printf("进程内存申请失败!\n");
        return;
    }
    printf("申请进程内存的首地址为0x%x\n",pAddrStart);

    //将需要运行的dll名写入申请的内存地址
    bSuccess = WriteProcessMemory(hProcessHandle,pAddrStart,pDllName,1024,0);
    if(!bSuccess)
    {
        printf("WriteProcessMemory失败!\n");
        return -1;
    }

    //注入,即GetModuleHandleA函数获取mydll.dll的实例,目的是为了后面的通过GetExitCodeThread获得mydll.dll的句柄,最后执行FreeLibrary
    hThreadHandle = CreateRemoteThread(hProcessHandle,
                                       0,
                                       0,
                                       GetProcAddress(GetModuleHandle("kernel32.dll"),"GetModuleHandleA"),//函数GetModuleHandleA的地址
                                       pAddrStart,//mydll.dll
                                       0,
                                       0);
    //用GetExitCodeThread取出dll句柄
    WaitForSingleObject(hThreadHandle,INFINITE);
    GetExitCodeThread(hThreadHandle,&hDllHandle);

    //把FreeLibrary注入到进程,释放注入的DLL
    hThreadHandle=CreateRemoteThread(hProcessHandle,
                                       0,
                                       0,
                                       GetProcAddress(GetModuleHandle("kernel32.dll"),"FreeLibrary"),
                                       hDllHandle,
                                       0,
                                       0);

    //释放
    WaitForSingleObject(hThreadHandle,INFINITE);
    VirtualFreeEx(hProcessHandle,pAddrStart,0,MEM_RELEASE);
    CloseHandle(hThreadHandle);
    CloseHandle(hProcessHandle);

    return 0;
}

int main()
{
    //将mydll.dll注入到QQ中
    dll_inject("QQ.exe","mydll.dll");
    //卸载注入的dll
    dll_free("QQ.exe","mydll.dll");

    printf("Hello world!\n");

    return 0;
}

上面完成了将dll注入进程,下面是要注入的dll的实现,其实就是一个普通的dll:

#include "main.h"

// a sample exported function
void DLL_EXPORT SomeFunction(const LPCSTR sometext)
{
    MessageBoxA(0, sometext, "DLL Message", MB_OK | MB_ICONINFORMATION);
}

extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            // attach to process
            // return FALSE to fail DLL load
            MessageBoxA(0, "I am a dll!", "DLL Message", MB_OK | MB_ICONINFORMATION);
            break;

        case DLL_PROCESS_DETACH:
            // detach from process
            break;

        case DLL_THREAD_ATTACH:
            // attach to thread
            break;

        case DLL_THREAD_DETACH:
            // detach from thread
            break;
    }
    return TRUE; // succesful
}

在dll入口函数中,case DLL_PROCESS_ATTACH分支即dll加载时执行处加入自己的代码,这里是弹出一个对话框。生成的mydll.dll放到system32下。

运行上面的dll注入程序,弹出了对话框,说明dll注入成功。

当然,参照注入的方法也可以在dll非入口函数中通过GetProcAddress获取要执行的函数的地址执行自己想要完成的功能。

你可能感兴趣的:(C/C++)