线程的远程注入

要实现线程的远程注入必须使用Windows提供的CreateRemoteThread函数来创建一个远程线程
该函数的原型如下:
HANDLE CreateRemoteThread(
    HANDLE hProcess,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    SIZE_T dwStackSize,
    LPTHREAD_START_ROUTINE lpStartAddress,
    LPVOID lpParameter,
    DWORD dwCreationFlags,
    LPDWORD lpThreadId
);

参数说明:
hProcess:目标进程的句柄
lpThreadAttributes:指向线程的安全描述结构体的指针,一般设置为NULL,表示使用默认的安全级别
dwStackSize:线程堆栈大小,一般设置为0,表示使用默认的大小,一般为1M
lpStartAddress:线程函数的地址
lpParameter:线程参数
dwCreationFlags:线程的创建方式
                 CREATE_SUSPENDED 线程以挂起方式创建
lpThreadId:输出参数,记录创建的远程线程的ID

CreateRemoteThread函数介绍完毕,其他详细信息参考MSDN中关于该函数的详细说明!
既然知道了使用这个函数来创建一个远程线程,接下来我们就来定义线程函数体,和普通的线程函数的
定义相同,远程线程的线程函数必须定义程类的静态成员函数或者全局函数
例如:
DWORD __stdcall threadProc(LPVOID lParam)
{
   //我们在这里先将该线程函数定义为空函数
   return 0;
}
在这里我们先将线程函数体定义为空,因为要作为远程注入的线程,线程函数体的编写方式和普通线程函数
稍有不同。

然后将线程代码拷贝到目标进程地址空间中(该地址必须是页面属性为PAGE_EXECUTE_READWRITE的页面)或者
其他宿主进程能执行地方(如:共享内存映射区)。在这里我们选择宿主进程。在拷贝线程体的时候我们需要
使用VirtualAllocEx函数在宿主进程中申请一块存储区域,然后再通过WriteProcessMemory函数将线程代码写
入宿主进程中。

要取得宿主进程的ID可以有很多种方法可以使用Psapi.h中的函数,也可以使用Toolhelp函数,在这里提供一种
使用Toolhelp实现的函数,函数如下

//根据进程名称得到进程的ID,如果有多个实例在同时运行的话,只返回第一个枚举到的进程ID
DWORD processNameToId(LPCTSTR lpszProcessName)
{
   HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
   PROCESSENTRY32 pe;
   pe.dwSize = sizeof(PROCESSENTRY32);

   if (!Process32First(hSnapshot, &pe)) {
       MessageBox(NULL, 
           "The frist entry of the process list has not been copyied to the buffer", 
           "Notice", MB_ICONINFORMATION | MB_OK);
       return 0;
   }

    while (Process32Next(hSnapshot, &pe)) {
        if (!strcmp(lpszProcessName, pe.szExeFile)) {
            return pe.th32ProcessID;
        }
    }
 
    return 0;
}

以上步骤完成之后就可以使用CreateRemoteThread创建远程线程了!示例代码如下

#include <windows.h>
#include <TlHelp32.h>
#include <iostream>

//要插入宿主进程中的线程函数
DWORD __stdcall threadProc(LPVOID lParam)
{
    return 0;
}

int main(int argc, char* argv[])
{
    const DWORD dwThreadSize = 4096;
    DWORD dwWriteBytes;

    std::cout << "Please input the name of target process" << std::endl;
    char szExeName[MAX_PATH] = { 0 };
    //等待输入宿主进程名称
    std::cin >> szExeName;
 
    //得到指定名称进程的进程ID,如果有多个进程实例,则得到第一个进程ID
    DWORD dwProcessId = processNameToId(szExeName);
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId)
    void* pRemoteThread = VirtualAllocEx(hTargetProcess, 0,
    dwThreadSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    //把线程体写入宿主进程中
    if (!WriteProcessMemory(hTargetProcess,
        pRemoteThread, &threadProc, dwThreadSize, 0)) {
        MessageBox(NULL, "Write data to target process failed !",
            "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }
    //在宿主进程中创建线程
    HANDLE hRemoteThread = CreateRemoteThread(
        hTargetProcess, NULL, 0, (DWORD (__stdcall *)(void *))pRemoteThread,
        NULL, 0, &dwWriteBytes);
    if (!hRemoteThread) {
        MessageBox(NULL, "Create remote thread failed !", "Notice", MB_ICONSTOP);
        return -1;
    }
    return 0;
}

当上面的代码运行的时候会在宿主进程中创建一条由程序员定义的线程,只不过现在这个线程函数体为空
什么都不做。
下面我们来编写具体的线程函数体的内容,在这里我们只是简单的显示一个消息对话框MessageBox
修改之后的线程函数体如下:
DWORD __stdcall threadProc(LPVOID lParam)
{
    MessageBox(NULL, "hello", "hello", MB_OK);
    return 0;
}

线程体修改完毕之后我们运行程序,将线程注入到宿主进程之中。不过此时会产生一个非法访问的错误。原
因就是线程体中的MessageBox(NULL, "hello", "hello", MB_OK);函数的第二和第三个参数所指向的字符串
是存在于当前进程的地址空间中,宿主进程中的线程访问该字符串"hello"就会出现访问内存非法的错误。
解决的方法就是将该字符串的内容也拷贝到宿主进程的地址空间中,而且连同MessageBox函数在User32.dll
中的地址也拷贝到宿主进程之中。
要将字符串和MessageBox函数的入口地址拷贝到宿主进程中我们首先定义下面这个RemoteParam结构体,用来
存放MessageBox函数的入口地址和MessageBox显示的字符串的内容,该结构的定义如下:
//线程参数
typedef struct _RemoteParam {
    char szMsg[12];    //MessageBox函数显示的字符串
    DWORD dwMessageBox;//MessageBox函数的入口地址
} RemoteParam, * PRemoteParam;

RemoteParam remoteData;
ZeroMemory(&remoteData, sizeof(RemoteParam));
 
HINSTANCE hUser32 = LoadLibrary("User32.dll");
remoteData.dwMessageBox = (DWORD)GetProcAddress(hUser32, "MessageBoxA");
strcat(remoteData.szMsg, "Hello/0");

//在宿主进程中分配存储空间
RemoteParam* pRemoteParam = (RemoteParam*)VirtualAllocEx(
    hTargetProcess , 0, sizeof(RemoteParam), MEM_COMMIT, PAGE_READWRITE);
 
if (!pRemoteParam) {
    MessageBox(NULL, "Alloc memory failed !",
        "Notice", MB_ICONINFORMATION | MB_OK);
    return 0;
}

//将字符串和MessageBox函数的入口地址写入宿主进程
if (!WriteProcessMemory(hTargetProcess ,
        pRemoteParam, &remoteData, sizeof(remoteData), 0)) {
    MessageBox(NULL, "Write data to target process failed !",
        "Notice", MB_ICONINFORMATION | MB_OK);
    return 0;
}
 
//创建远程线程
HANDLE hRemoteThread = CreateRemoteThread(
    hTargetProcess, NULL, 0, (DWORD (__stdcall *)(void *))pRemoteThread,
    pRemoteParam, 0, &dwWriteBytes);

另外还需要注意的一点是,在打开进程的时候有些系统进程是无法用OpenProcess函数
打开的,这个时候就需要提升进程的访问权限,进而来达到访问系统进程的目的,在这里
我提供了一个提升进程访问权限的函数enableDebugPriv(),该函数的定义如下:

//提升进程访问权限
bool enableDebugPriv()
{
    HANDLE hToken;
    LUID sedebugnameValue;
    TOKEN_PRIVILEGES tkp;
  
    if (!OpenProcessToken(GetCurrentProcess(),
        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        return false;
    }

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) {
        CloseHandle(hToken);
        return false;
    }

    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = sedebugnameValue;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) {
        CloseHandle(hToken);
        return false;
    }

    return true;
}

至此创建远程线程的工作全部结束,下面就给出完整的代码:

#pragma once
#include "stdafx.h"
#include <windows.h>
#include <TlHelp32.h>
#include <iostream>

//线程参数结构体定义
typedef struct _RemoteParam {
    char szMsg[12];    //MessageBox函数中显示的字符提示
    DWORD dwMessageBox;//MessageBox函数的入口地址
} RemoteParam, * PRemoteParam;

//定义MessageBox类型的函数指针
typedef int (__stdcall * PFN_MESSAGEBOX)(HWND, LPCTSTR, LPCTSTR, DWORD);


//线程函数定义
DWORD __stdcall threadProc(LPVOID lParam)
{
    RemoteParam* pRP = (RemoteParam*)lParam;
 
    PFN_MESSAGEBOX pfnMessageBox;
    pfnMessageBox = (PFN_MESSAGEBOX)pRP->dwMessageBox;
    pfnMessageBox(NULL, pRP->szMsg, pRP->szMsg, 0);

    return 0;
}

//提升进程访问权限
bool enableDebugPriv()
{
    HANDLE hToken;
    LUID sedebugnameValue;
    TOKEN_PRIVILEGES tkp;
  
    if (!OpenProcessToken(GetCurrentProcess(),
        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
        return false;
    }

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) {
        CloseHandle(hToken);
        return false;
    }

    tkp.PrivilegeCount = 1;
    tkp.Privileges[0].Luid = sedebugnameValue;
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) {
        CloseHandle(hToken);
        return false;
    }

    return true;
}


//根据进程名称得到进程ID,如果有多个运行实例的话,返回第一个枚举到的进程的ID
DWORD processNameToId(LPCTSTR lpszProcessName)
{
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(hSnapshot, &pe)) {
        MessageBox(NULL,
            "The frist entry of the process list has not been copyied to the buffer",
           "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }

    while (Process32Next(hSnapshot, &pe)) {
        if (!strcmp(lpszProcessName, pe.szExeFile)) {
            return pe.th32ProcessID;
        }
    }
 
    return 0;
}

int main(int argc, char* argv[])
{
    //定义线程体的大小
    const DWORD dwThreadSize = 4096;
    DWORD dwWriteBytes;
    //提升进程访问权限
    enableDebugPriv();

    //等待输入进程名称,注意大小写匹配
    std::cout << "Please input the name of target process !" << std::endl;
    char szExeName[MAX_PATH] = { 0 };
    std::cin >> szExeName;

    DWORD dwProcessId = processNameToId(szExeName);

    if (dwProcessId == 0) {
        MessageBox(NULL, "The target process have not been found !",
            "Notice", MB_ICONINFORMATION | MB_OK);
        return -1;
    }

    //根据进程ID得到进程句柄
    HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
 
    if (!hTargetProcess) {
        MessageBox(NULL, "Open target process failed !",
            "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }
 
    //在宿主进程中为线程体开辟一块存储区域
    //在这里需要注意MEM_COMMIT | MEM_RESERVE内存非配类型以及PAGE_EXECUTE_READWRITE内存保护类型
    //其具体含义请参考MSDN中关于VirtualAllocEx函数的说明。
    void* pRemoteThread = VirtualAllocEx(hTargetProcess, 0,
        dwThreadSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    if (!pRemoteThread) {
        MessageBox(NULL, "Alloc memory in target process failed !",
            "notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }
 
    //将线程体拷贝到宿主进程中
    if (!WriteProcessMemory(hTargetProcess,
            pRemoteThread, &threadProc, dwThreadSize, 0)) {
        MessageBox(NULL, "Write data to target process failed !",
            "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }
    //定义线程参数结构体变量
    RemoteParam remoteData;
    ZeroMemory(&remoteData, sizeof(RemoteParam));
 
    //填充结构体变量中的成员
    HINSTANCE hUser32 = LoadLibrary("User32.dll");
    remoteData.dwMessageBox = (DWORD)GetProcAddress(hUser32, "MessageBoxA");
    strcat(remoteData.szMsg, "Hello/0");
 
    //为线程参数在宿主进程中开辟存储区域
    RemoteParam* pRemoteParam = (RemoteParam*)VirtualAllocEx(
    hTargetProcess , 0, sizeof(RemoteParam), MEM_COMMIT, PAGE_READWRITE);
 
    if (!pRemoteParam) {
        MessageBox(NULL, "Alloc memory failed !",
            "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }

    //将线程参数拷贝到宿主进程地址空间中
    if (!WriteProcessMemory(hTargetProcess ,
            pRemoteParam, &remoteData, sizeof(remoteData), 0)) {
        MessageBox(NULL, "Write data to target process failed !",
            "Notice", MB_ICONINFORMATION | MB_OK);
        return 0;
    }
 
    //在宿主进程中创建线程
    HANDLE hRemoteThread = CreateRemoteThread(
        hTargetProcess, NULL, 0, (DWORD (__stdcall *)(void *))pRemoteThread,
        pRemoteParam, 0, &dwWriteBytes);

    if (!hRemoteThread) {
        MessageBox(NULL, "Create remote thread failed !", "Notice",  MB_ICONINFORMATION | MB_OK);
        return 0;
    }

    CloseHandle(hRemoteThread);

    return 0;
}

上面是远程线程注入的一段简单的代码,以及一些简要的说明,放在这里和大家共享!
希望各位不要见笑! :)

### RT-DETRv3 网络结构分析 RT-DETRv3 是一种基于 Transformer 的实时端到端目标检测算法,其核心在于通过引入分层密集正监督方法以及一系列创新性的训练策略,解决了传统 DETR 模型收敛慢和解码器训练不足的问题。以下是 RT-DETRv3 的主要网络结构特点: #### 1. **基于 CNN 的辅助分支** 为了增强编码器的特征表示能力,RT-DETRv3 引入了一个基于卷积神经网络 (CNN) 的辅助分支[^3]。这一分支提供了密集的监督信号,能够与原始解码器协同工作,从而提升整体性能。 ```python class AuxiliaryBranch(nn.Module): def __init__(self, in_channels, out_channels): super(AuxiliaryBranch, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1) self.bn = nn.BatchNorm2d(out_channels) def forward(self, x): return F.relu(self.bn(self.conv(x))) ``` 此部分的设计灵感来源于传统的 CNN 架构,例如 YOLO 系列中的 CSPNet 和 PAN 结构[^2],这些技术被用来优化特征提取效率并减少计算开销。 --- #### 2. **自注意力扰动学习策略** 为解决解码器训练不足的问题,RT-DETRv3 提出了一种名为 *self-att 扰动* 的新学习策略。这种策略通过对多个查询组中阳性样本的标签分配进行多样化处理,有效增加了阳例的数量,进而提高了模型的学习能力和泛化性能。 具体实现方式是在训练过程中动态调整注意力权重分布,确保更多的高质量查询可以与真实标注 (Ground Truth) 进行匹配。 --- #### 3. **共享权重解编码器分支** 除了上述改进外,RT-DETRv3 还引入了一个共享权重的解编码器分支,专门用于提供密集的正向监督信号。这一设计不仅简化了模型架构,还显著降低了参数量和推理时间,使其更适合实时应用需求。 ```python class SharedDecoderEncoder(nn.Module): def __init__(self, d_model, nhead, num_layers): super(SharedDecoderEncoder, self).__init__() decoder_layer = nn.TransformerDecoderLayer(d_model=d_model, nhead=nhead) self.decoder = nn.TransformerDecoder(decoder_layer, num_layers=num_layers) def forward(self, tgt, memory): return self.decoder(tgt=tgt, memory=memory) ``` 通过这种方式,RT-DETRv3 实现了高效的目标检测流程,在保持高精度的同时大幅缩短了推理延迟。 --- #### 4. **与其他模型的关系** 值得一提的是,RT-DETRv3 并未完全抛弃经典的 CNN 技术,而是将其与 Transformer 结合起来形成混合架构[^4]。例如,它采用了 YOLO 系列中的 RepNCSP 模块替代冗余的多尺度自注意力层,从而减少了不必要的计算负担。 此外,RT-DETRv3 还借鉴了 DETR 的一对一匹配策略,并在此基础上进行了优化,进一步提升了小目标检测的能力。 --- ### 总结 综上所述,RT-DETRv3 的网络结构主要包括以下几个关键组件:基于 CNN 的辅助分支、自注意力扰动学习策略、共享权重解编码器分支以及混合编码器设计。这些技术创新共同推动了实时目标检测领域的发展,使其在复杂场景下的表现更加出色。 ---
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值