1use core::fmt;
4
5#[cfg(all(not(feature = "std"), feature = "alloc"))]
6use alloc::string::String;
7
8#[cfg(feature = "std")]
9use std::string::String;
10
11#[derive(Debug)]
13pub enum WraithError {
14 UnsupportedWindowsVersion { major: u32, minor: u32, build: u32 },
17
18 UnsupportedArchitecture,
20
21 InvalidPebAccess,
24
25 InvalidTebAccess,
27
28 CorruptedStructure {
30 name: &'static str,
31 reason: &'static str,
32 },
33
34 NullPointer { context: &'static str },
36
37 ModuleNotFound { name: String },
40
41 AddressNotInModule { address: u64 },
43
44 ThreadNotFound { tid: u32 },
46
47 UnlinkFailed { module: String, reason: String },
50
51 RelinkFailed { module: String, reason: String },
53
54 ListCorrupted { list_type: ModuleListType },
56
57 InvalidPeFormat { reason: String },
60
61 AllocationFailed { size: usize, protection: u32 },
63
64 MappingFailed { section: String, reason: String },
66
67 RelocationFailed { rva: u32, reason: String },
69
70 ImportResolutionFailed { dll: String, function: String },
72
73 ForwardedExport { forwarder: String },
75
76 TlsCallbackFailed { index: usize },
78
79 EntryPointFailed { status: i32 },
81
82 SyscallEnumerationFailed { reason: String },
85
86 SyscallNotFound { name: String },
88
89 SyscallFailed { name: String, status: i32 },
91
92 NtdllNotFound,
94
95 HookDetectionFailed { function: String, reason: String },
98
99 UnhookFailed { function: String, reason: String },
101
102 IntegrityCheckFailed { function: String },
104
105 CleanCopyUnavailable,
107
108 HookInstallFailed { target: u64, reason: String },
111
112 HookRestoreFailed { target: u64, reason: String },
114
115 InstructionDecodeFailed { address: u64, reason: String },
117
118 TrampolineAllocationFailed { near: u64, size: usize },
120
121 HookConflict { target: u64, existing_type: String },
123
124 InsufficientHookSpace { target: u64, available: usize, required: usize },
126
127 ReadFailed { address: u64, size: usize },
130
131 WriteFailed { address: u64, size: usize },
133
134 ProtectionChangeFailed { address: u64, size: usize },
136
137 PatternParseFailed { reason: String },
140
141 ProcessOpenFailed { pid: u32, reason: String },
144
145 ProcessNotFound { pid: u32 },
147
148 RemoteThreadFailed { reason: String },
150
151 InjectionFailed { method: String, reason: String },
153
154 RemoteModuleEnumFailed { reason: String },
156
157 HandleDuplicateFailed { reason: String },
159
160 SectionMappingFailed { reason: String },
162
163 ApcQueueFailed { reason: String },
165
166 ThreadContextFailed { reason: String },
168
169 ThreadSuspendResumeFailed { reason: String },
171
172 GadgetNotFound { gadget_type: &'static str },
175
176 SpoofTrampolineFailed { reason: String },
178
179 StackSynthesisFailed { reason: String },
181
182 Win32Error { code: u32, context: &'static str },
185}
186
187#[derive(Debug, Clone, Copy, PartialEq, Eq)]
189pub enum ModuleListType {
190 InLoadOrder,
191 InMemoryOrder,
192 InInitializationOrder,
193}
194
195impl fmt::Display for ModuleListType {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 match self {
198 Self::InLoadOrder => write!(f, "InLoadOrderModuleList"),
199 Self::InMemoryOrder => write!(f, "InMemoryOrderModuleList"),
200 Self::InInitializationOrder => write!(f, "InInitializationOrderModuleList"),
201 }
202 }
203}
204
205#[cfg(feature = "std")]
206impl std::error::Error for WraithError {}
207
208impl fmt::Display for WraithError {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 match self {
211 Self::UnsupportedWindowsVersion { major, minor, build } => {
212 write!(f, "unsupported Windows version: {major}.{minor}.{build}")
213 }
214 Self::UnsupportedArchitecture => {
215 write!(f, "unsupported architecture (only x86/x64 supported)")
216 }
217 Self::InvalidPebAccess => {
218 write!(f, "failed to access PEB")
219 }
220 Self::InvalidTebAccess => {
221 write!(f, "failed to access TEB")
222 }
223 Self::CorruptedStructure { name, reason } => {
224 write!(f, "corrupted structure {name}: {reason}")
225 }
226 Self::NullPointer { context } => {
227 write!(f, "unexpected null pointer in {context}")
228 }
229 Self::ModuleNotFound { name } => {
230 write!(f, "module not found: {name}")
231 }
232 Self::AddressNotInModule { address } => {
233 write!(f, "address {address:#x} not in any loaded module")
234 }
235 Self::ThreadNotFound { tid } => {
236 write!(f, "thread {tid} not found")
237 }
238 Self::UnlinkFailed { module, reason } => {
239 write!(f, "failed to unlink {module}: {reason}")
240 }
241 Self::RelinkFailed { module, reason } => {
242 write!(f, "failed to relink {module}: {reason}")
243 }
244 Self::ListCorrupted { list_type } => {
245 write!(f, "PEB {list_type} appears corrupted")
246 }
247 Self::InvalidPeFormat { reason } => {
248 write!(f, "invalid PE format: {reason}")
249 }
250 Self::AllocationFailed { size, protection } => {
251 write!(
252 f,
253 "failed to allocate {size} bytes with protection {protection:#x}"
254 )
255 }
256 Self::MappingFailed { section, reason } => {
257 write!(f, "failed to map section {section}: {reason}")
258 }
259 Self::RelocationFailed { rva, reason } => {
260 write!(f, "relocation failed at RVA {rva:#x}: {reason}")
261 }
262 Self::ImportResolutionFailed { dll, function } => {
263 write!(f, "failed to resolve {dll}!{function}")
264 }
265 Self::ForwardedExport { forwarder } => {
266 write!(f, "export forwarded to {forwarder}")
267 }
268 Self::TlsCallbackFailed { index } => {
269 write!(f, "TLS callback {index} failed")
270 }
271 Self::EntryPointFailed { status } => {
272 write!(f, "entry point returned {status}")
273 }
274 Self::SyscallEnumerationFailed { reason } => {
275 write!(f, "syscall enumeration failed: {reason}")
276 }
277 Self::SyscallNotFound { name } => {
278 write!(f, "syscall not found: {name}")
279 }
280 Self::SyscallFailed { name, status } => {
281 write!(f, "syscall {name} failed with status {status:#x}")
282 }
283 Self::NtdllNotFound => {
284 write!(f, "ntdll.dll not found in loaded modules")
285 }
286 Self::HookDetectionFailed { function, reason } => {
287 write!(f, "hook detection failed for {function}: {reason}")
288 }
289 Self::UnhookFailed { function, reason } => {
290 write!(f, "unhook failed for {function}: {reason}")
291 }
292 Self::IntegrityCheckFailed { function } => {
293 write!(f, "integrity check failed for {function}")
294 }
295 Self::CleanCopyUnavailable => {
296 write!(f, "clean copy of module not available for comparison")
297 }
298 Self::HookInstallFailed { target, reason } => {
299 write!(f, "failed to install hook at {target:#x}: {reason}")
300 }
301 Self::HookRestoreFailed { target, reason } => {
302 write!(f, "failed to restore hook at {target:#x}: {reason}")
303 }
304 Self::InstructionDecodeFailed { address, reason } => {
305 write!(f, "instruction decode failed at {address:#x}: {reason}")
306 }
307 Self::TrampolineAllocationFailed { near, size } => {
308 write!(f, "failed to allocate {size} bytes trampoline near {near:#x}")
309 }
310 Self::HookConflict { target, existing_type } => {
311 write!(f, "hook conflict at {target:#x}: already hooked ({existing_type})")
312 }
313 Self::InsufficientHookSpace { target, available, required } => {
314 write!(
315 f,
316 "insufficient hook space at {target:#x}: need {required} bytes, have {available}"
317 )
318 }
319 Self::ReadFailed { address, size } => {
320 write!(f, "failed to read {size} bytes at {address:#x}")
321 }
322 Self::WriteFailed { address, size } => {
323 write!(f, "failed to write {size} bytes at {address:#x}")
324 }
325 Self::ProtectionChangeFailed { address, size } => {
326 write!(
327 f,
328 "failed to change protection for {size} bytes at {address:#x}"
329 )
330 }
331 Self::PatternParseFailed { reason } => {
332 write!(f, "failed to parse pattern: {reason}")
333 }
334 Self::ProcessOpenFailed { pid, reason } => {
335 write!(f, "failed to open process {pid}: {reason}")
336 }
337 Self::ProcessNotFound { pid } => {
338 write!(f, "process {pid} not found")
339 }
340 Self::RemoteThreadFailed { reason } => {
341 write!(f, "remote thread creation failed: {reason}")
342 }
343 Self::InjectionFailed { method, reason } => {
344 write!(f, "injection via {method} failed: {reason}")
345 }
346 Self::RemoteModuleEnumFailed { reason } => {
347 write!(f, "remote module enumeration failed: {reason}")
348 }
349 Self::HandleDuplicateFailed { reason } => {
350 write!(f, "handle duplication failed: {reason}")
351 }
352 Self::SectionMappingFailed { reason } => {
353 write!(f, "section mapping failed: {reason}")
354 }
355 Self::ApcQueueFailed { reason } => {
356 write!(f, "APC queue operation failed: {reason}")
357 }
358 Self::ThreadContextFailed { reason } => {
359 write!(f, "thread context operation failed: {reason}")
360 }
361 Self::ThreadSuspendResumeFailed { reason } => {
362 write!(f, "thread suspend/resume failed: {reason}")
363 }
364 Self::GadgetNotFound { gadget_type } => {
365 write!(f, "no suitable {gadget_type} gadget found")
366 }
367 Self::SpoofTrampolineFailed { reason } => {
368 write!(f, "spoof trampoline failed: {reason}")
369 }
370 Self::StackSynthesisFailed { reason } => {
371 write!(f, "stack frame synthesis failed: {reason}")
372 }
373 Self::Win32Error { code, context } => {
374 write!(f, "Win32 error {code:#x} in {context}")
375 }
376 }
377 }
378}
379
380pub type Result<T> = core::result::Result<T, WraithError>;
382
383impl WraithError {
384 pub fn from_last_error(context: &'static str) -> Self {
386 let code = unsafe { GetLastError() };
388 Self::Win32Error { code, context }
389 }
390}
391
392#[link(name = "kernel32")]
393extern "system" {
394 fn GetLastError() -> u32;
395}