当前位置:首页 > c++ > 正文内容

c++实现windows进程伪装 - 进程隐藏技术

xuwenyan1年前 (2022-01-04)c++1403

进程伪装

进程伪装,其实就是通过修改peb里的进程名,可以将当前进程的信息指向一个存在甚至是不存在的进程。比如当前以a.exe运行,在运行后修改peb里的进程名为b.exe,那么他人想要获取当前进程的路径时,获取到的就是b.exe,然而我们在本地还是a.exe,因此就无法正确获取到我们的进程信息了,这就达到了伪装的目的。关于peb(Process Envirorment Block Structure)详情可以查看微软文档:peb

使用API

NtQueryInformationProcess

ReadProcessMemory

WriteProcessMemory

OpenProcess

LoadGetModuleHandle

GetProcAddress

注意NtQueryInformationProcess是隐藏api,并未导出。所以需要从ntdll.dll中动态获取。

基本实现步骤

1:使用OpenProcess打开需要伪装的进程(需使用PROCESS_ALL_ACCESS权限打开)

2:从ntdll.dll中动态获取到NtQueryInformationProcess函数

3:使用NtQueryInformationProcess获取进程的pbi信息

4:使用ReadProcessMemory获取进程的peb信息和进程参数信息(包含进程路径的长度、命令行长度等)

5:使用WriteProcessMemory修改进程的路径和命令行信息

代码实现

disguise_process.h

#ifndef DISGUISE_PROCESS_H_
#define DISGUISE_PROCESS_H_

#include <windows.h>

/**
 * 功能:伪造进程路径,进程命令行
 * 参数:process_id:需要伪造的进程id,当前进程使用::GetCurrentProcessId()
 *      image_path:需要伪造的进程路径,不需要传null
 *      command_line:需要伪造的命令行参数,不需要传null
 * 返回值:成功返回true,失败返回false
 */
bool DisguiseProcess(const DWORD process_id, const wchar_t* image_path, const wchar_t* command_line);

#endif // DISGUISE_PROCESS_H_

disguise_process.cpp

#include "disguise_process.h"
#include <winternl.h>

typedef
NTSTATUS(WINAPI* pfnNtQueryInformationProcess)
(HANDLE ProcessHandle, ULONG ProcessInformationClass,
  PVOID ProcessInformation, UINT32 ProcessInformationLength,
  UINT32* ReturnLength);

bool DisguiseProcess(const DWORD process_id, const wchar_t* image_path, const wchar_t* command_line) {
  // 打开进程获取句柄
  HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_id);
  if (hProcess == nullptr)
    return false;

  do {
    pfnNtQueryInformationProcess NtQueryInformationProcess = nullptr;
    PROCESS_BASIC_INFORMATION pbi = { 0 };

    // 需要通过 GetModuleHandle、GetProcessAddress 从 ntdll.dll 中获取地址
    NtQueryInformationProcess = (pfnNtQueryInformationProcess)::GetProcAddress(
      ::GetModuleHandle(L"ntdll.dll"), "NtQueryInformationProcess");
    if (NtQueryInformationProcess == nullptr)
      break;

    // 获取指定进程的基本信息
    NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), nullptr);
    if (!NT_SUCCESS(status))
      break;

    PEB peb = { 0 };
    RTL_USER_PROCESS_PARAMETERS Param = { 0 };

    /*
    注意在读写其他进程的时候,注意要使用ReadProcessMemory/WriteProcessMemory进行操作,
    每个指针指向的内容都需要获取,因为指针只能指向本进程的地址空间,必须要读取到本进程空间。
    要不然一直提示位置访问错误!
    */
    ::ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), nullptr);
    ::ReadProcessMemory(hProcess, peb.ProcessParameters, &Param, sizeof(Param), nullptr);

    if (command_line) {
      USHORT usCmdLen = (::wcslen(command_line) + 1) * sizeof(wchar_t);
      ::WriteProcessMemory(hProcess, Param.CommandLine.Buffer, command_line, usCmdLen, nullptr);
      ::WriteProcessMemory(hProcess, &Param.CommandLine.Length, &usCmdLen, sizeof(usCmdLen), nullptr);
    }

    if (image_path) {
      USHORT usPathLen = (::wcslen(image_path) + 1) * sizeof(wchar_t);
      ::WriteProcessMemory(hProcess, Param.ImagePathName.Buffer, image_path, usPathLen, nullptr);
      ::WriteProcessMemory(hProcess, &Param.ImagePathName.Length, &usPathLen, sizeof(usPathLen), nullptr);
    }
  } while (0);

  ::CloseHandle(hProcess);

  return true;
}

使用示例

调用DisguiseProcess传入pid、进程路径名、进程命令行即可,如果需要伪装当前进程,可以使用GetCurrentProcessId获取当前进程的pid。

#include <windows.h>
#include "disguise_process.h"

#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")

void main() {
  wchar_t szPath[MAX_PATH] = { 0 };
  ::GetModuleFileName(NULL, szPath, MAX_PATH);
  ::PathRemoveFileSpec(szPath);
  ::PathAppend(szPath, L"Hash.exe");

  STARTUPINFOW si = { 0 };
  PROCESS_INFORMATION pi = { 0 };
  si.cb = sizeof(STARTUPINFOW);
  BOOL succeed = ::CreateProcess(
    szPath,
    L"",
    nullptr,
    nullptr,
    FALSE,
    CREATE_SUSPENDED,
    nullptr,
    nullptr,
    &si,
    &pi);

  if (!succeed)
    return;

  DisguiseProcess(pi.dwProcessId, L"Test.exe", L"Test.exe");
  ::ResumeThread(pi.hThread);
}

注意事项

需要注意,由于peb结构所限制,修改后的进程名长度和命令行长度必须小于等于之前的,否则会出现一些未知问题。

    文章作者:xuwenyan
    版权声明:本文为本站原创文章,转载请注明出处,非常感谢,如版权漏申明或您觉得任何有异议的地方欢迎与本站取得联系。

    扫描二维码推送至手机访问。

    版权声明:本文由艺文笔记发布,如需转载请注明出处。

    本文链接:https://www.xuwenyan.com/archives/2350

    分享给朋友:

    “c++实现windows进程伪装 - 进程隐藏技术” 的相关文章

    C++隐藏程序崩溃,让程序优雅的崩溃

    C++隐藏程序崩溃,让程序优雅的崩溃

    我们的程序并不能保证是完全稳定的,当程序崩溃时会展示一个崩溃提示框给用户,这给用户带来的感觉非常不友好。当我们的程序是一个服务程序时(没有ui界面),用户可能根本就感知不到这个程序的存在,这种情况下如果程序崩溃,在不显示崩溃提示的前提下,我们只需要将这个服务程序重启就可以了,这对用户来说可能会友好...

    C++如何实现窗口全屏显示

    C++如何实现窗口全屏显示

    窗口全屏,直接上代码:void FullScreen(HWND hwnd) {   //去掉所有边框,解决虚拟机win10任务栏显示问题   DWORD style = ::GetWindowLo...

    C++指针*为什么靠后会比较好?

    C++指针*为什么靠后会比较好?

    大多数书中和大神的代码里,往往指针的*都是靠变量而不是靠类型的,这主要是为了不造成我们第一眼对变量类型的误解和对指针类型的误解,比如: int* p1,p2 我们一眼看上去是不是通常会觉得p1、p1都是一个int*的指针呢?因为我们通常会误把int*当作一个类型,然而无论int*还是i...

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    例如,我用VC2015的工程向导新建一个ATL的工程名字叫myAtl,那么VC会同时给我生成一个叫做myAtlPS的工程。这个myAtlPS工程是做什么的?什么情况下可以不需要它?什么情况下它又是必须存在的? PS工程是什么?可以不要吗? 这个PS工程叫做代理与存根(proxy&nbs...

    解决程序在xp系统总是莫名奇妙的崩溃问题(/Zc:threadSafeInit- )

    解决程序在xp系统总是莫名奇妙的崩溃问题(/Zc:threadSafeInit- )

    现象:程序在xp系统上面总是莫名其妙的崩溃,检查代码看不出任何问题,感觉代码都很好。即使你远程调试,找到了崩溃的点,当你注释了崩溃点之后,还是会崩溃到别的地方。当你遇到了这种情况的时候,不妨参照一下下面的方法看看,说不定可以解决问题。如何解决?将崩溃程序相关的所有工程代码全部关闭全局变量的线程安全检...

    uafxcwd.lib(afxmem.obj) : error LNK2005:

    uafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)"解决办法

    如果在编译MFC程序的时候出现下列及类似的错误: 1˃uafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) 已经在 LIBCMTD.lib(new...