phnt/
lib.rs

1// MIT License
2//
3// Copyright (c) 2024 oberrich <oberrich.llvm@proton.me>
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22//
23#![no_std]
24#![cfg_attr(docsrs, feature(doc_cfg))]
25#![doc = include_str!("../README.md")]
26#![allow(
27   warnings,
28   unused,
29   non_snake_case,
30   non_camel_case_types,
31   non_upper_case_globals
32)]
33
34/// Bindings for `phnt` (nightly) generated by `bindgen`
35pub mod ffi {
36   // use vendored bindings
37   #[cfg_attr(docsrs, doc(cfg(not(feature = "regenerate"))))]
38   #[cfg(all(not(feature = "regenerate"), target_arch = "x86"))]
39   include!("ffi/x86_bindgen.rs");
40   #[cfg_attr(docsrs, doc(cfg(not(feature = "regenerate"))))]
41   #[cfg(all(not(feature = "regenerate"), target_arch = "x86_64"))]
42   include!("ffi/x86_64_bindgen.rs");
43   #[cfg_attr(docsrs, doc(cfg(not(feature = "regenerate"))))]
44   #[cfg(all(not(feature = "regenerate"), target_arch = "aarch64"))]
45   include!("ffi/aarch64_bindgen.rs");
46
47   // use regenerated bindings
48   #[cfg_attr(docsrs, doc(cfg(feature = "regenerate")))]
49   #[cfg(all(feature = "regenerate", target_arch = "x86"))]
50   include!(concat!(env!("OUT_DIR"), "/x86_bindgen.rs"));
51   #[cfg_attr(docsrs, doc(cfg(feature = "regenerate")))]
52   #[cfg(all(feature = "regenerate", target_arch = "x86_64"))]
53   include!(concat!(env!("OUT_DIR"), "/x86_64_bindgen.rs"));
54   #[cfg_attr(docsrs, doc(cfg(feature = "regenerate")))]
55   #[cfg(all(feature = "regenerate", target_arch = "aarch64"))]
56   include!(concat!(env!("OUT_DIR"), "/aarch64_bindgen.rs"));
57}
58
59/// Extensions to the bindings (useful functions, macros, etc.)
60pub mod ext {
61   use crate::ffi::*;
62   use core::{arch::asm, mem, ptr};
63
64   #[inline]
65   #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
66   pub unsafe fn __readfsdword(offset: u32) -> usize {
67      let out: usize;
68      asm!(
69          "mov {}, fs:[{}]",
70          lateout(reg) out, in(reg) offset,
71          options(nostack, pure, readonly),
72      );
73      out
74   }
75
76   #[inline]
77   #[cfg(target_arch = "aarch64")]
78   pub unsafe fn __readfsdword(offset: u32) -> usize {
79      unimplemented!("not implemented on this arch")
80   }
81
82   #[inline]
83   #[cfg(target_arch = "x86_64")]
84   pub unsafe fn __readgsqword(offset: u32) -> usize {
85      let out: usize;
86      asm!(
87          "mov {}, gs:[{}]",
88          lateout(reg) out, in(reg) offset,
89          options(nostack, pure, readonly),
90      );
91      out
92   }
93
94   #[inline]
95   #[cfg(any(target_arch = "aarch64", target_arch = "x86"))]
96   pub unsafe fn __readgsqword(offset: u32) -> usize {
97      unimplemented!("not implemented on this arch")
98   }
99
100   #[inline]
101   #[cfg(target_arch = "aarch64")]
102   pub unsafe fn read_x18() -> usize {
103      let out: usize;
104      asm!(
105          "mov {}, x18",
106          lateout(reg) out,
107          options(nostack, pure, readonly),
108      );
109      out
110   }
111
112   #[inline]
113   #[cfg(not(target_arch = "aarch64"))]
114   pub unsafe fn read_x18() -> usize {
115      unimplemented!("not implemented on this arch")
116   }
117
118   #[inline]
119   pub unsafe fn NtCurrentTeb() -> *mut TEB {
120      const TEB_OFFSET: u32 = mem::offset_of!(NT_TIB, Self_) as u32;
121      if cfg!(target_arch = "x86_64") {
122         __readgsqword(TEB_OFFSET) as *mut TEB
123      } else if cfg!(target_arch = "x86") {
124         __readfsdword(TEB_OFFSET) as *mut TEB
125      } else if cfg!(target_arch = "aarch64") {
126         ((read_x18().wrapping_add(TEB_OFFSET as usize)) as *mut *mut TEB).read()
127      } else {
128         unimplemented!("target architecture not implemented yet")
129      }
130   }
131
132   #[cfg(test)]
133   mod tests {
134      use super::*;
135      use windows_sys::Win32::System::Threading::GetCurrentThreadId;
136
137      #[test]
138      fn test_teb() {
139         let cur_thread = unsafe { (*NtCurrentTeb()).ClientId.UniqueThread as isize };
140         let cur_thread_sys = unsafe { GetCurrentThreadId() as isize };
141         assert_eq!(cur_thread, cur_thread_sys);
142      }
143   }
144}