-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfreshycalls.rs
68 lines (56 loc) · 2.67 KB
/
freshycalls.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use thermite::error;
use thermite::peb_walk::{ExportedFunction, get_all_exported_functions, get_module_handle};
use thermite::syscalls::find_ssn;
use thermite::syscalls::Syscall;
/* This example is a demonstration of Freshycalls 's technique to retrieve hooked syscall IDs.
Since on most versions of windows, all syscalls are in order, we can easily derive the syscall ID from their addresses.
We only need to find every syscalls and sort our list of syscalls using their addresses.
When this is done, we can observe that all the SSNs are in order as well.
As a demonstration i created a second array that i populated using data from our usual find_ssn() function,
to make sure the SSN we found we all valid, and lo and behold, they all were.
*/
fn main() {
// First we get an array of every function exported by ntdll starting by "Nt"
let ntdll_handle = unsafe { get_module_handle("ntdll.dll") }.unwrap();
let binding = unsafe { get_all_exported_functions(ntdll_handle) }.unwrap();
let mut all_exports: Vec<&ExportedFunction> = binding
.iter()
.filter(|x1| x1.name.starts_with("Nt") && !x1.name.starts_with("Ntdll"))
.collect();
// We sort every function by its address
all_exports.sort_by(|a, b| a.address.cmp(&b.address));
// We then simply number every function
let guessed_syscalls: Vec<Syscall> =
all_exports.iter().enumerate()
.map(|(idx, &ex)| {
Syscall {
address: ex.address,
name: ex.name.clone(),
ssn: idx as u16,
}
}).collect();
// Because SSNs are numbered incrementally, they should all have the correct SSN
// Let get a control array, numbered using our "find_ssn" function, as usual
let verif_binding = unsafe { get_all_exported_functions(ntdll_handle) }.unwrap();
let verif_all_exports: Vec<&ExportedFunction> = verif_binding
.iter()
.filter(|x1| x1.name.starts_with("Nt") && !x1.name.starts_with("Ntdll"))
.collect();
let mut control: Vec<Syscall> = verif_all_exports.iter().filter_map(|x| unsafe {
find_ssn(x.address).map(|ssn| Syscall {
name: x.name.clone(),
address: x.address,
ssn,
})
}).collect();
// We sort the control array by address too
control.sort_by(|a, b| a.address.cmp(&b.address));
// Now we can check that the two arrays are the exact same,
// using zip we iterate over the two arrays simultaneously
// Using filter_map, we keep only those who aren't correct, then print is using error
// If everything goes well, we shouldn't see any errors o/
let _: Vec<_> = guessed_syscalls.iter().zip(control.iter_mut())
.filter_map(|(x1, &mut ref x2)| { x1.ssn.ne(&x2.ssn).then_some((x1, x2)) })
.map(|x| error!("{:#x?}", x))
.collect();
}