远程线程注入DLL-读取指定进程中的模块

5 篇文章 0 订阅

步骤:

(1)用VirtualAllocEx函数在远程进程的地址空间中分配一块内存

(2)用WriteProcessMemory把函数DLL的路径名字复制到第一步分配的内存中

(3)用GetProcAddress函数来得到LoadLibraryW或LoadLibraryA函数在Kernel32.dll中的实际地址

解释下为什么可以这么做:

*为什么可以直接用GetProcAddress获取LoadLibraryW在Kernel32.dll的地址然后传给CreateRemoteThread中,因为Kernel32.dll在所有进程中的基地址都是一样的。

*既然如此那为什么不直接传递LoadLibrary给CreateRemoteThread还需要通过GetProcAddress获取地址呢?因为我们自己的模块会包含一个导入段,改段由一系列转换函数组成,这些转换函数用来跳转到导入函数。因此代码调用LoadLibrary时链接器会生成一个调用,来调用我们模块中的导入段中的一个转换函数,这个转换函数会跳转到实际的函数中。

(4)用CreateRemoteThread在远程进程中创建一个线程,让新线程调用正确的LoadLibrary函数并在参数中传入第一步分配的内存地址,这个时候,DLL以及被注入到远程进程的地址空间中,DLL的DllMain函数会受到DLL_PROCESS_ATTACH通知并且可以执行我们想要执行的代码,当DllMain返回的时候,远程线程会从LoadLibraryW/A调用返回到BaseThreadStart函数,然后该函数调用ExitThread离开线程

(5)用VirtualFreeEx来释放第一步申请的内存

(6)用GetProcAddress获取FreeLibrary函数在Kernel32.dll中的实际地址

(7)用CreateRemoteThread函数在远程线程中创建一个线程,该线程调用FreeLibrary函数并传入远程DLL的HMODULE

给出的例子有两部分:一个是要注入的DLL,成为InjLKDLL,一个是我们自己的程序用于注入该DLL,为InjDll.

先给出InjLKDLL的代码:

#define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>
#include <string>
#include <sstream>
#include <fstream>
#include <Windows.h>
#include <TlHelp32.h>

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {

        MessageBoxA(NULL, "DLL Attached!\n", "Game Hacking", MB_OK | MB_TOPMOST);
        //我们要处理的逻辑
        DWORD dwCurProcessId = GetCurrentProcessId();
        char szProcessName[MAX_PATH];
        GetModuleFileNameA(NULL, szProcessName, MAX_PATH);

        std::string strProcessName = szProcessName;
        SIZE_T index = strProcessName.find_last_of('\\');
        std::string strExeName = strProcessName.substr(index + 1);

        char outFileName[MAX_PATH] = { 0 };
        sprintf_s(outFileName, "D:\\%s-%lu.txt", strExeName.c_str(), dwCurProcessId);

        std::wofstream outFile;
        outFile.open(outFileName, std::ios::out);
        if (outFile.good())
        {
            outFile.imbue(std::locale("chs"));

            outFile << L"注入成功:" << dwCurProcessId<< std::endl;

            HANDLE hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwCurProcessId);
            if (hthSnapshot == INVALID_HANDLE_VALUE) 
            {
                outFile << L"读取模块失败" << std::endl;
                break;
            }

            MODULEENTRY32 me = { sizeof(me) };
            BOOL bFound = FALSE;
            BOOL bMoreMods = Module32FirstW(hthSnapshot, &me);

            WCHAR szContext[MAX_PATH * 2] = { 0 };

            for (; bMoreMods; bMoreMods = Module32NextW(hthSnapshot, &me))
            {
                wsprintf(szContext, L"0x%016x\t%s", me.modBaseAddr, me.szExePath);
                outFile << szContext << std::endl;
            }

            CloseHandle(hthSnapshot);

            outFile.close();
        }

        break;
    }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

InjDll代码实现如下:

#include <iostream>
#include <fstream>
#include <Windows.h>
#include <TlHelp32.h>

BOOL InjectDLL(DWORD dwProcessId, PCWSTR pszDllFile);
BOOL EjectDLL(DWORD dwProcessId, PCWSTR pszDllFile);

int main()
{
    WCHAR szDllFile[MAX_PATH] = L"D:\\VSWorkSpace\\InjDll\\x64\\Release\\InjLKDLL.dll";
    DWORD dwProcessId = 0;

    do
    {
        std::cout << "输入要注入的进程号:" << std::endl;
        std::cin >> dwProcessId;

        if (dwProcessId > 0)
        {
            if (InjectDLL(dwProcessId, szDllFile))
            {
                std::cout << "注入成功" << std::endl;
                if (EjectDLL(dwProcessId, szDllFile))
                    std::cout << "卸载成功" << std::endl;
                else
                    std::cout << "卸载失败" << std::endl;
            }
            else
            {
                std::cout << "注入失败" << std::endl;
            }
        }
        else
            break;

    } while (1);

    std::cout << "Hello World!\n";
    system("pause");
    return 1;
}


BOOL InjectDLL(DWORD dwProcessId, PCWSTR pszDllFile)
{
    BOOL bOk = FALSE;
    HANDLE hProcess = NULL, hThread = NULL;

    PWSTR pszDllFileRemote = NULL;
    HANDLE hthSnapshot = NULL;
    do
    {
        hProcess = OpenProcess(
            PROCESS_ALL_ACCESS,
            FALSE,
            dwProcessId);
        if (hProcess == NULL) break;

        //计算DLL路径需要的大小
        int cch = 1 + lstrlenW(pszDllFile);
        int cb = cch * sizeof(wchar_t);

        pszDllFileRemote = (PWSTR)VirtualAllocEx(
            hProcess,
            NULL,
            cb,
            MEM_COMMIT,
            PAGE_READWRITE);

        if (pszDllFileRemote == NULL) break;

        if (!WriteProcessMemory(
            hProcess,
            pszDllFileRemote,
            (PVOID)pszDllFile,
            cb,
            NULL)) break;

        PTHREAD_START_ROUTINE pfnThreadRtn =
            (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");

        if (pfnThreadRtn == NULL) break;

        char pfnThreadRtnAddre[100];
        sprintf_s(pfnThreadRtnAddre, "0x%016x", pfnThreadRtn, 100);
        std::cout << pfnThreadRtnAddre << std::endl;

        hThread = CreateRemoteThread(
            hProcess,
            NULL,
            0,
            pfnThreadRtn,
            pszDllFileRemote,
            0,
            NULL);

        std::cout << "GetLastErr:" << GetLastError() << std::endl;

        if (hThread == NULL) break;

        WaitForSingleObject(hThread, INFINITE);

        bOk = TRUE;
    } while (0);

    if (hthSnapshot != NULL) CloseHandle(hthSnapshot);

    if (pszDllFileRemote != NULL)
        VirtualFreeEx(hProcess, pszDllFileRemote, 0, MEM_RELEASE);

    if (hThread != NULL)
        CloseHandle(hThread);

    if (hProcess != NULL)
        CloseHandle(hProcess);

    return (bOk);
}

BOOL EjectDLL(DWORD dwProcessId, PCWSTR pszDllFile)
{
    BOOL bOk = FALSE;
    HANDLE hthSnapshot = NULL;
    HANDLE hProcess = NULL, hThread = NULL;

    do
    {
        //查找我们注入的模块
        hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
        if (hthSnapshot == INVALID_HANDLE_VALUE) return FALSE;

        MODULEENTRY32 me = { sizeof(me) };
        BOOL bFound = FALSE;
        BOOL bMoreMods = Module32FirstW(hthSnapshot, &me);

        for (; bMoreMods; bMoreMods = Module32NextW(hthSnapshot, &me))
        {
            bFound = (_wcsicmp(me.szModule, pszDllFile) == 0) ||
                (_wcsicmp(me.szExePath, pszDllFile) == 0);

            //std::wcout.imbue(std::locale("chs"));
            //std::wcout << me.szExePath << std::endl;

            if (bFound) break;
        }

        if (!bFound) break;

        hProcess = OpenProcess(
            PROCESS_ALL_ACCESS,
            FALSE,
            dwProcessId);

        if (hProcess == NULL) break;

        PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)
            GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "FreeLibrary");

        if (pfnThreadRtn == NULL) break;

        hThread = CreateRemoteThread(
            hProcess,
            NULL,
            0,
            pfnThreadRtn,
            me.modBaseAddr,
            0,
            NULL);

        if (hThread == NULL) break;

        WaitForSingleObject(hThread, INFINITE);

        bOk = TRUE;

    } while (0);

    if (hthSnapshot != NULL) CloseHandle(hthSnapshot);
    if (hThread != NULL) CloseHandle(hThread);
    if (hProcess != NULL) CloseHandle(hProcess);

    return (bOk);
}

几个疑问:

(1)有些进程会注入失败,不知道什么原因

答:可能是权限不够

(2)有些进程注入成功,但是不加载DLL,我在win10上个微信注入就会遇到这种情况

答:因为微信是32位的,注入的进程也需要时32位的,设置为x86即可

(3)CreateToolhelp32Snapshot好像并不能枚举进程中所有的模块,对微信进程枚举只有四五个作用,很诡异。

答案:因为调用该函数的进程与目标进程的位数不一样,目标进程可能是32位,但是调用进程是64位就出现这个问题

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值