[c++]远程线程注入

网上例子很多,但对细枝末节的处理少,某些情况下这些细节决定了注入的成功与否。

花了一点时间,自己写了个通用的标准远程线程注入。

#include <iostream>
#include <Windows.h>
#include <tchar.h>
#include <tlhelp32.h>
#include <shlobj_core.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")

// 寻找进程PID
DWORD FindPid(LPCTSTR name);
// 远程写入值
void WriteVal(LPVOID addr, LPVOID buff, SIZE_T size);
// 开启调试权限
BOOL EnableDebugPrivilege(BOOL fEnable);
// 提升特权
void PromotePrivilege();
// false=无特权  true=有特权
bool HasPrivilege();

HANDLE g_hProcess;
wchar_t* char2wchar(const char* cchar);

int main(int argc, char const* argv[])
{
    if (argc <= 1) return 0;
    // 提升管理员特权
    if (!HasPrivilege()) {
        printf("无特权,是否尝试提升特权?\n");
        system("pause");
        PromotePrivilege();
    }
    // 获取参数
    const char* dll_path = argv[1];
    wchar_t* process_name = char2wchar(argv[2]);
    DWORD pid = FindPid(process_name);
    if (pid <= 0) {
        printf("无效进程 \n");
        return 0;
    }
    printf("DLL路径:%s\n进程名:%ws (%d)(%0X)\n", dll_path, process_name, pid, pid);
    DWORD buffSize = strlen(dll_path) + 1;
    //1打开目标进程
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (hProcess == NULL) {
        printf("目标进程无效\n");
        return 0;
    }
    printf("目标进程HANDLE:%d\n", (int)hProcess);
    //2.申请远程内存空间
    char* str = (char*)VirtualAllocEx(hProcess, 0, buffSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    printf("申请到的远程内存空间地址:%0X\n", (int)str);
    if (str == NULL) {
        printf("申请失败!\n");
        return 0;
    }
    //3.将dll文件路径写入到远程内存
    DWORD realWrite = 0;
    BOOL bs1 = WriteProcessMemory(hProcess, str, dll_path, buffSize, &realWrite);
    printf("将dll文件路径[%s]写入被注入程序的内存:%s\n", dll_path, bs1 ?"成功":"失败");
    //4.创建远程线程
    HMODULE hK32Mod = GetModuleHandleA("Kernel32.dll");
    if (hK32Mod == NULL) {
        printf("获取Kernel32.dll地址为空\n");
        return 0;
    }
    printf(" -- Kernel32.dll : %0X \n", (DWORD)hK32Mod);
    int* pLoadLibrary = (int*)GetProcAddress(hK32Mod, "LoadLibraryA");
    if (pLoadLibrary == NULL) {
        printf("获取LoadLibraryA地址为空\n");
        return 0;
    }
    printf("    LoadLibraryA : %0X \n", (DWORD)pLoadLibrary);
    HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, str, 0, 0);
    if (hThread == NULL) {
        printf("远程线程创建失败\n");
        return 0;
    }
    printf("使用CreateRemoteThread呼叫LoadLibraryA,远程线程句柄:%0X \n", (int)hThread);
    printf("等待信号量 ...\n");
    WaitForSingleObject(hThread, -1);
    printf("收到退出信号量 ...\n");
    DWORD pExitCode; // 线程退出代码,在这里当然是LoadLibrary的返回值啦
    GetExitCodeThread(hThread, &pExitCode);
    printf("被注入的DLL在对方内存的地址:%0X \n", pExitCode);
    CloseHandle(hThread); //关闭线程句柄
    //释放内存空间
    BOOL bs2 = VirtualFreeEx(hProcess, str, 0, MEM_RELEASE);
    printf("释放dll文件路径的内存空间:%s\n", bs2 ? "成功" : "失败");
    CloseHandle(hProcess);  //关闭进程句柄
    system("pause");
    return 0;
}

// 远程内存写入
void WriteVal(LPVOID addr, LPVOID buff ,SIZE_T size) {
    // 代码段置为可写
    DWORD oldProtect;
    VirtualProtect(addr, sizeof(DWORD), PAGE_READWRITE, &oldProtect);
    SIZE_T realWriteNum;

    WriteProcessMemory(g_hProcess, addr, buff, size, &realWriteNum);

    // 代码段置为不可写
    DWORD oldProtect2;
    VirtualProtect(addr, sizeof(WORD), oldProtect, &oldProtect2);

}

// 根据进程名获取进程id
DWORD FindPid(LPCTSTR name) {
    DWORD aProcesses[1024], cbNeeded, ModNeeded;
    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
        return -1;
    HANDLE hProcess;
    HMODULE hMod;
    TCHAR szProcessName[MAX_PATH] = _T("unknown");
    int nProcesses = cbNeeded / sizeof(DWORD);
    for (int i = 0; i < nProcesses; i++) {
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
            PROCESS_VM_READ,
            FALSE, aProcesses[i]);
        if (NULL != hProcess) {
            if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &ModNeeded)) {
                GetModuleBaseName(hProcess, hMod, szProcessName, sizeof(szProcessName));
                if (lstrcmpi(szProcessName, name) == 0) {
                    return aProcesses[i];
                }
            }
            else
                continue;
        }
    }
    return -1;
}

// 单字符转宽字符
wchar_t* char2wchar(const char* cchar)
{
    wchar_t* m_wchar;
    int len = MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), NULL, 0);
    m_wchar = new wchar_t[len + 1];
    MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), m_wchar, len);
    m_wchar[len] = '\0';
    return m_wchar;
}

//提升为调试权限
BOOL EnableDebugPrivilege(BOOL fEnable) {   
    BOOL fOk = FALSE;    HANDLE hToken;
    // 以修改权限的方式,打开进程的令牌
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES,
        &hToken)) {
        // 令牌权限结构体
        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount = 1;
        //获得LUID
        LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
        tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
        AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); //修改权限
        fOk = (GetLastError() == ERROR_SUCCESS);
        CloseHandle(hToken);
    }
    return(fOk);
}

// 提升特权
void PromotePrivilege() {
    // 2. 获取当前程序路径
    WCHAR szApplication[MAX_PATH] = { 0 };
    DWORD cchLength = _countof(szApplication);
    QueryFullProcessImageName(GetCurrentProcess(), 0,
        szApplication, &cchLength);
    // 3. 以管理员权限重新打开进程
    SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
    sei.lpVerb = L"runas";      // 请求提升权限
    sei.lpFile = szApplication; // 可执行文件路径
    sei.lpParameters = NULL;          // 不需要参数
    sei.nShow = SW_SHOWNORMAL; // 正常显示窗口
    if (ShellExecuteEx(&sei)) {
        // 重启获得特权
        printf("重启程序 尝试提权\n");
        exit(0);
    } else {
        // 已有特权
        return;
    }
}

// false=无特权  true=有特权
bool HasPrivilege() {
    HANDLE hToken = NULL;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
        return false;
    // 2. 获取提升类型
    TOKEN_ELEVATION_TYPE ElevationType = TokenElevationTypeDefault;
    BOOL                 bIsAdmin = false;
    DWORD                dwSize = 0;
    if (GetTokenInformation(hToken, TokenElevationType, &ElevationType,
        sizeof(TOKEN_ELEVATION_TYPE), &dwSize)) {
        // 2.1 创建管理员组的对应SID
        BYTE adminSID[SECURITY_MAX_SID_SIZE];
        dwSize = sizeof(adminSID);
        CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &adminSID, &dwSize);
        // 2.2 判断当前进程运行用户角色是否为管理员
        if (ElevationType == TokenElevationTypeLimited) {
            // a. 获取连接令牌的句柄
            HANDLE hUnfilteredToken = NULL;
            GetTokenInformation(hToken, TokenLinkedToken, (PVOID)&hUnfilteredToken,
                sizeof(HANDLE), &dwSize);
            // b. 检查这个原始的令牌是否包含管理员的SID
            if (!CheckTokenMembership(hUnfilteredToken, &adminSID, &bIsAdmin))
                return false;
            CloseHandle(hUnfilteredToken);
        }
        else {
            bIsAdmin = IsUserAnAdmin();
        }
        CloseHandle(hToken);
    }
    // 3. 判断具体的权限状况
    BOOL bFullToken = false;
    switch (ElevationType) {
    case TokenElevationTypeDefault: /* 默认的用户或UAC被禁用 */
        if (IsUserAnAdmin())  bFullToken = true; // 默认用户有管理员权限
        else                  bFullToken = false;// 默认用户不是管理员组
        break;
    case TokenElevationTypeFull:    /* 已经成功提高进程权限 */
        if (IsUserAnAdmin())  bFullToken = true; //当前以管理员权限运行
        else                  bFullToken = false;//当前未以管理员权限运行
        break;
    case TokenElevationTypeLimited: /* 进程在以有限的权限运行 */
        if (bIsAdmin)  bFullToken = false;//用户有管理员权限,但进程权限有限
        else           bFullToken = false;//用户不是管理员组,且进程权限有限
    }
    return bFullToken;
}

使用方法,生成exe,假设名称为RemoteThreadDll.exe

exe同目录下创建一个bat文件,内容如下

RemoteThreadDll.exe D:\ap114\Dll1.dll kyodai.exe

注入器exe    dll文件路径   被注入的目标程序

 运行run.bat效果

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值