原文链接:https://xz.aliyun.com/t/16858
作者:Bat-Hibara
鄙人最近在某某群中寻找到了一个不知道谁的后门,心血来潮写下此文,以此提供一些蓝队简易反钓鱼的策略
ps.(下篇文章就写红队如何高概率钓鱼,期待一下)
本文所用环境:VS2022
通过对IP查找,特殊文件名,文件编译器,启动项的检查,选出第一批可疑进程,再对其筛选,最终以弹窗的形式呈现
1.获取所有进程的IP连接:
#include<fstream>
#include<string>
#include<vector>
#include<winsock2.h>
#include<iphlpapi.h>
#include<windows.h>
#include<tlhelp32.h>
#include<psapi.h>
#include<ws2tcpip.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "advapi32.lib") // For UAC check and elevation
// Function to get the process name given its PID
std::wstring getProcessName(DWORD pid) {
wchar_t processName[MAX_PATH] = L"<未知>";
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
HMODULE hMod;
DWORD cbNeeded;
if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
GetModuleBaseNameW(hProcess, hMod, processName, sizeof(processName) / sizeof(wchar_t));
}
CloseHandle(hProcess);
}
return std::wstring(processName);
}
// Function to get the process path given its PID
std::wstring getProcessPath(DWORD pid) {
wchar_t processPath[MAX_PATH] = L"<未知>";
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
GetModuleFileNameExW(hProcess, NULL, processPath, sizeof(processPath) / sizeof(wchar_t));
CloseHandle(hProcess);
}
return std::wstring(processPath);
}
// Function to enumerate all network connections
void enumerateConnections() {
PMIB_TCPTABLE2 tcpTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
tcpTable = (MIB_TCPTABLE2*)malloc(sizeof(MIB_TCPTABLE2));
if (tcpTable == NULL) {
std::cerr << "分配内存时出错" << std::endl;
return;
}
dwSize = sizeof(MIB_TCPTABLE2);
if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == ERROR_INSUFFICIENT_BUFFER) {
free(tcpTable);
tcpTable = (MIB_TCPTABLE2*)malloc(dwSize);
if (tcpTable == NULL) {
std::cerr << "分配内存时出错" << std::endl;
return;
}
}
if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == NO_ERROR) {
char ipStringBuffer[INET_ADDRSTRLEN];
std::wstring output;
for (int i = 0; i < (int)tcpTable->dwNumEntries; i++) {
inet_ntop(AF_INET, &tcpTable->table[i].dwRemoteAddr, ipStringBuffer, INET_ADDRSTRLEN);
std::string remoteIp(ipStringBuffer);
DWORD pid = tcpTable->table[i].dwOwningPid;
std::wstring processName = getProcessName(pid);
std::wstring processPath = getProcessPath(pid);
output += L"程序名称: " + processName + L"n连接的IP: " + std::wstring(remoteIp.begin(), remoteIp.end()) +
L"n程序路径: " + processPath + L"n---------------------------------n";
}
// Show the output in a message box
if (!output.empty()) {
MessageBoxW(NULL, output.c_str(), L"IP 和进程监控", MB_OK);
}
else {
MessageBoxW(NULL, L"未找到任何连接信息。", L"IP 和进程监控", MB_OK);
}
}
else {
std::cerr << "GetTcpTable2 调用失败,错误代码: " << dwRetVal << std::endl;
}
if (tcpTable != NULL) {
free(tcpTable);
tcpTable = NULL;
}
}
// Function to check if the program is running as administrator
bool isRunningAsAdmin() {
BOOL fIsRunAsAdmin = FALSE;
PSID pAdministratorsGroup = NULL;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (AllocateAndInitializeSid(&NtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAdministratorsGroup))
{
if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) {
fIsRunAsAdmin = FALSE;
}
FreeSid(pAdministratorsGroup);
}
return fIsRunAsAdmin;
}
// Function to restart the program with UAC elevation
void runAsAdmin() {
wchar_t szPath[MAX_PATH];
if (GetModuleFileNameW(NULL, szPath, ARRAYSIZE(szPath))) {
SHELLEXECUTEINFOW sei = { sizeof(sei) };
sei.lpVerb = L"runas";
sei.lpFile = szPath;
sei.hwnd = NULL;
sei.nShow = SW_NORMAL;
if (!ShellExecuteExW(&sei)) {
DWORD dwError = GetLastError();
if (dwError == ERROR_CANCELLED) {
MessageBoxW(NULL, L"用户拒绝了权限提升请求。", L"错误", MB_OK);
}
}
else {
ExitProcess(0); // Terminate the current process since it's being restarted with elevation
}
}
}
int main() {
// Step 1: Check for administrator privileges
if (!isRunningAsAdmin()) {
MessageBoxW(NULL, L"尝试以管理员权限运行...", L"提示", MB_OK);
runAsAdmin();
return 0;
}
// Step 2: Enumerate all connections
enumerateConnections();
return 0;
}
功能解释:
头文件和库的导入部分
#include<fstream>
#include<string>
#include<vector>
#include<winsock2.h>
#include<iphlpapi.h>
#include<windows.h>
#include<tlhelp32.h>
#include<psapi.h>
#include<ws2tcpip.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "advapi32.lib") // For UAC check and elevation
功能说明:
- 头文件:
iostream
, fstream
: 用于输入输出流操作。string
, vector
: 提供字符串处理和动态数组的支持。winsock2.h
: 提供 Windows 套接字(网络编程)接口。 iphlpapi.h
: 包含与 IP 地址和网络接口相关的 API。 windows.h
: Windows API 的通用头文件,提供多种核心功能。 tlhelp32.h
: 提供与进程、线程快照相关的 API。 psapi.h
: 用于获取进程相关信息(如模块和内存使用情况)。 ws2tcpip.h
: 提供对 IPv6、地址转换和其他网络功能的支持。
- 库链接:
iphlpapi.lib
: 提供 IP 助手 API 的支持。 ws2_32.lib
: 提供套接字编程所需的基础支持。 user32.lib
: 提供与 GUI 和用户界面交互相关的 API。 advapi32.lib
: 提供与权限提升(如 UAC 检查)相关的 API。
获取进程名称的函数
std::wstring getProcessName(DWORD pid) {
wchar_t processName[MAX_PATH] = L"<未知>";
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
HMODULE hMod;
DWORD cbNeeded;
if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
GetModuleBaseNameW(hProcess, hMod, processName, sizeof(processName) / sizeof(wchar_t));
}
CloseHandle(hProcess);
}
return std::wstring(processName);
}
功能说明:
- 输入:
pid
: 进程的 PID(Process ID)。
- 输出:
-
该 PID 对应的进程名称。
-
- 详细逻辑:
PROCESS_QUERY_INFORMATION
: 允许查询进程信息。 PROCESS_VM_READ
: 允许读取进程的虚拟内存。
-
调用 OpenProcess
打开目标进程句柄,权限为PROCESS_QUERY_INFORMATION | PROCESS_VM_READ
。 -
使用 EnumProcessModules
获取进程的第一个模块句柄(通常是主程序)。 -
调用 GetModuleBaseNameW
获取该模块(即程序)的名称。 -
若无法获取,返回默认值 <未知>
。 -
关闭进程句柄以释放资源。
获取进程路径的函数
std::wstring getProcessPath(DWORD pid) {
wchar_t processPath[MAX_PATH] = L"<未知>";
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
GetModuleFileNameExW(hProcess, NULL, processPath, sizeof(processPath) / sizeof(wchar_t));
CloseHandle(hProcess);
}
return std::wstring(processPath);
}
功能说明:
- 输入:
pid
: 进程的 PID(Process ID)。
- 输出:
-
该 PID 对应的可执行文件完整路径。
-
- 详细逻辑:
-
与获取进程名称类似,但这里使用 GetModuleFileNameExW
,返回的是可执行文件的完整路径(包括磁盘路径)。 -
如果进程无法访问,返回默认值 <未知>
。
-
枚举所有网络连接的函数
voidenumerateConnections(){
PMIB_TCPTABLE2 tcpTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
tcpTable = (MIB_TCPTABLE2*)malloc(sizeof(MIB_TCPTABLE2));
if (tcpTable == NULL) {
std::cerr << "分配内存时出错" << std::endl;
return;
}
功能说明:
- 步骤 1:分配空间
-
调用 malloc
为MIB_TCPTABLE2
分配内存,用于存储 TCP 连接表。
-
cpp复制代码
if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == ERROR_INSUFFICIENT_BUFFER) {
free(tcpTable);
tcpTable = (MIB_TCPTABLE2*)malloc(dwSize);
if (tcpTable == NULL) {
std::cerr << "分配内存时出错" << std::endl;
return;
}
}
- 步骤 2:获取 TCP 连接表
-
使用 GetTcpTable2
获取当前的 TCP 连接表。 -
如果内存不足,重新分配足够的空间。
-
cpp复制代码
if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == NO_ERROR) {
char ipStringBuffer[INET_ADDRSTRLEN];
std::wstring output;
for (int i = 0; i < (int)tcpTable->dwNumEntries; i++) {
inet_ntop(AF_INET, &tcpTable->table[i].dwRemoteAddr, ipStringBuffer, INET_ADDRSTRLEN);
std::string remoteIp(ipStringBuffer);
DWORD pid = tcpTable->table[i].dwOwningPid;
std::wstring processName = getProcessName(pid);
std::wstring processPath = getProcessPath(pid);
output += L"程序名称: " + processName + L"n连接的IP: " + std::wstring(remoteIp.begin(), remoteIp.end()) +
L"n程序路径: " + processPath + L"n---------------------------------n";
}
- 步骤 3:解析每个连接
-
遍历 tcpTable->table
中的每个 TCP 连接项。 -
使用 inet_ntop
将二进制的远程 IP 地址转换为字符串形式。 -
调用 getProcessName
和getProcessPath
获取连接对应进程的名称和路径。 -
将结果拼接到 output
中。
-
cpp复制代码
if(!output.empty()) {
MessageBoxW(NULL, output.c_str(), L"IP 和进程监控", MB_OK);
}
else {
MessageBoxW(NULL, L"未找到任何连接信息。", L"IP 和进程监控", MB_OK);
}
}
- 步骤 4:输出结果
-
如果存在连接信息,将结果显示在消息框中。 -
如果没有任何连接,显示提示信息。
-
cpp复制代码
if (tcpTable != NULL) {
free(tcpTable);
tcpTable = NULL;
}
- 步骤 5:释放资源
-
释放之前分配的内存,避免内存泄漏。
-
检查程序是否以管理员权限运行
bool isRunningAsAdmin() {
BOOL fIsRunAsAdmin = FALSE;
PSID pAdministratorsGroup = NULL;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (AllocateAndInitializeSid(&NtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAdministratorsGroup))
{
if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) {
fIsRunAsAdmin = FALSE;
}
FreeSid(pAdministratorsGroup);
}
return fIsRunAsAdmin;
}
功能说明:
-
通过 CheckTokenMembership
检查当前用户是否属于管理员组。 -
如果属于管理员组,返回 true
;否则返回false
。
请求权限提升
voidrunAsAdmin(){
wchar_t szPath[MAX_PATH];
if (GetModuleFileNameW(NULL, szPath, ARRAYSIZE(szPath))) {
SHELLEXECUTEINFOW sei = { sizeof(sei) };
sei.lpVerb = L"runas";
sei.lpFile = szPath;
sei.hwnd = NULL;
sei.nShow = SW_NORMAL;
if (!ShellExecuteExW(&sei)) {
DWORD dwError = GetLastError();
if (dwError == ERROR_CANCELLED) {
MessageBoxW(NULL, L"用户拒绝了权限提升请求。", L"错误", MB_OK);
}
}
else {
ExitProcess(0);
}
}
}
功能说明:
-
如果程序未以管理员权限运行,调用 ShellExecuteExW
重新启动程序,并请求权限提升。
主函数
intmain() {
if (!isRunningAsAdmin()) {
MessageBoxW(NULL, L"尝试以管理员权限运行...", L"提示", MB_OK);
runAsAdmin();
return0;
}
enumerateConnections();
return0;
}
功能说明:
-
检查程序是否以管理员权限运行。 -
如果未以管理员权限运行,尝试权限提升。 -
如果权限足够,则调用 enumerateConnections
列出所有网络连接。
2.过筛-192,127,0等
code:
#include<fstream>
#include<string>
#include<vector>
#include<winsock2.h>
#include<iphlpapi.h>
#include<windows.h>
#include<tlhelp32.h>
#include<psapi.h>
#include<ws2tcpip.h>
#define _CRT_SECURE_NO_WARNINGS
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "advapi32.lib") // For UAC check and elevation
// Function to check if an IP is public (exclude private/internal IPs)
bool isPublicIP(const std::string& ip) {
// Split IP into 4 octets
unsigned int octet1, octet2, octet3, octet4;
if (sscanf_s(ip.c_str(), "%u.%u.%u.%u", &octet1, &octet2, &octet3, &octet4) != 4) {
return false; // Invalid IP format
}
// Exclude private IP ranges
if ((octet1 == 10) || // 10.0.0.0/8
(octet1 == 127) || // 127.0.0.0/8 (loopback)
(octet1 == 192 && octet2 == 168) || // 192.168.0.0/16
(octet1 == 172 && (octet2 >= 16 && octet2 <= 31)) || // 172.16.0.0/12
(octet1 == 0) || // 0.0.0.0 (invalid address)
(octet1 == 169 && octet2 == 254)) { // 169.254.0.0/16 (APIPA)
return false;
}
return true; // Public IP
}
// Function to get the process name given its PID
std::wstring getProcessName(DWORD pid) {
wchar_t processName[MAX_PATH] = L"<未知>";
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
HMODULE hMod;
DWORD cbNeeded;
if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
GetModuleBaseNameW(hProcess, hMod, processName, sizeof(processName) / sizeof(wchar_t));
}
CloseHandle(hProcess);
}
return std::wstring(processName);
}
// Function to get the process path given its PID
std::wstring getProcessPath(DWORD pid) {
wchar_t processPath[MAX_PATH] = L"<未知>";
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
GetModuleFileNameExW(hProcess, NULL, processPath, sizeof(processPath) / sizeof(wchar_t));
CloseHandle(hProcess);
}
return std::wstring(processPath);
}
// Function to enumerate all network connections
void enumerateConnections() {
PMIB_TCPTABLE2 tcpTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
tcpTable = (MIB_TCPTABLE2*)malloc(sizeof(MIB_TCPTABLE2));
if (tcpTable == NULL) {
std::cerr << "分配内存时出错" << std::endl;
return;
}
dwSize = sizeof(MIB_TCPTABLE2);
if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == ERROR_INSUFFICIENT_BUFFER) {
free(tcpTable);
tcpTable = (MIB_TCPTABLE2*)malloc(dwSize);
if (tcpTable == NULL) {
std::cerr << "分配内存时出错" << std::endl;
return;
}
}
if ((dwRetVal = GetTcpTable2(tcpTable, &dwSize, TRUE)) == NO_ERROR) {
char ipStringBuffer[INET_ADDRSTRLEN];
std::wstring output;
for (int i = 0; i < (int)tcpTable->dwNumEntries; i++) {
inet_ntop(AF_INET, &tcpTable->table[i].dwRemoteAddr, ipStringBuffer, INET_ADDRSTRLEN);
std::string remoteIp(ipStringBuffer);
// Filter out private/internal IPs
if (!isPublicIP(remoteIp)) {
continue; // Skip internal/private IPs
}
DWORD pid = tcpTable->table[i].dwOwningPid;
std::wstring processName = getProcessName(pid);
std::wstring processPath = getProcessPath(pid);
output += L"程序名称: " + processName + L"n连接的IP: " + std::wstring(remoteIp.begin(), remoteIp.end()) +
L"n程序路径: " + processPath + L"n---------------------------------n";
}
// Show the output in a message box
if (!output.empty()) {
MessageBoxW(NULL, output.c_str(), L"IP 和进程监控", MB_OK);
}
else {
MessageBoxW(NULL, L"未找到任何有效的公网连接信息。", L"IP 和进程监控", MB_OK);
}
}
else {
std::cerr << "GetTcpTable2 调用失败,错误代码: " << dwRetVal << std::endl;
}
if (tcpTable != NULL) {
free(tcpTable);
tcpTable = NULL;
}
}
// Function to check if the program is running as administrator
bool isRunningAsAdmin() {
BOOL fIsRunAsAdmin = FALSE;
PSID pAdministratorsGroup = NULL;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (AllocateAndInitializeSid(&NtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAdministratorsGroup))
{
if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) {
fIsRunAsAdmin = FALSE;
}
FreeSid(pAdministratorsGroup);
}
return fIsRunAsAdmin;
}
// Function to restart the program with UAC elevation
void runAsAdmin() {
wchar_t szPath[MAX_PATH];
if (GetModuleFileNameW(NULL, szPath, ARRAYSIZE(szPath))) {
SHELLEXECUTEINFOW sei = { sizeof(sei) };
sei.lpVerb = L"runas";
sei.lpFile = szPath;
sei.hwnd = NULL;
sei.nShow = SW_NORMAL;
if (!ShellExecuteExW(&sei)) {
DWORD dwError = GetLastError();
if (dwError == ERROR_CANCELLED) {
MessageBoxW(NULL, L"用户拒绝了权限提升请求。", L"错误", MB_OK);
}
}
else {
ExitProcess(0); // Terminate the current process since it's being restarted with elevation
}
}
}
int main() {
// Step 1: Check for administrator privileges
if (!isRunningAsAdmin()) {
MessageBoxW(NULL, L"尝试以管理员权限运行...", L"提示", MB_OK);
runAsAdmin();
return 0;
}
// Step 2: Enumerate all connections
enumerateConnections();
return 0;
}
- 新增
**isPublicIP**
函数
: -
对 IP 地址进行解析,筛选出公网 IP。 -
剔除内网范围(如 127.0.0.0/8
、192.168.0.0/16
、172.16.0.0/12
等)。
-
- 在
**enumerateConnections**
函数中调用**isPublicIP**
: -
遍历每个 TCP 连接时,使用 isPublicIP
检查远程 IP 地址,剔除内网 IP 和无效地址。
-
1.启动目录及任务启动
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
#include <shlobj.h>
#include <tlhelp32.h>
#pragma comment(lib, "shell32.lib")
std::vector<std::wstring> getFilesInDirectory(const std::wstring& directoryPath) {
std::vector<std::wstring> filePaths;
WIN32_FIND_DATA findFileData;
HANDLE hFind = FindFirstFile((directoryPath + L"\*").c_str(), &findFileData);
if (hFind == INVALID_HANDLE_VALUE) {
return filePaths;
}
do {
conststd::wstring fileOrDirName = findFileData.cFileName;
if (fileOrDirName != L"." && fileOrDirName != L"..") {
conststd::wstring fullPath = directoryPath + L"\" + fileOrDirName;
if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
filePaths.push_back(fullPath);
}
}
} while (FindNextFile(hFind, &findFileData) != 0);
FindClose(hFind);
return filePaths;
}
voidshowMessage(const std::wstring& message) {
MessageBoxW(NULL, message.c_str(), L"启动项检查", MB_OK | MB_ICONINFORMATION);
}
voidcheckStartupDirectories() {
wchar_t* userName = nullptr;
size_t len = 0;
_wdupenv_s(&userName, &len, L"USERNAME");
// 定义常见的启动目录
std::wstring startupDirectories[] = {
L"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup",
L"C:\Users\" + std::wstring(userName) + L"\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup",
L"C:\Users\" + std::wstring(userName) + L"\AppData\Local\Microsoft\Windows\Startup",
L"C:\Users\" + std::wstring(userName) + L"\AppData\Roaming\Microsoft\Windows\Startup"
};
free(userName); // 释放分配的内存
std::wstring message = L"";
for (const auto& directory : startupDirectories) {
std::vector<std::wstring> files = getFilesInDirectory(directory);
if (!files.empty()) {
message += L"在目录 " + directory + L" 中找到以下启动项:n";
for (const auto& file : files) {
message += L" - " + file + L"n";
}
message += L"n";
}
}
if (!message.empty()) {
showMessage(L"以下是各启动目录中的文件:n" + message);
} else {
showMessage(L"未检测到各启动目录中的启动项文件。");
}
}
void checkTaskSchedulerStartupItems() {
// 定义任务计划程序路径的查询命令
std::wstring command = L"schtasks /query /fo LIST /v";
std::wstring result = L"";
FILE* pipe = _wpopen(command.c_str(), L"r");
if (!pipe) {
showMessage(L"无法执行任务计划程序查询命令!");
return;
}
wchar_t buffer[1024];
while (fgetws(buffer, sizeof(buffer) / sizeof(wchar_t), pipe) != NULL) {
result += buffer;
}
_pclose(pipe);
if (!result.empty()) {
showMessage(L"任务计划启动项内容:n" + result);
} else {
showMessage(L"未检测到任务计划中的启动项。");
}
}
int main() {
checkStartupDirectories();
checkTaskSchedulerStartupItems();
return 0;
}
(1)getFilesInDirectory()
- 扫描目录中的文件
std::vector<std::wstring> getFilesInDirectory(const std::wstring& directoryPath){
std::vector<std::wstring> filePaths;
WIN32_FIND_DATA findFileData;
HANDLE hFind = FindFirstFile((directoryPath + L"\*").c_str(), &findFileData);
if (hFind == INVALID_HANDLE_VALUE) {
return filePaths;
}
do {
const std::wstring fileOrDirName = findFileData.cFileName;
if (fileOrDirName != L"." && fileOrDirName != L"..") {
const std::wstring fullPath = directoryPath + L"\" + fileOrDirName;
if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
filePaths.push_back(fullPath);
}
}
} while (FindNextFile(hFind, &findFileData) != 0);
FindClose(hFind);
return filePaths;
}
- 作用
:获取指定目录中的所有文件路径。 - 逻辑
: -
调用 FindFirstFile()
和FindNextFile()
遍历目录。 -
忽略 .
和..
(表示当前目录和父目录)。 -
只将非目录的文件路径加入结果列表。
-
- 返回值
:包含文件路径的 std::vector
。
(2)checkStartupDirectories()
- 检查常见启动目录
void checkStartupDirectories() {
wchar_t* userName = nullptr;
size_t len = 0;
_wdupenv_s(&userName, &len, L"USERNAME");
// 定义常见的启动目录
std::wstring startupDirectories[] = {
L"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup",
L"C:\Users\" + std::wstring(userName) + L"\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup",
L"C:\Users\" + std::wstring(userName) + L"\AppData\Local\Microsoft\Windows\Startup",
L"C:\Users\" + std::wstring(userName) + L"\AppData\Roaming\Microsoft\Windows\Startup"
};
free(userName); // 释放分配的内存
std::wstring message = L"";
for (const auto& directory : startupDirectories) {
std::vector<std::wstring> files = getFilesInDirectory(directory);
if (!files.empty()) {
message += L"在目录 " + directory + L" 中找到以下启动项:n";
for (const auto& file : files) {
message += L" - " + file + L"n";
}
message += L"n";
}
}
if (!message.empty()) {
showMessage(L"以下是各启动目录中的文件:n" + message);
} else {
showMessage(L"未检测到各启动目录中的启动项文件。");
}
}
- 作用
:扫描系统中几个常见启动目录,列出其中的文件。 - 步骤
: -
调用 getFilesInDirectory()
检查目录中的文件。 -
如果存在文件,将其路径记录到消息内容中。
-
-
-
公共启动目录: C:ProgramData...
-
当前用户的启动目录: C:Users[USERNAME]AppData...
-
获取当前用户名(用于构造用户相关的目录路径)。 -
定义常见的启动目录路径数组,包括: -
遍历每个目录: -
弹窗显示结果。
-
- 功能覆盖
: -
扫描所有用户级别和全局级别的启动目录。
-
(3)checkTaskSchedulerStartupItems()
- 检查任务计划中的启动项
void checkTaskSchedulerStartupItems() {
// 定义任务计划程序路径的查询命令
std::wstring command = L"schtasks /query /fo LIST /v";
std::wstring result = L"";
FILE* pipe = _wpopen(command.c_str(), L"r");
if (!pipe) {
showMessage(L"无法执行任务计划程序查询命令!");
return;
}
wchar_t buffer[1024];
while (fgetws(buffer, sizeof(buffer) / sizeof(wchar_t), pipe) != NULL) {
result += buffer;
}
_pclose(pipe);
if (!result.empty()) {
showMessage(L"任务计划启动项内容:n" + result);
} else {
showMessage(L"未检测到任务计划中的启动项。");
}
}
- 作用
:通过命令行工具 schtasks
获取任务计划中定义的启动项。 - 步骤
: /query
:查询任务计划。 /fo LIST
:输出为列表格式。 /v
:显示详细信息。
-
定义命令: schtasks /query /fo LIST /v
-
使用 _wpopen()
打开命令行管道,执行命令。 -
读取命令输出,将其存储为字符串。 -
如果有输出,弹窗显示任务计划项的内容;否则提示没有启动项。
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <wintrust.h>
#include <softpub.h>
#include <winreg.h>
#include <iphlpapi.h>
#include <sddl.h>
#include <fstream>
#include <chrono>
#include <thread>
#include <Lmcons.h>
#include <ShlObj.h>
#include <ctime>
#include <regex>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "wintrust.lib")
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "shell32.lib")
std::vector<std::wstring> getFilesInDirectory(const std::wstring& directoryPath) {
std::vector<std::wstring> filePaths;
WIN32_FIND_DATA findFileData;
HANDLE hFind = FindFirstFile((directoryPath + L"\*").c_str(), &findFileData);
if (hFind == INVALID_HANDLE_VALUE) {
return filePaths;
}
do {
const std::wstring fileOrDirName = findFileData.cFileName;
if (fileOrDirName != L"." && fileOrDirName != L"..") {
const std::wstring fullPath = directoryPath + L"\" + fileOrDirName;
if (!(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
filePaths.push_back(fullPath);
}
}
} while (FindNextFile(hFind, &findFileData) != 0);
FindClose(hFind);
return filePaths;
}
bool isRunningAsAdmin() {
BOOL isAdmin = FALSE;
PSID adminGroup = NULL;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &adminGroup)) {
CheckTokenMembership(NULL, adminGroup, &isAdmin);
FreeSid(adminGroup);
}
return isAdmin;
}
void restartAsAdmin() {
wchar_t szPath[MAX_PATH];
if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath))) {
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.lpVerb = L"runas";
sei.lpFile = szPath;
sei.hwnd = NULL;
sei.nShow = SW_NORMAL;
if (!ShellExecuteEx(&sei)) {
std::cerr << "请求管理员权限失败。" << std::endl;
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
}
std::wstring getProcessName(DWORD pid) {
wchar_t processName[MAX_PATH] = L"<未知>";
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
HMODULE hMod;
DWORD cbNeeded;
if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
GetModuleBaseNameW(hProcess, hMod, processName, sizeof(processName) / sizeof(wchar_t));
}
CloseHandle(hProcess);
}
return std::wstring(processName);
}
std::wstring getProcessPath(DWORD pid) {
wchar_t processPath[MAX_PATH] = L"<未知>";
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
GetModuleFileNameExW(hProcess, NULL, processPath, sizeof(processPath) / sizeof(wchar_t));
CloseHandle(hProcess);
}
return std::wstring(processPath);
}
bool isSystemProcess(HANDLE hProcess) {
HANDLE hToken = NULL;
if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
returnfalse;
}
DWORD dwSize = 0;
GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
PTOKEN_USER pTokenUser = (PTOKEN_USER)malloc(dwSize);
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwSize, &dwSize)) {
free(pTokenUser);
CloseHandle(hToken);
returnfalse;
}
WCHAR szName[MAX_PATH];
WCHAR szDomain[MAX_PATH];
DWORD dwNameSize = MAX_PATH;
DWORD dwDomainSize = MAX_PATH;
SID_NAME_USE sidType;
if (LookupAccountSidW(NULL, pTokenUser->User.Sid, szName, &dwNameSize, szDomain, &dwDomainSize, &sidType)) {
if (wcscmp(szName, L"SYSTEM") == 0) {
free(pTokenUser);
CloseHandle(hToken);
returntrue;
}
}
free(pTokenUser);
CloseHandle(hToken);
returnfalse;
}
std::vector<std::wstring> getExternalIPs(DWORD pid) {
std::vector<std::wstring> externalIPs;
PMIB_TCPTABLE2 tcpTable;
DWORD dwSize = 0;
GetTcpTable2(NULL, &dwSize, TRUE);
tcpTable = (PMIB_TCPTABLE2)malloc(dwSize);
if (GetTcpTable2(tcpTable, &dwSize, TRUE) == NO_ERROR) {
for (DWORD i = 0; i < tcpTable->dwNumEntries; i++) {
if (tcpTable->table[i].dwOwningPid == pid) {
DWORD ipAddr = tcpTable->table[i].dwRemoteAddr;
BYTE* ipBytes = (BYTE*)&ipAddr;
std::wstring ipString = std::to_wstring(ipBytes[0]) + L"." +
std::to_wstring(ipBytes[1]) + L"." +
std::to_wstring(ipBytes[2]) + L"." +
std::to_wstring(ipBytes[3]);
if (!(ipBytes[0] == 192 && ipBytes[1] == 168) &&
!(ipBytes[0] == 127 && ipBytes[1] == 0) &&
!(ipAddr == 0)) {
externalIPs.push_back(ipString);
}
}
}
}
free(tcpTable);
return externalIPs;
}
enum ProcessSignatureStatus {
SIGNED_AND_TRUSTED,
SIGNED_BUT_NOT_TRUSTED,
NOT_SIGNED
};
ProcessSignatureStatus checkProcessSignature(const std::wstring& processPath) {
WINTRUST_FILE_INFO fileInfo = { 0 };
fileInfo.cbStruct = sizeof(fileInfo);
fileInfo.pcwszFilePath = processPath.c_str();
WINTRUST_DATA winTrustData = { 0 };
winTrustData.cbStruct = sizeof(winTrustData);
winTrustData.dwUIChoice = WTD_UI_NONE;
winTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
winTrustData.dwUnionChoice = WTD_CHOICE_FILE;
winTrustData.dwStateAction = WTD_STATEACTION_VERIFY;
winTrustData.pFile = &fileInfo;
GUID policyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
LONG status = WinVerifyTrust(NULL, &policyGUID, &winTrustData);
winTrustData.dwStateAction = WTD_STATEACTION_CLOSE;
WinVerifyTrust(NULL, &policyGUID, &winTrustData);
if (status == ERROR_SUCCESS) {
return SIGNED_AND_TRUSTED;
}
elseif (status == TRUST_E_NOSIGNATURE) {
return NOT_SIGNED;
}
else {
return SIGNED_BUT_NOT_TRUSTED;
}
}
bool detectTrojanBehavior(DWORD pid, const std::wstring& processPath) {
bool hasSuspiciousBehavior = false;
std::vector<std::wstring> sensitiveDirs = { L"C:\Windows\System32", L"C:\Users" };
for (const auto& dir : sensitiveDirs) {
if (processPath.find(dir) != std::wstring::npos) {
hasSuspiciousBehavior = true;
break;
}
}
if (isSystemProcess(OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid))) {
hasSuspiciousBehavior = true;
}
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap != INVALID_HANDLE_VALUE) {
if (Process32First(hProcessSnap, &pe32)) {
do {
if (pe32.th32ProcessID != pid) {
hasSuspiciousBehavior = true;
break;
}
} while (Process32Next(hProcessSnap, &pe32));
}
CloseHandle(hProcessSnap);
}
return hasSuspiciousBehavior;
}
bool isHighRiskProcess(const std::wstring& processName, const std::wstring& processPath) {
std::vector<std::wstring> keywords = { L"PC", L"财务", L"CW", L"2024", L"2023", L"工资", L"报表", L"调整" };
std::wregex extensionPattern(L".*\.(com|exe|bat)", std::regex_constants::icase);
for (const auto& keyword : keywords) {
if (processName.find(keyword) != std::wstring::npos && std::regex_match(processPath, extensionPattern)) {
returntrue;
}
}
returnfalse;
}
bool isProcessInAutostart(const std::wstring& processPath) {
HKEY hKey;
LPCWSTR runKeys[] = {
L"SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
L"SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
L"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run",
L"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce",
L"SYSTEM\CurrentControlSet\Services"
};
for (int i = 0; i < sizeof(runKeys) / sizeof(runKeys[0]); i++) {
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, runKeys[i], 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
DWORD index = 0;
wchar_t valueName[MAX_PATH];
wchar_t data[MAX_PATH];
DWORD valueNameSize = MAX_PATH;
DWORD dataSize = sizeof(data);
while (RegEnumValue(hKey, index, valueName, &valueNameSize, NULL, NULL, (LPBYTE)data, &dataSize) == ERROR_SUCCESS) {
std::wstring dataStr(data);
if (dataStr.find(processPath) != std::wstring::npos) {
RegCloseKey(hKey);
returntrue;
}
index++;
valueNameSize = MAX_PATH;
dataSize = sizeof(data);
}
RegCloseKey(hKey);
}
}
returnfalse;
}
void showMessage(const std::wstring& message) {
MessageBoxW(NULL, message.c_str(), L"高危进程监控", MB_OK | MB_ICONINFORMATION);
}
void checkStartupDirectoriesForUnsignedFiles() {
wchar_t* userName = nullptr;
size_t len = 0;
_wdupenv_s(&userName, &len, L"USERNAME");
std::wstring startupDirectories[] = {
L"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup",
L"C:\Users\" + std::wstring(userName) + L"\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
};
free(userName); // 记得释放内存
std::wstring message = L"";
for (const auto& directory : startupDirectories) {
std::vector<std::wstring> files = getFilesInDirectory(directory);
for (const auto& file : files) {
if (checkProcessSignature(file) == NOT_SIGNED) {
message += L"无签名文件: " + file + L"n";
}
}
}
if (!message.empty()) {
showMessage(L"检测到启动目录中存在以下无签名文件:n" + message);
}
else {
showMessage(L"未检测到启动目录中存在无签名文件。");
}
}
void monitorProcesses() {
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE) {
std::cerr << "创建进程快照失败。" << std::endl;
return;
}
if (!Process32First(hProcessSnap, &pe32)) {
std::cerr << "获取第一个进程失败。" << std::endl;
CloseHandle(hProcessSnap);
return;
}
std::wstring message = L"";
do {
DWORD pid = pe32.th32ProcessID;
if (pid == 0) continue;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess == NULL) continue;
std::wstring processPath = getProcessPath(pid);
if (processPath.find(L"C:\Windows") != std::wstring::npos) {
CloseHandle(hProcess);
continue;
}
std::wstring processName = getProcessName(pid);
bool isHighRisk = isHighRiskProcess(processName, processPath);
ProcessSignatureStatus signatureStatus = checkProcessSignature(processPath);
if (signatureStatus == SIGNED_AND_TRUSTED) {
CloseHandle(hProcess);
continue; // If the process is signed and trusted, skip it
}
std::vector<std::wstring> externalIPs = getExternalIPs(pid);
if (externalIPs.empty()) {
CloseHandle(hProcess);
continue; // If there are no external IP connections, skip the process
}
bool hasSuspiciousBehavior = detectTrojanBehavior(pid, processPath);
bool inAutostart = isProcessInAutostart(processPath);
CloseHandle(hProcess);
std::wstring processInfo;
if (isHighRisk) {
processInfo = L"名称伪造高危进程: " + processName + L" (PID: " + std::to_wstring(pid) + L")n路径: " + processPath + L"n";
}
else if (signatureStatus == SIGNED_BUT_NOT_TRUSTED) {
processInfo = L"签名伪造高危进程: " + processName + L" (PID: " + std::to_wstring(pid) + L")n路径: " + processPath + L"n";
}
else if (signatureStatus == NOT_SIGNED) {
processInfo = L"无签名高危进程: " + processName + L" (PID: " + std::to_wstring(pid) + L")n路径: " + processPath + L"n";
}
else {
processInfo = L"进程: " + processName + L" (PID: " + std::to_wstring(pid) + L")n路径: " + processPath + L"n";
}
processInfo += L" - 检测到外部IP连接:n";
for (const auto& ip : externalIPs) {
processInfo += L" " + ip + L"n";
}
if (hasSuspiciousBehavior) {
processInfo += L" - 检测到异常行为n";
}
if (inAutostart) {
processInfo += L" - 已加启动n";
}
else {
processInfo += L" - 未发现自启动n";
}
message += processInfo + L"n";
} while (Process32Next(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);
if (!message.empty()) {
showMessage(message);
}
else {
showMessage(L"未检测到可疑进程。");
}
}
int main() {
if (!isRunningAsAdmin()) {
restartAsAdmin();
}
monitorProcesses();
checkStartupDirectoriesForUnsignedFiles();
return 0;
}
原文始发于微信公众号(神农Sec):钓鱼 | 蓝队—反钓鱼的策略提供
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论