DLL注入——使用远程线程

1.简介

从根本上来说,DLL注入技术要求目标进程中的一个线程调用LoadLibrary来载入我们想要的DLL。由于我们不能轻易地控制别人进程中的线程,因此这种方法要求我们在目标进程中创建一个新的线程,Windows提供了创建远程线程的函数。

HANDLE CreateRemoteThread(
  [in]  HANDLE                 hProcess,
  [in]  LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  [in]  SIZE_T                 dwStackSize,
  [in]  LPTHREAD_START_ROUTINE lpStartAddress,
  [in]  LPVOID                 lpParameter,
  [in]  DWORD                  dwCreationFlags,
  [out] LPDWORD                lpThreadId
);
  • hProcess:用于创建线程的进程的句柄。
  • lpThreadAttributes:指向SECURITY_ATTRIBUTES结构的指针,该结构确定返回的句柄是否可以被子进程继承。
  • dwStackSize:堆栈的初始大小,以字节为单位。如果此参数为零,则新线程使用默认大小。
  • lpStartAddress:指向线程要执行的应用程序定义函数的指针。
  • lpParameter:指向要传递给线程的变量的指针。
  • dwCreationFlags:控制线程创建的标志。
  • lpThreadId:指向接收线程标识符的变量的指针。如果该参数为NULL,则不返回线程标识符。

2.步骤

  • 用VirtualAllocEx函数在远程进程的地址空间中分配一块内存。
  • 用WriteProcessMemory函数把DLL的路径名复制到第一步分配的内存中。
  • 用GetProcAddress函数来得到LoadLibraryW或LoadLibraryA函数的实际地址(在Kernel32.dll中)
  • 用CreateRemoteThread函数在远程进程中创建一个线程,让新线程调用正确的LoadLibrary函数并在参数中传入第一步分配的内存地址。这时,DLL已经被注入到远程进程的地址空间中,DLL的DllMain函数会收到DLL_PROCESS_ATTACH通知并且执行我们想要执行的代码。
  • VirtualFreeEx来释放第1步分配的内存。
  • 用GetProcAddress函数来得到FreeLibrary函数的实际地址(在Kernel32.dll中)
  • 用CreateRemoteThread函数在远程进程中创建一个线程,让新线程调用FreeLibrary函数并在参数中传入远程DLL的HMODULE。

步骤1、2、3原理简介:

字符串“D://remoteDll.dll”,位于调用进程的空间地址中,我们把这个地址传给新创建的远程线程,远程线程再把它传给LoadLibrary,当LoadLibrary去访问这个内存地址的时候,DLL的路径字符串并不在那里,远程进程的线程就很可能引发访问违规。为了解决这个问题,我们需要把DLL的字符串存放到远程进程的地址空间中去,所以会使用VirtualAllocEx和WriteProcessMemory方法。

3.示例

3.1先做一个动态库remoteDll.dll

此库的功能是,一旦被注入到进程的地址空间中,就报告该进程正在使用的所有DLL,并将打印信息写入到本地文件D://out.txt中。

const char* filepath = "D://out.txt";

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        FILE* fp = freopen(filepath, "w", stdout);
        
        PBYTE pb = NULL;
        MEMORY_BASIC_INFORMATION mbi;
        while (VirtualQuery(pb, &mbi, sizeof(mbi)) == sizeof(mbi))
        {
            int nlen;
            char szModName[MAX_PATH];
            if (mbi.State == MEM_FREE)
                mbi.AllocationBase = mbi.BaseAddress;
            if ((mbi.AllocationBase == hModule) || (mbi.AllocationBase != mbi.BaseAddress) || (mbi.AllocationBase == NULL))
                nlen = 0;
            else
            {
                nlen = GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, szModName, _countof(szModName));
            }
            if (nlen > 0)
            {
                char szBuf[MAX_PATH] = { 0 };
                wsprintfA(szBuf, "\n%p-%s", mbi.AllocationBase, szModName);
                printf("%s\n", szBuf);
            }

            pb += mbi.RegionSize;
        } 

        fclose(fp);
    }
    break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

3.2写一个测试程序

新建一个带界面的程序

改了一下窗口界面,这里加了一个菜单项注入。

点击注入出现弹窗,如下图所示。

输入进程ID,点击确定即可,下面是注入的回调函数。

// “注入”框的消息处理程序。
INT_PTR CALLBACK Inject(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
    {
        return (INT_PTR)TRUE;
    }
    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK)
        {
            //获取ID值
            DWORD processID = GetDlgItemInt(hDlg, IDC_EDIT1, NULL, FALSE);
            if (processID == 0)
            {
                processID = GetCurrentProcessId();
            }

            if (InjectLib(processID, TEXT("D://remoteDll.dll")))
            {
                printf("inject ok");
                EjectLib(processID, TEXT("D://remoteDll.dll"));
            }
            else
            {
                printf("inject failed");
            }

            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        else if (LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

InjectLib函数如下:

BOOL WINAPI InjectLib(DWORD processID, PCWSTR pszLibFile)
{
    BOOL bOk = FALSE;
    HANDLE hProcess = NULL, hThread = NULL;
    PWSTR pszLibFileRemote = NULL;

    __try
    {
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD |
            PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, processID);

        if (hProcess == NULL)
            __leave;

        int cch = 1 + lstrlenW(pszLibFile);
        int cb = cch * sizeof(wchar_t);

        pszLibFileRemote = (PWSTR)VirtualAllocEx(hProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE);
        if (pszLibFileRemote == NULL)
            __leave;

        if (!WriteProcessMemory(hProcess, pszLibFileRemote, (PVOID)pszLibFile, cb, NULL))
            __leave;

        FARPROC pfnThreadRtn = GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
        if (pfnThreadRtn == NULL)
            __leave;

        hThread = CreateRemoteThread(hProcess, NULL, 0, (PTHREAD_START_ROUTINE)pfnThreadRtn, pszLibFileRemote, 0, NULL);
        if (hThread == NULL)
            __leave;

        WaitForSingleObject(hThread, INFINITE);

        bOk = TRUE;
    }
    __finally
    {
        if (pszLibFileRemote != NULL)
            VirtualFreeEx(hProcess, pszLibFileRemote, 0, MEM_RELEASE);

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

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

    return bOk;
}

EjectLib函数如下:

BOOL WINAPI EjectLib(DWORD processID, PCWSTR pszLibFile)
{
    BOOL bOk = FALSE;
    HANDLE hthSnapshot = NULL;
    HANDLE hProcess = NULL, hThread = NULL;
    PWSTR pszLibFileRemote = NULL;

    __try
    {
        //获取指定进程的快照,以及这些进程使用的堆、模块和线程。
        hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processID);
        if (hthSnapshot == INVALID_HANDLE_VALUE)
            __leave;

        MODULEENTRY32W me = { sizeof(me) };
        BOOL bFound = FALSE;
        BOOL bMoreMods = Module32FirstW(hthSnapshot, &me);  //检索与进程关联的第一个模块的信息。
        for (; bMoreMods; bMoreMods = Module32NextW(hthSnapshot, &me)) //检索与进程或线程关联的下一个模块的信息
        {
            bFound = (_wcsicmp(me.szModule, pszLibFile) == 0) || (_wcsicmp(me.szExePath, pszLibFile));
            if (bFound)
                break;
        }

        if (!bFound)
            __leave;

        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD |
            PROCESS_VM_OPERATION, FALSE, processID);

        if (hProcess == NULL)
            __leave;

        FARPROC pfnThreadRtn = GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "FreeLibrary");
        if (pfnThreadRtn == NULL)
            __leave;

        //me.modBaseAddr 在所属进程的上下文中模块的基地址。
        hThread = CreateRemoteThread(hProcess, NULL, 0, (PTHREAD_START_ROUTINE)pfnThreadRtn, me.modBaseAddr, 0, NULL);
        if (hThread == NULL)
            __leave;

        WaitForSingleObject(hThread, INFINITE);

        bOk = TRUE;
    }
    __finally
    {
        if (hthSnapshot != NULL)
            CloseHandle(hthSnapshot);

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

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

    return bOk;
}

3.3执行程序

打开一个记事本程序,找到PID,如下图所示,PID = 20752。

运行3.2中的程序,输入这个PID,点击确定注入成功。

3.4运行结果

注入之后,在本地文件out.txt中,可以看见正在该记事本程序正在使用的DLL。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 示例代码:#include <windows.h> #include <stdio.h> #include <tlhelp32.h> // 远程线程注入dll BOOL InjectDLL(DWORD dwPID, char *szDLLName); int main(int argc, char *argv[]) { printf("远程线程注入dll演示程序\n"); if (argc == 3) { DWORD dwPID = atoi(argv[1]); char *szDLLName = argv[2]; InjectDLL(dwPID, szDLLName); } else { printf("用法:InjectDLL.exe <PID> <DLLName>\n"); } return 0; } // 远程线程注入dll BOOL InjectDLL(DWORD dwPID, char *szDLLName) { HANDLE hProcess, hThread; LPVOID lpBaseAddress; LPTHREAD_START_ROUTINE lpStartAddress; DWORD dwSize, dwThreadId; char szPath[256]; char szBuffer[1024]; // 打开进程 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID); if (hProcess == NULL) { printf("OpenProcess() Error: %d\n", GetLastError()); return FALSE; } // 获取DLL的完整路径 GetFullPathName(szDLLName, 256, szPath, NULL); // 在进程中申请虚拟内存 dwSize = strlen(szPath) + 1; lpBaseAddress = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE); if (lpBaseAddress == NULL) { printf("VirtualAllocEx() Error: %d\n", GetLastError()); return FALSE; } // 将DLL路径写入到虚拟内存 int nBytesWritten; WriteProcessMemory(hProcess, lpBaseAddress, szPath, dwSize, &nBytesWritten); if (nBytesWritten != dwSize) { printf("WriteProcessMemory() Error: %d\n", GetLastError()); return FALSE; } // 加载Kernel32.dll HMODULE hKernel32 = GetModuleHandle("Kernel32"); if (hKernel32 == NULL) { printf("GetModuleHandle() Error: %d\n", GetLastError()); return FALSE; } // 获取LoadLibraryA函数地址 lpStartAddress = GetProcAddress(hKernel32, "LoadLibraryA"); if (lpStartAddress == NULL) { printf("GetProcAddress() Error: %d\n", GetLastError()); return FALSE; } // 创建远程线程 hThread = CreateRemoteThread(hProcess, NULL, 0, lpStartAddress, lpBaseAddress, 0, &dwThreadId); if (hThread == NULL) { printf("CreateRemoteThread() Error: %d\n", GetLastError()); return FALSE; } // 等待远程线程结束 WaitForSingleObject(hThread, INFINITE); // 读取线程退出码 DWORD dwExitCode; GetExitCodeThread(hThread, &dwExitCode); if (dwExitCode == 0) { printf("LoadLibrary() Error: %d\n", GetLastError()); return FALSE; } // 关闭句柄 CloseHandle(hProcess); CloseHandle(hThread); return TRUE; }我不能帮助你编写代码,但是我可以提供一些参考资料,帮助你编写远程线程注入dll代码。 ### 回答2: 远程线程注入DLL是一种技术,用于在目标进程中注入自定义的动态链接库(DLL)并执行其中的代码。以下是一个使用C语言编写的远程线程注入DLL的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <windows.h> int main() { // 目标进程的进程ID DWORD pid = 1234; // 加载要注入DLL路径 char dllPath[] = "C:\\path_to_dll\\mydll.dll"; // 获取目标进程句柄 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (hProcess == NULL) { printf("无法打开目标进程"); return -1; } // 在目标进程中为DLL路径分配内存 LPVOID dllPathAddr = VirtualAllocEx(hProcess, NULL, sizeof(dllPath), MEM_COMMIT, PAGE_READWRITE); if (dllPathAddr == NULL) { printf("无法在目标进程中分配内存"); CloseHandle(hProcess); return -1; } // 在目标进程中写入DLL路径 if (!WriteProcessMemory(hProcess, dllPathAddr, dllPath, sizeof(dllPath), NULL)) { printf("无法写入DLL路径到目标进程"); VirtualFreeEx(hProcess, dllPathAddr, 0, MEM_RELEASE); CloseHandle(hProcess); return -1; } // 获取Kernel32.dll中LoadLibrary函数的地址 HMODULE kernel32 = GetModuleHandle("kernel32.dll"); FARPROC loadLibrary = GetProcAddress(kernel32, "LoadLibraryA"); // 创建远程线程在目标进程中执行LoadLibrary函数,将DLL路径作为参数 HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)loadLibrary, dllPathAddr, 0, NULL); if (hThread == NULL) { printf("无法在目标进程中创建远程线程"); VirtualFreeEx(hProcess, dllPathAddr, 0, MEM_RELEASE); CloseHandle(hProcess); return -1; } // 等待远程线程执行结束 WaitForSingleObject(hThread, INFINITE); // 清理资源 VirtualFreeEx(hProcess, dllPathAddr, 0, MEM_RELEASE); CloseHandle(hThread); CloseHandle(hProcess); printf("远程线程注入DLL成功"); return 0; } ``` 这段代码首先通过`OpenProcess`函数打开目标进程,然后使用`VirtualAllocEx`在目标进程中为DLL路径分配内存,并使用`WriteProcessMemory`将DLL路径写入目标进程内存。接着,使用`GetModuleHandle`和`GetProcAddress`获取`LoadLibrary`函数的地址,然后使用`CreateRemoteThread`在目标进程中创建一个远程线程,让其执行`LoadLibrary`函数,将DLL路径作为参数传递给它。最后,使用`WaitForSingleObject`等待远程线程执行完毕,并释放之前分配的资源。 ### 回答3: 使用C语言编写远程线程注入DLL的代码可以通过以下步骤实现: 1. 首先,需要创建一个目标进程的句柄。可以使用`OpenProcess`函数来打开目标进程,并获得进程的句柄。 2. 接下来,需要在目标进程中分配一块内存空间,用于存储DLL的路径和名称。可以使用`VirtualAllocEx`函数在目标进程内部分配内存。 3. 在分配的内存空间中写入DLL的路径和名称。可以使用`WriteProcessMemory`函数将DLL的路径和名称写入到目标进程的内存中。 4. 使用`GetProcAddress`函数获取`LoadLibraryA`函数的地址,该函数用于加载DLL。可以使用`GetModuleHandle`函数获取kernel32.dll的句柄,然后再调用`GetProcAddress`函数来获取`LoadLibraryA`函数的地址。 5. 使用`CreateRemoteThread`函数在目标进程中创建一个远程线程,将`LoadLibraryA`函数地址作为线程的入口点,将DLL的路径和名称作为线程的参数传递。这样,在目标进程中就会自动加载并执行DLL。 完整的代码示例如下: ```c #include <windows.h> int main() { // Step 1: 打开目标进程句柄 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PROCESS_ID); // Step 2: 分配内存空间 LPVOID lpRemoteBuffer = VirtualAllocEx(hProcess, NULL, MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); // Step 3: 写入DLL路径和名称 char dllPath[] = "C:\\path\\to\\dll.dll"; WriteProcessMemory(hProcess, lpRemoteBuffer, (LPVOID)dllPath, sizeof(dllPath), NULL); // Step 4: 获取LoadLibraryA函数地址 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); FARPROC lpLoadLibraryA = GetProcAddress(hKernel32, "LoadLibraryA"); // Step 5: 创建远程线程注入DLL HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpLoadLibraryA, lpRemoteBuffer, 0, NULL); // 关闭句柄 CloseHandle(hThread); CloseHandle(hProcess); return 0; } ``` 以上就是使用C语言编写远程线程注入DLL的代码。请注意,使用远程线程注入DLL可能存在一些安全风险,请谨慎使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灬Sunnnnn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值