1use core::fmt::{Display, Formatter};
3#[derive(Debug)]
4pub enum Error {
6 Winapi(&'static str, u32),
10 Ntdll(i32),
14 WTFConvert(widestring::error::DecodeUtf16Error), #[cfg(feature = "std")]
17 Io(std::io::Error),
19 #[cfg(target_family = "windows")]
20 Pelite(pelite::Error),
24 Unsupported(Option<&'static str>),
26 InjectLib(CustomError),
28}
29
30#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
31#[non_exhaustive]
34pub enum CustomError {
36 NoViableInjector,
39 WaitForSingleObject(u32),
41 ModuleListLoop,
43 ZeroBytes,
45 LDRUninit,
47 InvalidStructure,
49 DllPathNoFile,
51 MempageInvalidProcess,
53 InvalidInput,
55 PermissionDenied,
57 LibraryNotFound(alloc::string::String),
59}
60
61impl From<CustomError> for Error {
62 fn from(x: CustomError) -> Self {
63 Error::InjectLib(x)
64 }
65}
66#[cfg(feature = "std")]
67impl From<std::io::Error> for Error {
68 fn from(e: std::io::Error) -> Self {
70 Error::Io(e)
71 }
72}
73impl Error {
74 fn get_winapi(&self) -> Option<(&&'static str, &u32)> {
76 match self {
77 Error::Winapi(x, y) => Some((x, y)),
78 _ => None,
79 }
80 }
81 fn get_ntdll(&self) -> Option<&i32> {
83 match self {
84 Error::Ntdll(x) => Some(x),
85 _ => None,
86 }
87 }
88 fn get_wtfconvert(&self) -> Option<&widestring::error::DecodeUtf16Error> {
90 match self {
91 Error::WTFConvert(x) => Some(x),
92 _ => None,
93 }
94 }
95 #[cfg(feature = "std")]
96 fn get_io(&self) -> Option<&std::io::Error> {
98 match self {
99 Error::Io(x) => Some(x),
100 _ => None,
101 }
102 }
103 fn get_unsupported(&self) -> Option<&Option<&'static str>> {
105 match self {
106 Error::Unsupported(x) => Some(x),
107 _ => None,
108 }
109 }
110
111 #[cfg(target_family = "windows")]
112 fn get_pelite(&self) -> Option<&pelite::Error> {
114 match self {
115 Error::Pelite(x) => Some(x),
116 _ => None,
117 }
118 }
119 fn get_injectlib(&self) -> Option<&CustomError> {
121 match self {
122 Error::InjectLib(x) => Some(x),
123 _ => None,
124 }
125 }
126}
127impl PartialEq<Self> for Error {
129 fn eq(&self, other: &Self) -> bool {
130 fn helper(me: &Error, other: &Error) -> Option<bool> {
131 Some(match me {
132 Error::Winapi(x, y) => other.get_winapi()?.eq(&(x, y)),
133 Error::Ntdll(x) => other.get_ntdll()?.eq(x),
134 Error::WTFConvert(x) => other.get_wtfconvert()?.eq(x),
135 #[cfg(feature = "std")]
136 Error::Io(x) => other.get_io()?.kind() == x.kind(), #[cfg(target_family = "windows")]
138 Error::Pelite(x) => other.get_pelite()?.eq(x),
139 Error::InjectLib(x) => other.get_injectlib()?.eq(x),
140 Error::Unsupported(x) => other.get_unsupported()?.eq(x),
141 })
142 }
143 *helper(self, other).get_or_insert(false)
144 }
145}
146
147#[cfg(target_family = "windows")]
148mod windows {
149 use crate::error::Error;
150 use winapi::um::errhandlingapi::GetLastError;
151
152 impl From<pelite::Error> for Error {
153 fn from(e: pelite::Error) -> Self {
154 Error::Pelite(e)
155 }
156 }
157 impl From<&'static str> for Error {
158 fn from(s: &'static str) -> Self {
159 Error::Winapi(s, unsafe { GetLastError() })
160 }
161 }
162}
163
164impl Display for Error {
165 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
166 match self {
167 Error::Winapi(s, n) => write!(f, "Winapi error:{} failed with code {}", s, n),
168 Error::Ntdll(n) => write!(f, "Ntdll({:#x})", n),
169 Error::WTFConvert(_) => write!(f, "WTFConvert: Buffer contained non UTF-8 characters."), Error::Unsupported(r) => write!(
171 f,
172 "Unsupported({})",
173 if let Some(s) = r { s } else { "None" }
174 ),
175 #[cfg(feature = "std")]
176 Error::Io(e) => write!(f, "io:{}", e),
177 Error::InjectLib(e) => write!(f, "Inject-Lib({})", e),
178 #[cfg(target_family = "windows")]
179 Error::Pelite(e) => write!(f, "pelite({})", e),
180 }
181 }
182}
183
184impl Display for CustomError {
185 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
186 match self {
187 CustomError::NoViableInjector=>write!(f,"Could not find a viable injection method for the circumstances"),
188 CustomError::WaitForSingleObject(x)=>write!(f,"WaitForSingleObject return code {:#x}",x),
189 CustomError::ModuleListLoop=>write!(f,"We looped through the whole InLoadOrderModuleList, but still have no match. Aborting, because this would end in an endless loop."),
190 CustomError::ZeroBytes=>write!(f,"Zero bytes read, but the requested type is not Zero sized."),
191 CustomError::LDRUninit=>write!(f,"LDR is not initialised"),
192 CustomError::InvalidStructure=>write!(f,"a structure in inject-lib is invalid."),
193 CustomError::DllPathNoFile=>write!(f,"The Dll File Path provided did not point to a file."),
194 CustomError::MempageInvalidProcess=>write!(f,"The Mempage did not belong to the expected Process."),
195 CustomError::InvalidInput=>write!(f,"The Provided Input was invalid."),
196 CustomError::PermissionDenied=>write!(f,"The requested Action would result in a Permission Error."),
197 CustomError::LibraryNotFound(lib)=>write!(f,"It was expected, that the Library:'{}' would be loaded when it wasn't",lib),
198 }
199 }
200}
201
202#[derive(Debug, Clone)]
203pub enum Ntdll {
205 Success(i32),
207 Information(i32),
209 Warning(i32),
211 Error(i32),
213 Other(i32),
215}
216
217impl Ntdll {
218 pub fn get_status(&self) -> &i32 {
220 match self {
221 Ntdll::Error(v) => v,
222 Ntdll::Warning(v) => v,
223 Ntdll::Other(v) => v,
224 Ntdll::Success(v) => v,
225 Ntdll::Information(v) => v,
226 }
227 }
228}
229impl Display for Ntdll {
230 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
231 match self {
232 Ntdll::Error(v) => write!(f, "Ntdll::Error({:#x})", v),
233 Ntdll::Warning(v) => write!(f, "Ntdll::Warning({:#x})", v),
234 Ntdll::Other(v) => write!(f, "Ntdll::Other({:#x})", v),
235 Ntdll::Success(v) => write!(f, "Ntdll::Success({:#x})", v),
236 Ntdll::Information(v) => write!(f, "Ntdll::Information({:#x})", v),
237 }
238 }
239}
240
241#[cfg(windows)]
242mod ntdll {
243 use crate::error::{Error, Ntdll};
244 use log::error;
245 use winapi::shared::ntdef::{NTSTATUS, NT_ERROR, NT_INFORMATION, NT_SUCCESS, NT_WARNING};
246
247 impl crate::error::Ntdll {
248 pub fn new(n: NTSTATUS) -> Self {
250 if NT_ERROR(n) {
251 Ntdll::Error(n)
252 } else if NT_WARNING(n) {
253 Ntdll::Warning(n)
254 } else if NT_INFORMATION(n) {
255 Ntdll::Information(n)
256 } else if NT_SUCCESS(n) {
257 Ntdll::Success(n)
258 } else {
259 error!("");
260 Ntdll::Other(n)
261 }
262 }
263 pub fn is_error(&self) -> bool {
265 match self {
266 Ntdll::Error(_) => true,
267 _ => false,
268 }
269 }
270 pub fn is_warning(&self) -> bool {
272 match self {
273 Ntdll::Warning(_) => true,
274 _ => false,
275 }
276 }
277 pub fn is_info(&self) -> bool {
279 match self {
280 Ntdll::Information(_) => true,
281 _ => false,
282 }
283 }
284 pub fn is_success(&self) -> bool {
286 match self {
287 Ntdll::Success(_) => true,
288 _ => false,
289 }
290 }
291 pub fn is_other(&self) -> bool {
293 match self {
294 Ntdll::Other(_) => true,
295 _ => false,
296 }
297 }
298 }
299 impl Into<Error> for Ntdll {
300 fn into(self) -> Error {
302 match self {
303 Ntdll::Error(v) => Error::Ntdll(v),
304 Ntdll::Warning(v) => Error::Ntdll(v),
305 Ntdll::Information(v) => Error::Ntdll(v),
306 Ntdll::Success(v) => Error::Ntdll(v),
307 Ntdll::Other(v) => Error::Ntdll(v),
308 }
309 }
310 }
311}