-
Notifications
You must be signed in to change notification settings - Fork 54
291 lines (246 loc) · 9.78 KB
/
Copy pathtest.yml
File metadata and controls
291 lines (246 loc) · 9.78 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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
name: Parser Tests
on:
push:
branches: [ main, master, claude/** ]
pull_request:
branches: [ main, master ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y gcc-mingw-w64-x86-64
- name: Install Python dependencies
run: |
pip install --upgrade pip
pip install lief docopt-ng
- name: Create test PE binary
run: |
cat > /tmp/test_pe.c << 'EOF'
#include <stdio.h>
int main() {
printf("Hello from PE test binary\n");
return 0;
}
EOF
x86_64-w64-mingw32-gcc /tmp/test_pe.c -o /tmp/test.exe
file /tmp/test.exe
- name: Create Mach-O test binary
run: |
python3 << 'EOF'
import struct
# Create Mach-O binary with sections
MH_MAGIC_64 = 0xFEEDFACF
CPU_TYPE_X86_64 = 0x01000007
CPU_SUBTYPE_X86_64_ALL = 0x00000003
MH_EXECUTE = 0x00000002
LC_SEGMENT_64 = 0x19
SECTION_64_SIZE = 80
data = bytearray()
# Mach-O header
data += struct.pack('<I', MH_MAGIC_64)
data += struct.pack('<I', CPU_TYPE_X86_64)
data += struct.pack('<I', CPU_SUBTYPE_X86_64_ALL)
data += struct.pack('<I', MH_EXECUTE)
data += struct.pack('<I', 1)
data += struct.pack('<I', 72 + (2 * SECTION_64_SIZE))
data += struct.pack('<I', 0)
data += struct.pack('<I', 0)
# LC_SEGMENT_64 command
data += struct.pack('<I', LC_SEGMENT_64)
data += struct.pack('<I', 72 + (2 * SECTION_64_SIZE))
data += b'__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
data += struct.pack('<Q', 0x100000000)
data += struct.pack('<Q', 0x1000)
data += struct.pack('<Q', 0)
data += struct.pack('<Q', 0x1000)
data += struct.pack('<I', 7)
data += struct.pack('<I', 5)
data += struct.pack('<I', 2) # 2 sections
data += struct.pack('<I', 0)
# Section 1: __text
data += b'__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
data += b'__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
data += struct.pack('<Q', 0x100000000)
data += struct.pack('<Q', 0x100)
data += struct.pack('<I', 0x100)
data += struct.pack('<I', 4)
data += struct.pack('<I', 0)
data += struct.pack('<I', 0)
data += struct.pack('<I', 0x80000400)
data += struct.pack('<I', 0)
data += struct.pack('<I', 0)
data += struct.pack('<I', 0)
# Section 2: __const
data += b'__const\x00\x00\x00\x00\x00\x00\x00\x00\x00'
data += b'__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
data += struct.pack('<Q', 0x100000100)
data += struct.pack('<Q', 0x50)
data += struct.pack('<I', 0x200)
data += struct.pack('<I', 3)
data += struct.pack('<I', 0)
data += struct.pack('<I', 0)
data += struct.pack('<I', 0)
data += struct.pack('<I', 0)
data += struct.pack('<I', 0)
data += struct.pack('<I', 0)
# Pad and add section data
current_size = len(data)
data += b'\x00' * (0x100 - current_size)
# __text section: some code then padding
data += b'\x90' * 0x50 # Some NOP instructions
data += b'\x00' * 0xB0 # Large null byte area (176 bytes)
# __const section: some data then padding
data += b'Mach-O test data\x00'
data += b'\x00' * 0x40 # Large null byte area (64 bytes)
data += b'\x00' * (0x1000 - len(data))
with open('/tmp/test_macho', 'wb') as f:
f.write(data)
print(f"Created Mach-O test binary with 2 sections: {len(data)} bytes")
EOF
file /tmp/test_macho
- name: Test parser imports
run: |
python3 -c "from cave_miner.formats import Elf, Pe, MachO; print('✅ All parsers imported successfully')"
- name: Test ELF parser
run: |
python3 << 'EOF'
from cave_miner.formats import Elf
print("Testing ELF Parser...")
elf = Elf.from_file('/bin/ls')
assert elf.header.section_headers is not None
assert len(elf.header.section_headers) > 0
print(f"✅ ELF Parser: Found {len(elf.header.section_headers)} sections")
EOF
- name: Test PE parser
run: |
python3 << 'EOF'
from cave_miner.formats import Pe
print("Testing PE Parser...")
pe = Pe.from_file('/tmp/test.exe')
assert pe.sections is not None
assert len(pe.sections) > 0
assert pe.optional_hdr is not None
print(f"✅ PE Parser: Found {len(pe.sections)} sections")
print(f"✅ PE Format: {'PE32' if pe.optional_hdr.std.format == Pe.PeFormat.pe32 else 'PE32+'}")
EOF
- name: Test Mach-O parser
run: |
python3 << 'EOF'
from cave_miner.formats import MachO
print("Testing Mach-O Parser...")
macho = MachO.from_file('/tmp/test_macho')
assert macho.load_commands is not None
assert len(macho.load_commands) > 0
print(f"✅ Mach-O Parser: Found {len(macho.load_commands)} load commands")
EOF
- name: Test ELF cave search
run: |
echo "Testing ELF cave search on /bin/ls..."
python3 -m cave_miner search --size=64 --bytes=0x00 /bin/ls > /tmp/elf_output.txt
# Validate output
if grep -q "Starting cave mining process" /tmp/elf_output.txt && \
grep -q "Mining finished" /tmp/elf_output.txt; then
echo "✅ ELF cave search: Process completed successfully"
if grep -q "New cave detected" /tmp/elf_output.txt; then
CAVE_COUNT=$(grep -c "New cave detected" /tmp/elf_output.txt)
echo "✅ Found $CAVE_COUNT code cave(s)"
# Validate cave details are present
if grep -q "section_name:" /tmp/elf_output.txt && \
grep -q "cave_begin:" /tmp/elf_output.txt && \
grep -q "cave_size:" /tmp/elf_output.txt && \
grep -q "vaddress:" /tmp/elf_output.txt; then
echo "✅ Cave details validated (section, address, size)"
else
echo "❌ Missing cave detail fields"
exit 1
fi
else
echo "⚠️ No caves found (acceptable for this binary)"
fi
else
echo "❌ ELF cave search failed to complete"
cat /tmp/elf_output.txt
exit 1
fi
- name: Test PE cave search
run: |
echo "Testing PE cave search on /tmp/test.exe..."
python3 -m cave_miner search --size=64 --bytes=0x00 /tmp/test.exe > /tmp/pe_output.txt
# Validate output
if grep -q "Starting cave mining process" /tmp/pe_output.txt && \
grep -q "Mining finished" /tmp/pe_output.txt; then
echo "✅ PE cave search: Process completed successfully"
if grep -q "New cave detected" /tmp/pe_output.txt; then
CAVE_COUNT=$(grep -c "New cave detected" /tmp/pe_output.txt)
echo "✅ Found $CAVE_COUNT code cave(s)"
# Validate cave details are present
if grep -q "section_name:" /tmp/pe_output.txt && \
grep -q "cave_begin:" /tmp/pe_output.txt && \
grep -q "cave_size:" /tmp/pe_output.txt && \
grep -q "vaddress:" /tmp/pe_output.txt; then
echo "✅ Cave details validated (section, address, size)"
else
echo "❌ Missing cave detail fields"
exit 1
fi
else
echo "⚠️ No caves found (acceptable for this binary)"
fi
else
echo "❌ PE cave search failed to complete"
cat /tmp/pe_output.txt
exit 1
fi
- name: Test Mach-O cave search
run: |
echo "Testing Mach-O cave search on /tmp/test_macho..."
python3 -m cave_miner search --size=32 --bytes=0x00 /tmp/test_macho > /tmp/macho_output.txt
# Validate output
if grep -q "Starting cave mining process" /tmp/macho_output.txt && \
grep -q "Mining finished" /tmp/macho_output.txt; then
echo "✅ Mach-O cave search: Process completed successfully"
if grep -q "New cave detected" /tmp/macho_output.txt; then
CAVE_COUNT=$(grep -c "New cave detected" /tmp/macho_output.txt)
echo "✅ Found $CAVE_COUNT code cave(s)"
# Validate cave details are present
if grep -q "section_name:" /tmp/macho_output.txt && \
grep -q "cave_begin:" /tmp/macho_output.txt && \
grep -q "cave_size:" /tmp/macho_output.txt && \
grep -q "vaddress:" /tmp/macho_output.txt; then
echo "✅ Cave details validated (section, address, size)"
else
echo "❌ Missing cave detail fields"
exit 1
fi
else
echo "⚠️ No caves found (acceptable for this binary)"
fi
else
echo "❌ Mach-O cave search failed to complete"
cat /tmp/macho_output.txt
exit 1
fi
- name: Test help command
run: |
python3 -m cave_miner --help
echo "✅ Help command works"
- name: Run comprehensive test suite
run: |
python3 test_parsers.py
- name: Test Summary
if: always()
run: |
echo "=========================================="
echo " TEST SUMMARY"
echo "=========================================="
echo "All parser tests completed!"
echo "Check individual step outputs above for details."