wraith/manipulation/antidebug/
thread_hide.rs1use crate::error::Result;
7use crate::structures::Teb;
8use std::collections::HashSet;
9use std::sync::{LazyLock, Mutex};
10
11#[cfg(feature = "syscalls")]
13use crate::manipulation::syscall::{
14 nt_set_information_thread, CURRENT_THREAD, THREAD_HIDE_FROM_DEBUGGER,
15};
16
17static HIDDEN_THREADS: LazyLock<Mutex<HashSet<u32>>> =
19 LazyLock::new(|| Mutex::new(HashSet::new()));
20
21#[cfg(feature = "syscalls")]
26pub fn hide_thread(thread_handle: usize) -> Result<()> {
27 nt_set_information_thread(
28 thread_handle,
29 THREAD_HIDE_FROM_DEBUGGER,
30 core::ptr::null(),
31 0,
32 )
33}
34
35#[cfg(feature = "syscalls")]
37pub fn hide_current_thread() -> Result<()> {
38 hide_thread(CURRENT_THREAD)?;
39
40 if let Ok(teb) = Teb::current() {
42 let tid = teb.thread_id();
43 if let Ok(mut hidden) = HIDDEN_THREADS.lock() {
44 hidden.insert(tid);
45 }
46 }
47
48 Ok(())
49}
50
51#[cfg(not(feature = "syscalls"))]
53pub fn hide_thread(_thread_handle: usize) -> Result<()> {
54 Err(crate::error::WraithError::SyscallNotFound {
55 name: "NtSetInformationThread (syscalls feature disabled)".into(),
56 })
57}
58
59#[cfg(not(feature = "syscalls"))]
60pub fn hide_current_thread() -> Result<()> {
61 Err(crate::error::WraithError::SyscallNotFound {
62 name: "NtSetInformationThread (syscalls feature disabled)".into(),
63 })
64}
65
66pub fn is_thread_hidden(tid: u32) -> bool {
68 HIDDEN_THREADS
69 .lock()
70 .map(|h| h.contains(&tid))
71 .unwrap_or(false)
72}
73
74pub fn get_hidden_threads() -> Vec<u32> {
76 HIDDEN_THREADS
77 .lock()
78 .map(|h| h.iter().copied().collect())
79 .unwrap_or_default()
80}
81
82pub fn hidden_count() -> usize {
84 HIDDEN_THREADS.lock().map(|h| h.len()).unwrap_or(0)
85}
86
87pub fn clear_tracking() {
89 if let Ok(mut hidden) = HIDDEN_THREADS.lock() {
90 hidden.clear();
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn test_tracking() {
100 clear_tracking();
101
102 if let Ok(mut hidden) = HIDDEN_THREADS.lock() {
104 hidden.insert(1234);
105 }
106
107 assert!(is_thread_hidden(1234));
108 assert!(!is_thread_hidden(5678));
109
110 let threads = get_hidden_threads();
111 assert!(threads.contains(&1234));
112
113 clear_tracking();
114 assert!(!is_thread_hidden(1234));
115 }
116}