1use alloc::string::String;
8use core::ptr::read;
9
10use data::lc;
11
12#[doc(hidden)]
13pub mod asm;
14
15const RANGE: usize = 255;
17
18const DOWN: usize = 32;
20
21const UP: isize = -32;
23
24pub fn extract_ssn(address: *const u8) -> Option<u16> {
27 unsafe {
28 if read(address) == 0x4C
30 && read(address.add(1)) == 0x8B
31 && read(address.add(2)) == 0xD1
32 && read(address.add(3)) == 0xB8
33 && read(address.add(6)) == 0x00
34 && read(address.add(7)) == 0x00
35 {
36 let high = read(address.add(5)) as u16;
37 let low = read(address.add(4)) as u16;
38 return Some((high << 8) | low);
39 }
40
41 if read(address) == 0xE9 {
43 return search_neighbors(address);
44 }
45
46 if read(address.add(3)) == 0xE9 {
48 return search_neighbors(address);
49 }
50 }
51 None
52}
53
54fn search_neighbors(address: *const u8) -> Option<u16> {
57 unsafe {
58 for idx in 1..RANGE {
59 if read(address.add(idx * DOWN)) == 0x4C
63 && read(address.add(1 + idx * DOWN)) == 0x8B
64 && read(address.add(2 + idx * DOWN)) == 0xD1
65 && read(address.add(3 + idx * DOWN)) == 0xB8
66 && read(address.add(6 + idx * DOWN)) == 0x00
67 && read(address.add(7 + idx * DOWN)) == 0x00
68 {
69 let high = read(address.add(5 + idx * DOWN)) as u16;
70 let low = read(address.add(4 + idx * DOWN)) as u16;
71 let neighbor_ssn = (high << 8) | low;
72 return Some(neighbor_ssn.wrapping_sub(idx as u16));
73 }
74
75 if read(address.offset(idx as isize * UP)) == 0x4C
78 && read(address.offset(1 + idx as isize * UP)) == 0x8B
79 && read(address.offset(2 + idx as isize * UP)) == 0xD1
80 && read(address.offset(3 + idx as isize * UP)) == 0xB8
81 && read(address.offset(6 + idx as isize * UP)) == 0x00
82 && read(address.offset(7 + idx as isize * UP)) == 0x00
83 {
84 let high = read(address.offset(5 + idx as isize * UP)) as u16;
85 let low = read(address.offset(4 + idx as isize * UP)) as u16;
86 let neighbor_ssn = (high << 8) | low;
87 return Some(neighbor_ssn.wrapping_add(idx as u16));
88 }
89 }
90 }
91 None
92}
93
94pub fn get_syscall_address(address: *mut core::ffi::c_void) -> Option<usize> {
99 unsafe {
100 let p = address.cast::<u8>();
101 (1..RANGE).find_map(|i| {
102 if read(p.add(i)) == 0x0F
103 && read(p.add(i + 1)) == 0x05
104 && read(p.add(i + 2)) == 0xC3
105 {
106 Some(p.add(i) as usize)
107 } else {
108 None
109 }
110 })
111 }
112}
113
114#[derive(Debug)]
116pub enum SyscallError {
117 NtdllMissing,
118 FunctionNotFound(String),
119 SsnNotFound(String),
120 SyscallAddrNotFound(String),
121}
122
123impl core::fmt::Display for SyscallError {
124 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
125 match self {
126 SyscallError::NtdllMissing => write!(f, "ntdll.dll not loaded"),
127 SyscallError::FunctionNotFound(n) => write!(f, "export not found: {}", n),
128 SyscallError::SsnNotFound(n) => write!(f, "SSN not extractable for {}", n),
129 SyscallError::SyscallAddrNotFound(n) => write!(f, "syscall instr not found for {}", n),
130 }
131 }
132}
133
134impl core::error::Error for SyscallError {}
135
136pub fn resolve_syscall(name: &str) -> Result<(u16, usize), SyscallError> {
138 let ntdll = crate::get_module_base_address(&lc!("ntdll.dll"));
139 if ntdll == 0 {
140 return Err(SyscallError::NtdllMissing);
141 }
142 let stub = crate::get_function_address(ntdll, name);
143 if stub == 0 {
144 return Err(SyscallError::FunctionNotFound(name.into()));
145 }
146 let ssn = extract_ssn(stub as *const u8)
147 .ok_or_else(|| SyscallError::SsnNotFound(name.into()))?;
148 let addr = get_syscall_address(stub as *mut _)
149 .ok_or_else(|| SyscallError::SyscallAddrNotFound(name.into()))?;
150 Ok((ssn, addr))
151}