-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
144 lines (122 loc) · 5.31 KB
/
main.cpp
File metadata and controls
144 lines (122 loc) · 5.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <iostream>
#include <fstream>
#include <vector>
#include <windows.h>
#include <iomanip>
/**
* 结构体用于存储代码洞的信息
*/
struct CodeCave {
std::string sectionName; // 所属区域名称
DWORD offset; // 文件偏移
DWORD rva; // 相对虚拟地址 (Relative Virtual Address)
size_t size; // 代码洞大小
};
/**
* 检查一个字节序列是否被视为“代码洞”的一部分
* 通常代码洞由连续的 0x00 或 0x90 (NOP) 组成
*/
bool isCaveByte(unsigned char b) {
return b == 0x00 || b == 0x90;
}
/**
* 扫描指定的可执行文件以查找代码洞
* @param filePath PE文件的路径
* @param minSize 最小代码洞大小(字节)
*/
void findCodeCaves(const std::string& filePath, size_t minSize = 16) {
std::ifstream file(filePath, std::ios::binary);
if (!file.is_open()) {
std::cerr << "无法打开文件: " << filePath << std::endl;
return;
}
// 1. 读取 DOS 头
IMAGE_DOS_HEADER dosHeader;
file.read(reinterpret_cast<char*>(&dosHeader), sizeof(IMAGE_DOS_HEADER));
if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
std::cerr << "错误: 不是有效的 DOS 文件 (缺少 MZ 签名)" << std::endl;
return;
}
// 2. 定位并读取 NT 头 (PE 头)
file.seekg(dosHeader.e_lfanew, std::ios::beg);
IMAGE_NT_HEADERS ntHeaders;
file.read(reinterpret_cast<char*>(&ntHeaders), sizeof(IMAGE_NT_HEADERS));
if (ntHeaders.Signature != IMAGE_NT_SIGNATURE) {
std::cerr << "错误: 不是有效的 PE 文件 (缺少 PE 签名)" << std::endl;
return;
}
std::cout << "正在分析文件: " << filePath << std::endl;
std::cout << "目标平台: " << (ntHeaders.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 ? "x64" : "x86") << std::endl;
std::cout << "------------------------------------------------------------" << std::endl;
std::cout << std::left << std::setw(15) << "区域名称"
<< std::setw(15) << "文件偏移"
<< std::setw(15) << "RVA"
<< std::setw(10) << "大小(字节)" << std::endl;
std::cout << "------------------------------------------------------------" << std::endl;
// 3. 遍历节表 (Section Table)
int sectionCount = ntHeaders.FileHeader.NumberOfSections;
std::vector<IMAGE_SECTION_HEADER> sections(sectionCount);
file.read(reinterpret_cast<char*>(sections.data()), sizeof(IMAGE_SECTION_HEADER) * sectionCount);
bool foundAny = false;
for (const auto& section : sections) {
// 只检查可执行区域 (IMAGE_SCN_MEM_EXECUTE)
if (section.Characteristics & IMAGE_SCN_MEM_EXECUTE) {
std::string sectionName(reinterpret_cast<const char*>(section.Name), 8);
// 去掉末尾可能的空字符
sectionName = sectionName.c_str();
// 读取节数据
std::vector<unsigned char> buffer(section.SizeOfRawData);
file.seekg(section.PointerToRawData, std::ios::beg);
file.read(reinterpret_cast<char*>(buffer.data()), section.SizeOfRawData);
// 扫描代码洞
size_t currentCaveSize = 0;
DWORD caveStartOffset = 0;
for (size_t i = 0; i < buffer.size(); ++i) {
if (isCaveByte(buffer[i])) {
if (currentCaveSize == 0) {
caveStartOffset = section.PointerToRawData + i;
}
currentCaveSize++;
} else {
if (currentCaveSize >= minSize) {
DWORD rva = section.VirtualAddress + (caveStartOffset - section.PointerToRawData);
std::cout << std::left << std::setw(15) << sectionName
<< "0x" << std::hex << std::setw(13) << caveStartOffset
<< "0x" << std::hex << std::setw(13) << rva
<< std::dec << currentCaveSize << std::endl;
foundAny = true;
}
currentCaveSize = 0;
}
}
// 检查节末尾是否存在代码洞
if (currentCaveSize >= minSize) {
DWORD rva = section.VirtualAddress + (caveStartOffset - section.PointerToRawData);
std::cout << std::left << std::setw(15) << sectionName
<< "0x" << std::hex << std::setw(13) << caveStartOffset
<< "0x" << std::hex << std::setw(13) << rva
<< std::dec << currentCaveSize << std::endl;
foundAny = true;
}
}
}
if (!foundAny) {
std::cout << "未在可执行区域发现符合条件的代码洞。" << std::endl;
}
std::cout << "------------------------------------------------------------" << std::endl;
}
int main(int argc, char* argv[]) {
// 设置控制台输出为 UTF-8,以支持中文显示
SetConsoleOutputCP(CP_UTF8);
if (argc < 2) {
std::cout << "用法: " << argv[0] << " <PE文件路径> [最小洞大小, 默认16]" << std::endl;
return 1;
}
std::string filePath = argv[1];
size_t minSize = 16;
if (argc >= 3) {
minSize = std::stoul(argv[2]);
}
findCodeCaves(filePath, minSize);
return 0;
}