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