anti_debug/
lib.rs

1pub fn is_debugger_present() -> Result<bool, std::io::Error> {
2    #[cfg(target_os = "windows")] {
3        // Check with `IsDebuggerPresent`.
4        unsafe {
5            let result = windows_sys::Win32::System::Diagnostics::Debug::IsDebuggerPresent();
6            if result != windows_sys::Win32::Foundation::FALSE {
7                return Ok(true);
8            }
9        }
10        // Check with `CheckRemoteDebuggerPresent`.
11        #[cfg(feature = "deep-detect")]
12        unsafe {
13            let mut p_debugger_present = windows_sys::Win32::Foundation::FALSE;
14            let result = windows_sys::Win32::System::Diagnostics::Debug::CheckRemoteDebuggerPresent(
15                windows_sys::Win32::System::Threading::GetCurrentProcess(),
16                &mut p_debugger_present,
17            );
18            if result == windows_sys::Win32::Foundation::FALSE {
19                return Err(errno::errno().into());
20            }
21            if p_debugger_present != windows_sys::Win32::Foundation::FALSE {
22                return Ok(true);
23            }
24        }
25        // Check with `NtQueryInformationProcess`.
26        #[cfg(feature = "deep-detect")]
27        unsafe {
28            let mut p_debug_port = 0i32;
29            let result = windows_sys::Wdk::System::Threading::NtQueryInformationProcess(
30                windows_sys::Win32::System::Threading::GetCurrentProcess(),
31                windows_sys::Wdk::System::Threading::ProcessDebugPort,
32                &mut p_debug_port as *mut _ as _,
33                size_of::<i32>() as _,
34                &mut 0,
35            );
36            let result = windows_sys::Win32::Foundation::RtlNtStatusToDosError(result);
37            if result != 0 {
38                return Err(errno::Errno(result as _).into());
39            }
40            if p_debug_port != 0 {
41                return Ok(true);
42            }
43        }
44       return Ok(false);
45    }
46    #[cfg(any(target_os = "linux", target_os = "android"))] {
47        // Check with `/proc/self/status`.
48        {
49            let proc = std::fs::read_to_string("/proc/self/status")?;
50            let pid = proc
51                .lines()
52                .filter_map(|line| line.strip_prefix("TracerPid:"))
53                .filter_map(|pid| pid.trim().parse::<i32>().ok())
54                .next()
55                .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid pid format"))?;
56            if pid != 0 {
57                return Ok(true);
58            }
59        }
60        return Ok(false);
61    }
62    #[cfg(target_os = "macos")] {
63        // Check with `proc_pidinfo`.
64        {
65            let pid = std::process::id() as i32;
66            let result = libproc::proc_pid::pidinfo::<libproc::bsd_info::BSDInfo>(pid, 0);
67            let proc_bsdinfo = match result {
68                Ok(proc_bsdinfo) => proc_bsdinfo,
69                Err(_message) => return Err(errno::errno().into()),
70            };
71            const PROC_FLAG_TRACED: u32 = 2; // use libproc::osx_libproc_bindings::PROC_FLAG_TRACED;
72            if proc_bsdinfo.pbi_flags & PROC_FLAG_TRACED != 0 { return Ok(true); }
73        }
74        return Ok(false);
75    }
76    #[cfg(not(any(
77        target_os = "windows",
78        target_os = "linux",
79        target_os = "android",
80        target_os = "macos",
81    )))]
82    compile_error!("Anti-Debug doesn't support current platform.")
83}
84
85#[cfg(test)]
86mod tests {
87    #[test]
88    fn test_is_debugger_present() {
89        assert!(!super::is_debugger_present().unwrap_or(false));
90        assert!(!super::is_debugger_present().unwrap_or(false));
91        assert!(!super::is_debugger_present().unwrap_or(false));
92    }
93}