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 Win32Error { code: u32, context: &'static str },
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq)]
142pub enum ModuleListType {
143 InLoadOrder,
144 InMemoryOrder,
145 InInitializationOrder,
146}
147
148impl fmt::Display for ModuleListType {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 match self {
151 Self::InLoadOrder => write!(f, "InLoadOrderModuleList"),
152 Self::InMemoryOrder => write!(f, "InMemoryOrderModuleList"),
153 Self::InInitializationOrder => write!(f, "InInitializationOrderModuleList"),
154 }
155 }
156}
157
158impl std::error::Error for WraithError {}
159
160impl fmt::Display for WraithError {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 match self {
163 Self::UnsupportedWindowsVersion { major, minor, build } => {
164 write!(f, "unsupported Windows version: {major}.{minor}.{build}")
165 }
166 Self::UnsupportedArchitecture => {
167 write!(f, "unsupported architecture (only x86/x64 supported)")
168 }
169 Self::InvalidPebAccess => {
170 write!(f, "failed to access PEB")
171 }
172 Self::InvalidTebAccess => {
173 write!(f, "failed to access TEB")
174 }
175 Self::CorruptedStructure { name, reason } => {
176 write!(f, "corrupted structure {name}: {reason}")
177 }
178 Self::NullPointer { context } => {
179 write!(f, "unexpected null pointer in {context}")
180 }
181 Self::ModuleNotFound { name } => {
182 write!(f, "module not found: {name}")
183 }
184 Self::AddressNotInModule { address } => {
185 write!(f, "address {address:#x} not in any loaded module")
186 }
187 Self::ThreadNotFound { tid } => {
188 write!(f, "thread {tid} not found")
189 }
190 Self::UnlinkFailed { module, reason } => {
191 write!(f, "failed to unlink {module}: {reason}")
192 }
193 Self::RelinkFailed { module, reason } => {
194 write!(f, "failed to relink {module}: {reason}")
195 }
196 Self::ListCorrupted { list_type } => {
197 write!(f, "PEB {list_type} appears corrupted")
198 }
199 Self::InvalidPeFormat { reason } => {
200 write!(f, "invalid PE format: {reason}")
201 }
202 Self::AllocationFailed { size, protection } => {
203 write!(
204 f,
205 "failed to allocate {size} bytes with protection {protection:#x}"
206 )
207 }
208 Self::MappingFailed { section, reason } => {
209 write!(f, "failed to map section {section}: {reason}")
210 }
211 Self::RelocationFailed { rva, reason } => {
212 write!(f, "relocation failed at RVA {rva:#x}: {reason}")
213 }
214 Self::ImportResolutionFailed { dll, function } => {
215 write!(f, "failed to resolve {dll}!{function}")
216 }
217 Self::ForwardedExport { forwarder } => {
218 write!(f, "export forwarded to {forwarder}")
219 }
220 Self::TlsCallbackFailed { index } => {
221 write!(f, "TLS callback {index} failed")
222 }
223 Self::EntryPointFailed { status } => {
224 write!(f, "entry point returned {status}")
225 }
226 Self::SyscallEnumerationFailed { reason } => {
227 write!(f, "syscall enumeration failed: {reason}")
228 }
229 Self::SyscallNotFound { name } => {
230 write!(f, "syscall not found: {name}")
231 }
232 Self::SyscallFailed { name, status } => {
233 write!(f, "syscall {name} failed with status {status:#x}")
234 }
235 Self::NtdllNotFound => {
236 write!(f, "ntdll.dll not found in loaded modules")
237 }
238 Self::HookDetectionFailed { function, reason } => {
239 write!(f, "hook detection failed for {function}: {reason}")
240 }
241 Self::UnhookFailed { function, reason } => {
242 write!(f, "unhook failed for {function}: {reason}")
243 }
244 Self::IntegrityCheckFailed { function } => {
245 write!(f, "integrity check failed for {function}")
246 }
247 Self::CleanCopyUnavailable => {
248 write!(f, "clean copy of module not available for comparison")
249 }
250 Self::HookInstallFailed { target, reason } => {
251 write!(f, "failed to install hook at {target:#x}: {reason}")
252 }
253 Self::HookRestoreFailed { target, reason } => {
254 write!(f, "failed to restore hook at {target:#x}: {reason}")
255 }
256 Self::InstructionDecodeFailed { address, reason } => {
257 write!(f, "instruction decode failed at {address:#x}: {reason}")
258 }
259 Self::TrampolineAllocationFailed { near, size } => {
260 write!(f, "failed to allocate {size} bytes trampoline near {near:#x}")
261 }
262 Self::HookConflict { target, existing_type } => {
263 write!(f, "hook conflict at {target:#x}: already hooked ({existing_type})")
264 }
265 Self::InsufficientHookSpace { target, available, required } => {
266 write!(
267 f,
268 "insufficient hook space at {target:#x}: need {required} bytes, have {available}"
269 )
270 }
271 Self::ReadFailed { address, size } => {
272 write!(f, "failed to read {size} bytes at {address:#x}")
273 }
274 Self::WriteFailed { address, size } => {
275 write!(f, "failed to write {size} bytes at {address:#x}")
276 }
277 Self::ProtectionChangeFailed { address, size } => {
278 write!(
279 f,
280 "failed to change protection for {size} bytes at {address:#x}"
281 )
282 }
283 Self::PatternParseFailed { reason } => {
284 write!(f, "failed to parse pattern: {reason}")
285 }
286 Self::Win32Error { code, context } => {
287 write!(f, "Win32 error {code:#x} in {context}")
288 }
289 }
290 }
291}
292
293pub type Result<T> = std::result::Result<T, WraithError>;
295
296impl WraithError {
297 pub fn from_last_error(context: &'static str) -> Self {
299 let code = unsafe { GetLastError() };
301 Self::Win32Error { code, context }
302 }
303}
304
305#[link(name = "kernel32")]
306extern "system" {
307 fn GetLastError() -> u32;
308}