1use crate::core::heuristics::disassemble_section;
46use crate::core::traits::HeuristicPlugin;
47use crate::core::{AnalysisContext, AnalysisProgress, Result, parser::Parser};
48use crate::core::{packer_sig_check, string_check};
49use crate::utils::get_metadata::get_binary_metadata;
50
51pub struct DisassemblyPlugin;
54
55impl HeuristicPlugin for DisassemblyPlugin {
56 fn name(&self) -> &'static str {
57 "disassembly"
58 }
59
60 fn run(&self, ctx: &AnalysisContext) -> Result<AnalysisProgress> {
61 let (code_cave, blacklisted_mnemonics) =
62 disassemble_section(ctx.text_bytes, &ctx.entry_addr, &ctx.os, &ctx.arch)?;
63 Ok(AnalysisProgress::Disassembly((
64 code_cave,
65 blacklisted_mnemonics,
66 )))
67 }
68}
69
70pub struct StringCheckPlugin;
73
74impl HeuristicPlugin for StringCheckPlugin {
75 fn name(&self) -> &'static str {
76 "string_check"
77 }
78
79 fn run(&self, ctx: &AnalysisContext) -> Result<AnalysisProgress> {
80 let results = string_check(ctx.buffer, ctx.section_ranges)?;
81 Ok(AnalysisProgress::Strings(results))
82 }
83}
84
85pub struct PackerSigCheckPlugin;
87
88impl HeuristicPlugin for PackerSigCheckPlugin {
89 fn name(&self) -> &'static str {
90 "packer_sig_check"
91 }
92
93 fn run(&self, ctx: &AnalysisContext) -> Result<AnalysisProgress> {
94 let results = packer_sig_check(ctx.buffer, ctx.section_ranges)?;
95 Ok(AnalysisProgress::PackerSigs(results))
96 }
97}
98
99pub struct EntropyPlugin;
101
102impl HeuristicPlugin for EntropyPlugin {
103 fn name(&self) -> &'static str {
104 "entropy"
105 }
106
107 fn run(&self, ctx: &AnalysisContext) -> Result<AnalysisProgress> {
108 let parser = Parser::new(ctx.buffer, ctx.binary_object);
109 let results = parser.evaluate_section_entropy()?;
110 Ok(AnalysisProgress::Entropy(results))
111 }
112}
113
114pub struct ApiHookingPlugin;
116
117impl HeuristicPlugin for ApiHookingPlugin {
118 fn name(&self) -> &'static str {
119 "api_hooking"
120 }
121
122 fn run(&self, ctx: &AnalysisContext) -> Result<AnalysisProgress> {
123 let parser = Parser::new(ctx.buffer, ctx.binary_object);
124 let results = parser.detect_api_hooking(ctx.section_ranges)?;
125 Ok(AnalysisProgress::ApiHooking(results))
126 }
127}
128
129pub struct ProcessInjectionPlugin;
131
132impl HeuristicPlugin for ProcessInjectionPlugin {
133 fn name(&self) -> &'static str {
134 "process_injection"
135 }
136
137 fn run(&self, ctx: &AnalysisContext) -> Result<AnalysisProgress> {
138 let parser = Parser::new(ctx.buffer, ctx.binary_object);
139 let results = parser.check_process_injec()?;
140 Ok(AnalysisProgress::ProcessInjection(results))
141 }
142}
143
144pub struct MetadataPlugin;
146
147impl HeuristicPlugin for MetadataPlugin {
148 fn name(&self) -> &'static str {
149 "metadata"
150 }
151
152 fn run(&self, ctx: &AnalysisContext) -> Result<AnalysisProgress> {
153 let results = get_binary_metadata(ctx.binary_object)?;
154 Ok(AnalysisProgress::BinaryMetadata(results))
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161 use crate::core::{BinaryArch, BinaryOS};
162 use crate::utils::test_helpers::test_helpers;
163 use goblin::Object;
164 use std::fs;
165 use tempfile::tempdir;
166
167 #[test]
168 fn test_metadata_plugin() {
169 let dir = tempdir().unwrap();
170 let path = dir.path().join("mock_elf");
171 test_helpers::generate_elf(&path);
172
173 let buffer = fs::read(&path).unwrap();
174 let obj = Object::parse(&buffer).unwrap();
175 let section_ranges =
176 crate::utils::section_offset::build_section_map(&obj, &buffer).unwrap();
177
178 let ctx = AnalysisContext {
179 buffer: &buffer,
180 binary_object: &obj,
181 section_ranges: §ion_ranges,
182 os: BinaryOS::Linux,
183 arch: BinaryArch::X64,
184 text_bytes: &[],
185 entry_addr: 0x1000,
186 };
187
188 let result = MetadataPlugin.run(&ctx).unwrap();
189 match result {
190 AnalysisProgress::BinaryMetadata(meta) => {
191 assert_eq!(meta.binary_type, "Linux ELF");
192 }
193 _ => panic!("Expected BinaryMetadata progress"),
194 }
195 }
196
197 #[test]
198 fn test_entropy_plugin() {
199 let dir = tempdir().unwrap();
200 let path = dir.path().join("mock_elf");
201 test_helpers::generate_elf(&path);
202
203 let buffer = fs::read(&path).unwrap();
204 let obj = Object::parse(&buffer).unwrap();
205 let section_ranges =
206 crate::utils::section_offset::build_section_map(&obj, &buffer).unwrap();
207
208 let ctx = AnalysisContext {
209 buffer: &buffer,
210 binary_object: &obj,
211 section_ranges: §ion_ranges,
212 os: BinaryOS::Linux,
213 arch: BinaryArch::X64,
214 text_bytes: &[],
215 entry_addr: 0x1000,
216 };
217
218 let result = EntropyPlugin.run(&ctx).unwrap();
219 match result {
220 AnalysisProgress::Entropy(entropy) => {
221 assert!(!entropy.is_empty());
222 }
223 _ => panic!("Expected Entropy progress"),
224 }
225 }
226
227 #[test]
228 fn test_disassembly_plugin() {
229 let dir = tempdir().unwrap();
230 let path = dir.path().join("mock_elf");
231 test_helpers::generate_elf(&path);
232
233 let buffer = fs::read(&path).unwrap();
234 let obj = Object::parse(&buffer).unwrap();
235 let section_ranges =
236 crate::utils::section_offset::build_section_map(&obj, &buffer).unwrap();
237
238 let text_bytes = vec![0x90; 128];
239
240 let ctx = AnalysisContext {
241 buffer: &buffer,
242 binary_object: &obj,
243 section_ranges: §ion_ranges,
244 os: BinaryOS::Linux,
245 arch: BinaryArch::X64,
246 text_bytes: &text_bytes,
247 entry_addr: 0x1000,
248 };
249
250 let result = DisassemblyPlugin.run(&ctx).unwrap();
251 match result {
252 AnalysisProgress::Disassembly((code_cave, _)) => {
253 assert!(code_cave.contains_key("nop_addr"));
254 }
255 _ => panic!("Expected Disassembly progress"),
256 }
257 }
258}