c++ windows DLL远程注入

这次使用远程线程来进行DLL注入,它提供了最高的灵活性。从根本上说DLL注入要求目标进程中的一个线程使用LoadLibrary来载入我们的DLL。

由于我们不能随意的控制别的线程,因此我们需要在目标进程创建一个新的线程,远程创建线程可以使用 CreateRemoteThread 来进行创建,下面是函数原型。

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 );

除了CreateRemoteThread有一个额外的参数 hProcess 以外其他的都和CreateThread完全相同,hProcess 这个参数表示创建的进程归那个进程所有。

下一步我们需要让该线程调用LoadLibrary函数来载入我们的DLL,通过函数原型发现他们两个非常相似,都是一个参数一个返回值,函数约定都是WINAPI 。

LoadLibrary函数原型
HMODULE WINAPI LoadLibraryA(_In_ LPCSTR lpLibFileName);
HMODULE WINAPI LoadLibraryW(_In_ LPCWSTR lpLibFileName);

线程回调的原型
DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter);

那么只要我们把线程函数回调地址改成LoadLibrary是不是就ok了?如下

使用多字符
    HANDLE hThread = CreateRemoteThread(handle, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryA, "c:\\myLib.dll", 0, NULL);

使用宽字符
    HANDLE hThread = CreateRemoteThread(handle, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, L"c:\\myLib.dll", 0, NULL);

当新线程被创建时会立刻调用LoadLibrary,并传入DLL路径,但是这还存在其他两个问题。

第一 直接把LoadLibrary传给CreateRemoteThread第四个参数,在编译和链接的时候会把函数放到一个二进制文件的导入段中,通过这个二进制的文件来获取实际的跳转地址。当我们在远程直接调用LoadLibrary,会被解析成我们模块导入段的LoadLibrary,所以解析的数据鬼知道是那个地址,这样会造成违规访问。

第二个问题就是 你传入给LoadLibrary的字符串,也就是CreateRemoteThread第五个参数,你传入的是本地空间的字符串指针,所以当LoadLibrary进行操作字符串时也会发生访问违规。

解决第一个问题我们可以使用GetProcAddress函数来获取LoadLibrary的实际地址,因为LoadLibrary函数是在Kernel32.dll里面,系统会把Kernel32.dll映射到每一个进程里,所以以下操作可以获取LoadLibrary在当前线程的真实地址。

    PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleW(L"Kernel32"), "LoadLibraryW");

    HANDLE hThread = CreateRemoteThread(handle, NULL, 0, pfnThreadRtn, L"c:\\myLib.dll", 0, NULL);

好了,第一个问题解决了还有第二个问题,怎么把字符串放到远程的线程中呢?好在windows为我们提供了在一个进程给另一个进程的地址空间分配一块内存 VirtualAllocEx ,还提供了让我们释放这块内存 VirtualFreeEx。

我们在另一个进程开辟了内存,还需要把字符串复制到开辟的内存中,所以需要WriteProcessMemory函数来把当前进程的字符串写入到另一个进程中。

    wstring dllPath = L"c:\\myLib.dll";

    DWORD dwSize = dllPath.length();
    dwSize = dwSize * sizeof(WCHAR);

    LPWCH pszLibFileRemote = (LPWCH)VirtualAllocEx(handle, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);

    // 把dll路径复制到创建的内存中
    WriteProcessMemory(handle, pszLibFileRemote, dllPath.c_str(), dwSize, NULL);

    PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleW(L"Kernel32"), "LoadLibraryW");

    HANDLE hThread = CreateRemoteThread(handle, NULL, 0, pfnThreadRtn, "c:\\myLib.dll", 0, NULL);

这个样子就基本完成了。下面补充一下还需要进行获取要注入进程的句柄,可以通过进程id来获取,下面是完整的一个注入函数。

//参数dwProcessId 表示要注入的进程的PID
//参数dllPath 表示需要注入进程的路径
    
BOOL Injection(DWORD dwProcessId, wstring dllPath)
{
    HANDLE handle = OpenProcess(
        PROCESS_QUERY_INFORMATION | // 需要检索有关进程的某些信息
        PROCESS_CREATE_THREAD |     // 需要创建线程。
        PROCESS_VM_OPERATION |      // 需要对进程的地址空间执行操作
        PROCESS_VM_WRITE,           // 需要使用WriteProcessMemory 写入进程中的内存
        FALSE, dwProcessId);
    if (handle == NULL)
    {
        return FALSE;
    }

    DWORD dwSize = dllPath.length();
    dwSize = dwSize * sizeof(WCHAR);

    LPWCH pszLibFileRemote = (LPWCH)VirtualAllocEx(handle, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
    if (NULL == pszLibFileRemote)
    {
        return FALSE;
    }

    // 把dll路径复制到创建的内存中
    if (!WriteProcessMemory(handle, pszLibFileRemote, dllPath.c_str(), dwSize, NULL))
    {
        return FALSE;
    }

    // 获取LoadLibrary所在Kernel32.dll中的实际地址(系统每个进程都会需要Kernel32.dll)
    PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleW(L"Kernel32"), "LoadLibraryW");

    HANDLE hThread = CreateRemoteThread(handle, NULL, 0, pfnThreadRtn, pszLibFileRemote, 0, NULL);
    if (hThread == NULL)
    {
        return FALSE;
    }

    if (pszLibFileRemote != NULL)
        VirtualFreeEx(handle, pszLibFileRemote, 0, MEM_RELEASE);

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

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

    return TRUE;
}

下面是卸载这个dll


BOOL UnInjection(DWORD processId, wstring dllPath)
{
    BOOL bRtn = FALSE;

    HANDLE hThread;
    HANDLE hProcess;
    HANDLE hthSnapshot;
    //远程删除操作步骤
    do
    {
        // 获取指定进程的快照,以及这些进程使用的堆、模块和线程。
        hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processId);
        if (hthSnapshot == INVALID_HANDLE_VALUE) break;

        // 获取模块信息
        MODULEENTRY32W me = { sizeof(me) };
        BOOL bFound = FALSE;
        //检索模块的信息
        BOOL bMoreMods = Module32FirstW(hthSnapshot, &me);
        for (; bMoreMods; bMoreMods = Module32NextW(hthSnapshot, &me))
        {
            //判断是否是我们加载的dll
            bFound = (_wcsicmp(me.szModule, dllPath.c_str()) == 0) || (_wcsicmp(me.szExePath, dllPath.c_str()) == 0);
            if (bFound) break;
        }
        if (!bFound) break;

        hProcess = OpenProcess(
            PROCESS_QUERY_INFORMATION |   // Required by Alpha
            PROCESS_CREATE_THREAD |   // For CreateRemoteThread
            PROCESS_VM_OPERATION |   // For VirtualAllocEx/VirtualFreeEx
            PROCESS_VM_WRITE,             // For WriteProcessMemory
            FALSE, processId);
        if (hProcess == NULL)
            break;

        PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleW(L"Kernel32"), "FreeLibrary");
        // 在远程进程中创建另一个线程,调用FreeLibrary
        hThread = CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, me.modBaseAddr, 0, NULL);
        if (hThread == NULL)
            break;

        WaitForSingleObject(hThread, INFINITE);

        bRtn = TRUE;
    } while (FALSE);

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

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

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

    return bRtn;
}

参考资料:windows核心编程第五版

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值