Compare commits
20 Commits
v0.2-alpha
...
master
Author | SHA1 | Date | |
---|---|---|---|
ae679b62be | |||
e2eac767e0 | |||
967684f140 | |||
2d7576b1e2 | |||
60513ee142 | |||
09114848fc | |||
a154c71f9b | |||
b1c3107c74 | |||
4e67e10aee | |||
8cb553eb11 | |||
abb7a70b72 | |||
199c3ca10b | |||
0350ec46d9 | |||
5619048a4a | |||
8cf91aef79 | |||
1707b301ff | |||
060f222c0a | |||
72a947ccd7 | |||
8c642f6ba0 | |||
c8ce82e8a7 |
5
.cargo/config
Normal file
5
.cargo/config
Normal file
@ -0,0 +1,5 @@
|
||||
[target.x86_64-pc-windows-msvc]
|
||||
# CRT static to make run on machine without VC++
|
||||
# https://github.com/rust-lang/rust/pull/66801#issuecomment-558947376
|
||||
# >> "-Clink-args=/subsystem:console,5.02"
|
||||
rustflags = ["-Ctarget-feature=+crt-static"]
|
525
Cargo.lock
generated
525
Cargo.lock
generated
@ -1,5 +1,13 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.26"
|
||||
@ -16,6 +24,26 @@ dependencies = [
|
||||
"xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
@ -31,11 +59,61 @@ name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "blake2b_simd"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "0.5.4"
|
||||
@ -69,6 +147,25 @@ dependencies = [
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.6.4"
|
||||
@ -83,11 +180,83 @@ name = "core-foundation-sys"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-next"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dirs-sys-next 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.22"
|
||||
@ -96,6 +265,11 @@ dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.1.6"
|
||||
@ -174,6 +348,14 @@ dependencies = [
|
||||
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.14"
|
||||
@ -218,11 +400,6 @@ dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.0"
|
||||
@ -354,13 +531,26 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parse_int 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pdb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"prettytable-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rust-embed 5.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustyline 6.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"widestring 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maplit"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
@ -441,6 +631,18 @@ dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "4.2.3"
|
||||
@ -485,6 +687,11 @@ dependencies = [
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.28"
|
||||
@ -515,6 +722,14 @@ dependencies = [
|
||||
"vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse_int"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pdb"
|
||||
version = "0.5.0"
|
||||
@ -530,6 +745,45 @@ name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ucd-trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest_generator 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest_meta 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.4.8"
|
||||
@ -568,6 +822,19 @@ name = "ppv-lite86"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "prettytable-rs"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
@ -642,6 +909,24 @@ name = "redox_syscall"
|
||||
version = "0.1.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.2"
|
||||
@ -684,6 +969,46 @@ dependencies = [
|
||||
"winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "5.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rust-embed-impl 5.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rust-embed-utils 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-impl"
|
||||
version = "5.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rust-embed-utils 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-utils"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
@ -692,11 +1017,37 @@ dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustyline"
|
||||
version = "6.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dirs-next 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8parse 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.17"
|
||||
@ -706,6 +1057,11 @@ dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "scroll"
|
||||
version = "0.9.2"
|
||||
@ -764,7 +1120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.48"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -783,6 +1139,17 @@ dependencies = [
|
||||
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell32-sys"
|
||||
version = "0.1.2"
|
||||
@ -807,6 +1174,11 @@ name = "sourcefile"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.44"
|
||||
@ -840,6 +1212,24 @@ dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.42"
|
||||
@ -898,6 +1288,16 @@ name = "try-lock"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
@ -927,6 +1327,11 @@ name = "unicode-segmentation"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
@ -947,6 +1352,11 @@ dependencies = [
|
||||
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.7.4"
|
||||
@ -957,6 +1367,20 @@ name = "vcpkg"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vergen"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.5"
|
||||
@ -967,6 +1391,21 @@ name = "version_check"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.0"
|
||||
@ -988,7 +1427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@ -1080,7 +1519,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "0.4.0"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@ -1107,6 +1546,14 @@ name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
@ -1135,21 +1582,42 @@ version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c"
|
||||
"checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d"
|
||||
"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
||||
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
|
||||
"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
|
||||
"checksum bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931"
|
||||
"checksum bumpalo 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f359dc14ff8911330a51ef78022d376f25ed00248912803b58f00cb1c27f742"
|
||||
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
"checksum bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1"
|
||||
"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
|
||||
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01"
|
||||
"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
||||
"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
|
||||
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
|
||||
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
"checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279"
|
||||
"checksum csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
|
||||
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
|
||||
"checksum dirs-next 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1cbcf9241d9e8d106295bd496bbe2e9cffd5fa098f2a8c9e2bbcbf09773c11a8"
|
||||
"checksum dirs-sys-next 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c60f7b8a8953926148223260454befb50c751d3c50e1c178c4fd1ace4083c9a"
|
||||
"checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3"
|
||||
"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
"checksum encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28"
|
||||
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
"checksum fallible-iterator 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eb7217124812dc5672b7476d0c2d20cfe9f7c0f1ba0904b674a9762a0212f72e"
|
||||
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
@ -1162,11 +1630,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6"
|
||||
"checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27"
|
||||
"checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5"
|
||||
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
|
||||
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
"checksum h2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9433d71e471c1736fd5a61b671fc0b148d7a2992f666c958d03cd8feb3b88d1"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
|
||||
"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
|
||||
"checksum http 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b708cc7f06493459026f53b9a61a7a121a5d1ec6238dee58ea4941132b30156b"
|
||||
"checksum http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"
|
||||
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
|
||||
@ -1181,6 +1649,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
"checksum memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53445de381a1f436797497c61d851644d0e8e88e6140f22872ad33a704933978"
|
||||
"checksum mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||
@ -1189,22 +1658,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
|
||||
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||
"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
|
||||
"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||
"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
||||
"checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c"
|
||||
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
"checksum openssl 0.10.28 (registry+https://github.com/rust-lang/crates.io-index)" = "973293749822d7dd6370d6da1e523b0d1db19f06c459134c658b2a4261378b52"
|
||||
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||
"checksum openssl-sys 0.9.54 (registry+https://github.com/rust-lang/crates.io-index)" = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986"
|
||||
"checksum parse_int 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82db48cac18f0963b10ddad303fa88447b95bbe0e6dbe3385f98402b63d0cc48"
|
||||
"checksum pdb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6b57b7067dc9dbd04b1305bb51a8ae7d0fc645956a73b6cb2807dd956ab6929"
|
||||
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
"checksum pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
|
||||
"checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
|
||||
"checksum pest_generator 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
|
||||
"checksum pest_meta 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
|
||||
"checksum pin-project 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7804a463a8d9572f13453c516a5faea534a2403d7ced2f0c7e100eeff072772c"
|
||||
"checksum pin-project-internal 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "385322a45f2ecf3410c68d2a549a4a2685e8051d0f278e39743ff4e451cb9b3f"
|
||||
"checksum pin-project-lite 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae"
|
||||
"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
|
||||
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
|
||||
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||
"checksum prettytable-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0fd04b170004fa2daccf418a7f8253aaf033c27760b5f225889024cf66d7ac2e"
|
||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
|
||||
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||
@ -1214,11 +1691,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
|
||||
"checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
|
||||
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||
"checksum reqwest 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0e798e19e258bf6c30a304622e3e9ac820e483b06a1857a026e1f109b113fe4"
|
||||
"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
|
||||
"checksum rust-embed 5.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "213acf1bc5a6dfcd70b62db1e9a7d06325c0e73439c312fcb8599d456d9686ee"
|
||||
"checksum rust-embed-impl 5.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7903c2cf599db8f310b392332f38367ca4acc84420fa1aee3536299f433c10d5"
|
||||
"checksum rust-embed-utils 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97655158074ccb2d2cfb1ccb4c956ef0f4054e43a2c1e71146d4991e6961e105"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum rustyline 6.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3358c21cbbc1a751892528db4e1de4b7a2b6a73f001e215aaba97d712cfa9777"
|
||||
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
|
||||
"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
"checksum schannel 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "507a9e6e8ffe0a4e0ebb9a10293e62fdf7657c06f1b8bb07a8fcf697d2abf295"
|
||||
"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
"checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383"
|
||||
"checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb"
|
||||
"checksum security-framework 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8ef2429d7cefe5fd28bd1d2ed41c944547d4ff84776f5935b456da44593a16df"
|
||||
@ -1226,32 +1712,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
||||
"checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25"
|
||||
"checksum serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226"
|
||||
"checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
|
||||
"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
|
||||
"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc"
|
||||
"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"
|
||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
|
||||
"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
|
||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
"checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum tokio 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8fdd17989496f49cdc57978c96f0c9fe5e4a58a8bddc6813c449a4624f6a030b"
|
||||
"checksum tokio-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bde02a3a5291395f59b06ec6945a3077602fac2b07eeeaf0dee2122f3619828"
|
||||
"checksum tokio-util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "571da51182ec208780505a32528fc5512a8fe1443ab960b3f2f3ef093cd16930"
|
||||
"checksum tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860"
|
||||
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
|
||||
"checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
|
||||
"checksum ucd-trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||
"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
|
||||
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
|
||||
"checksum utf8parse 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
|
||||
"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
|
||||
"checksum vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
|
||||
"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
"checksum vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb"
|
||||
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
"checksum want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
|
||||
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
"checksum wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "5205e9afdf42282b192e2310a5b463a6d1c1d774e30dc3c791ac37ab42d2616c"
|
||||
@ -1263,11 +1761,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ef012a0d93fc0432df126a8eaf547b2dce25a8ce9212e1d3cbeef5c11157975d"
|
||||
"checksum web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf97caf6aa8c2b1dac90faf0db529d9d63c93846cca4911856f78a83cebf53b"
|
||||
"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164"
|
||||
"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6"
|
||||
"checksum widestring 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a763e303c0e0f23b0da40888724762e802a8ffefbc22de4127ef42493c2ea68c"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
|
||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
|
14
Cargo.toml
14
Cargo.toml
@ -12,9 +12,21 @@ doctest = false
|
||||
|
||||
[dependencies]
|
||||
app_dirs = "1.2.1"
|
||||
hex = "0.4.2"
|
||||
pdb = "0.5.0"
|
||||
chrono = "0.4"
|
||||
widestring = "0.4.0"
|
||||
winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg", "fileapi", "ioapiset", "winioctl", "errhandlingapi", "sysinfoapi"] }
|
||||
reqwest = { version = "0.10.1", features = ["blocking"] }
|
||||
serde_json = "1.0.55"
|
||||
parse_int = "0.4.0"
|
||||
# repl dependencies
|
||||
rustyline = "6.2.0"
|
||||
pest = "2.1.3"
|
||||
pest_derive = "2.1.0"
|
||||
# others
|
||||
prettytable-rs = "^0.8"
|
||||
rust-embed="5.6.0"
|
||||
clap="2.33.1"
|
||||
|
||||
[build-dependencies]
|
||||
vergen="3.1.0"
|
||||
|
78
README.md
78
README.md
@ -1,6 +1,16 @@
|
||||
# LPUS (A live pool-tag scanning solution)
|
||||
|
||||
This is the frontend to the live pool tag scanning solution, the backend is a driver (which is now closed source).
|
||||
This is the frontend to the live pool tag scanning solution, the backend is a
|
||||
driver (which is now closed source).
|
||||
|
||||
Works on Windows 7 and above (Vista not tested, but 7 ok and 10 ok), and on x64
|
||||
systems only. (I hardcoded the address as u64 so only 64 systems should run this).
|
||||
|
||||
> The binary is runable, without crashing. But I still need to add some
|
||||
manual instructions on referencing the structs and offset on some places.
|
||||
> Windows 10, versions 2018, 2019 and 2020 is tested and works.
|
||||
|
||||
Windows XP is not supported: Windows XP Win32Api is missing here and there.
|
||||
|
||||
## How this works
|
||||
|
||||
@ -21,7 +31,7 @@ use lpus::{
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
driver.scan_pool(b"Tag ", |pool_addr, header, data_addr| {
|
||||
driver.scan_pool(b"Tag ", "_STRUCT_NAME", |pool_addr, header, data_addr| {
|
||||
})?;
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
}
|
||||
@ -33,3 +43,67 @@ Parsing the struct data is up to you.
|
||||
You can use `driver.deref_addr(addr, &value)` to dereference an address in kernel space
|
||||
and `driver.pdb_store.get_offset_r("offset")?` to get an offset from PDB file.
|
||||
|
||||
We also have a set of functions for scanning a specific tag/object.
|
||||
|
||||
- `pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn scan_file(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn scan_ethread(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn scan_mutant(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn scan_kernel_module(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
|
||||
And a list traversing the kernel object:
|
||||
|
||||
- `pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn traverse_activehead(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- missing symbols `pub fn traverse_afdendpoint(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn traverse_kiprocesslist(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn traverse_handletable(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
- `pub fn traverse_unloadeddrivers(driver: &DriverState) -> BoxResult<Vec<Value>>`
|
||||
|
||||
## Things to note
|
||||
|
||||
Right now, we only have one symbol file of ntoskrnl.exe. While we may need more
|
||||
symbols, kernel32.sys, win32k.sys, tcpis.sys... This will be a future update
|
||||
where symbols are combined into one big `HashMap` but still retain the module. I
|
||||
haven't tested the debug symbols of others binary, I wonder if the PDB file even
|
||||
exists.
|
||||
|
||||
The pdb file is not restricted in ntoskrnl.exe, I might need to split to a
|
||||
smaller module or such.
|
||||
|
||||
Also the symbols list is parsed directly from the PDB file, but some structs
|
||||
(like the callback routine members or network structs) are missing. Right now a
|
||||
simple hardcoded to add in a struct member is used, but it would break if the
|
||||
OS running have a different layout.
|
||||
|
||||
The HashMap of symbols/struct is now using string and u32 to store member
|
||||
offset and types, this should be changed into something that would be type-safe
|
||||
and more functional.
|
||||
|
||||
I also follow a few Volatility implementation on Rootkit, The art of Memory
|
||||
forensics Chapter 13. Scanning in Windows 10 yields promising result, though I
|
||||
haven't tested on any malware to see if we can have the "same" result.
|
||||
|
||||
At the pace of development, I seperate the binary to functionalities for
|
||||
testing, I would add a CLI and a REPL.
|
||||
|
||||
One last thing, the backend doesn't have any check on address referencing, so
|
||||
one may get a blue screen, eventhough I tried to avoid it, I'm not 100% sure it
|
||||
would not crash the system.
|
||||
|
||||
## Future works
|
||||
|
||||
- [ ] An interactive repl (1)
|
||||
- [ ] More kernel modules symbols (2)
|
||||
- [ ] Implementation of more technique (reference Volatility here)
|
||||
- [ ] Quick and easy way to add manual struct, symbols (3)
|
||||
|
||||
(1) This is quite hard to work out, because we have to make the *types* works.
|
||||
The currently chosen repl is based on Lisp, because lisp is cool. If the repl
|
||||
is online, we can combine everything into one binary.
|
||||
|
||||
(2) We may need to download it all and combine to one `HashMap`, with their
|
||||
types as a specific struct. (Try to avoid string).
|
||||
|
||||
(3) Have no idea on this.
|
||||
|
8
build.rs
Normal file
8
build.rs
Normal file
@ -0,0 +1,8 @@
|
||||
extern crate vergen;
|
||||
|
||||
use vergen::{generate_cargo_keys, ConstantsFlags};
|
||||
|
||||
fn main() {
|
||||
let flags = ConstantsFlags::all();
|
||||
generate_cargo_keys(flags).expect("Unable to generate the cargo keys!");
|
||||
}
|
74
logs/build_process_tree.py
Normal file
74
logs/build_process_tree.py
Normal file
@ -0,0 +1,74 @@
|
||||
import sys
|
||||
import re
|
||||
import collections
|
||||
|
||||
class Process:
|
||||
def __init__(self, e, pid, ppid, name, path):
|
||||
self.e = e
|
||||
self.pid = pid
|
||||
self.ppid = ppid
|
||||
self.name = name
|
||||
self.path = path
|
||||
def __str__(self):
|
||||
return f'{self.e} {self.pid} {self.ppid} {self.name} {self.path}'
|
||||
def __repr__(self):
|
||||
return f'{self.e} {self.pid} {self.ppid} {self.name} {self.path}'
|
||||
|
||||
process_map = {}
|
||||
|
||||
# shamelessly steal from https://github.com/giampaolo/psutil/blob/master/scripts/pstree.py
|
||||
# not work if a detached node presents
|
||||
def print_tree(parent, tree, indent='', traversed=[]):
|
||||
try:
|
||||
p = process_map[parent]
|
||||
name = f"{p.pid} [{p.name}] {p.path}"
|
||||
except:
|
||||
name = f"{parent} [UNNOWN]"
|
||||
# input(name)
|
||||
if parent in traversed:
|
||||
print(name, "[LOOP]")
|
||||
return
|
||||
else:
|
||||
print(name)
|
||||
traversed += [parent]
|
||||
|
||||
if parent not in tree:
|
||||
return
|
||||
children = tree[parent][:-1]
|
||||
for child in children:
|
||||
print(indent + "|- ", end='')
|
||||
print_tree(child.pid, tree, indent + "| ", traversed)
|
||||
child = tree[parent][-1]
|
||||
print(indent + "`_ ", end='')
|
||||
print_tree(child.pid, tree, indent + " ", traversed)
|
||||
|
||||
lpus = re.finditer(r'^pool: 0x[0-9a-f]+ \| eprocess: (0x[0-9a-f]+) \| pid: (\d+) \| ppid: (\d+) \| name: ([^|]*) \| (.*)$',
|
||||
open(sys.argv[1], 'r', encoding='utf-8').read(), re.MULTILINE)
|
||||
|
||||
process_tree = {}
|
||||
for v in lpus:
|
||||
e, pid, ppid, name, path = list(v.groups())
|
||||
proc = Process(e, int(pid), int(ppid), name, path)
|
||||
process_map[int(pid)] = proc
|
||||
if int(ppid) in process_tree:
|
||||
process_tree[int(ppid)] += [proc]
|
||||
else:
|
||||
process_tree[int(ppid)] = [proc]
|
||||
|
||||
if 0 in process_tree:
|
||||
process_tree.pop(0)
|
||||
|
||||
remove = []
|
||||
for k, child in process_tree.items():
|
||||
for c in child:
|
||||
if c.pid in process_tree and c.ppid in process_tree:
|
||||
# print('remove', c)
|
||||
remove += [c.pid]
|
||||
break
|
||||
|
||||
# print(remove)
|
||||
for k in process_tree.keys():
|
||||
if k not in remove:
|
||||
print_tree(k, process_tree)
|
||||
# input()
|
||||
|
118
logs/dump_test/1/eprocess_lpusscan.csv
Normal file
118
logs/dump_test/1/eprocess_lpusscan.csv
Normal file
@ -0,0 +1,118 @@
|
||||
address,process,fullpath
|
||||
0xffff948957c6c080,svchost.exe,
|
||||
0xffff948957caa080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895ad15080,powershell.exe,
|
||||
0xffff94895ad1a080,CodeHelper.exe,\Users\User\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\platform\files\node\watcher\win32\CodeHelper.exe
|
||||
0xffff94895b394080,Code.exe,\Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe
|
||||
0xffff94895ba28080,MicrosoftEdgeC,\Windows\System32\MicrosoftEdgeCP.exe
|
||||
0xffff94895ba2b080,sppsvc.exe,\Windows\System32\sppsvc.exe
|
||||
0xffff94895ba433c0,audiodg.exe,\Windows\System32\audiodg.exe
|
||||
0xffff94895bb21380,powershell.exe,\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
|
||||
0xffff94895bb25080,MicrosoftEdgeC,\Windows\System32\MicrosoftEdgeCP.exe
|
||||
0xffff94895bb28080,conhost.exe,\Windows\System32\conhost.exe
|
||||
0xffff94895bb8a080,conhost.exe,\Windows\System32\conhost.exe
|
||||
0xffff94895cbc9080,Code.exe,\Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe
|
||||
0xffff94895ce98400,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895cea7080,MemCompression,
|
||||
0xffff94895ceb5380,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895cec9080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895cf2e3c0,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895cf5c400,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895cf90400,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895cf98400,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e017440,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e02b380,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e072400,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e077400,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e0ce400,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e0d8400,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e1670c0,sqlwriter.exe,\Program Files\Microsoft SQL Server\90\Shared\sqlwriter.exe
|
||||
0xffff94895e169380,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e16a080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e16b080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e16c080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e16d080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e170080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e171080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e172080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e174080,spoolsv.exe,\Windows\System32\spoolsv.exe
|
||||
0xffff94895e1780c0,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e38b080,WindowsInterna,\Windows\SystemApps\InputApp_cw5n1h2txyewy\WindowsInternal.ComposableShell.Experiences.TextInput.InputApp.exe
|
||||
0xffff94895e390080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e391080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e392080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e394080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e395080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e396080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895e3990c0,wlms.exe,\Windows\System32\wlms\wlms.exe
|
||||
0xffff94895e54e4c0,NisSrv.exe,\ProgramData\Microsoft\Windows Defender\Platform\4.18.2005.5-0\NisSrv.exe
|
||||
0xffff94895e929480,smartscreen.ex,\Windows\System32\smartscreen.exe
|
||||
0xffff94895e92a080,Code.exe,\Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe
|
||||
0xffff94895e9412c0,Windows.WARP.J,\Windows\System32\Windows.WARP.JITService.exe
|
||||
0xffff94895e9512c0,MsMpEng.exe,\ProgramData\Microsoft\Windows Defender\Platform\4.18.2005.5-0\MsMpEng.exe
|
||||
0xffff94895e970080,SearchUI.exe,\Windows\SystemApps\Microsoft.Windows.Cortana_cw5n1h2txyewy\SearchUI.exe
|
||||
0xffff94895eaaf440,sihost.exe,\Windows\System32\sihost.exe
|
||||
0xffff94895eaee480,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895eaf54c0,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895eaf84c0,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895eb4f080,svchost.exe,
|
||||
0xffff94895eb57380,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895eb5b4c0,taskhostw.exe,\Windows\System32\taskhostw.exe
|
||||
0xffff94895ebbd3c0,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895ebc2440,ctfmon.exe,\Windows\System32\ctfmon.exe
|
||||
0xffff94895ec48400,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895ec5e080,userinit.exe,
|
||||
0xffff94895ec62080,explorer.exe,\Windows\explorer.exe
|
||||
0xffff94895ec70080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895ec77080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895ec934c0,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895eccc4c0,Code.exe,\Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe
|
||||
0xffff94895ece5080,dllhost.exe,\Windows\System32\dllhost.exe
|
||||
0xffff94895edca080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895edda080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895edf6080,StartMenuExper,\Windows\SystemApps\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\StartMenuExperienceHost.exe
|
||||
0xffff94895ef1b480,RuntimeBroker.,\Windows\System32\RuntimeBroker.exe
|
||||
0xffff94895efb9080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895f089480,RuntimeBroker.,\Windows\System32\RuntimeBroker.exe
|
||||
0xffff94895f118480,RuntimeBroker.,\Windows\System32\RuntimeBroker.exe
|
||||
0xffff94895f119080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895f122380,SearchIndexer.,\Windows\System32\SearchIndexer.exe
|
||||
0xffff94895f19e080,Windows.WARP.J,\Windows\System32\Windows.WARP.JITService.exe
|
||||
0xffff94895f2020c0,MicrosoftEdge.,\Windows\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\MicrosoftEdge.exe
|
||||
0xffff94895f2074c0,ApplicationFra,\Windows\System32\ApplicationFrameHost.exe
|
||||
0xffff94895f267440,cmd.exe,\Windows\System32\cmd.exe
|
||||
0xffff94895f2c8080,SgrmBroker.exe,\Windows\System32\SgrmBroker.exe
|
||||
0xffff94895f2db080,SkypeBackgroun,\Program Files\WindowsApps\Microsoft.SkypeApp_14.56.102.0_x64__kzf8qxf38zg5c\SkypeBackgroundHost.exe
|
||||
0xffff94895f2dd080,SkypeApp.exe,\Program Files\WindowsApps\Microsoft.SkypeApp_14.56.102.0_x64__kzf8qxf38zg5c\SkypeApp.exe
|
||||
0xffff94895f3be480,browser_broker,\Windows\System32\browser_broker.exe
|
||||
0xffff94895f3c5080,YourPhone.exe,\Program Files\WindowsApps\Microsoft.YourPhone_1.20041.91.0_x64__8wekyb3d8bbwe\YourPhone.exe
|
||||
0xffff94895f3ce400,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895f419080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895f449080,WinStore.App.e,\Program Files\WindowsApps\Microsoft.WindowsStore_12005.1001.1.0_x64__8wekyb3d8bbwe\WinStore.App.exe
|
||||
0xffff94895f44b480,RuntimeBroker.,\Windows\System32\RuntimeBroker.exe
|
||||
0xffff94895f4b1080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895f4e5080,RuntimeBroker.,\Windows\System32\RuntimeBroker.exe
|
||||
0xffff94895f4e9240,MicrosoftEdgeC,\Windows\System32\MicrosoftEdgeCP.exe
|
||||
0xffff94895f571480,RuntimeBroker.,\Windows\System32\RuntimeBroker.exe
|
||||
0xffff94895f5880c0,RuntimeBroker.,\Windows\System32\RuntimeBroker.exe
|
||||
0xffff94895f58e080,VBoxTray.exe,\Windows\System32\VBoxTray.exe
|
||||
0xffff94895f5c7080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff94895f603080,MicrosoftEdgeS,\Windows\System32\MicrosoftEdgeSH.exe
|
||||
0xffff94895f7c7080,OneDrive.exe,\Users\User\AppData\Local\Microsoft\OneDrive\OneDrive.exe
|
||||
0xffff94895f7c8080,SecurityHealth,\Windows\System32\SecurityHealthSystray.exe
|
||||
0xffff94895f7ca380,SecurityHealth,\Windows\System32\SecurityHealthService.exe
|
||||
0xffff94895fce60c0,backgroundTask,\Windows\System32\backgroundTaskHost.exe
|
||||
0xffff94895fdd2080,Code.exe,\Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe
|
||||
0xffff94895ffce080,MicrosoftEdgeC,
|
||||
0xffff94895ffe2080,Code.exe,\Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe
|
||||
0xffff94895ffef080,backgroundTask,\Windows\System32\backgroundTaskHost.exe
|
||||
0xffff94895fff2480,conhost.exe,\Windows\System32\conhost.exe
|
||||
0xffff9489600c50c0,Code.exe,\Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe
|
||||
0xffff9489600cf340,eprocess_scan.,\Users\User\Desktop\lpus-0.3-alpha\target\release\eprocess_scan.exe
|
||||
0xffff9489602ec080,dllhost.exe,\Windows\System32\dllhost.exe
|
||||
0xffff9489602f0080,conhost.exe,
|
||||
0xffff9489602f5080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff9489603ca080,Windows.WARP.J,\Windows\System32\Windows.WARP.JITService.exe
|
||||
0xffff948960acc080,svchost.exe,\Windows\System32\svchost.exe
|
||||
0xffff948960ad3080,RuntimeBroker.,\Windows\System32\RuntimeBroker.exe
|
||||
0xffff9489610de080,MicrosoftEdgeC,\Windows\System32\MicrosoftEdgeCP.exe
|
|
121
logs/dump_test/1/eprocess_scan_log.txt
Normal file
121
logs/dump_test/1/eprocess_scan_log.txt
Normal file
@ -0,0 +1,121 @@
|
||||
PDB for Amd64, guid: e7477a03-a707-8050-cb79-36455ce346b5, age: 1
|
||||
|
||||
NtLoadDriver() -> 0x0
|
||||
pool: 0xffff948957c6c000 | eprocess: 0xffff948957c6c080 | | svchost.exe
|
||||
pool: 0xffff948957caa000 | eprocess: 0xffff948957caa080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895ad15000 | eprocess: 0xffff94895ad15080 | | powershell.exe
|
||||
pool: 0xffff94895ad1a000 | eprocess: 0xffff94895ad1a080 | \Users\User\AppData\Local\Programs\Microsoft VS Code\resources\app\out\vs\platform\files\node\watcher\win32\CodeHelper.exe | CodeHelper.exe
|
||||
pool: 0xffff94895b394000 | eprocess: 0xffff94895b394080 | \Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe | Code.exe
|
||||
pool: 0xffff94895ba28000 | eprocess: 0xffff94895ba28080 | \Windows\System32\MicrosoftEdgeCP.exe | MicrosoftEdgeC
|
||||
pool: 0xffff94895ba2b000 | eprocess: 0xffff94895ba2b080 | \Windows\System32\sppsvc.exe | sppsvc.exe
|
||||
pool: 0xffff94895ba43360 | eprocess: 0xffff94895ba433c0 | \Windows\System32\audiodg.exe | audiodg.exe
|
||||
pool: 0xffff94895bb21310 | eprocess: 0xffff94895bb21380 | \Windows\System32\WindowsPowerShell\v1.0\powershell.exe | powershell.exe
|
||||
pool: 0xffff94895bb25000 | eprocess: 0xffff94895bb25080 | \Windows\System32\MicrosoftEdgeCP.exe | MicrosoftEdgeC
|
||||
pool: 0xffff94895bb28000 | eprocess: 0xffff94895bb28080 | \Windows\System32\conhost.exe | conhost.exe
|
||||
pool: 0xffff94895bb8a000 | eprocess: 0xffff94895bb8a080 | \Windows\System32\conhost.exe | conhost.exe
|
||||
pool: 0xffff94895cbc9000 | eprocess: 0xffff94895cbc9080 | \Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe | Code.exe
|
||||
pool: 0xffff94895ce98390 | eprocess: 0xffff94895ce98400 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895cea7040 | eprocess: 0xffff94895cea7080 | | MemCompression
|
||||
pool: 0xffff94895ceb5310 | eprocess: 0xffff94895ceb5380 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895cec9000 | eprocess: 0xffff94895cec9080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895cf2e350 | eprocess: 0xffff94895cf2e3c0 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895cf5c390 | eprocess: 0xffff94895cf5c400 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895cf90390 | eprocess: 0xffff94895cf90400 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895cf98390 | eprocess: 0xffff94895cf98400 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e0173c0 | eprocess: 0xffff94895e017440 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e02b310 | eprocess: 0xffff94895e02b380 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e072390 | eprocess: 0xffff94895e072400 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e077390 | eprocess: 0xffff94895e077400 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e0ce390 | eprocess: 0xffff94895e0ce400 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e0d8390 | eprocess: 0xffff94895e0d8400 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e167040 | eprocess: 0xffff94895e1670c0 | \Program Files\Microsoft SQL Server\90\Shared\sqlwriter.exe | sqlwriter.exe
|
||||
pool: 0xffff94895e169310 | eprocess: 0xffff94895e169380 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e16a000 | eprocess: 0xffff94895e16a080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e16b000 | eprocess: 0xffff94895e16b080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e16c000 | eprocess: 0xffff94895e16c080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e16d000 | eprocess: 0xffff94895e16d080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e170000 | eprocess: 0xffff94895e170080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e171000 | eprocess: 0xffff94895e171080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e172000 | eprocess: 0xffff94895e172080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e174000 | eprocess: 0xffff94895e174080 | \Windows\System32\spoolsv.exe | spoolsv.exe
|
||||
pool: 0xffff94895e178040 | eprocess: 0xffff94895e1780c0 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e38b000 | eprocess: 0xffff94895e38b080 | \Windows\SystemApps\InputApp_cw5n1h2txyewy\WindowsInternal.ComposableShell.Experiences.TextInput.InputApp.exe | WindowsInterna
|
||||
pool: 0xffff94895e390000 | eprocess: 0xffff94895e390080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e391000 | eprocess: 0xffff94895e391080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e392000 | eprocess: 0xffff94895e392080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e394000 | eprocess: 0xffff94895e394080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e395000 | eprocess: 0xffff94895e395080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e396000 | eprocess: 0xffff94895e396080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895e399040 | eprocess: 0xffff94895e3990c0 | \Windows\System32\wlms\wlms.exe | wlms.exe
|
||||
pool: 0xffff94895e54e450 | eprocess: 0xffff94895e54e4c0 | \ProgramData\Microsoft\Windows Defender\Platform\4.18.2005.5-0\NisSrv.exe | NisSrv.exe
|
||||
pool: 0xffff94895e929410 | eprocess: 0xffff94895e929480 | \Windows\System32\smartscreen.exe | smartscreen.ex
|
||||
pool: 0xffff94895e92a000 | eprocess: 0xffff94895e92a080 | \Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe | Code.exe
|
||||
pool: 0xffff94895e941250 | eprocess: 0xffff94895e9412c0 | \Windows\System32\Windows.WARP.JITService.exe | Windows.WARP.J
|
||||
pool: 0xffff94895e951230 | eprocess: 0xffff94895e9512c0 | \ProgramData\Microsoft\Windows Defender\Platform\4.18.2005.5-0\MsMpEng.exe | MsMpEng.exe
|
||||
pool: 0xffff94895e970000 | eprocess: 0xffff94895e970080 | \Windows\SystemApps\Microsoft.Windows.Cortana_cw5n1h2txyewy\SearchUI.exe | SearchUI.exe
|
||||
pool: 0xffff94895eaaf3b0 | eprocess: 0xffff94895eaaf440 | \Windows\System32\sihost.exe | sihost.exe
|
||||
pool: 0xffff94895eaee420 | eprocess: 0xffff94895eaee480 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895eaf5430 | eprocess: 0xffff94895eaf54c0 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895eaf8430 | eprocess: 0xffff94895eaf84c0 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895eb4f000 | eprocess: 0xffff94895eb4f080 | | svchost.exe
|
||||
pool: 0xffff94895eb57310 | eprocess: 0xffff94895eb57380 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895eb5b430 | eprocess: 0xffff94895eb5b4c0 | \Windows\System32\taskhostw.exe | taskhostw.exe
|
||||
pool: 0xffff94895ebbd340 | eprocess: 0xffff94895ebbd3c0 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895ebc23b0 | eprocess: 0xffff94895ebc2440 | \Windows\System32\ctfmon.exe | ctfmon.exe
|
||||
pool: 0xffff94895ec48380 | eprocess: 0xffff94895ec48400 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895ec5e000 | eprocess: 0xffff94895ec5e080 | | userinit.exe
|
||||
pool: 0xffff94895ec62000 | eprocess: 0xffff94895ec62080 | \Windows\explorer.exe | explorer.exe
|
||||
pool: 0xffff94895ec70000 | eprocess: 0xffff94895ec70080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895ec77000 | eprocess: 0xffff94895ec77080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895ec93430 | eprocess: 0xffff94895ec934c0 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895eccc450 | eprocess: 0xffff94895eccc4c0 | \Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe | Code.exe
|
||||
pool: 0xffff94895ece5000 | eprocess: 0xffff94895ece5080 | \Windows\System32\dllhost.exe | dllhost.exe
|
||||
pool: 0xffff94895edca000 | eprocess: 0xffff94895edca080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895edda000 | eprocess: 0xffff94895edda080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895edf6000 | eprocess: 0xffff94895edf6080 | \Windows\SystemApps\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\StartMenuExperienceHost.exe | StartMenuExper
|
||||
pool: 0xffff94895ef1b420 | eprocess: 0xffff94895ef1b480 | \Windows\System32\RuntimeBroker.exe | RuntimeBroker.
|
||||
pool: 0xffff94895efb9000 | eprocess: 0xffff94895efb9080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895f089420 | eprocess: 0xffff94895f089480 | \Windows\System32\RuntimeBroker.exe | RuntimeBroker.
|
||||
pool: 0xffff94895f118420 | eprocess: 0xffff94895f118480 | \Windows\System32\RuntimeBroker.exe | RuntimeBroker.
|
||||
pool: 0xffff94895f119000 | eprocess: 0xffff94895f119080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895f122310 | eprocess: 0xffff94895f122380 | \Windows\System32\SearchIndexer.exe | SearchIndexer.
|
||||
pool: 0xffff94895f19e000 | eprocess: 0xffff94895f19e080 | \Windows\System32\Windows.WARP.JITService.exe | Windows.WARP.J
|
||||
pool: 0xffff94895f202040 | eprocess: 0xffff94895f2020c0 | \Windows\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\MicrosoftEdge.exe | MicrosoftEdge.
|
||||
pool: 0xffff94895f207440 | eprocess: 0xffff94895f2074c0 | \Windows\System32\ApplicationFrameHost.exe | ApplicationFra
|
||||
pool: 0xffff94895f2673c0 | eprocess: 0xffff94895f267440 | \Windows\System32\cmd.exe | cmd.exe
|
||||
pool: 0xffff94895f2c8000 | eprocess: 0xffff94895f2c8080 | \Windows\System32\SgrmBroker.exe | SgrmBroker.exe
|
||||
pool: 0xffff94895f2db000 | eprocess: 0xffff94895f2db080 | \Program Files\WindowsApps\Microsoft.SkypeApp_14.56.102.0_x64__kzf8qxf38zg5c\SkypeBackgroundHost.exe | SkypeBackgroun
|
||||
pool: 0xffff94895f2dd000 | eprocess: 0xffff94895f2dd080 | \Program Files\WindowsApps\Microsoft.SkypeApp_14.56.102.0_x64__kzf8qxf38zg5c\SkypeApp.exe | SkypeApp.exe
|
||||
pool: 0xffff94895f3be420 | eprocess: 0xffff94895f3be480 | \Windows\System32\browser_broker.exe | browser_broker
|
||||
pool: 0xffff94895f3c5000 | eprocess: 0xffff94895f3c5080 | \Program Files\WindowsApps\Microsoft.YourPhone_1.20041.91.0_x64__8wekyb3d8bbwe\YourPhone.exe | YourPhone.exe
|
||||
pool: 0xffff94895f3ce390 | eprocess: 0xffff94895f3ce400 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895f419000 | eprocess: 0xffff94895f419080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895f449000 | eprocess: 0xffff94895f449080 | \Program Files\WindowsApps\Microsoft.WindowsStore_12005.1001.1.0_x64__8wekyb3d8bbwe\WinStore.App.exe | WinStore.App.e
|
||||
pool: 0xffff94895f44b420 | eprocess: 0xffff94895f44b480 | \Windows\System32\RuntimeBroker.exe | RuntimeBroker.
|
||||
pool: 0xffff94895f4b1000 | eprocess: 0xffff94895f4b1080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895f4e5000 | eprocess: 0xffff94895f4e5080 | \Windows\System32\RuntimeBroker.exe | RuntimeBroker.
|
||||
pool: 0xffff94895f4e91d0 | eprocess: 0xffff94895f4e9240 | \Windows\System32\MicrosoftEdgeCP.exe | MicrosoftEdgeC
|
||||
pool: 0xffff94895f571420 | eprocess: 0xffff94895f571480 | \Windows\System32\RuntimeBroker.exe | RuntimeBroker.
|
||||
pool: 0xffff94895f588040 | eprocess: 0xffff94895f5880c0 | \Windows\System32\RuntimeBroker.exe | RuntimeBroker.
|
||||
pool: 0xffff94895f58e000 | eprocess: 0xffff94895f58e080 | \Windows\System32\VBoxTray.exe | VBoxTray.exe
|
||||
pool: 0xffff94895f5c7000 | eprocess: 0xffff94895f5c7080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff94895f603000 | eprocess: 0xffff94895f603080 | \Windows\System32\MicrosoftEdgeSH.exe | MicrosoftEdgeS
|
||||
pool: 0xffff94895f7c7000 | eprocess: 0xffff94895f7c7080 | \Users\User\AppData\Local\Microsoft\OneDrive\OneDrive.exe | OneDrive.exe
|
||||
pool: 0xffff94895f7c8000 | eprocess: 0xffff94895f7c8080 | \Windows\System32\SecurityHealthSystray.exe | SecurityHealth
|
||||
pool: 0xffff94895f7ca320 | eprocess: 0xffff94895f7ca380 | \Windows\System32\SecurityHealthService.exe | SecurityHealth
|
||||
pool: 0xffff94895fce6040 | eprocess: 0xffff94895fce60c0 | \Windows\System32\backgroundTaskHost.exe | backgroundTask
|
||||
pool: 0xffff94895fdd2000 | eprocess: 0xffff94895fdd2080 | \Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe | Code.exe
|
||||
pool: 0xffff94895ffce000 | eprocess: 0xffff94895ffce080 | | MicrosoftEdgeC
|
||||
pool: 0xffff94895ffe2000 | eprocess: 0xffff94895ffe2080 | \Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe | Code.exe
|
||||
pool: 0xffff94895ffef000 | eprocess: 0xffff94895ffef080 | \Windows\System32\backgroundTaskHost.exe | backgroundTask
|
||||
pool: 0xffff94895fff2400 | eprocess: 0xffff94895fff2480 | \Windows\System32\conhost.exe | conhost.exe
|
||||
pool: 0xffff9489600c5040 | eprocess: 0xffff9489600c50c0 | \Users\User\AppData\Local\Programs\Microsoft VS Code\Code.exe | Code.exe
|
||||
pool: 0xffff9489600cf2b0 | eprocess: 0xffff9489600cf340 | \Users\User\Desktop\lpus-0.3-alpha\target\release\eprocess_scan.exe | eprocess_scan.
|
||||
pool: 0xffff9489602ec000 | eprocess: 0xffff9489602ec080 | \Windows\System32\dllhost.exe | dllhost.exe
|
||||
pool: 0xffff9489602f0000 | eprocess: 0xffff9489602f0080 | | conhost.exe
|
||||
pool: 0xffff9489602f5000 | eprocess: 0xffff9489602f5080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff9489603ca000 | eprocess: 0xffff9489603ca080 | \Windows\System32\Windows.WARP.JITService.exe | Windows.WARP.J
|
||||
pool: 0xffff948960acc000 | eprocess: 0xffff948960acc080 | \Windows\System32\svchost.exe | svchost.exe
|
||||
pool: 0xffff948960ad3000 | eprocess: 0xffff948960ad3080 | \Windows\System32\RuntimeBroker.exe | RuntimeBroker.
|
||||
pool: 0xffff9489610de000 | eprocess: 0xffff9489610de080 | \Windows\System32\MicrosoftEdgeCP.exe | MicrosoftEdgeC
|
||||
NtUnloadDriver() -> 0x0
|
29
logs/dump_test/1/eprocess_to_csv.py
Normal file
29
logs/dump_test/1/eprocess_to_csv.py
Normal file
@ -0,0 +1,29 @@
|
||||
import re
|
||||
import csv
|
||||
|
||||
vp = re.compile(r'^(0x[0-9a-f]+)\s+(.{15})\s+\d+\s+\d+.*$')
|
||||
|
||||
vol = map(lambda x: x.group(1, 2), filter(lambda x: x is not None, map(vp.match, open('eprocess_volscan.txt', 'r').read().split('\n'))))
|
||||
|
||||
with open('eprocess_volscan.csv', 'w', newline='') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(['address', 'process'])
|
||||
for v in vol:
|
||||
a, b = list(v)
|
||||
a = hex(int(a, 16) + 0xffff000000000000)
|
||||
b = b.rstrip(' ')
|
||||
writer.writerow([a, b])
|
||||
|
||||
|
||||
# lp = re.compile(r'pool: 0x[0-9a-f]+ \| file object: (0x[0-9a-f]+) \| offsetby: 0x[0-9a-f]+\s+(.*)$', re.MULTILINE)
|
||||
|
||||
lpus = re.finditer(r'pool: 0x[0-9a-f]+ \| eprocess: (0x[0-9a-f]+) \| ([^|]*) \| (.*)$',
|
||||
open('eprocess_scan_log.txt', 'r', encoding='utf-8').read(), re.MULTILINE)
|
||||
|
||||
with open('eprocess_lpusscan.csv', 'w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(['address', 'process', 'fullpath'])
|
||||
for v in lpus:
|
||||
a, b, c = list(v.groups())
|
||||
writer.writerow([a, c, b])
|
||||
|
75
logs/dump_test/1/eprocess_volscan.csv
Normal file
75
logs/dump_test/1/eprocess_volscan.csv
Normal file
@ -0,0 +1,75 @@
|
||||
address,process
|
||||
0xffff948957c67080,VBoxService.ex
|
||||
0xffff948957c6c080,svchost.exe
|
||||
0xffff948957caa080,svchost.exe
|
||||
0xffff948957ce3080,svchost.exe
|
||||
0xffff948957d1b080,svchost.exe
|
||||
0xffff948957ddf040,Registry
|
||||
0xffff94895ac79400,smss.exe
|
||||
0xffff94895ad15080,powershell.exe
|
||||
0xffff94895b0452c0,csrss.exe
|
||||
0xffff94895ba28080,MicrosoftEdgeC
|
||||
0xffff94895bb25080,MicrosoftEdgeC
|
||||
0xffff94895bdb0080,winlogon.exe
|
||||
0xffff94895bdf51c0,services.exe
|
||||
0xffff94895ca5f280,fontdrvhost.ex
|
||||
0xffff94895ca6a280,fontdrvhost.ex
|
||||
0xffff94895ca70380,svchost.exe
|
||||
0xffff94895caf6400,svchost.exe
|
||||
0xffff94895cb3a380,svchost.exe
|
||||
0xffff94895cbd8400,svchost.exe
|
||||
0xffff94895cc15440,svchost.exe
|
||||
0xffff94895cc223c0,svchost.exe
|
||||
0xffff94895cc5b380,svchost.exe
|
||||
0xffff94895ccae400,svchost.exe
|
||||
0xffff94895cdac400,svchost.exe
|
||||
0xffff94895cdae400,svchost.exe
|
||||
0xffff94895ce19400,svchost.exe
|
||||
0xffff94895ce1b080,svchost.exe
|
||||
0xffff94895ce98400,svchost.exe
|
||||
0xffff94895cea7080,MemCompression
|
||||
0xffff94895ceb5380,svchost.exe
|
||||
0xffff94895cf2e3c0,svchost.exe
|
||||
0xffff94895cf90400,svchost.exe
|
||||
0xffff94895cf98400,svchost.exe
|
||||
0xffff94895e017440,svchost.exe
|
||||
0xffff94895e02b380,svchost.exe
|
||||
0xffff94895e077400,svchost.exe
|
||||
0xffff94895e0ce400,svchost.exe
|
||||
0xffff94895e0d8400,svchost.exe
|
||||
0xffff94895e169380,svchost.exe
|
||||
0xffff94895e171080,svchost.exe
|
||||
0xffff94895e391080,SearchProtocol
|
||||
0xffff94895e54e4c0,NisSrv.exe
|
||||
0xffff94895e929480,smartscreen.ex
|
||||
0xffff94895e9412c0,Windows.WARP.J
|
||||
0xffff94895e9512c0,MsMpEng.exe
|
||||
0xffff94895e970080,SearchUI.exe
|
||||
0xffff94895eaaf440,sihost.exe
|
||||
0xffff94895eaee480,svchost.exe
|
||||
0xffff94895eaf54c0,svchost.exe
|
||||
0xffff94895eaf84c0,svchost.exe
|
||||
0xffff94895eb5b4c0,taskhostw.exe
|
||||
0xffff94895ebbd3c0,svchost.exe
|
||||
0xffff94895ebc2440,ctfmon.exe
|
||||
0xffff94895ec5e080,userinit.exe
|
||||
0xffff94895eccc4c0,Code.exe
|
||||
0xffff94895ece5080,dllhost.exe
|
||||
0xffff94895edf6080,StartMenuExper
|
||||
0xffff94895ef1b480,RuntimeBroker.
|
||||
0xffff94895f2074c0,ApplicationFra
|
||||
0xffff94895f2dd080,SkypeApp.exe
|
||||
0xffff94895f3be480,browser_broker
|
||||
0xffff94895f3c5080,YourPhone.exe
|
||||
0xffff94895f3ce400,svchost.exe
|
||||
0xffff94895f449080,WinStore.App.e
|
||||
0xffff94895f44b480,RuntimeBroker.
|
||||
0xffff94895f4e9240,MicrosoftEdgeC
|
||||
0xffff94895f571480,RuntimeBroker.
|
||||
0xffff94895f7ca380,SecurityHealth
|
||||
0xffff94895ffce080,MicrosoftEdgeC
|
||||
0xffff94895fff2480,conhost.exe
|
||||
0xffff9489600c50c0,Code.exe
|
||||
0xffff9489602ec080,dllhost.exe
|
||||
0xffff9489603ca080,Windows.WARP.J
|
||||
0xffff948960acc080,svchost.exe
|
|
77
logs/dump_test/1/eprocess_volscan.txt
Normal file
77
logs/dump_test/1/eprocess_volscan.txt
Normal file
@ -0,0 +1,77 @@
|
||||
Volatility Foundation Volatility Framework 2.6.1
|
||||
Offset(P) Name PID PPID PDB Time created Time exited
|
||||
------------------ ---------------- ------ ------ ------------------ ------------------------------ ------------------------------
|
||||
0x0000948957c67080 VBoxService.ex 1604 596 0x00000000205e9002 2020-06-04 20:20:35 UTC+0000
|
||||
0x0000948957c6c080 svchost.exe 6904 596 0x0000000009506002 2020-06-04 06:25:45 UTC+0000 2020-06-04 06:27:55 UTC+0000
|
||||
0x0000948957caa080 svchost.exe 6448 596 0x000000006a7bc002 2020-06-04 06:21:12 UTC+0000
|
||||
0x0000948957ce3080 svchost.exe 1508 596 0x000000001ff45002 2020-06-04 20:20:35 UTC+0000
|
||||
0x0000948957d1b080 svchost.exe 1444 596 0x000000001e3b9002 2020-06-04 20:20:35 UTC+0000
|
||||
0x0000948957ddf040 Registry 68 4 0x0000000000341002 2020-06-04 20:20:13 UTC+0000
|
||||
0x000094895ac79400 smss.exe 324 4 0x0000000101742002 2020-06-04 20:20:19 UTC+0000
|
||||
0x000094895ad15080 powershell.exe 408 1060 0x00000000b5241002 2020-06-04 07:19:20 UTC+0000 2020-06-04 07:20:22 UTC+0000
|
||||
0x000094895b0452c0 csrss.exe 416 408 0x0000000002e84002 2020-06-04 20:20:33 UTC+0000
|
||||
0x000094895ba28080 MicrosoftEdgeC 1436 772 0x000000011866b002 2020-06-04 07:16:47 UTC+0000
|
||||
0x000094895bb25080 MicrosoftEdgeC 2776 772 0x00000000d2641002 2020-06-04 07:16:57 UTC+0000
|
||||
0x000094895bdb0080 winlogon.exe 544 480 0x0000000001add002 2020-06-04 20:20:33 UTC+0000
|
||||
0x000094895bdf51c0 services.exe 596 488 0x0000000016c16002 2020-06-04 20:20:33 UTC+0000
|
||||
0x000094895ca5f280 fontdrvhost.ex 680 544 0x0000000019366002 2020-06-04 20:20:33 UTC+0000
|
||||
0x000094895ca6a280 fontdrvhost.ex 688 488 0x0000000015d1b002 2020-06-04 20:20:33 UTC+0000
|
||||
0x000094895ca70380 svchost.exe 708 596 0x0000000017338002 2020-06-04 20:20:33 UTC+0000
|
||||
0x000094895caf6400 svchost.exe 824 596 0x0000000019ad0002 2020-06-04 20:20:34 UTC+0000
|
||||
0x000094895cb3a380 svchost.exe 876 596 0x000000001a2b4002 2020-06-04 20:20:34 UTC+0000
|
||||
0x000094895cbd8400 svchost.exe 384 596 0x000000001950d002 2020-06-04 20:20:34 UTC+0000
|
||||
0x000094895cc15440 svchost.exe 420 596 0x000000001c315002 2020-06-04 20:20:34 UTC+0000
|
||||
0x000094895cc223c0 svchost.exe 592 596 0x000000001c549002 2020-06-04 20:20:34 UTC+0000
|
||||
0x000094895cc5b380 svchost.exe 1064 596 0x000000001d1a4002 2020-06-04 20:20:34 UTC+0000
|
||||
0x000094895ccae400 svchost.exe 1148 596 0x000000001ddbf002 2020-06-04 20:20:34 UTC+0000
|
||||
0x000094895cdac400 svchost.exe 1372 596 0x000000001ca24002 2020-06-04 20:20:35 UTC+0000
|
||||
0x000094895cdae400 svchost.exe 1452 596 0x00000000206dd002 2020-06-04 20:20:35 UTC+0000
|
||||
0x000094895ce19400 svchost.exe 1632 596 0x0000000023c4f002 2020-06-04 20:20:35 UTC+0000
|
||||
0x000094895ce1b080 svchost.exe 1640 596 0x0000000022b39002 2020-06-04 20:20:35 UTC+0000
|
||||
0x000094895ce98400 svchost.exe 1772 596 0x0000000020e71002 2020-06-04 06:20:37 UTC+0000
|
||||
0x000094895cea7080 MemCompression 1812 4 0x00000000236f8002 2020-06-04 06:20:37 UTC+0000
|
||||
0x000094895ceb5380 svchost.exe 1868 596 0x0000000025c34002 2020-06-04 06:20:37 UTC+0000
|
||||
0x000094895cf2e3c0 svchost.exe 1936 596 0x0000000024179002 2020-06-04 06:20:37 UTC+0000
|
||||
0x000094895cf90400 svchost.exe 1660 596 0x0000000022790002 2020-06-04 06:20:37 UTC+0000
|
||||
0x000094895cf98400 svchost.exe 1352 596 0x0000000025171002 2020-06-04 06:20:37 UTC+0000
|
||||
0x000094895e017440 svchost.exe 2088 596 0x0000000021120002 2020-06-04 06:20:38 UTC+0000
|
||||
0x000094895e02b380 svchost.exe 2128 596 0x0000000027d28002 2020-06-04 06:20:38 UTC+0000
|
||||
0x000094895e077400 svchost.exe 2160 596 0x0000000025ec9002 2020-06-04 06:20:38 UTC+0000
|
||||
0x000094895e0ce400 svchost.exe 2208 596 0x00000000260c0002 2020-06-04 06:20:38 UTC+0000
|
||||
0x000094895e0d8400 svchost.exe 2232 596 0x000000002652a002 2020-06-04 06:20:38 UTC+0000
|
||||
0x000094895e169380 svchost.exe 2928 596 0x000000002e054002 2020-06-04 06:20:39 UTC+0000
|
||||
0x000094895e171080 svchost.exe 2684 596 0x000000002ad7c002 2020-06-04 06:20:39 UTC+0000
|
||||
0x000094895e391080 SearchProtocol 1648 5160 0x000000009b248002 2020-06-04 07:26:11 UTC+0000
|
||||
0x000094895e54e4c0 NisSrv.exe 2016 596 0x00000000b4eff002 2020-06-04 06:28:41 UTC+0000
|
||||
0x000094895e929480 smartscreen.ex 3256 772 0x00000000c11d6002 2020-06-04 07:16:27 UTC+0000
|
||||
0x000094895e9412c0 Windows.WARP.J 5712 5580 0x00000000c0f76002 2020-06-04 07:16:26 UTC+0000
|
||||
0x000094895e9512c0 MsMpEng.exe 4676 596 0x0000000044f09002 2020-06-04 06:28:33 UTC+0000
|
||||
0x000094895e970080 SearchUI.exe 4692 772 0x0000000057496002 2020-06-04 06:21:01 UTC+0000
|
||||
0x000094895eaaf440 sihost.exe 432 1292 0x0000000043c29002 2020-06-04 06:20:50 UTC+0000
|
||||
0x000094895eaee480 svchost.exe 1588 596 0x0000000043ecd002 2020-06-04 06:20:50 UTC+0000
|
||||
0x000094895eaf54c0 svchost.exe 3152 596 0x0000000045d46002 2020-06-04 06:20:50 UTC+0000
|
||||
0x000094895eaf84c0 svchost.exe 3672 596 0x00000000465a3002 2020-06-04 06:20:50 UTC+0000
|
||||
0x000094895eb5b4c0 taskhostw.exe 4124 1064 0x0000000046bc4002 2020-06-04 06:20:50 UTC+0000
|
||||
0x000094895ebbd3c0 svchost.exe 4232 596 0x000000004306e002 2020-06-04 06:20:50 UTC+0000
|
||||
0x000094895ebc2440 ctfmon.exe 4300 4232 0x0000000041c8c002 2020-06-04 06:20:50 UTC+0000
|
||||
0x000094895ec5e080 userinit.exe 4400 544 0x0000000046ed7002 2020-06-04 06:20:51 UTC+0000 2020-06-04 06:21:20 UTC+0000
|
||||
0x000094895eccc4c0 Code.exe 6968 3736 0x00000000bb0c4002 2020-06-04 07:19:16 UTC+0000
|
||||
0x000094895ece5080 dllhost.exe 4648 772 0x00000000502b5002 2020-06-04 06:20:53 UTC+0000
|
||||
0x000094895edf6080 StartMenuExper 4972 772 0x0000000053638002 2020-06-04 06:21:00 UTC+0000
|
||||
0x000094895ef1b480 RuntimeBroker. 5092 772 0x0000000056e70002 2020-06-04 06:21:00 UTC+0000
|
||||
0x000094895f2074c0 ApplicationFra 5336 772 0x000000005c223002 2020-06-04 06:21:04 UTC+0000
|
||||
0x000094895f2dd080 SkypeApp.exe 5412 772 0x000000005fea5002 2020-06-04 06:21:05 UTC+0000
|
||||
0x000094895f3be480 browser_broker 5544 772 0x0000000060a28002 2020-06-04 06:21:05 UTC+0000
|
||||
0x000094895f3c5080 YourPhone.exe 5588 772 0x000000006315e002 2020-06-04 06:21:05 UTC+0000
|
||||
0x000094895f3ce400 svchost.exe 5580 596 0x0000000063376002 2020-06-04 06:21:05 UTC+0000
|
||||
0x000094895f449080 WinStore.App.e 5952 772 0x00000001142d1002 2020-06-04 06:22:36 UTC+0000
|
||||
0x000094895f44b480 RuntimeBroker. 5860 772 0x0000000061748002 2020-06-04 06:21:06 UTC+0000
|
||||
0x000094895f4e9240 MicrosoftEdgeC 6048 772 0x0000000063ba6002 2020-06-04 06:21:07 UTC+0000
|
||||
0x000094895f571480 RuntimeBroker. 6908 772 0x000000006dcb1002 2020-06-04 06:21:16 UTC+0000
|
||||
0x000094895f7ca380 SecurityHealth 2248 596 0x000000006f4ba002 2020-06-04 06:21:21 UTC+0000
|
||||
0x000094895ffce080 MicrosoftEdgeC 3288 772 0x00000000bd993002 2020-06-04 07:16:41 UTC+0000 2020-06-04 07:19:52 UTC+0000
|
||||
0x000094895fff2480 conhost.exe 5696 1892 0x0000000058bc3002 2020-06-04 07:19:49 UTC+0000
|
||||
0x00009489600c50c0 Code.exe 1060 3736 0x000000003859d002 2020-06-04 07:19:17 UTC+0000
|
||||
0x00009489602ec080 dllhost.exe 4156 772 0x000000009589c002 2020-06-04 07:16:29 UTC+0000
|
||||
0x00009489603ca080 Windows.WARP.J 7068 5580 0x00000000bb4da002 2020-06-04 07:16:48 UTC+0000
|
||||
0x0000948960acc080 svchost.exe 3204 596 0x00000000c4173002 2020-06-04 07:19:47 UTC+0000
|
16450
logs/dump_test/1/file_lpusscan.csv
Normal file
16450
logs/dump_test/1/file_lpusscan.csv
Normal file
File diff suppressed because it is too large
Load Diff
32903
logs/dump_test/1/file_scan_log.txt
Normal file
32903
logs/dump_test/1/file_scan_log.txt
Normal file
File diff suppressed because it is too large
Load Diff
29
logs/dump_test/1/file_to_csv.py
Normal file
29
logs/dump_test/1/file_to_csv.py
Normal file
@ -0,0 +1,29 @@
|
||||
import re
|
||||
import csv
|
||||
|
||||
vp = re.compile(r'(0x[0-9a-f]+)\s+\d+\s+[01]\s+[RWDrwd-]+\s+(.*)')
|
||||
|
||||
vol = map(lambda x: x.group(1, 2), filter(lambda x: x is not None, map(vp.match, open('file_volscan.txt', 'r').read().split('\n'))))
|
||||
|
||||
with open('file_volscan.csv', 'w', newline='') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(['address', 'file'])
|
||||
for v in vol:
|
||||
a, b = list(v)
|
||||
a = hex(int(a, 16) + 0xffff000000000000)
|
||||
writer.writerow([a, b])
|
||||
|
||||
|
||||
# lp = re.compile(r'pool: 0x[0-9a-f]+ \| file object: (0x[0-9a-f]+) \| offsetby: 0x[0-9a-f]+\s+(.*)$', re.MULTILINE)
|
||||
|
||||
lpus = map(lambda x: x.group(1, 2), filter(lambda x: x is not None, map(vp.match, open('file_volscan.txt', 'r').read().split('\n'))))
|
||||
|
||||
lpus = re.finditer(r'pool: 0x[0-9a-f]+ \| file object: (0x[0-9a-f]+) \| offsetby: 0x[0-9a-f]+\s+(.*)$',
|
||||
open('file_scan_log.txt', 'r', encoding='utf-8').read(), re.MULTILINE)
|
||||
|
||||
with open('file_lpusscan.csv', 'w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(['address', 'file'])
|
||||
for v in lpus:
|
||||
a, b = list(v.groups())
|
||||
writer.writerow([a, b])
|
7896
logs/dump_test/1/file_volscan.csv
Normal file
7896
logs/dump_test/1/file_volscan.csv
Normal file
File diff suppressed because it is too large
Load Diff
7921
logs/dump_test/1/file_volscan.txt
Normal file
7921
logs/dump_test/1/file_volscan.txt
Normal file
File diff suppressed because it is too large
Load Diff
50
logs/dump_test/1/stat.py
Normal file
50
logs/dump_test/1/stat.py
Normal file
@ -0,0 +1,50 @@
|
||||
import pandas as pd
|
||||
|
||||
elpus = pd.read_csv('eprocess_lpusscan.csv')
|
||||
flpus = pd.read_csv('file_lpusscan.csv', encoding='utf-8')
|
||||
|
||||
evol = pd.read_csv('eprocess_volscan.csv')
|
||||
fvol = pd.read_csv('file_volscan.csv')
|
||||
|
||||
print('''
|
||||
A simple statistics for LPUS and Volatility
|
||||
|
||||
Environment: Windows 10 2019 (build number 18362) on VirtualBox
|
||||
RAM: 4GB
|
||||
|
||||
> The VM is downloaded through Microsoft
|
||||
|
||||
LPUS scan _EPROCESS and _FILE_OBJECT.
|
||||
The scan time: approximate 5 minutes.
|
||||
|
||||
After that, use VirtualBox command to generate the memory image
|
||||
|
||||
> "C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" debugvm "<name>" dumpvmcore --filename "/path/to/<name>.elf"
|
||||
|
||||
Volatility version is at 5f685e5
|
||||
|
||||
> The latest release of Volatility doesn't have support for Windows build no. 18362
|
||||
|
||||
Then compare the log from LPUS and the two volatility command with profile Win10x64_18362:
|
||||
- psscan to scan _EPROCESS, approximate 30 minutes
|
||||
- filescan to scan _EPROCESS, approximate 2-3 hours
|
||||
|
||||
(The log file is then converted to csv files, see 'eprocess_to_csv.py' and 'file_to_csv.py')
|
||||
|
||||
''')
|
||||
|
||||
print('==================================================')
|
||||
|
||||
print('_EPROCESS')
|
||||
print('lpus scan: ', elpus['address'].shape, 'results')
|
||||
print('volatility scan: ', evol['address'].shape, 'results')
|
||||
print('volatility scan misses lpus: ', elpus['address'][~elpus['address'].isin(evol['address'])].shape, 'results')
|
||||
print('lpus scan misses volatility: ', evol['address'][~evol['address'].isin(elpus['address'])].shape, 'results')
|
||||
|
||||
print('==================================================')
|
||||
|
||||
print('_FILE_OBJECT')
|
||||
print('lpus scan: ', flpus['address'].shape, 'results')
|
||||
print('volatility scan: ', fvol['address'].shape, 'results')
|
||||
print('volatility scan misses lpus: ', flpus['address'][~flpus['address'].isin(fvol['address'])].shape, 'results')
|
||||
print('lpus scan misses volatility: ', fvol['address'][~fvol['address'].isin(flpus['address'])].shape, 'results')
|
138
logs/eprocess_scan.log
Normal file
138
logs/eprocess_scan.log
Normal file
@ -0,0 +1,138 @@
|
||||
PDB for Amd64, guid: 8b11040a-5928-757b-1139-0ac78f6b6925, age: 1
|
||||
|
||||
NtLoadDriver() -> 0x0
|
||||
pool: 0xffffe282a0463000 | eprocess: 0xffffe282a0463080 | pid: 1088 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a0465010 | eprocess: 0xffffe282a0465080 | pid: 1032 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a046b160 | eprocess: 0xffffe282a046b1c0 | pid: 4 | ppid: 0 | name: System | path:
|
||||
pool: 0xffffe282a047e000 | eprocess: 0xffffe282a047e080 | pid: 1080 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a0482260 | eprocess: 0xffffe282a04822c0 | pid: 1812 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a04b6000 | eprocess: 0xffffe282a04b6080 | pid: 1220 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a04ed000 | eprocess: 0xffffe282a04ed080 | pid: 1276 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a050d000 | eprocess: 0xffffe282a050d080 | pid: 1148 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a0511000 | eprocess: 0xffffe282a0511080 | pid: 1156 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a31d04d0 | eprocess: 0xffffe282a31d0540 | pid: 288 | ppid: 4 | name: smss.exe | path: \Windows\System32\smss.exe
|
||||
pool: 0xffffe282a3cbe1f0 | eprocess: 0xffffe282a3cbe280 | pid: 6736 | ppid: 756 | name: smartscreen.ex | path: \Windows\System32\smartscreen.exe
|
||||
pool: 0xffffe282a3cd94d0 | eprocess: 0xffffe282a3cd9540 | pid: 4976 | ppid: 4868 | name: Windows.WARP.J | path: \Windows\System32\Windows.WARP.JITService.exe
|
||||
pool: 0xffffe282a3d45000 | eprocess: 0xffffe282a3d45080 | pid: 808 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a3d4b000 | eprocess: 0xffffe282a3d4b080 | pid: 452 | ppid: 376 | name: wininit.exe | path: \Windows\System32\wininit.exe
|
||||
pool: 0xffffe282a3d500b0 | eprocess: 0xffffe282a3d50140 | pid: 460 | ppid: 444 | name: csrss.exe | path: \Windows\System32\csrss.exe
|
||||
pool: 0xffffe282a3d65000 | eprocess: 0xffffe282a3d65080 | pid: 512 | ppid: 444 | name: winlogon.exe | path: \Windows\System32\winlogon.exe
|
||||
pool: 0xffffe282a3dc90d0 | eprocess: 0xffffe282a3dc9140 | pid: 560 | ppid: 452 | name: services.exe | path: \Windows\System32\services.exe
|
||||
pool: 0xffffe282a3dd50b0 | eprocess: 0xffffe282a3dd5140 | pid: 584 | ppid: 452 | name: lsass.exe | path: \Windows\System32\lsass.exe
|
||||
pool: 0xffffe282a3e910b0 | eprocess: 0xffffe282a3e91140 | pid: 384 | ppid: 376 | name: csrss.exe | path: \Windows\System32\csrss.exe
|
||||
pool: 0xffffe282a3f08260 | eprocess: 0xffffe282a3f082c0 | pid: 4964 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a4c2b2d0 | eprocess: 0xffffe282a4c2b340 | pid: 660 | ppid: 512 | name: fontdrvhost.ex | path: \Windows\System32\fontdrvhost.exe
|
||||
pool: 0xffffe282a4c2f000 | eprocess: 0xffffe282a4c2f080 | pid: 668 | ppid: 452 | name: fontdrvhost.ex | path: \Windows\System32\fontdrvhost.exe
|
||||
pool: 0xffffe282a4c76290 | eprocess: 0xffffe282a4c76300 | pid: 684 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a4cd1280 | eprocess: 0xffffe282a4cd1300 | pid: 756 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a4e06290 | eprocess: 0xffffe282a4e06300 | pid: 852 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a4e9a0e0 | eprocess: 0xffffe282a4e9a140 | pid: 928 | ppid: 512 | name: LogonUI.exe | path:
|
||||
pool: 0xffffe282a4e9c240 | eprocess: 0xffffe282a4e9c2c0 | pid: 936 | ppid: 512 | name: dwm.exe | path: \Windows\System32\dwm.exe
|
||||
pool: 0xffffe282a4f61290 | eprocess: 0xffffe282a4f61300 | pid: 1008 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a4f68310 | eprocess: 0xffffe282a4f68380 | pid: 1020 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a4f76340 | eprocess: 0xffffe282a4f763c0 | pid: 336 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a4fc62c0 | eprocess: 0xffffe282a4fc6340 | pid: 348 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a60c3340 | eprocess: 0xffffe282a60c33c0 | pid: 376 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a623c000 | eprocess: 0xffffe282a623c080 | pid: 1456 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a623f2b0 | eprocess: 0xffffe282a623f340 | pid: 1300 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a628f320 | eprocess: 0xffffe282a628f380 | pid: 1312 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a62c3270 | eprocess: 0xffffe282a62c3300 | pid: 1372 | ppid: 560 | name: VBoxService.ex | path: \Windows\System32\VBoxService.exe
|
||||
pool: 0xffffe282a62c62b0 | eprocess: 0xffffe282a62c6340 | pid: 1464 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a62ca290 | eprocess: 0xffffe282a62ca300 | pid: 1484 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a64d6000 | eprocess: 0xffffe282a64d6040 | pid: 1548 | ppid: 4 | name: MemCompression | path:
|
||||
pool: 0xffffe282a64d9280 | eprocess: 0xffffe282a64d9300 | pid: 1560 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a64dc320 | eprocess: 0xffffe282a64dc380 | pid: 1568 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a65242d0 | eprocess: 0xffffe282a6524340 | pid: 1608 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a653a320 | eprocess: 0xffffe282a653a380 | pid: 1628 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a653f000 | eprocess: 0xffffe282a653f080 | pid: 2108 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6546320 | eprocess: 0xffffe282a6546380 | pid: 1668 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a659c320 | eprocess: 0xffffe282a659c380 | pid: 1772 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a659e000 | eprocess: 0xffffe282a659e080 | pid: 1780 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6652350 | eprocess: 0xffffe282a66523c0 | pid: 1832 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a665d000 | eprocess: 0xffffe282a665d080 | pid: 1388 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a665e000 | eprocess: 0xffffe282a665e080 | pid: 1320 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a666b000 | eprocess: 0xffffe282a666b080 | pid: 2020 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a666c000 | eprocess: 0xffffe282a666c080 | pid: 2012 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a666e000 | eprocess: 0xffffe282a666e080 | pid: 1936 | ppid: 1032 | name: CompatTelRunne | path: \Windows\System32\CompatTelRunner.exe
|
||||
pool: 0xffffe282a6670000 | eprocess: 0xffffe282a6670080 | pid: 1920 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6673000 | eprocess: 0xffffe282a6673080 | pid: 1900 | ppid: 560 | name: spoolsv.exe | path: \Windows\System32\spoolsv.exe
|
||||
pool: 0xffffe282a67eb000 | eprocess: 0xffffe282a67eb080 | pid: 2384 | ppid: 560 | name: MsMpEng.exe | path: \ProgramData\Microsoft\Windows Defender\Platform\4.18.2005.5-0\MsMpEng.exe
|
||||
pool: 0xffffe282a67ec000 | eprocess: 0xffffe282a67ec080 | pid: 2376 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a67ed000 | eprocess: 0xffffe282a67ed080 | pid: 2368 | ppid: 560 | name: ruby.exe | path: \Program Files\Puppet Labs\Puppet\sys\ruby\bin\ruby.exe
|
||||
pool: 0xffffe282a67f0000 | eprocess: 0xffffe282a67f0080 | pid: 2296 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a67f2000 | eprocess: 0xffffe282a67f2080 | pid: 2272 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a67f4000 | eprocess: 0xffffe282a67f4080 | pid: 2252 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a67f6000 | eprocess: 0xffffe282a67f6080 | pid: 2240 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a67f7000 | eprocess: 0xffffe282a67f7080 | pid: 2220 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6802040 | eprocess: 0xffffe282a68020c0 | pid: 2200 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a694c260 | eprocess: 0xffffe282a694c2c0 | pid: 1896 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a694d000 | eprocess: 0xffffe282a694d080 | pid: 3016 | ppid: 2964 | name: dasHost.exe | path: \Windows\System32\dasHost.exe
|
||||
pool: 0xffffe282a6950000 | eprocess: 0xffffe282a6950080 | pid: 2964 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6953000 | eprocess: 0xffffe282a6953080 | pid: 2728 | ppid: 560 | name: sppsvc.exe | path: \Windows\System32\sppsvc.exe
|
||||
pool: 0xffffe282a6956040 | eprocess: 0xffffe282a69560c0 | pid: 2500 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6959000 | eprocess: 0xffffe282a6959080 | pid: 2444 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a695c000 | eprocess: 0xffffe282a695c080 | pid: 2400 | ppid: 560 | name: wlms.exe | path: \Windows\System32\wlms\wlms.exe
|
||||
pool: 0xffffe282a6d1e450 | eprocess: 0xffffe282a6d1e4c0 | pid: 3316 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6d26000 | eprocess: 0xffffe282a6d26080 | pid: 3256 | ppid: 1032 | name: taskhostw.exe | path: \Windows\System32\taskhostw.exe
|
||||
pool: 0xffffe282a6d29000 | eprocess: 0xffffe282a6d29080 | pid: 6516 | ppid: 756 | name: RuntimeBroker. | path: \Windows\System32\RuntimeBroker.exe
|
||||
pool: 0xffffe282a6d2a000 | eprocess: 0xffffe282a6d2a080 | pid: 3172 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6d2b000 | eprocess: 0xffffe282a6d2b080 | pid: 6804 | ppid: 560 | name: SecurityHealth | path: \Windows\System32\SecurityHealthService.exe
|
||||
pool: 0xffffe282a6d2d000 | eprocess: 0xffffe282a6d2d080 | pid: 3140 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6d2f000 | eprocess: 0xffffe282a6d2f080 | pid: 3108 | ppid: 1148 | name: sihost.exe | path: \Windows\System32\sihost.exe
|
||||
pool: 0xffffe282a6d30000 | eprocess: 0xffffe282a6d30080 | pid: 4372 | ppid: 756 | name: SearchUI.exe | path: \Windows\SystemApps\Microsoft.Windows.Cortana_cw5n1h2txyewy\SearchUI.exe
|
||||
pool: 0xffffe282a6d35040 | eprocess: 0xffffe282a6d350c0 | pid: 2192 | ppid: 560 | name: NisSrv.exe | path: \ProgramData\Microsoft\Windows Defender\Platform\4.18.2005.5-0\NisSrv.exe
|
||||
pool: 0xffffe282a6ece000 | eprocess: 0xffffe282a6ece080 | pid: 4016 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6ed0000 | eprocess: 0xffffe282a6ed0080 | pid: 3892 | ppid: 3788 | name: explorer.exe | path: \Windows\explorer.exe
|
||||
pool: 0xffffe282a6ed1000 | eprocess: 0xffffe282a6ed1080 | pid: 3224 | ppid: 3892 | name: OneDrive.exe | path: \Users\IEUser\AppData\Local\Microsoft\OneDrive\OneDrive.exe
|
||||
pool: 0xffffe282a6ed3000 | eprocess: 0xffffe282a6ed3080 | pid: 3808 | ppid: 1936 | name: conhost.exe | path: \Windows\System32\conhost.exe
|
||||
pool: 0xffffe282a6ed4000 | eprocess: 0xffffe282a6ed4080 | pid: 6296 | ppid: 5824 | name: SearchProtocol | path: \Windows\System32\SearchProtocolHost.exe
|
||||
pool: 0xffffe282a6ed5000 | eprocess: 0xffffe282a6ed5080 | pid: 3788 | ppid: 512 | name: userinit.exe | path:
|
||||
pool: 0xffffe282a6ed7000 | eprocess: 0xffffe282a6ed7080 | pid: 3752 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6ed9000 | eprocess: 0xffffe282a6ed9080 | pid: 3656 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6edc040 | eprocess: 0xffffe282a6edc0c0 | pid: 3548 | ppid: 3460 | name: ctfmon.exe | path: \Windows\System32\ctfmon.exe
|
||||
pool: 0xffffe282a6edf000 | eprocess: 0xffffe282a6edf080 | pid: 3468 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a6ee0000 | eprocess: 0xffffe282a6ee0080 | pid: 3460 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a722d310 | eprocess: 0xffffe282a722d380 | pid: 5068 | ppid: 756 | name: backgroundTask | path: \Windows\System32\backgroundTaskHost.exe
|
||||
pool: 0xffffe282a724f000 | eprocess: 0xffffe282a724f080 | pid: 4256 | ppid: 756 | name: ShellExperienc | path: \Windows\SystemApps\ShellExperienceHost_cw5n1h2txyewy\ShellExperienceHost.exe
|
||||
pool: 0xffffe282a72f02d0 | eprocess: 0xffffe282a72f0340 | pid: 6612 | ppid: 756 | name: RuntimeBroker. | path: \Windows\System32\RuntimeBroker.exe
|
||||
pool: 0xffffe282a7437370 | eprocess: 0xffffe282a7437400 | pid: 4548 | ppid: 756 | name: RuntimeBroker. | path: \Windows\System32\RuntimeBroker.exe
|
||||
pool: 0xffffe282a74bc000 | eprocess: 0xffffe282a74bc080 | pid: 6012 | ppid: 756 | name: RuntimeBroker. | path: \Windows\System32\RuntimeBroker.exe
|
||||
pool: 0xffffe282a74cf000 | eprocess: 0xffffe282a74cf080 | pid: 7592 | ppid: 7584 | name: conhost.exe | path: \Windows\System32\conhost.exe
|
||||
pool: 0xffffe282a74f43a0 | eprocess: 0xffffe282a74f4400 | pid: 4632 | ppid: 756 | name: ApplicationFra | path: \Windows\System32\ApplicationFrameHost.exe
|
||||
pool: 0xffffe282a75484d0 | eprocess: 0xffffe282a7548540 | pid: 6776 | ppid: 3892 | name: SecurityHealth | path: \Windows\System32\SecurityHealthSystray.exe
|
||||
pool: 0xffffe282a7564040 | eprocess: 0xffffe282a75640c0 | pid: 4668 | ppid: 756 | name: MicrosoftEdge. | path: \Windows\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\MicrosoftEdge.exe
|
||||
pool: 0xffffe282a75a2000 | eprocess: 0xffffe282a75a2080 | pid: 5636 | ppid: 756 | name: LockApp.exe | path: \Windows\SystemApps\Microsoft.LockApp_cw5n1h2txyewy\LockApp.exe
|
||||
pool: 0xffffe282a768a320 | eprocess: 0xffffe282a768a380 | pid: 4868 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a768f380 | eprocess: 0xffffe282a768f400 | pid: 4876 | ppid: 756 | name: browser_broker | path: \Windows\System32\browser_broker.exe
|
||||
pool: 0xffffe282a7724040 | eprocess: 0xffffe282a77240c0 | pid: 1604 | ppid: 756 | name: backgroundTask | path: \Windows\System32\backgroundTaskHost.exe
|
||||
pool: 0xffffe282a7740290 | eprocess: 0xffffe282a7740300 | pid: 3364 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a778f040 | eprocess: 0xffffe282a778f0c0 | pid: 736 | ppid: 756 | name: YourPhone.exe | path: \Program Files\WindowsApps\Microsoft.YourPhone_1.20051.93.0_x64__8wekyb3d8bbwe\YourPhone.exe
|
||||
pool: 0xffffe282a77e1370 | eprocess: 0xffffe282a77e1400 | pid: 4128 | ppid: 756 | name: RuntimeBroker. | path: \Windows\System32\RuntimeBroker.exe
|
||||
pool: 0xffffe282a7813040 | eprocess: 0xffffe282a78130c0 | pid: 5204 | ppid: 756 | name: SkypeBackgroun | path: \Program Files\WindowsApps\Microsoft.SkypeApp_14.56.102.0_x64__kzf8qxf38zg5c\SkypeBackgroundHost.exe
|
||||
pool: 0xffffe282a78171d0 | eprocess: 0xffffe282a7817240 | pid: 5260 | ppid: 756 | name: SkypeApp.exe | path: \Program Files\WindowsApps\Microsoft.SkypeApp_14.56.102.0_x64__kzf8qxf38zg5c\SkypeApp.exe
|
||||
pool: 0xffffe282a781b1d0 | eprocess: 0xffffe282a781b240 | pid: 5284 | ppid: 756 | name: MicrosoftEdgeC | path: \Windows\System32\MicrosoftEdgeCP.exe
|
||||
pool: 0xffffe282a78a4040 | eprocess: 0xffffe282a78a40c0 | pid: 5384 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a78b3000 | eprocess: 0xffffe282a78b3080 | pid: 5432 | ppid: 4128 | name: MicrosoftEdgeS | path: \Windows\System32\MicrosoftEdgeSH.exe
|
||||
pool: 0xffffe282a78bb290 | eprocess: 0xffffe282a78bb300 | pid: 5504 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a79f1000 | eprocess: 0xffffe282a79f1080 | pid: 5756 | ppid: 756 | name: backgroundTask | path: \Windows\System32\backgroundTaskHost.exe
|
||||
pool: 0xffffe282a7a1c370 | eprocess: 0xffffe282a7a1c400 | pid: 5704 | ppid: 756 | name: RuntimeBroker. | path: \Windows\System32\RuntimeBroker.exe
|
||||
pool: 0xffffe282a7a44290 | eprocess: 0xffffe282a7a44300 | pid: 5824 | ppid: 560 | name: SearchIndexer. | path: \Windows\System32\SearchIndexer.exe
|
||||
pool: 0xffffe282a7a90320 | eprocess: 0xffffe282a7a90380 | pid: 5904 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a7b02040 | eprocess: 0xffffe282a7b020c0 | pid: 7900 | ppid: 7584 | name: eprocess_scan. | path: \Users\IEUser\Downloads\eprocess_scan.exe
|
||||
pool: 0xffffe282a7b03000 | eprocess: 0xffffe282a7b03080 | pid: 6820 | ppid: 2368 | name: cmd.exe | path:
|
||||
pool: 0xffffe282a7b0e000 | eprocess: 0xffffe282a7b0e080 | pid: 6164 | ppid: 756 | name: RuntimeBroker. | path: \Windows\System32\RuntimeBroker.exe
|
||||
pool: 0xffffe282a7b20430 | eprocess: 0xffffe282a7b204c0 | pid: 5936 | ppid: 756 | name: RuntimeBroker. | path: \Windows\System32\RuntimeBroker.exe
|
||||
pool: 0xffffe282a7b4a000 | eprocess: 0xffffe282a7b4a080 | pid: 6860 | ppid: 756 | name: RuntimeBroker. | path: \Windows\System32\RuntimeBroker.exe
|
||||
pool: 0xffffe282a7ba32c0 | eprocess: 0xffffe282a7ba3340 | pid: 6232 | ppid: 756 | name: WmiPrvSE.exe | path: \Windows\System32\wbem\WmiPrvSE.exe
|
||||
pool: 0xffffe282a7cea000 | eprocess: 0xffffe282a7cea080 | pid: 6456 | ppid: 5824 | name: SearchFilterHo | path: \Windows\System32\SearchFilterHost.exe
|
||||
pool: 0xffffe282a7e7f000 | eprocess: 0xffffe282a7e7f080 | pid: 7028 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a7e843a0 | eprocess: 0xffffe282a7e84400 | pid: 7000 | ppid: 3892 | name: VBoxTray.exe | path: \Windows\System32\VBoxTray.exe
|
||||
pool: 0xffffe282a7ed23c0 | eprocess: 0xffffe282a7ed2440 | pid: 7104 | ppid: 756 | name: dllhost.exe | path: \Windows\System32\dllhost.exe
|
||||
pool: 0xffffe282a7ed8000 | eprocess: 0xffffe282a7ed8080 | pid: 5672 | ppid: 6820 | name: ruby.exe | path:
|
||||
pool: 0xffffe282a7f15000 | eprocess: 0xffffe282a7f15080 | pid: 7656 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a7f16000 | eprocess: 0xffffe282a7f16080 | pid: 6392 | ppid: 756 | name: WindowsInterna | path: \Windows\SystemApps\InputApp_cw5n1h2txyewy\WindowsInternal.ComposableShell.Experiences.TextInput.InputApp.exe
|
||||
pool: 0xffffe282a80f12b0 | eprocess: 0xffffe282a80f1340 | pid: 6904 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a811a340 | eprocess: 0xffffe282a811a3c0 | pid: 7184 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a81cd290 | eprocess: 0xffffe282a81cd300 | pid: 7288 | ppid: 560 | name: svchost.exe | path: \Windows\System32\svchost.exe
|
||||
pool: 0xffffe282a81ce000 | eprocess: 0xffffe282a81ce080 | pid: 7584 | ppid: 3892 | name: cmd.exe | path: \Windows\System32\cmd.exe
|
||||
NtUnloadDriver() -> 0x0
|
7
other/to_epoch.py
Normal file
7
other/to_epoch.py
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
windows_epoch_diff = 11644473600000 * 10000
|
||||
filetime = 132380977838542980
|
||||
|
||||
process_time_epoch = (filetime - windows_epoch_diff) // 10000
|
||||
print(process_time_epoch)
|
||||
|
177
src/address.rs
Normal file
177
src/address.rs
Normal file
@ -0,0 +1,177 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
use std::rc::Rc;
|
||||
|
||||
// pub struct Object {
|
||||
// name: String,
|
||||
// address: Address
|
||||
// }
|
||||
//
|
||||
// impl Object {
|
||||
// pub fn get<F>(&self, resolver: &F) -> u64
|
||||
// where F: Fn(u64) -> u64 {
|
||||
// // this function returns address of Object
|
||||
// self.address.get(resolver)
|
||||
// }
|
||||
// }
|
||||
|
||||
pub struct Address {
|
||||
base: u64,
|
||||
pointer: Option<Rc<Address>>,
|
||||
offset: u64,
|
||||
// TODO: resolver
|
||||
// It would be nice to have an address resolver
|
||||
// Then implement Deref trait to call get()
|
||||
// resolver uses DriverState address decompose
|
||||
// lifetime issue occur
|
||||
}
|
||||
|
||||
impl Address {
|
||||
pub fn from_base(base: u64) -> Self {
|
||||
Address {
|
||||
base: base,
|
||||
pointer: None,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
pub fn from_ptr(pointer: Address) -> Self {
|
||||
Address {
|
||||
base: 0,
|
||||
pointer: Some(Rc::new(pointer)),
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
fn deref<F>(&self, resolver: &F) -> Address
|
||||
where
|
||||
F: Fn(u64) -> u64,
|
||||
{
|
||||
match &self.pointer {
|
||||
Some(p) => {
|
||||
let addr = p.deref(resolver);
|
||||
// println!("deref: {} -> {}; resolve: 0x{:x}", self, addr, addr.base + addr.offset);
|
||||
let base = if addr.base != 0 {
|
||||
resolver(addr.base + addr.offset)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
Address {
|
||||
base: base,
|
||||
pointer: None,
|
||||
offset: self.offset,
|
||||
}
|
||||
}
|
||||
None => Address {
|
||||
base: self.base,
|
||||
pointer: None,
|
||||
offset: self.offset,
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn get<F>(&self, resolver: &F) -> u64
|
||||
where
|
||||
F: Fn(u64) -> u64,
|
||||
{
|
||||
if self.pointer.is_some() {
|
||||
self.deref(resolver).get(resolver)
|
||||
} else if self.base == 0 {
|
||||
0
|
||||
} else {
|
||||
self.base + self.offset
|
||||
}
|
||||
}
|
||||
pub fn address(&self) -> u64 {
|
||||
self.base + self.offset
|
||||
}
|
||||
// pub fn to(&self, name: &str) -> Object {
|
||||
// Object {
|
||||
// name: name.to_string(),
|
||||
// address: self.clone()
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
impl Add<u64> for Address {
|
||||
type Output = Self;
|
||||
fn add(self, other: u64) -> Self {
|
||||
Self {
|
||||
base: self.base,
|
||||
pointer: self.pointer.map(|p| Rc::clone(&p)),
|
||||
offset: self.offset + other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<u64> for Address {
|
||||
fn add_assign(&mut self, other: u64) {
|
||||
*self = Self {
|
||||
base: self.base,
|
||||
pointer: self.pointer.clone(),
|
||||
offset: self.offset + other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<u64> for Address {
|
||||
type Output = Self;
|
||||
fn sub(self, other: u64) -> Self {
|
||||
Self {
|
||||
base: self.base,
|
||||
pointer: self.pointer.map(|p| Rc::clone(&p)),
|
||||
offset: self.offset - other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<u64> for Address {
|
||||
fn sub_assign(&mut self, other: u64) {
|
||||
*self = Self {
|
||||
base: self.base,
|
||||
pointer: self.pointer.clone(),
|
||||
offset: self.offset - other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Address {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.pointer.is_none()
|
||||
&& other.pointer.is_none()
|
||||
&& self.base == other.base
|
||||
&& self.offset == other.offset
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Address {
|
||||
fn partial_cmp(&self, other: &Address) -> Option<Ordering> {
|
||||
if self.pointer.is_some() || other.pointer.is_some() {
|
||||
None
|
||||
} else {
|
||||
let this = self.base + self.offset;
|
||||
let that = other.base + other.offset;
|
||||
Some(this.cmp(&that))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Address {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if let Some(p) = &self.pointer {
|
||||
write!(f, "*({}) + 0x{:x}", *p, self.offset)
|
||||
} else if self.offset != 0 {
|
||||
write!(f, "0x{:x} + 0x{:x}", self.base, self.offset)
|
||||
} else {
|
||||
write!(f, "0x{:x}", self.base)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Address {
|
||||
fn clone(&self) -> Self {
|
||||
Address {
|
||||
base: self.base,
|
||||
pointer: self.pointer.clone(),
|
||||
offset: self.offset,
|
||||
}
|
||||
}
|
||||
}
|
82
src/bin/driver_irp.rs
Normal file
82
src/bin/driver_irp.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use std::error::Error;
|
||||
|
||||
use parse_int::parse;
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::Editor;
|
||||
|
||||
use lpus::{driver_state::DriverState, get_irp_name, scan_driver, scan_kernel_module};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
if !driver.is_supported() {
|
||||
return Err(format!(
|
||||
"Windows version {:?} is not supported",
|
||||
driver.windows_ffi.short_version
|
||||
)
|
||||
.into());
|
||||
}
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
|
||||
let drivers = scan_driver(&driver).unwrap_or(Vec::new());
|
||||
let kmods = scan_kernel_module(&driver).unwrap_or(Vec::new());
|
||||
|
||||
for d in drivers.iter() {
|
||||
println!("{} {}", d["address"], d["device"]);
|
||||
}
|
||||
|
||||
let mut rl = Editor::<()>::new();
|
||||
loop {
|
||||
let readline = rl.readline("irp> ");
|
||||
match readline {
|
||||
Ok(line) => {
|
||||
rl.add_history_entry(line.as_str());
|
||||
for d in drivers.iter() {
|
||||
if d["address"].as_str().unwrap_or("") == line {
|
||||
println!("{:#}", d);
|
||||
for (idx, addr_) in d["major_function"]
|
||||
.as_array()
|
||||
.unwrap_or(&Vec::new())
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
let addr: u64 = addr_.as_str().and_then(|x| parse(x).ok()).unwrap_or(0);
|
||||
let mut owner = "(??)";
|
||||
println!("{} {}", addr, get_irp_name(idx));
|
||||
for kmod in kmods.iter() {
|
||||
let base: u64 = kmod["dllbase"]
|
||||
.as_str()
|
||||
.and_then(|x| parse(x).ok())
|
||||
.unwrap_or(0);
|
||||
let size: u64 = kmod["size"]
|
||||
.as_str()
|
||||
.and_then(|x| parse(x).ok())
|
||||
.unwrap_or(0);
|
||||
if addr > base && addr < base + size {
|
||||
owner = kmod["BaseName"].as_str().unwrap_or("(??)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
println!("\towned by {}", owner);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => {
|
||||
println!("CTRL-C");
|
||||
break;
|
||||
}
|
||||
Err(ReadlineError::Eof) => {
|
||||
println!("CTRL-D");
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
Ok(())
|
||||
}
|
24
src/bin/driver_scan.rs
Normal file
24
src/bin/driver_scan.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use std::error::Error;
|
||||
|
||||
use lpus::{driver_state::DriverState, scan_driver};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
if !driver.is_supported() {
|
||||
return Err(format!(
|
||||
"Windows version {:?} is not supported",
|
||||
driver.windows_ffi.short_version
|
||||
)
|
||||
.into());
|
||||
}
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
|
||||
let result = scan_driver(&driver).unwrap_or(Vec::new());
|
||||
|
||||
for r in result.iter() {
|
||||
println!("{:#}", r.to_string());
|
||||
}
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
Ok(())
|
||||
}
|
@ -1,91 +1,104 @@
|
||||
use serde_json::Value;
|
||||
use std::collections::HashSet;
|
||||
use std::error::Error;
|
||||
use std::str::{from_utf8};
|
||||
use chrono::Utc;
|
||||
use chrono::{DateTime};
|
||||
use std::time::{UNIX_EPOCH, Duration};
|
||||
|
||||
#[macro_use]
|
||||
extern crate prettytable;
|
||||
use prettytable::Table;
|
||||
|
||||
use lpus::{
|
||||
driver_state::{DriverState /* , EprocessPoolChunk */}
|
||||
driver_state::DriverState, scan_eprocess, scan_ethread, traverse_activehead,
|
||||
traverse_handletable, traverse_kiprocesslist,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn to_str_time(time_ms: u64) -> String {
|
||||
if time_ms == 0 {
|
||||
return "".to_string();
|
||||
fn process_in_list(addr: &str, list: &Vec<Value>) -> bool {
|
||||
for r in list.iter() {
|
||||
if r["address"].as_str().unwrap() == addr {
|
||||
return true;
|
||||
}
|
||||
let d = UNIX_EPOCH + Duration::from_millis(time_ms);
|
||||
let datetime = DateTime::<Utc>::from(d);
|
||||
let timestamp_str = datetime.format("%Y-%m-%d %H:%M:%S.%f").to_string();
|
||||
timestamp_str
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// for windows admin require
|
||||
// https://github.com/nabijaczleweli/rust-embed-resource
|
||||
fn get_from_list(addr: &str, list: &Vec<Value>) -> Option<Value> {
|
||||
for r in list.iter() {
|
||||
if r["address"].as_str().unwrap() == addr {
|
||||
return Some(r.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn process_in_list_thread(addr: &str, list: &Vec<Value>) -> bool {
|
||||
for r in list.iter() {
|
||||
if r["eprocess"].as_str().unwrap() == addr {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// fn get_process_from_list(addr: String, list: &Vec<Value>) -> String { }
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
if !driver.is_supported() {
|
||||
return Err(format!(
|
||||
"Windows version {:?} is not supported",
|
||||
driver.windows_ffi.short_version
|
||||
)
|
||||
.into());
|
||||
}
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
|
||||
// let eprocess_scan_head = driver.scan_active_head(ntosbase)?;
|
||||
// let mut eprocess_list: Vec<EprocessPoolChunk> = Vec::new();
|
||||
driver.scan_pool(b"Proc", |pool_addr, header, data_addr| {
|
||||
let chunk_size = (header[2] as u64) * 16u64;
|
||||
let process_scan = scan_eprocess(&driver).unwrap_or(Vec::new());
|
||||
let thread_scan = scan_ethread(&driver).unwrap_or(Vec::new());
|
||||
let activehead = traverse_activehead(&driver).unwrap_or(Vec::new());
|
||||
let kiprocesslist = traverse_kiprocesslist(&driver).unwrap_or(Vec::new());
|
||||
let handletable = traverse_handletable(&driver).unwrap_or(Vec::new());
|
||||
|
||||
let eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
|
||||
let eprocess_name_offset = driver.pdb_store.get_offset_r("_EPROCESS.ImageFileName")?;
|
||||
let eprocess_create_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.CreateTime")?;
|
||||
let fob_filename_offset = driver.pdb_store.get_offset_r("_FILE_OBJECT.FileName")?;
|
||||
let eprocess_image_file_ptr_offset = driver.pdb_store.get_offset_r("_EPROCESS.ImageFilePointer")?;
|
||||
// let eprocess_exit_time_offset = driver.pdb_store.get_offset_r("_EPROCESS.ExitTime")?;
|
||||
|
||||
let eprocess_valid_start = data_addr;
|
||||
let eprocess_valid_end = (pool_addr + chunk_size) - eprocess_size;
|
||||
let mut try_eprocess_ptr = eprocess_valid_start;
|
||||
|
||||
let mut create_time = 0u64;
|
||||
// let mut exit_time = 0u64;
|
||||
while try_eprocess_ptr <= eprocess_valid_end {
|
||||
driver.deref_addr(try_eprocess_ptr + eprocess_create_time_offset, &mut create_time);
|
||||
// driver.deref_addr(try_eprocess_ptr + eprocess_exit_time_offset, &mut exit_time);
|
||||
// using heuristics to eliminate false positive
|
||||
if driver.windows_ffi.valid_process_time(create_time) {
|
||||
break;
|
||||
let mut unique_process = HashSet::new();
|
||||
for list in [&process_scan, &activehead, &kiprocesslist, &handletable].iter() {
|
||||
for r in list.iter() {
|
||||
let addr = r["address"].as_str().unwrap();
|
||||
unique_process.insert(addr);
|
||||
}
|
||||
try_eprocess_ptr += 0x4; // search exhaustively
|
||||
}
|
||||
if try_eprocess_ptr > eprocess_valid_end {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let mut image_name = [0u8; 15];
|
||||
let mut file_object_ptr = 0u64;
|
||||
|
||||
driver.deref_addr(try_eprocess_ptr + eprocess_name_offset, &mut image_name);
|
||||
driver.deref_addr(try_eprocess_ptr + eprocess_image_file_ptr_offset, &mut file_object_ptr);
|
||||
let filename = if file_object_ptr != 0 { driver.get_unicode_string(file_object_ptr + fob_filename_offset, true)? }
|
||||
else { "".to_string() };
|
||||
|
||||
if let Ok(name) = from_utf8(&image_name) {
|
||||
let eprocess_name = name
|
||||
.to_string()
|
||||
.trim_end_matches(char::from(0))
|
||||
.to_string();
|
||||
println!("pool: 0x{:x} | eprocess: 0x{:x} | {} | {}", pool_addr, try_eprocess_ptr, filename, eprocess_name);
|
||||
let mut table = Table::new();
|
||||
table.add_row(row![
|
||||
"Address",
|
||||
"Name",
|
||||
"pid",
|
||||
"ppid",
|
||||
"PoolTagScan",
|
||||
"ActiveProcessHead",
|
||||
"KiProcessListHead",
|
||||
"HandleTableList",
|
||||
"ThreadScan"
|
||||
]);
|
||||
for p in &unique_process {
|
||||
let addr = p.to_string();
|
||||
let v = get_from_list(&addr, &activehead).unwrap_or_default();
|
||||
table.add_row(row![
|
||||
&addr,
|
||||
v["name"].as_str().unwrap_or("(??)"),
|
||||
v["pid"].as_i64().unwrap_or(-1),
|
||||
v["ppid"].as_i64().unwrap_or(-1),
|
||||
process_in_list(&addr, &process_scan),
|
||||
process_in_list(&addr, &activehead),
|
||||
process_in_list(&addr, &kiprocesslist),
|
||||
process_in_list(&addr, &handletable),
|
||||
process_in_list_thread(&addr, &thread_scan)
|
||||
]);
|
||||
}
|
||||
else {
|
||||
println!("pool: 0x{:x} | eprocess: 0x{:x} | {} | {:?}", pool_addr, try_eprocess_ptr, filename, image_name);
|
||||
}
|
||||
Ok(true)
|
||||
// eprocess_list.push(EprocessPoolChunk {
|
||||
// pool_addr,
|
||||
// eprocess_addr: try_eprocess_ptr,
|
||||
// eprocess_name: eprocess_name,
|
||||
// create_time: to_epoch(create_time),
|
||||
// exit_time: to_epoch(exit_time)
|
||||
// });
|
||||
})?;
|
||||
|
||||
table.printstd();
|
||||
|
||||
// for r in process_scan.iter() {
|
||||
// println!("{:#}", r.to_string());
|
||||
// }
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
36
src/bin/eprocess_traverse.rs
Normal file
36
src/bin/eprocess_traverse.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use std::error::Error;
|
||||
|
||||
use lpus::{
|
||||
driver_state::DriverState, traverse_activehead, traverse_handletable, traverse_kiprocesslist,
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
if !driver.is_supported() {
|
||||
return Err(format!(
|
||||
"Windows version {:?} is not supported",
|
||||
driver.windows_ffi.short_version
|
||||
)
|
||||
.into());
|
||||
}
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
|
||||
let activehead = traverse_activehead(&driver).unwrap_or(Vec::new());
|
||||
let kiprocesslist = traverse_kiprocesslist(&driver).unwrap_or(Vec::new());
|
||||
let handletable = traverse_handletable(&driver).unwrap_or(Vec::new());
|
||||
|
||||
for r in activehead.iter() {
|
||||
println!("{:#}", r.to_string());
|
||||
}
|
||||
println!("=========================================");
|
||||
for r in kiprocesslist.iter() {
|
||||
println!("{:#}", r.to_string());
|
||||
}
|
||||
println!("=========================================");
|
||||
for r in handletable.iter() {
|
||||
println!("{:#}", r.to_string());
|
||||
}
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
Ok(())
|
||||
}
|
28
src/bin/ethread_scan.rs
Normal file
28
src/bin/ethread_scan.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use std::error::Error;
|
||||
|
||||
use lpus::{driver_state::DriverState, scan_ethread /* scan_mutant */};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
if !driver.is_supported() {
|
||||
return Err(format!(
|
||||
"Windows version {:?} is not supported",
|
||||
driver.windows_ffi.short_version
|
||||
)
|
||||
.into());
|
||||
}
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
|
||||
let threads = scan_ethread(&driver).unwrap_or(Vec::new());
|
||||
// let mutants = scan_mutant(&driver).unwrap_or(Vec::new());
|
||||
|
||||
for r in threads.iter() {
|
||||
println!("{:#}", r.to_string());
|
||||
}
|
||||
// for r in mutants.iter() {
|
||||
// println!("{:#}", r.to_string());
|
||||
// }
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
Ok(())
|
||||
}
|
@ -1,56 +1,24 @@
|
||||
use std::error::Error;
|
||||
|
||||
use lpus::{
|
||||
driver_state::{DriverState}
|
||||
};
|
||||
use lpus::{driver_state::DriverState, scan_file};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
if !driver.is_supported() {
|
||||
return Err(format!(
|
||||
"Windows version {:?} is not supported",
|
||||
driver.windows_ffi.short_version
|
||||
)
|
||||
.into());
|
||||
}
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
|
||||
driver.scan_pool(b"File", |pool_addr, header, data_addr| {
|
||||
let chunk_size = (header[2] as u64) * 16u64;
|
||||
let result = scan_file(&driver).unwrap_or(Vec::new());
|
||||
|
||||
let fob_size = driver.pdb_store.get_offset_r("_FILE_OBJECT.struct_size")?;
|
||||
let fob_size_offset = driver.pdb_store.get_offset_r("_FILE_OBJECT.Size")?;
|
||||
let fob_read_access_offset = driver.pdb_store.get_offset_r("_FILE_OBJECT.ReadAccess")?;
|
||||
let fob_filename_offset = driver.pdb_store.get_offset_r("_FILE_OBJECT.FileName")?;
|
||||
|
||||
let valid_end = (pool_addr + chunk_size) - fob_size;
|
||||
let mut try_ptr = data_addr;
|
||||
|
||||
let mut ftype = 0u16;
|
||||
let mut size = 0u16;
|
||||
while try_ptr <= valid_end {
|
||||
driver.deref_addr(try_ptr, &mut ftype);
|
||||
driver.deref_addr(try_ptr + fob_size_offset, &mut size);
|
||||
if (size as u64) == fob_size && ftype == 5u16 {
|
||||
break;
|
||||
for r in result.iter() {
|
||||
println!("{:#}", r.to_string());
|
||||
}
|
||||
try_ptr += 0x4; // search exhaustively
|
||||
}
|
||||
if try_ptr > valid_end {
|
||||
println!("pool: 0x{:x} cannot detect file object", pool_addr);
|
||||
return Ok(false);
|
||||
}
|
||||
let fob_addr = try_ptr;
|
||||
let mut read_ok = 0u8;
|
||||
driver.deref_addr(fob_addr + fob_read_access_offset, &mut read_ok);
|
||||
|
||||
println!("pool: 0x{:x} | file object: 0x{:x} | offsetby: 0x{:x}", pool_addr, fob_addr, fob_addr - pool_addr);
|
||||
if read_ok == 0 {
|
||||
println!(" [NOT READABLE]");
|
||||
return Ok(true);
|
||||
}
|
||||
if let Ok(filename) = driver.get_unicode_string(fob_addr + fob_filename_offset, true) {
|
||||
println!(" {}", filename);
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(false)
|
||||
})?;
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
24
src/bin/kernel_module_scan.rs
Normal file
24
src/bin/kernel_module_scan.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use std::error::Error;
|
||||
|
||||
use lpus::{driver_state::DriverState, scan_kernel_module};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
if !driver.is_supported() {
|
||||
return Err(format!(
|
||||
"Windows version {:?} is not supported",
|
||||
driver.windows_ffi.short_version
|
||||
)
|
||||
.into());
|
||||
}
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
|
||||
let result = scan_kernel_module(&driver).unwrap_or(Vec::new());
|
||||
|
||||
for r in result.iter() {
|
||||
println!("{:#}", r.to_string());
|
||||
}
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
Ok(())
|
||||
}
|
78
src/bin/kernel_module_traverse.rs
Normal file
78
src/bin/kernel_module_traverse.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use std::error::Error;
|
||||
|
||||
use parse_int::parse;
|
||||
|
||||
use lpus::{
|
||||
driver_state::DriverState, ssdt_table, traverse_loadedmodulelist, traverse_unloadeddrivers,
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
if !driver.is_supported() {
|
||||
return Err(format!(
|
||||
"Windows version {:?} is not supported",
|
||||
driver.windows_ffi.short_version
|
||||
)
|
||||
.into());
|
||||
}
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
|
||||
let loaded = traverse_loadedmodulelist(&driver).unwrap_or(Vec::new());
|
||||
let unloaded = traverse_unloadeddrivers(&driver).unwrap_or(Vec::new());
|
||||
let ssdt = ssdt_table(&driver)?;
|
||||
let ntosbase = driver.get_kernel_base();
|
||||
|
||||
// for r in loaded.iter() {
|
||||
// println!("{:#}", r.to_string());
|
||||
// }
|
||||
println!("=============================================");
|
||||
for r in unloaded.iter() {
|
||||
println!("{:#}", r);
|
||||
}
|
||||
println!("=============================================");
|
||||
for (idx, func) in ssdt.iter().enumerate() {
|
||||
println!("SSDT [{}]\t0x{:x}", idx, func);
|
||||
let owner = loaded.iter().find_map(|r| {
|
||||
let base = r["dllbase"]
|
||||
.as_str()
|
||||
.and_then(|b| parse::<u64>(b).ok())
|
||||
.unwrap_or(0);
|
||||
let size = r["size"]
|
||||
.as_str()
|
||||
.and_then(|s| parse::<u64>(s).ok())
|
||||
.unwrap_or(0);
|
||||
|
||||
if *func > base && *func < base + size {
|
||||
let module = r["BaseName"].as_str().unwrap();
|
||||
Some(module)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
if owner == Some("ntoskrnl.exe") {
|
||||
let offset = func - ntosbase.address();
|
||||
let funcname: String = {
|
||||
driver
|
||||
.pdb_store
|
||||
.symbols
|
||||
.iter()
|
||||
.find_map(|(name, o)| {
|
||||
if o.clone() == offset {
|
||||
Some(name.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or("(??)".to_string())
|
||||
};
|
||||
println!("\towned by nt!{}", funcname);
|
||||
} else if let Some(owner_) = owner {
|
||||
println!("\\thooked by {}", owner_);
|
||||
} else {
|
||||
println!("\tmissing owner");
|
||||
}
|
||||
}
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
Ok(())
|
||||
}
|
143
src/bin/lpus.rs
Normal file
143
src/bin/lpus.rs
Normal file
@ -0,0 +1,143 @@
|
||||
use serde_json::json;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
|
||||
extern crate clap;
|
||||
extern crate prettytable;
|
||||
use app_dirs::{app_dir, AppDataType};
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use rust_embed::RustEmbed;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "resource"]
|
||||
struct Asset;
|
||||
|
||||
use lpus::{
|
||||
commands::{driverscan, modscan, psxview, ssdt, unloadedmodules},
|
||||
driver_state::DriverState,
|
||||
APP_INFO,
|
||||
};
|
||||
|
||||
fn extract_driver() {
|
||||
let driver_bytes = Asset::get("lpus.sys").unwrap();
|
||||
|
||||
let mut driver_location =
|
||||
app_dir(AppDataType::UserData, &APP_INFO, &format!("driver")).unwrap();
|
||||
driver_location.push("lpus.sys");
|
||||
println!("driver location: {:?}", driver_location);
|
||||
|
||||
if let Ok(mut f) = fs::File::create(driver_location) {
|
||||
f.write_all(&driver_bytes).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let version = format!(
|
||||
"{}-{} commit on {}",
|
||||
env!("VERGEN_SEMVER"),
|
||||
env!("VERGEN_SHA_SHORT"),
|
||||
env!("VERGEN_COMMIT_DATE")
|
||||
);
|
||||
let matches = App::new("LPUS")
|
||||
.version(&*version)
|
||||
.author("Khoa Nguyen Anh <mail.nganhkhoa@gmail.com>")
|
||||
.about("Live memory fornesics on Windows")
|
||||
.arg(
|
||||
Arg::with_name("load")
|
||||
.short("l")
|
||||
.help("Load the driver and exit"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("unload")
|
||||
.short("u")
|
||||
.help("Unload the driver and exit"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("repl").about("Run the Interactive REPL (in development)"),
|
||||
)
|
||||
.subcommand(SubCommand::with_name("pdb").about("Inspect the PDB file"))
|
||||
.subcommand(
|
||||
SubCommand::with_name("hide_notepad")
|
||||
.about("Compare processes found from multiple commands"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("psxview")
|
||||
.about("Compare processes found from multiple commands"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("unloadedmodules")
|
||||
.about("Compare processes found from multiple commands"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("modscan")
|
||||
.about("Compare processes found from multiple commands"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("driverscan")
|
||||
.about("Compare processes found from multiple commands"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("ssdt")
|
||||
.about("Dump the SSDT table")
|
||||
.arg(
|
||||
Arg::with_name("hook")
|
||||
.short("h")
|
||||
.help("print only hooked function"),
|
||||
),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
extract_driver();
|
||||
let mut driver = DriverState::new();
|
||||
if !driver.is_supported() {
|
||||
return Err(format!(
|
||||
"Windows version {:?} is not supported",
|
||||
driver.windows_ffi.short_version
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
if matches.is_present("load") {
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
return Ok(());
|
||||
}
|
||||
if matches.is_present("unload") {
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
driver.connect();
|
||||
|
||||
if let Some(_c) = matches.subcommand_matches("hide_notepad") {
|
||||
driver.hide_notepad();
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(c) = matches.subcommand_matches("ssdt") {
|
||||
ssdt(&driver, c.is_present("hook"));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(_c) = matches.subcommand_matches("psxview") {
|
||||
psxview(&driver);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(_c) = matches.subcommand_matches("unloadedmodules") {
|
||||
unloadedmodules(&driver);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(_c) = matches.subcommand_matches("driverscan") {
|
||||
driverscan(&driver);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(_c) = matches.subcommand_matches("modscan") {
|
||||
modscan(&driver);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
53
src/bin/lpus_all.rs
Normal file
53
src/bin/lpus_all.rs
Normal file
@ -0,0 +1,53 @@
|
||||
use serde_json::json;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
|
||||
use lpus::{
|
||||
driver_state::DriverState, scan_driver, scan_eprocess, scan_ethread, scan_kernel_module,
|
||||
ssdt_table, traverse_activehead, traverse_handletable, traverse_kiprocesslist,
|
||||
traverse_loadedmodulelist, traverse_unloadeddrivers,
|
||||
};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
if !driver.is_supported() {
|
||||
return Err(format!(
|
||||
"Windows version {:?} is not supported",
|
||||
driver.windows_ffi.short_version
|
||||
)
|
||||
.into());
|
||||
}
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
|
||||
let eprocess_1 = scan_eprocess(&driver)?;
|
||||
let eprocess_2 = traverse_activehead(&driver)?;
|
||||
let eprocess_3 = traverse_kiprocesslist(&driver)?;
|
||||
let eprocess_4 = traverse_handletable(&driver)?;
|
||||
let ethread = scan_ethread(&driver)?;
|
||||
let drivers = scan_driver(&driver)?;
|
||||
let kernel_module_1 = scan_kernel_module(&driver)?;
|
||||
let kernel_module_2 = traverse_loadedmodulelist(&driver)?;
|
||||
let unloaded_driver = traverse_unloadeddrivers(&driver)?;
|
||||
let ssdt: Vec<String> = ssdt_table(&driver)?
|
||||
.into_iter()
|
||||
.map(|x| format!("0x{:x}", x))
|
||||
.collect();
|
||||
|
||||
let result = json!({
|
||||
"scan_eprocess": eprocess_1,
|
||||
"traverse_activehead": eprocess_2,
|
||||
"traverse_kiprocesslist": eprocess_3,
|
||||
"traverse_handletable": eprocess_4,
|
||||
"scan_ethread": ethread,
|
||||
"scan_driver": drivers,
|
||||
"scan_kernel_module": kernel_module_1,
|
||||
"traverse_loadedmodulelist": kernel_module_2,
|
||||
"traverse_unloadeddrivers": unloaded_driver,
|
||||
"ssdt_table": ssdt
|
||||
});
|
||||
|
||||
fs::write("./lpus.json", format!("{:#}", result)).ok();
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
Ok(())
|
||||
}
|
@ -1,12 +1,61 @@
|
||||
use std::error::Error;
|
||||
// use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use lpus::{
|
||||
driver_state::{DriverState}
|
||||
};
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::Editor;
|
||||
|
||||
use lpus::driver_state::DriverState;
|
||||
|
||||
pub fn to_epoch(filetime: u64) -> u64 {
|
||||
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
|
||||
let windows_epoch_diff = 11644473600000 * 10000;
|
||||
if filetime < windows_epoch_diff {
|
||||
return 0;
|
||||
}
|
||||
let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
|
||||
// let now_ms = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis() as u64;
|
||||
|
||||
process_time_epoch
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let driver = DriverState::new();
|
||||
driver.windows_ffi.print_version();
|
||||
driver.pdb_store.print_default_information();
|
||||
|
||||
println!("{}", to_epoch(0xfffffa80018cb688));
|
||||
println!("{}", to_epoch(0x01d64ecd8b295318));
|
||||
|
||||
let mut rl = Editor::<()>::new();
|
||||
if rl.load_history("history.lpus").is_err() {
|
||||
println!("No previous history.");
|
||||
}
|
||||
loop {
|
||||
let readline = rl.readline(">> ");
|
||||
match readline {
|
||||
Ok(line) => {
|
||||
rl.add_history_entry(line.as_str());
|
||||
println!("Line: {}", line);
|
||||
// TODO: add parser here
|
||||
if let Err(e) = driver.pdb_store.dt(&line) {
|
||||
println!("{}", e);
|
||||
}
|
||||
}
|
||||
Err(ReadlineError::Interrupted) => {
|
||||
println!("CTRL-C");
|
||||
break;
|
||||
}
|
||||
Err(ReadlineError::Eof) => {
|
||||
println!("CTRL-D");
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rl.save_history("history.lpus").unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
11
src/bin/test_load.rs
Normal file
11
src/bin/test_load.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use std::error::Error;
|
||||
|
||||
use lpus::driver_state::DriverState;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let mut driver = DriverState::new();
|
||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||
|
||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||
Ok(())
|
||||
}
|
190
src/commands.rs
Normal file
190
src/commands.rs
Normal file
@ -0,0 +1,190 @@
|
||||
use serde_json::Value;
|
||||
use std::collections::HashSet;
|
||||
use std::error::Error;
|
||||
|
||||
use prettytable::{cell, row, Table};
|
||||
|
||||
use parse_int::parse;
|
||||
|
||||
use crate::{
|
||||
driver_state::DriverState, scan_driver, scan_eprocess, scan_ethread, scan_kernel_module,
|
||||
ssdt_table, traverse_activehead, traverse_handletable, traverse_kiprocesslist,
|
||||
traverse_loadedmodulelist, traverse_unloadeddrivers,
|
||||
};
|
||||
|
||||
pub fn ssdt(driver: &DriverState, only_hooked: bool) {
|
||||
let loaded = traverse_loadedmodulelist(&driver).unwrap_or(Vec::new());
|
||||
let ssdt = ssdt_table(&driver).unwrap_or(Vec::new());
|
||||
let ntosbase = driver.get_kernel_base();
|
||||
|
||||
for (idx, func) in ssdt.iter().enumerate() {
|
||||
let owner = loaded.iter().find_map(|r| {
|
||||
let base = r["dllbase"]
|
||||
.as_str()
|
||||
.and_then(|b| parse::<u64>(b).ok())
|
||||
.unwrap_or(0);
|
||||
let size = r["size"]
|
||||
.as_str()
|
||||
.and_then(|s| parse::<u64>(s).ok())
|
||||
.unwrap_or(0);
|
||||
|
||||
if *func > base && *func < base + size {
|
||||
let module = r["BaseName"].as_str().unwrap();
|
||||
Some(module)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
if owner == Some("ntoskrnl.exe") {
|
||||
if !only_hooked {
|
||||
let offset = func - ntosbase.address();
|
||||
let funcname: String = {
|
||||
driver
|
||||
.pdb_store
|
||||
.symbols
|
||||
.iter()
|
||||
.find_map(|(name, o)| {
|
||||
if o.clone() == offset {
|
||||
Some(name.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or("(??)".to_string())
|
||||
};
|
||||
println!("SSDT [{}]\t0x{:x}", idx, func);
|
||||
println!("\towned by nt!{}", funcname);
|
||||
}
|
||||
} else if let Some(owner_) = owner {
|
||||
println!("SSDT [{}]\t0x{:x}", idx, func);
|
||||
println!("\\thooked by {}", owner_);
|
||||
} else {
|
||||
println!("SSDT [{}]\t0x{:x}", idx, func);
|
||||
println!("\tmissing owner");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn psxview(driver: &DriverState) {
|
||||
fn process_in_list(addr: &str, list: &Vec<Value>) -> bool {
|
||||
for r in list.iter() {
|
||||
if r["address"].as_str().unwrap() == addr {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn get_from_list(addr: &str, list: &Vec<Value>) -> Option<Value> {
|
||||
for r in list.iter() {
|
||||
if r["address"].as_str().unwrap() == addr {
|
||||
return Some(r.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn process_in_list_thread(addr: &str, list: &Vec<Value>) -> bool {
|
||||
for r in list.iter() {
|
||||
if r["eprocess"].as_str().unwrap() == addr {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
let process_scan = scan_eprocess(&driver).unwrap_or(Vec::new());
|
||||
let thread_scan = scan_ethread(&driver).unwrap_or(Vec::new());
|
||||
let activehead = traverse_activehead(&driver).unwrap_or(Vec::new());
|
||||
let kiprocesslist = traverse_kiprocesslist(&driver).unwrap_or(Vec::new());
|
||||
let handletable = traverse_handletable(&driver).unwrap_or(Vec::new());
|
||||
|
||||
let mut unique_process = HashSet::new();
|
||||
for list in [&process_scan, &activehead, &kiprocesslist, &handletable].iter() {
|
||||
for r in list.iter() {
|
||||
let addr = r["address"].as_str().unwrap();
|
||||
unique_process.insert(addr);
|
||||
}
|
||||
}
|
||||
|
||||
let mut table = Table::new();
|
||||
table.add_row(row![
|
||||
"Address",
|
||||
"Name",
|
||||
"pid",
|
||||
"ppid",
|
||||
"PoolTagScan",
|
||||
"ActiveProcessHead",
|
||||
"KiProcessListHead",
|
||||
"HandleTableList",
|
||||
"ThreadScan"
|
||||
]);
|
||||
for p in &unique_process {
|
||||
let addr = p.to_string();
|
||||
let v = {
|
||||
if let Some(vv) = get_from_list(&addr, &activehead) {
|
||||
vv
|
||||
} else {
|
||||
get_from_list(&addr, &process_scan).unwrap_or_default()
|
||||
}
|
||||
};
|
||||
table.add_row(row![
|
||||
&addr,
|
||||
v["name"].as_str().unwrap_or("(??)"),
|
||||
v["pid"].as_i64().unwrap_or(-1),
|
||||
v["ppid"].as_i64().unwrap_or(-1),
|
||||
process_in_list(&addr, &process_scan),
|
||||
process_in_list(&addr, &activehead),
|
||||
process_in_list(&addr, &kiprocesslist),
|
||||
process_in_list(&addr, &handletable),
|
||||
process_in_list_thread(&addr, &thread_scan)
|
||||
]);
|
||||
}
|
||||
|
||||
table.printstd();
|
||||
}
|
||||
pub fn modscan(driver: &DriverState) {
|
||||
let dd = scan_kernel_module(&driver).unwrap_or(Vec::new());
|
||||
let mut table = Table::new();
|
||||
table.add_row(row!["Address", "Base name", "Base", "Size", "File"]);
|
||||
for d in &dd {
|
||||
table.add_row(row![
|
||||
d["address"].as_str().unwrap_or("(??)"),
|
||||
d["BaseName"].as_str().unwrap_or("(??)"),
|
||||
d["dllbase"].as_str().unwrap_or("(??)"),
|
||||
d["size"].as_str().unwrap_or("(??)"),
|
||||
d["FullName"].as_str().unwrap_or("(??)"),
|
||||
]);
|
||||
}
|
||||
table.printstd();
|
||||
}
|
||||
pub fn driverscan(driver: &DriverState) {
|
||||
let dd = scan_driver(&driver).unwrap_or(Vec::new());
|
||||
let mut table = Table::new();
|
||||
table.add_row(row!["Address", "Device", "Service key", "Start", "Size"]);
|
||||
for d in &dd {
|
||||
table.add_row(row![
|
||||
d["address"].as_str().unwrap_or("(??)"),
|
||||
d["device"].as_str().unwrap_or("(??)"),
|
||||
d["servicekey"].as_str().unwrap_or("(??)"),
|
||||
d["start"].as_str().unwrap_or("(??)"),
|
||||
d["size"].as_str().unwrap_or("(??)"),
|
||||
]);
|
||||
}
|
||||
table.printstd();
|
||||
}
|
||||
pub fn unloadedmodules(driver: &DriverState) {
|
||||
let modules = traverse_unloadeddrivers(&driver).unwrap_or(Vec::new());
|
||||
let mut table = Table::new();
|
||||
table.add_row(row!["Address", "Driver", "Start", "End", "Time"]);
|
||||
for m in &modules {
|
||||
table.add_row(row![
|
||||
m["address"].as_str().unwrap_or("(??)"),
|
||||
m["name"].as_str().unwrap_or("(??)"),
|
||||
m["start_addr"].as_str().unwrap_or("(??)"),
|
||||
m["end_addr"].as_str().unwrap_or("(??)"),
|
||||
m["time_rfc2822"].as_str().unwrap_or("(??)"),
|
||||
]);
|
||||
}
|
||||
table.printstd();
|
||||
}
|
53
src/downloader.rs
Normal file
53
src/downloader.rs
Normal file
@ -0,0 +1,53 @@
|
||||
use std::error::Error;
|
||||
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use reqwest::{header, Client};
|
||||
use std::path::Path;
|
||||
use structopt::StructOpt;
|
||||
use tokio::{fs, io::AsyncWriteExt};
|
||||
|
||||
type BoxResult<T> = Result<T, Box<dyn Error>>;
|
||||
|
||||
async fn download(url: &str, path: &PathBuf) -> BoxResult<()> {
|
||||
let client = Client::new();
|
||||
let total_size = {
|
||||
let resp = client.head(url).send().await?;
|
||||
if resp.status().is_success() {
|
||||
resp.headers()
|
||||
.get(header::CONTENT_LENGTH)
|
||||
.and_then(|ct_len| ct_len.to_str().ok())
|
||||
.and_then(|ct_len| ct_len.parse().ok())
|
||||
.unwrap_or(0)
|
||||
} else {
|
||||
return Err(format!("Couldn'n download URL: {}", url));
|
||||
}
|
||||
};
|
||||
|
||||
let mut request = client.get(url);
|
||||
let pb = ProgressBar::new(total_size);
|
||||
pb.set_style(
|
||||
ProgressStyle::default_bar()
|
||||
.template("{spinner:.green} [{elapsed_precise}] \
|
||||
[{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")
|
||||
.progress_chars("#>-"));
|
||||
|
||||
let file = Path::new(path);
|
||||
|
||||
if file.exists() {
|
||||
return Err(format!("File {:?} existed", file));
|
||||
// let size = file.metadata()?.len().saturating_sub(1);
|
||||
// request = request.header(header::RANGE, format!("bytes={}-", size));
|
||||
// pb.inc(size);
|
||||
}
|
||||
|
||||
let mut source = request.send().await?;
|
||||
let mut dest = fs::OpenOptions::new().create(true).append(true).open(&file).await?;
|
||||
while let Some(chunk) = source.chunk().await? {
|
||||
dest.write_all(&chunk).await?;
|
||||
pb.inc(chunk.len() as u64);
|
||||
}
|
||||
|
||||
println!("Download of '{}' has been completed.", file.to_str().unwrap());
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,21 +1,23 @@
|
||||
use std::clone::Clone;
|
||||
use std::default::Default;
|
||||
use std::error::Error;
|
||||
// use std::io::{Error, ErrorKind};
|
||||
use std::ffi::c_void;
|
||||
use std::mem::{size_of_val};
|
||||
use std::mem::{size_of, size_of_val};
|
||||
|
||||
use winapi::shared::ntdef::{NTSTATUS};
|
||||
use winapi::shared::minwindef::{DWORD};
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::shared::ntdef::NTSTATUS;
|
||||
use winapi::um::winioctl::{
|
||||
CTL_CODE, FILE_ANY_ACCESS,
|
||||
METHOD_IN_DIRECT, METHOD_OUT_DIRECT, /* METHOD_BUFFERED, */ METHOD_NEITHER
|
||||
CTL_CODE, FILE_ANY_ACCESS, METHOD_IN_DIRECT, /* METHOD_BUFFERED, */ METHOD_NEITHER,
|
||||
METHOD_OUT_DIRECT,
|
||||
};
|
||||
|
||||
use crate::pdb_store::{PdbStore, parse_pdb};
|
||||
use crate::windows::{WindowsFFI, WindowsVersion};
|
||||
use crate::address::Address;
|
||||
use crate::ioctl_protocol::{
|
||||
InputData, OffsetData, DerefAddr, ScanPoolData, /* HideProcess, */
|
||||
/* OutputData, */ Nothing
|
||||
DerefAddr, HideProcess, InputData, /* OutputData, */ Nothing, OffsetData, ScanPoolData,
|
||||
};
|
||||
use crate::pdb_store::{parse_pdb, PdbStore};
|
||||
use crate::windows::{WindowsFFI, WindowsVersion};
|
||||
|
||||
type BoxResult<T> = Result<T, Box<dyn Error>>;
|
||||
|
||||
@ -39,19 +41,33 @@ pub enum DriverAction {
|
||||
ScanPool,
|
||||
ScanPoolRemote,
|
||||
DereferenceAddress,
|
||||
HideProcess
|
||||
HideProcess,
|
||||
}
|
||||
|
||||
impl DriverAction {
|
||||
pub fn get_code(&self) -> DWORD {
|
||||
match self {
|
||||
DriverAction::SetupOffset => CTL_CODE(SIOCTL_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS),
|
||||
DriverAction::GetKernelBase => CTL_CODE(SIOCTL_TYPE, 0x901, METHOD_OUT_DIRECT, FILE_ANY_ACCESS),
|
||||
DriverAction::ScanPsActiveHead => CTL_CODE(SIOCTL_TYPE, 0x902, METHOD_NEITHER, FILE_ANY_ACCESS),
|
||||
DriverAction::ScanPool => CTL_CODE(SIOCTL_TYPE, 0x903, METHOD_IN_DIRECT, FILE_ANY_ACCESS),
|
||||
DriverAction::ScanPoolRemote => CTL_CODE(SIOCTL_TYPE, 0x904, METHOD_IN_DIRECT, FILE_ANY_ACCESS),
|
||||
DriverAction::DereferenceAddress => CTL_CODE(SIOCTL_TYPE, 0xA00, METHOD_OUT_DIRECT, FILE_ANY_ACCESS),
|
||||
DriverAction::HideProcess => CTL_CODE(SIOCTL_TYPE, 0xA01, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
||||
DriverAction::SetupOffset => {
|
||||
CTL_CODE(SIOCTL_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
||||
}
|
||||
DriverAction::GetKernelBase => {
|
||||
CTL_CODE(SIOCTL_TYPE, 0x901, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
|
||||
}
|
||||
DriverAction::ScanPsActiveHead => {
|
||||
CTL_CODE(SIOCTL_TYPE, 0x902, METHOD_NEITHER, FILE_ANY_ACCESS)
|
||||
}
|
||||
DriverAction::ScanPool => {
|
||||
CTL_CODE(SIOCTL_TYPE, 0x903, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
||||
}
|
||||
DriverAction::ScanPoolRemote => {
|
||||
CTL_CODE(SIOCTL_TYPE, 0x904, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
||||
}
|
||||
DriverAction::DereferenceAddress => {
|
||||
CTL_CODE(SIOCTL_TYPE, 0xA00, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
|
||||
}
|
||||
DriverAction::HideProcess => {
|
||||
CTL_CODE(SIOCTL_TYPE, 0xA01, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -62,7 +78,7 @@ pub struct EprocessPoolChunk {
|
||||
pub eprocess_addr: u64,
|
||||
pub eprocess_name: String,
|
||||
pub create_time: u64,
|
||||
pub exit_time: u64
|
||||
pub exit_time: u64,
|
||||
}
|
||||
|
||||
impl PartialEq for EprocessPoolChunk {
|
||||
@ -82,17 +98,20 @@ impl DriverState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
pdb_store: parse_pdb().expect("Cannot get PDB file"),
|
||||
windows_ffi: WindowsFFI::new()
|
||||
windows_ffi: WindowsFFI::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn startup(&mut self) -> NTSTATUS {
|
||||
let s = self.windows_ffi.load_driver();
|
||||
let mut input = InputData {
|
||||
offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version)
|
||||
offset_value: OffsetData::new(&self.pdb_store, self.windows_ffi.short_version),
|
||||
};
|
||||
self.windows_ffi.device_io(DriverAction::SetupOffset.get_code(),
|
||||
&mut input, &mut Nothing);
|
||||
self.windows_ffi.device_io(
|
||||
DriverAction::SetupOffset.get_code(),
|
||||
&mut input,
|
||||
&mut Nothing,
|
||||
);
|
||||
s
|
||||
}
|
||||
|
||||
@ -100,79 +119,101 @@ impl DriverState {
|
||||
self.windows_ffi.unload_driver()
|
||||
}
|
||||
|
||||
pub fn get_kernel_base(&self) -> u64 {
|
||||
let mut ntosbase = 0u64;
|
||||
self.windows_ffi.device_io(DriverAction::GetKernelBase.get_code(),
|
||||
&mut Nothing, &mut ntosbase);
|
||||
// println!("ntosbase: 0x{:x}", self.ntosbase);
|
||||
ntosbase
|
||||
pub fn connect(&mut self) {
|
||||
self.windows_ffi.file_connect();
|
||||
}
|
||||
|
||||
pub fn scan_active_head(&self) -> BoxResult<Vec<EprocessPoolChunk>> {
|
||||
let ntosbase = self.get_kernel_base();
|
||||
let ps_active_head = ntosbase + self.pdb_store.get_offset_r("PsActiveProcessHead")?;
|
||||
let flink_offset = self.pdb_store.get_offset_r("_LIST_ENTRY.Flink")?;
|
||||
let eprocess_link_offset = self.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?;
|
||||
let eprocess_name_offset = self.pdb_store.get_offset_r("_EPROCESS.ImageFileName")?;
|
||||
pub fn is_supported(&self) -> bool {
|
||||
self.windows_ffi.short_version.is_supported()
|
||||
}
|
||||
|
||||
let mut ptr = ps_active_head;
|
||||
self.deref_addr(ptr + flink_offset, &mut ptr);
|
||||
|
||||
let mut result: Vec<EprocessPoolChunk> = Vec::new();
|
||||
while ptr != ps_active_head {
|
||||
let mut image_name = [0u8; 15];
|
||||
let eprocess = ptr - eprocess_link_offset;
|
||||
self.deref_addr(eprocess + eprocess_name_offset, &mut image_name);
|
||||
match std::str::from_utf8(&image_name) {
|
||||
Ok(n) => {
|
||||
result.push(EprocessPoolChunk {
|
||||
pool_addr: 0,
|
||||
eprocess_addr: eprocess,
|
||||
eprocess_name: n.to_string()
|
||||
.trim_end_matches(char::from(0))
|
||||
.to_string(),
|
||||
create_time: 0,
|
||||
exit_time: 0
|
||||
|
||||
});
|
||||
pub fn hide_notepad(&self) {
|
||||
let s = String::from("notepad.exe");
|
||||
let s_bytes = s.as_bytes();
|
||||
let mut name = [0u8; 15];
|
||||
for i in 0..s.len() {
|
||||
name[i] = s_bytes[i];
|
||||
}
|
||||
let mut input = InputData {
|
||||
hide_process: HideProcess {
|
||||
name,
|
||||
size: s.len() as u64,
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
self.deref_addr(ptr + flink_offset, &mut ptr);
|
||||
}
|
||||
Ok(result)
|
||||
self.windows_ffi.device_io(
|
||||
DriverAction::HideProcess.get_code(),
|
||||
&mut input,
|
||||
&mut Nothing,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn scan_pool<F>(&self, tag: &[u8; 4], mut handler: F) -> BoxResult<bool>
|
||||
where F: FnMut(u64, &[u8], u64) -> BoxResult<bool>
|
||||
// F(Pool Address, Pool Header Data, Pool Data Address)
|
||||
pub fn use_old_tag(&self) -> bool {
|
||||
// use old tag to scan, for Window < 8
|
||||
if self.windows_ffi.short_version < WindowsVersion::Windows8 {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_kernel_base(&self) -> Address {
|
||||
let mut ntosbase = 0u64;
|
||||
self.windows_ffi.device_io(
|
||||
DriverAction::GetKernelBase.get_code(),
|
||||
&mut Nothing,
|
||||
&mut ntosbase,
|
||||
);
|
||||
Address::from_base(ntosbase)
|
||||
}
|
||||
|
||||
pub fn scan_pool<F>(
|
||||
&self,
|
||||
tag: &[u8; 4],
|
||||
expected_struct: &str,
|
||||
mut handler: F,
|
||||
) -> BoxResult<bool>
|
||||
where
|
||||
F: FnMut(Address, &[u8], Address) -> BoxResult<bool>, // F(Pool Address, Pool Header Data, Pool Data Address)
|
||||
// TODO: Pool Header as a real struct
|
||||
{
|
||||
let ntosbase = self.get_kernel_base();
|
||||
// TODO: scan large pool
|
||||
// TODO: make generator, in hold: https://github.com/rust-lang/rust/issues/43122
|
||||
// Making this function a generator will turn the call to a for loop
|
||||
// https://docs.rs/gen-iter/0.2.0/gen_iter/
|
||||
// >> More flexibility in code
|
||||
let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
|
||||
let minimum_block_size = self.get_minimum_block_size(tag)?;
|
||||
let minimum_block_size = self
|
||||
.pdb_store
|
||||
.get_offset_r(&format!("{}.struct_size", expected_struct))?
|
||||
+ pool_header_size;
|
||||
let code = DriverAction::ScanPoolRemote.get_code();
|
||||
let range = self.get_nonpaged_range(ntosbase)?;
|
||||
let start_address = range[0];
|
||||
let end_address = range[1];
|
||||
let ntosbase = self.get_kernel_base();
|
||||
let [start_address, end_address] = self.get_nonpaged_range(&ntosbase)?;
|
||||
|
||||
println!(
|
||||
"kernel base: {}; non-paged pool (start, end): ({}, {}); tag: {:?} {}",
|
||||
ntosbase, start_address, end_address, tag, expected_struct
|
||||
);
|
||||
|
||||
let mut ptr = start_address;
|
||||
while ptr < end_address {
|
||||
let mut next_found = 0u64;
|
||||
let mut input = InputData {
|
||||
scan_range: ScanPoolData::new(&[ptr, end_address], tag)
|
||||
scan_range: ScanPoolData::new(&[ptr.address(), end_address.address()], tag),
|
||||
};
|
||||
self.windows_ffi.device_io(code, &mut input, &mut ptr);
|
||||
// println!("found: 0x{:x}", ptr);
|
||||
self.windows_ffi
|
||||
.device_io(code, &mut input, &mut next_found);
|
||||
ptr = Address::from_base(next_found);
|
||||
if ptr >= end_address {
|
||||
break;
|
||||
}
|
||||
|
||||
let pool_addr = ptr;
|
||||
let mut header = vec![0u8; pool_header_size as usize];
|
||||
self.deref_addr_ptr(pool_addr, header.as_mut_ptr(), pool_header_size);
|
||||
let pool_addr = Address::from_base(ptr.address());
|
||||
let header: Vec<u8> = self.deref_array(&pool_addr, pool_header_size);
|
||||
let chunk_size = (header[2] as u64) * 16u64;
|
||||
|
||||
if pool_addr + chunk_size > end_address {
|
||||
// the chunk found is not a valid chunk for sure
|
||||
if pool_addr.address() + chunk_size > end_address.address() {
|
||||
// the chunk surpasses the non page pool range
|
||||
break;
|
||||
}
|
||||
|
||||
@ -182,139 +223,175 @@ impl DriverState {
|
||||
continue;
|
||||
}
|
||||
|
||||
let success = handler(pool_addr, &header, pool_addr + pool_header_size)?;
|
||||
let data_addr = Address::from_base(pool_addr.address() + pool_header_size);
|
||||
let success = handler(pool_addr, &header, data_addr).unwrap_or(false);
|
||||
if success {
|
||||
ptr += chunk_size; /* pass this chunk */
|
||||
// ptr += 0x4;
|
||||
}
|
||||
else {
|
||||
ptr += 0x4; /* search next */
|
||||
ptr += chunk_size; // skip this chunk
|
||||
} else {
|
||||
ptr += 0x4; // search next
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn get_minimum_block_size(&self, tag: &[u8; 4]) -> BoxResult<u64> {
|
||||
// Proc -> _EPROCESS
|
||||
// Thre -> _KTHREAD
|
||||
let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
|
||||
if tag == b"Proc" {
|
||||
let eprocess_size = self.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
|
||||
let minimum_data_size = eprocess_size + pool_header_size;
|
||||
Ok(minimum_data_size)
|
||||
}
|
||||
else if tag == b"File" {
|
||||
let file_object_size = self.pdb_store.get_offset_r("_FILE_OBJECT.struct_size")?;
|
||||
let minimum_data_size = file_object_size + pool_header_size;
|
||||
Ok(minimum_data_size)
|
||||
}
|
||||
else {
|
||||
Err("Tag unknown".into())
|
||||
}
|
||||
pub fn address_of(&self, addr: &Address, name: &str) -> BoxResult<u64> {
|
||||
let resolver = |p| self.deref_addr_new(p);
|
||||
let r = self.pdb_store.decompose(&addr, &name)?;
|
||||
Ok(r.get(&resolver))
|
||||
}
|
||||
|
||||
pub fn decompose<T: Default>(&self, addr: &Address, name: &str) -> BoxResult<T> {
|
||||
// interface to pdb_store.decompose
|
||||
let resolver = |p| self.deref_addr_new(p);
|
||||
let r: T = self.deref_addr_new(self.pdb_store.decompose(&addr, &name)?.get(&resolver));
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn decompose_array<T: Default + Clone>(
|
||||
&self,
|
||||
addr: &Address,
|
||||
name: &str,
|
||||
len: u64,
|
||||
) -> BoxResult<Vec<T>> {
|
||||
// interface to pdb_store.decompose for array
|
||||
let r: Vec<T> = self.deref_array(&self.pdb_store.decompose(&addr, &name)?, len);
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn deref_addr_new<T: Default>(&self, addr: u64) -> T {
|
||||
let mut r: T = Default::default();
|
||||
if addr != 0 {
|
||||
self.deref_addr(addr, &mut r);
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
pub fn deref_array<T: Default + Clone>(&self, addr: &Address, len: u64) -> Vec<T> {
|
||||
let resolver = |p| self.deref_addr_new(p);
|
||||
let mut r: Vec<T> = vec![Default::default(); len as usize];
|
||||
let size_in_byte = (len as usize) * size_of::<T>();
|
||||
self.deref_addr_ptr(addr.get(&resolver), r.as_mut_ptr(), size_in_byte as u64);
|
||||
r
|
||||
}
|
||||
|
||||
// #[deprecated(note="use deref_addr_new<T>")]
|
||||
pub fn deref_addr<T>(&self, addr: u64, outbuf: &mut T) {
|
||||
// println!("deref addr: 0x{:x}", addr);
|
||||
let code = DriverAction::DereferenceAddress.get_code();
|
||||
let size: usize = size_of_val(outbuf);
|
||||
let mut input = InputData {
|
||||
deref_addr: DerefAddr {
|
||||
addr,
|
||||
size: size as u64
|
||||
}
|
||||
size: size as u64,
|
||||
},
|
||||
};
|
||||
// unsafe { println!("Dereference {} bytes at 0x{:x}", input.deref_addr.size, input.deref_addr.addr) };
|
||||
self.windows_ffi.device_io(code, &mut input, outbuf);
|
||||
}
|
||||
|
||||
pub fn deref_addr_ptr<T>(&self, addr: u64, outptr: *mut T, output_len: u64) {
|
||||
// #[deprecated(note="use deref_array<T>")]
|
||||
pub fn deref_addr_ptr<T>(&self, addr: u64, outptr: *mut T, output_len_as_byte: u64) {
|
||||
let code = DriverAction::DereferenceAddress.get_code();
|
||||
let mut input = InputData {
|
||||
deref_addr: DerefAddr {
|
||||
addr,
|
||||
size: output_len
|
||||
}
|
||||
size: output_len_as_byte,
|
||||
},
|
||||
};
|
||||
self.windows_ffi.device_io_raw(code,
|
||||
&mut input as *mut _ as *mut c_void, size_of_val(&input) as DWORD,
|
||||
outptr as *mut c_void, output_len as DWORD);
|
||||
self.windows_ffi.device_io_raw(
|
||||
code,
|
||||
&mut input as *mut _ as *mut c_void,
|
||||
size_of_val(&input) as DWORD,
|
||||
outptr as *mut c_void,
|
||||
output_len_as_byte as DWORD,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn get_unicode_string(&self, unicode_str_addr: u64) -> BoxResult<String> {
|
||||
if unicode_str_addr == 0 {
|
||||
return Err("Not a valid address".into());
|
||||
}
|
||||
|
||||
pub fn get_unicode_string(&self, unicode_str_addr: u64, deref: bool) -> BoxResult<String> {
|
||||
let mut strlen = 0u16;
|
||||
let mut capacity = 0u16;
|
||||
let mut bufaddr = 0u64;
|
||||
let buffer_ptr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.Buffer")?;
|
||||
let capacity_addr = unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.MaximumLength")?;
|
||||
let buffer_ptr =
|
||||
unicode_str_addr + self.pdb_store.get_offset_r("_UNICODE_STRING.Buffer")?;
|
||||
let capacity_addr = unicode_str_addr
|
||||
+ self
|
||||
.pdb_store
|
||||
.get_offset_r("_UNICODE_STRING.MaximumLength")?;
|
||||
|
||||
self.deref_addr(unicode_str_addr, &mut strlen);
|
||||
self.deref_addr(capacity_addr, &mut capacity);
|
||||
self.deref_addr(buffer_ptr, &mut bufaddr);
|
||||
|
||||
// println!("unicode str: 0x{:x} size: 0x{:x} capacity: 0x{:x}", bufaddr, strlen, capacity);
|
||||
if bufaddr == 0 || strlen > capacity || strlen == 0 || strlen % 2 != 0 {
|
||||
return Err("Unicode string is empty".into());
|
||||
}
|
||||
|
||||
if !deref {
|
||||
return Ok("".to_string());
|
||||
}
|
||||
|
||||
let mut buf = vec![0u16; (strlen / 2) as usize];
|
||||
self.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen as u64);
|
||||
// TODO: BUG with deref_array, len is wrong,
|
||||
// >> the size of vector is strlen / 2
|
||||
// >> the size to dereference is strlen
|
||||
// XXX: use Vec<u8> and turn to Vec<u16>
|
||||
// let buf: Vec<u16> = self.deref_array(&Address::from_base(bufaddr), (strlen / 2) as u64);
|
||||
|
||||
Ok(String::from_utf16(&buf)?)
|
||||
}
|
||||
|
||||
pub fn get_nonpaged_range(&self, ntosbase: u64) -> BoxResult<[u64; 2]> {
|
||||
pub fn get_nonpaged_range(&self, ntosbase: &Address) -> BoxResult<[Address; 2]> {
|
||||
// TODO: Add support for other Windows version here
|
||||
match self.windows_ffi.short_version {
|
||||
WindowsVersion::Windows10FastRing => {
|
||||
let mistate = ntosbase + self.pdb_store.get_offset_r("MiState")?;
|
||||
let system_node_ptr = self.pdb_store.addr_decompose(
|
||||
mistate, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool")?;
|
||||
let mut system_node_addr = 0u64;
|
||||
self.deref_addr(system_node_ptr, &mut system_node_addr);
|
||||
|
||||
let mut first_va = 0u64;
|
||||
let mut last_va = 0u64;
|
||||
self.deref_addr(
|
||||
system_node_addr
|
||||
+ self.pdb_store.get_offset_r("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa")?,
|
||||
&mut first_va);
|
||||
|
||||
self.deref_addr(
|
||||
system_node_addr
|
||||
+ self.pdb_store.get_offset_r("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa")?,
|
||||
&mut last_va);
|
||||
|
||||
WindowsVersion::WindowsFastRing => {
|
||||
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
|
||||
let path_first_va: String = vec![
|
||||
"_MI_SYSTEM_INFORMATION",
|
||||
"Hardware",
|
||||
"SystemNodeNonPagedPool",
|
||||
"NonPagedPoolFirstVa",
|
||||
]
|
||||
.join(".");
|
||||
let path_last_va: String = vec![
|
||||
"_MI_SYSTEM_INFORMATION",
|
||||
"Hardware",
|
||||
"SystemNodeNonPagedPool",
|
||||
"NonPagedPoolLastVa",
|
||||
]
|
||||
.join(".");
|
||||
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
|
||||
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
|
||||
Ok([first_va, last_va])
|
||||
},
|
||||
WindowsVersion::Windows10_2019 => {
|
||||
let mistate = ntosbase + self.pdb_store.get_offset_r("MiState")?;
|
||||
let system_node_ptr = self.pdb_store.addr_decompose(
|
||||
mistate, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeInformation")?;
|
||||
let mut system_node_addr = 0u64;
|
||||
self.deref_addr(system_node_ptr, &mut system_node_addr);
|
||||
|
||||
let mut first_va = 0u64;
|
||||
let mut last_va = 0u64;
|
||||
self.deref_addr(
|
||||
system_node_addr
|
||||
+ self.pdb_store.get_offset_r("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa")?,
|
||||
&mut first_va);
|
||||
|
||||
self.deref_addr(
|
||||
system_node_addr
|
||||
+ self.pdb_store.get_offset_r("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa")?,
|
||||
&mut last_va);
|
||||
|
||||
}
|
||||
WindowsVersion::Windows10_2019 | WindowsVersion::Windows10_2018 => {
|
||||
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
|
||||
let path_first_va: String = vec![
|
||||
"_MI_SYSTEM_INFORMATION",
|
||||
"Hardware",
|
||||
"SystemNodeInformation",
|
||||
"NonPagedPoolFirstVa",
|
||||
]
|
||||
.join(".");
|
||||
let path_last_va: String = vec![
|
||||
"_MI_SYSTEM_INFORMATION",
|
||||
"Hardware",
|
||||
"SystemNodeInformation",
|
||||
"NonPagedPoolLastVa",
|
||||
]
|
||||
.join(".");
|
||||
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
|
||||
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
|
||||
Ok([first_va, last_va])
|
||||
},
|
||||
_ => {
|
||||
Err("Windows version for nonpaged pool algorithm is not implemented".into())
|
||||
}
|
||||
WindowsVersion::Windows7 => {
|
||||
let path_first_va =
|
||||
ntosbase.clone() + self.pdb_store.get_offset_r("MmNonPagedPoolStart")?;
|
||||
let path_last_va =
|
||||
ntosbase.clone() + self.pdb_store.get_offset_r("MiNonPagedPoolEnd")?;
|
||||
let first_va = Address::from_base(self.deref_addr_new(path_first_va.address()));
|
||||
let last_va = Address::from_base(self.deref_addr_new(path_last_va.address()));
|
||||
Ok([first_va, last_va])
|
||||
}
|
||||
_ => Err("Windows version for nonpaged pool algorithm is not implemented".into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,22 +21,101 @@ pub struct OffsetData {
|
||||
// TODO: Move to WindowsScanStrategy and return the corresponding struct base on Windows version
|
||||
impl OffsetData {
|
||||
pub fn new(pdb_store: &PdbStore, windows_version: WindowsVersion) -> Self {
|
||||
// TODO: Fix the backend so that only neccessary fields are used
|
||||
// This is too much, most of the functionality has been move to the frontend
|
||||
match windows_version {
|
||||
WindowsVersion::Windows10FastRing => Self {
|
||||
eprocess_name_offset: pdb_store.get_offset("_EPROCESS.ImageFileName").unwrap_or(0u64),
|
||||
eprocess_link_offset: pdb_store.get_offset("_EPROCESS.ActiveProcessLinks").unwrap_or(0u64),
|
||||
WindowsVersion::WindowsFastRing => Self {
|
||||
eprocess_name_offset: pdb_store
|
||||
.get_offset("_EPROCESS.ImageFileName")
|
||||
.unwrap_or(0u64),
|
||||
eprocess_link_offset: pdb_store
|
||||
.get_offset("_EPROCESS.ActiveProcessLinks")
|
||||
.unwrap_or(0u64),
|
||||
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
||||
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
|
||||
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
|
||||
hardware_offset: pdb_store.get_offset("_MI_SYSTEM_INFORMATION.Hardware").unwrap_or(0u64),
|
||||
system_node_offset: pdb_store.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool").unwrap_or(0u64),
|
||||
first_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa").unwrap_or(0u64),
|
||||
last_va_offset: pdb_store.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa").unwrap_or(0u64),
|
||||
hardware_offset: pdb_store
|
||||
.get_offset("_MI_SYSTEM_INFORMATION.Hardware")
|
||||
.unwrap_or(0u64),
|
||||
system_node_offset: pdb_store
|
||||
.get_offset("_MI_HARDWARE_STATE.SystemNodeNonPagedPool")
|
||||
.unwrap_or(0u64),
|
||||
first_va_offset: pdb_store
|
||||
.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa")
|
||||
.unwrap_or(0u64),
|
||||
last_va_offset: pdb_store
|
||||
.get_offset("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa")
|
||||
.unwrap_or(0u64),
|
||||
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
|
||||
large_page_size_offset: pdb_store.get_offset("PoolBigPageTableSize").unwrap_or(0u64),
|
||||
pool_chunk_size: pdb_store.get_offset("_POOL_HEADER.struct_size").unwrap_or(0u64),
|
||||
large_page_size_offset: pdb_store
|
||||
.get_offset("PoolBigPageTableSize")
|
||||
.unwrap_or(0u64),
|
||||
pool_chunk_size: pdb_store
|
||||
.get_offset("_POOL_HEADER.struct_size")
|
||||
.unwrap_or(0u64),
|
||||
},
|
||||
WindowsVersion::Windows10_2019 | WindowsVersion::Windows10_2018 => Self {
|
||||
eprocess_name_offset: pdb_store
|
||||
.get_offset("_EPROCESS.ImageFileName")
|
||||
.unwrap_or(0u64),
|
||||
eprocess_link_offset: pdb_store
|
||||
.get_offset("_EPROCESS.ActiveProcessLinks")
|
||||
.unwrap_or(0u64),
|
||||
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
||||
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
|
||||
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
|
||||
hardware_offset: pdb_store
|
||||
.get_offset("_MI_SYSTEM_INFORMATION.Hardware")
|
||||
.unwrap_or(0u64),
|
||||
system_node_offset: pdb_store
|
||||
.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation")
|
||||
.unwrap_or(0u64),
|
||||
first_va_offset: pdb_store
|
||||
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa")
|
||||
.unwrap_or(0u64),
|
||||
last_va_offset: pdb_store
|
||||
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa")
|
||||
.unwrap_or(0u64),
|
||||
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
|
||||
large_page_size_offset: pdb_store
|
||||
.get_offset("PoolBigPageTableSize")
|
||||
.unwrap_or(0u64),
|
||||
pool_chunk_size: pdb_store
|
||||
.get_offset("_POOL_HEADER.struct_size")
|
||||
.unwrap_or(0u64),
|
||||
},
|
||||
WindowsVersion::Windows7 => Self {
|
||||
eprocess_name_offset: pdb_store
|
||||
.get_offset("_EPROCESS.ImageFileName")
|
||||
.unwrap_or(0u64),
|
||||
eprocess_link_offset: pdb_store
|
||||
.get_offset("_EPROCESS.ActiveProcessLinks")
|
||||
.unwrap_or(0u64),
|
||||
list_blink_offset: pdb_store.get_offset("_LIST_ENTRY.Blink").unwrap_or(0u64),
|
||||
process_head_offset: pdb_store.get_offset("PsActiveProcessHead").unwrap_or(0u64),
|
||||
mistate_offset: pdb_store.get_offset("MiState").unwrap_or(0u64),
|
||||
hardware_offset: pdb_store
|
||||
.get_offset("_MI_SYSTEM_INFORMATION.Hardware")
|
||||
.unwrap_or(0u64),
|
||||
system_node_offset: pdb_store
|
||||
.get_offset("_MI_HARDWARE_STATE.SystemNodeInformation")
|
||||
.unwrap_or(0u64),
|
||||
first_va_offset: pdb_store
|
||||
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa")
|
||||
.unwrap_or(0u64),
|
||||
last_va_offset: pdb_store
|
||||
.get_offset("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa")
|
||||
.unwrap_or(0u64),
|
||||
large_page_table_offset: pdb_store.get_offset("PoolBigPageTable").unwrap_or(0u64),
|
||||
large_page_size_offset: pdb_store
|
||||
.get_offset("PoolBigPageTableSize")
|
||||
.unwrap_or(0u64),
|
||||
pool_chunk_size: pdb_store
|
||||
.get_offset("_POOL_HEADER.struct_size")
|
||||
.unwrap_or(0u64),
|
||||
},
|
||||
// TODO: Add other version of Windows here
|
||||
// TODO: Warn user of unknown windows version, because BSOD will occur
|
||||
_ => Self {
|
||||
eprocess_name_offset: 0u64,
|
||||
eprocess_link_offset: 0u64,
|
||||
@ -50,7 +129,7 @@ impl OffsetData {
|
||||
large_page_table_offset: 0u64,
|
||||
large_page_size_offset: 0u64,
|
||||
pool_chunk_size: 0u64,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,7 +138,7 @@ impl OffsetData {
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct DerefAddr {
|
||||
pub addr: u64,
|
||||
pub size: u64
|
||||
pub size: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@ -67,15 +146,15 @@ pub struct DerefAddr {
|
||||
pub struct ScanPoolData {
|
||||
pub start: u64,
|
||||
pub end: u64,
|
||||
pub tag: u32
|
||||
pub tag: u32,
|
||||
}
|
||||
|
||||
impl ScanPoolData{
|
||||
impl ScanPoolData {
|
||||
pub fn new(arr: &[u64; 2], tag: &[u8; 4]) -> Self {
|
||||
Self {
|
||||
start: arr[0],
|
||||
end: arr[1],
|
||||
tag: u32::from_le_bytes(*tag)
|
||||
tag: u32::from_le_bytes(*tag),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -84,7 +163,7 @@ impl ScanPoolData{
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct HideProcess {
|
||||
pub name: [u8; 15],
|
||||
pub size: u64
|
||||
pub size: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
592
src/lib.rs
592
src/lib.rs
@ -1,8 +1,594 @@
|
||||
extern crate chrono;
|
||||
extern crate app_dirs;
|
||||
extern crate chrono;
|
||||
|
||||
pub mod address;
|
||||
pub mod commands;
|
||||
pub mod driver_state;
|
||||
pub mod ioctl_protocol;
|
||||
pub mod object;
|
||||
pub mod pdb_store;
|
||||
pub mod windows;
|
||||
pub mod ioctl_protocol;
|
||||
pub mod driver_state;
|
||||
|
||||
use app_dirs::AppInfo;
|
||||
use chrono::{DateTime, Local, TimeZone};
|
||||
use serde_json::{json, Value};
|
||||
use std::error::Error;
|
||||
|
||||
use address::Address;
|
||||
use driver_state::DriverState;
|
||||
use object::*;
|
||||
|
||||
type BoxResult<T> = Result<T, Box<dyn Error>>;
|
||||
|
||||
pub const APP_INFO: AppInfo = AppInfo {
|
||||
name: "lpus",
|
||||
author: "nganhkhoa",
|
||||
};
|
||||
|
||||
pub fn to_epoch(filetime: u64) -> DateTime<Local> {
|
||||
// return seconds from epoch
|
||||
let windows_epoch_diff = 11_644_473_600_000 * 10_000;
|
||||
if filetime < windows_epoch_diff {
|
||||
return Local.timestamp(0, 0);
|
||||
}
|
||||
let filetime_epoch = (filetime - windows_epoch_diff) / 10_000_000;
|
||||
Local.timestamp(filetime_epoch as i64, 0)
|
||||
}
|
||||
|
||||
pub fn get_irp_name(idx: usize) -> String {
|
||||
let irp_names = vec![
|
||||
"IRP_MJ_CREATE",
|
||||
"IRP_MJ_CREATE_NAMED_PIPE",
|
||||
"IRP_MJ_CLOSE",
|
||||
"IRP_MJ_READ",
|
||||
"IRP_MJ_WRITE",
|
||||
"IRP_MJ_QUERY_INFORMATION",
|
||||
"IRP_MJ_SET_INFORMATION",
|
||||
"IRP_MJ_QUERY_EA",
|
||||
"IRP_MJ_SET_EA",
|
||||
"IRP_MJ_FLUSH_BUFFERS",
|
||||
"IRP_MJ_QUERY_VOLUME_INFORMATION",
|
||||
"IRP_MJ_SET_VOLUME_INFORMATION",
|
||||
"IRP_MJ_DIRECTORY_CONTROL",
|
||||
"IRP_MJ_FILE_SYSTEM_CONTROL",
|
||||
"IRP_MJ_DEVICE_CONTROL",
|
||||
"IRP_MJ_INTERNAL_DEVICE_CONTROL",
|
||||
"IRP_MJ_SHUTDOWN",
|
||||
"IRP_MJ_LOCK_CONTROL",
|
||||
"IRP_MJ_CLEANUP",
|
||||
"IRP_MJ_CREATE_MAILSLOT",
|
||||
"IRP_MJ_QUERY_SECURITY",
|
||||
"IRP_MJ_SET_SECURITY",
|
||||
"IRP_MJ_POWER",
|
||||
"IRP_MJ_SYSTEM_CONTROL",
|
||||
"IRP_MJ_DEVICE_CHANGE",
|
||||
"IRP_MJ_QUERY_QUOTA",
|
||||
"IRP_MJ_SET_QUOTA",
|
||||
"IRP_MJ_PNP",
|
||||
]
|
||||
.iter()
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
if let Some(name) = irp_names.get(idx) {
|
||||
name.clone()
|
||||
} else {
|
||||
"UNKNOWN".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_device_type(typ: u32) -> String {
|
||||
match typ {
|
||||
0x00000027 => "FILE_DEVICE_8042_PORT",
|
||||
0x00000032 => "FILE_DEVICE_ACPI",
|
||||
0x00000029 => "FILE_DEVICE_BATTERY",
|
||||
0x00000001 => "FILE_DEVICE_BEEP",
|
||||
0x0000002a => "FILE_DEVICE_BUS_EXTENDER",
|
||||
0x00000002 => "FILE_DEVICE_CD_ROM",
|
||||
0x00000003 => "FILE_DEVICE_CD_ROM_FILE_SYSTEM",
|
||||
0x00000030 => "FILE_DEVICE_CHANGER",
|
||||
0x00000004 => "FILE_DEVICE_CONTROLLER",
|
||||
0x00000005 => "FILE_DEVICE_DATALINK",
|
||||
0x00000006 => "FILE_DEVICE_DFS",
|
||||
0x00000035 => "FILE_DEVICE_DFS_FILE_SYSTEM",
|
||||
0x00000036 => "FILE_DEVICE_DFS_VOLUME",
|
||||
0x00000007 => "FILE_DEVICE_DISK",
|
||||
0x00000008 => "FILE_DEVICE_DISK_FILE_SYSTEM",
|
||||
0x00000033 => "FILE_DEVICE_DVD",
|
||||
0x00000009 => "FILE_DEVICE_FILE_SYSTEM",
|
||||
0x0000003a => "FILE_DEVICE_FIPS",
|
||||
0x00000034 => "FILE_DEVICE_FULLSCREEN_VIDEO",
|
||||
0x0000000a => "FILE_DEVICE_INPORT_PORT",
|
||||
0x0000000b => "FILE_DEVICE_KEYBOARD",
|
||||
0x0000002f => "FILE_DEVICE_KS",
|
||||
0x00000039 => "FILE_DEVICE_KSEC",
|
||||
0x0000000c => "FILE_DEVICE_MAILSLOT",
|
||||
0x0000002d => "FILE_DEVICE_MASS_STORAGE",
|
||||
0x0000000d => "FILE_DEVICE_MIDI_IN",
|
||||
0x0000000e => "FILE_DEVICE_MIDI_OUT",
|
||||
0x0000002b => "FILE_DEVICE_MODEM",
|
||||
0x0000000f => "FILE_DEVICE_MOUSE",
|
||||
0x00000010 => "FILE_DEVICE_MULTI_UNC_PROVIDER",
|
||||
0x00000011 => "FILE_DEVICE_NAMED_PIPE",
|
||||
0x00000012 => "FILE_DEVICE_NETWORK",
|
||||
0x00000013 => "FILE_DEVICE_NETWORK_BROWSER",
|
||||
0x00000014 => "FILE_DEVICE_NETWORK_FILE_SYSTEM",
|
||||
0x00000028 => "FILE_DEVICE_NETWORK_REDIRECTOR",
|
||||
0x00000015 => "FILE_DEVICE_NULL",
|
||||
0x00000016 => "FILE_DEVICE_PARALLEL_PORT",
|
||||
0x00000017 => "FILE_DEVICE_PHYSICAL_NETCARD",
|
||||
0x00000018 => "FILE_DEVICE_PRINTER",
|
||||
0x00000019 => "FILE_DEVICE_SCANNER",
|
||||
0x0000001c => "FILE_DEVICE_SCREEN",
|
||||
0x00000037 => "FILE_DEVICE_SERENUM",
|
||||
0x0000001a => "FILE_DEVICE_SERIAL_MOUSE_PORT",
|
||||
0x0000001b => "FILE_DEVICE_SERIAL_PORT",
|
||||
0x00000031 => "FILE_DEVICE_SMARTCARD",
|
||||
0x0000002e => "FILE_DEVICE_SMB",
|
||||
0x0000001d => "FILE_DEVICE_SOUND",
|
||||
0x0000001e => "FILE_DEVICE_STREAMS",
|
||||
0x0000001f => "FILE_DEVICE_TAPE",
|
||||
0x00000020 => "FILE_DEVICE_TAPE_FILE_SYSTEM",
|
||||
0x00000038 => "FILE_DEVICE_TERMSRV",
|
||||
0x00000021 => "FILE_DEVICE_TRANSPORT",
|
||||
0x00000022 => "FILE_DEVICE_UNKNOWN",
|
||||
0x0000002c => "FILE_DEVICE_VDM",
|
||||
0x00000023 => "FILE_DEVICE_VIDEO",
|
||||
0x00000024 => "FILE_DEVICE_VIRTUAL_DISK",
|
||||
0x00000025 => "FILE_DEVICE_WAVE_IN",
|
||||
0x00000026 => "FILE_DEVICE_WAVE_OUT",
|
||||
_ => "UNKNOWN",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let mut result: Vec<Value> = Vec::new();
|
||||
let tag = if driver.use_old_tag() {
|
||||
b"Pro\xe3"
|
||||
} else {
|
||||
b"Proc"
|
||||
};
|
||||
driver.scan_pool(tag, "_EPROCESS", |pool_addr, header, data_addr| {
|
||||
let chunk_size = (header[2] as u64) * 16u64;
|
||||
|
||||
let eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
|
||||
|
||||
let eprocess_valid_start = &data_addr;
|
||||
let eprocess_valid_end = (pool_addr.clone() + chunk_size) - eprocess_size;
|
||||
let mut try_eprocess_ptr = eprocess_valid_start.clone();
|
||||
|
||||
while try_eprocess_ptr <= eprocess_valid_end {
|
||||
let create_time: u64 = driver.decompose(&try_eprocess_ptr, "_EPROCESS.CreateTime")?;
|
||||
if driver.windows_ffi.valid_process_time(create_time) {
|
||||
break;
|
||||
}
|
||||
try_eprocess_ptr += 0x4; // search exhaustively
|
||||
}
|
||||
if try_eprocess_ptr > eprocess_valid_end {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
result.push(make_eprocess(driver, &try_eprocess_ptr)?);
|
||||
Ok(true)
|
||||
})?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn scan_file(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let mut result: Vec<Value> = Vec::new();
|
||||
|
||||
let tag = if driver.use_old_tag() {
|
||||
b"Fil\xe5"
|
||||
} else {
|
||||
b"File"
|
||||
};
|
||||
driver.scan_pool(tag, "_FILE_OBJECT", |pool_addr, header, data_addr| {
|
||||
let chunk_size = (header[2] as u64) * 16u64;
|
||||
|
||||
let fob_size = driver.pdb_store.get_offset_r("_FILE_OBJECT.struct_size")?;
|
||||
let valid_end = (pool_addr.clone() + chunk_size) - fob_size;
|
||||
let mut try_ptr = data_addr;
|
||||
|
||||
while try_ptr <= valid_end {
|
||||
let ftype: u16 = driver.decompose(&try_ptr, "_FILE_OBJECT.Type")?;
|
||||
let size: u16 = driver.decompose(&try_ptr, "_FILE_OBJECT.Size")?;
|
||||
if (size as u64) == fob_size && ftype == 5u16 {
|
||||
break;
|
||||
}
|
||||
try_ptr += 0x4; // search exhaustively
|
||||
}
|
||||
if try_ptr > valid_end {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let fob_addr = &try_ptr;
|
||||
let read_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.ReadAccess")?;
|
||||
let write_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.WriteAccess")?;
|
||||
let delete_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.DeleteAccess")?;
|
||||
let share_read_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.SharedRead")?;
|
||||
let share_write_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.SharedWrite")?;
|
||||
let share_delete_ok: u8 = driver.decompose(fob_addr, "_FILE_OBJECT.SharedDelete")?;
|
||||
let filename_ptr = driver.address_of(fob_addr, "_FILE_OBJECT.FileName")?;
|
||||
let devicename_ptr: u64 = driver.address_of(
|
||||
fob_addr,
|
||||
"_FILE_OBJECT.DeviceObject.DriverObject.DriverName",
|
||||
)?;
|
||||
let hardware_ptr: u64 = driver.decompose(
|
||||
fob_addr,
|
||||
"_FILE_OBJECT.DeviceObject.DriverObject.HardwareDatabase",
|
||||
)?;
|
||||
|
||||
let filename = if read_ok == 0 {
|
||||
"[NOT READABLE]".to_string()
|
||||
} else if let Ok(n) = driver.get_unicode_string(filename_ptr) {
|
||||
n
|
||||
} else {
|
||||
"[NOT A VALID _UNICODE_STRING]".to_string()
|
||||
};
|
||||
let devicename = driver
|
||||
.get_unicode_string(devicename_ptr)
|
||||
.unwrap_or("".to_string());
|
||||
let hardware = driver
|
||||
.get_unicode_string(hardware_ptr)
|
||||
.unwrap_or("".to_string());
|
||||
result.push(json!({
|
||||
"pool": format!("0x{:x}", pool_addr.address()),
|
||||
"address": format!("0x{:x}", fob_addr.address()),
|
||||
"type": "_FILE_OBJECT",
|
||||
"path": filename,
|
||||
"device": devicename,
|
||||
"hardware": hardware,
|
||||
"access": {
|
||||
"r": read_ok == 1,
|
||||
"w": write_ok == 1,
|
||||
"d": delete_ok == 1,
|
||||
"R": share_read_ok == 1,
|
||||
"W": share_write_ok == 1,
|
||||
"D": share_delete_ok == 1
|
||||
}
|
||||
}));
|
||||
Ok(true)
|
||||
})?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn scan_ethread(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let mut result: Vec<Value> = Vec::new();
|
||||
|
||||
let tag = if driver.use_old_tag() {
|
||||
b"Thr\xe5"
|
||||
} else {
|
||||
b"Thre"
|
||||
};
|
||||
driver.scan_pool(tag, "_ETHREAD", |pool_addr, header, data_addr| {
|
||||
let chunk_size = (header[2] as u64) * 16u64;
|
||||
|
||||
let object_header_size = driver
|
||||
.pdb_store
|
||||
.get_offset_r("_OBJECT_HEADER.struct_size")?;
|
||||
let header_size = driver.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
|
||||
let ethread_size = driver.pdb_store.get_offset_r("_ETHREAD.struct_size")?;
|
||||
let ethread_valid_start = &data_addr;
|
||||
let ethread_valid_end = (pool_addr.clone() + chunk_size) - ethread_size;
|
||||
let mut try_ethread_ptr = ethread_valid_start.clone();
|
||||
|
||||
if chunk_size == header_size + object_header_size + ethread_size {
|
||||
try_ethread_ptr = ethread_valid_end.clone();
|
||||
} else {
|
||||
while try_ethread_ptr <= ethread_valid_end {
|
||||
let create_time: u64 = driver.decompose(&try_ethread_ptr, "_ETHREAD.CreateTime")?;
|
||||
if driver.windows_ffi.valid_process_time(create_time) {
|
||||
break;
|
||||
}
|
||||
try_ethread_ptr += 0x4; // search exhaustively
|
||||
}
|
||||
if try_ethread_ptr > ethread_valid_end {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
result.push(make_ethread(driver, &try_ethread_ptr)?);
|
||||
Ok(true)
|
||||
})?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// Unstable, do not use
|
||||
// pub fn scan_mutant(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
// let mut result: Vec<Value> = Vec::new();
|
||||
//
|
||||
// let ntosbase = driver.get_kernel_base();
|
||||
// let [start, end] = driver.get_nonpaged_range(&ntosbase)?;
|
||||
//
|
||||
// let tag =
|
||||
// if driver.use_old_tag() { b"Mut\xe1" }
|
||||
// else { b"Muta" };
|
||||
// driver.scan_pool(tag, "_KMUTANT", |pool_addr, header, data_addr| {
|
||||
// let chunk_size = (header[2] as u64) * 16u64;
|
||||
//
|
||||
// let kmutant_size = driver.pdb_store.get_offset_r("_KMUTANT.struct_size")?;
|
||||
//
|
||||
// let kmutant_valid_start = data_addr;
|
||||
// let kmutant_valid_end = (pool_addr.clone() + chunk_size) - kmutant_size;
|
||||
// let mut try_kmutant_ptr = kmutant_valid_start.clone();
|
||||
//
|
||||
// while try_kmutant_ptr <= kmutant_valid_end {
|
||||
// // TODO: Stronger constrain
|
||||
// let kthread_ptr = driver.address_of(&try_kmutant_ptr, "_KMUTANT.OwnerThread")?;
|
||||
// if kthread_ptr > start.address() && kthread_ptr < end.address() {
|
||||
// break;
|
||||
// }
|
||||
// try_kmutant_ptr += 0x4; // search exhaustively
|
||||
// }
|
||||
// if try_kmutant_ptr > kmutant_valid_end {
|
||||
// return Ok(false);
|
||||
// }
|
||||
//
|
||||
// let kmutant_ptr = try_kmutant_ptr;
|
||||
// let ethread_ptr = Address::from_base(driver.address_of(&kmutant_ptr, "_KMUTANT.OwnerThread")?);
|
||||
//
|
||||
// let pid: u64 = driver.decompose(ðread_ptr, "_ETHREAD.Cid.UniqueProcess")?;
|
||||
// let tid: u64 = driver.decompose(ðread_ptr, "_ETHREAD.Cid.UniqueThread")?;
|
||||
// let unicode_str_ptr: u64 = driver.address_of(ðread_ptr, "_ETHREAD.ThreadName")?;
|
||||
//
|
||||
// let thread_name =
|
||||
// if let Ok(name) = driver.get_unicode_string(unicode_str_ptr) {
|
||||
// name
|
||||
// }
|
||||
// else {
|
||||
// "".to_string()
|
||||
// };
|
||||
//
|
||||
// result.push(json!({
|
||||
// "pool": format!("0x{:x}", pool_addr.address()),
|
||||
// "address": format!("0x{:x}", ethread_ptr.address()),
|
||||
// "type": "_KMUTANT",
|
||||
// "pid": pid,
|
||||
// "tid": tid,
|
||||
// "name": thread_name
|
||||
// }));
|
||||
// Ok(true)
|
||||
// })?;
|
||||
//
|
||||
// Ok(result)
|
||||
// }
|
||||
|
||||
pub fn scan_driver(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let mut result: Vec<Value> = Vec::new();
|
||||
|
||||
let tag = if driver.use_old_tag() {
|
||||
b"Dri\xf6"
|
||||
} else {
|
||||
b"Driv"
|
||||
};
|
||||
driver.scan_pool(tag, "_DRIVER_OBJECT", |pool_addr, header, data_addr| {
|
||||
let chunk_size = (header[2] as u64) * 16u64;
|
||||
|
||||
let dob_size = driver
|
||||
.pdb_store
|
||||
.get_offset_r("_DRIVER_OBJECT.struct_size")?;
|
||||
let valid_end = (pool_addr.clone() + chunk_size) - dob_size;
|
||||
let mut try_ptr = data_addr;
|
||||
|
||||
while try_ptr <= valid_end {
|
||||
// No documentation on type constrain
|
||||
let size: u16 = driver.decompose(&try_ptr, "_DRIVER_OBJECT.Size")?;
|
||||
if (size as u64) == dob_size {
|
||||
break;
|
||||
}
|
||||
try_ptr += 0x4; // search exhaustively
|
||||
}
|
||||
if try_ptr > valid_end {
|
||||
return Ok(false);
|
||||
}
|
||||
result.push(make_driver(driver, &try_ptr)?);
|
||||
Ok(true)
|
||||
})?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn scan_kernel_module(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let mut result: Vec<Value> = Vec::new();
|
||||
|
||||
driver.scan_pool(
|
||||
b"MmLd",
|
||||
"_LDR_DATA_TABLE_ENTRY",
|
||||
|_pool_addr, _, data_addr| {
|
||||
// By reversing, this structure does not have any header
|
||||
result.push(make_ldr(driver, &data_addr)?);
|
||||
Ok(true)
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn traverse_loadedmodulelist(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let ntosbase = driver.get_kernel_base();
|
||||
let module_list_head = ntosbase + driver.pdb_store.get_offset_r("PsLoadedModuleList")?;
|
||||
|
||||
let result = make_list_entry(
|
||||
driver,
|
||||
module_list_head.clone(),
|
||||
"_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks",
|
||||
)?
|
||||
.iter()
|
||||
.map(|x| make_ldr(driver, &x).unwrap_or(json!({})))
|
||||
.collect();
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// dx Debugger.Utility.Collections.FromListEntry( *(nt!_LIST_ENTRY*)&(nt!PsActiveProcessHead), "nt!_EPROCESS", "ActiveProcessLinks")
|
||||
pub fn traverse_activehead(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let mut result: Vec<Value> = Vec::new();
|
||||
|
||||
let ntosbase = driver.get_kernel_base();
|
||||
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("PsActiveProcessHead")?;
|
||||
let eprocess_listentry_offset = driver
|
||||
.pdb_store
|
||||
.get_offset_r("_EPROCESS.ActiveProcessLinks")?;
|
||||
|
||||
// TODO: make_list_entry
|
||||
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
||||
while ptr != process_list_head.address() {
|
||||
let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset);
|
||||
result.push(make_eprocess(driver, &eprocess_ptr)?);
|
||||
ptr = driver.decompose(&eprocess_ptr, "_EPROCESS.ActiveProcessLinks.Flink")?;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// TODO: where is afd!
|
||||
// dx Debugger.Utility.Collections.FromListEntry( *(nt!_LIST_ENTRY*)&(afd!AfdEndpointListHead), "nt!_EPROCESS", "ActiveProcessLinks")
|
||||
// pub fn traverse_afdendpoint(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
// let mut result: Vec<Value> = Vec::new();
|
||||
//
|
||||
// let ntosbase = driver.get_kernel_base();
|
||||
// let process_list_head = ntosbase + driver.pdb_store.get_offset_r("PsActiveProcessHead")?;
|
||||
// let eprocess_listentry_offset = driver.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?;
|
||||
//
|
||||
// let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
||||
// while ptr != process_list_head.address() {
|
||||
// let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset);
|
||||
//
|
||||
// let pid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.UniqueProcessId")?;
|
||||
// let ppid: u64 = driver.decompose(&eprocess_ptr, "_EPROCESS.InheritedFromUniqueProcessId")?;
|
||||
// let image_name: Vec<u8> = driver.decompose_array(&eprocess_ptr, "_EPROCESS.ImageFileName", 15)?;
|
||||
// let unicode_str_ptr = driver.address_of(&eprocess_ptr, "_EPROCESS.ImageFilePointer.FileName")?;
|
||||
//
|
||||
// let eprocess_name =
|
||||
// if let Ok(name) = from_utf8(&image_name) {
|
||||
// name.to_string().trim_end_matches(char::from(0)).to_string()
|
||||
// } else {
|
||||
// "".to_string()
|
||||
// };
|
||||
// let binary_path = driver.get_unicode_string(unicode_str_ptr)
|
||||
// .unwrap_or("".to_string());
|
||||
//
|
||||
// result.push(json!({
|
||||
// "address": format!("0x{:x}", &eprocess_ptr.address()),
|
||||
// "type": "_EPROCESS",
|
||||
// "pid": pid,
|
||||
// "ppid": ppid,
|
||||
// "name": eprocess_name,
|
||||
// "path": binary_path
|
||||
// }));
|
||||
//
|
||||
// ptr = driver.decompose(&eprocess_ptr, "_EPROCESS.ActiveProcessLinks.Flink")?;
|
||||
// }
|
||||
//
|
||||
// Ok(result)
|
||||
// }
|
||||
|
||||
// dx Debugger.Utility.Collections.FromListEntry( *(nt!_LIST_ENTRY*)&(nt!KiProcessListHead), "nt!_KPROCESS", "ProcessListEntry").Select( p => new {Process = (nt!_EPROCESS*)&p )
|
||||
pub fn traverse_kiprocesslist(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let mut result: Vec<Value> = Vec::new();
|
||||
|
||||
let ntosbase = driver.get_kernel_base();
|
||||
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("KiProcessListHead")?;
|
||||
let eprocess_listentry_offset = driver
|
||||
.pdb_store
|
||||
.get_offset_r("_KPROCESS.ProcessListEntry")?;
|
||||
|
||||
// TODO: make_list_entry
|
||||
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
||||
while ptr != process_list_head.address() {
|
||||
let eprocess_ptr = Address::from_base(ptr - eprocess_listentry_offset);
|
||||
result.push(make_eprocess(driver, &eprocess_ptr)?);
|
||||
|
||||
ptr = driver.decompose(&eprocess_ptr, "_KPROCESS.ProcessListEntry.Flink")?;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// dx Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY*)&nt!HandleTableListHead, "nt!_HANDLE_TABLE", "HandleTableList").Where(h => h.QuotaProcess != 0).Select( qp => new {Process= qp.QuotaProcess} )
|
||||
pub fn traverse_handletable(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let mut result: Vec<Value> = Vec::new();
|
||||
|
||||
let ntosbase = driver.get_kernel_base();
|
||||
let process_list_head = ntosbase + driver.pdb_store.get_offset_r("HandleTableListHead")?;
|
||||
let handle_list_offset = driver
|
||||
.pdb_store
|
||||
.get_offset_r("_HANDLE_TABLE.HandleTableList")?;
|
||||
|
||||
let mut ptr: u64 = driver.decompose(&process_list_head, "_LIST_ENTRY.Flink")?;
|
||||
while ptr != process_list_head.address() {
|
||||
let handle_ptr = Address::from_base(ptr - handle_list_offset);
|
||||
let quota_process: u64 = driver.decompose(&handle_ptr, "_HANDLE_TABLE.QuotaProcess")?;
|
||||
|
||||
if quota_process != 0 {
|
||||
let eprocess_ptr = Address::from_base(quota_process);
|
||||
result.push(make_eprocess(driver, &eprocess_ptr)?);
|
||||
}
|
||||
|
||||
ptr = driver.decompose(&handle_ptr, "_HANDLE_TABLE.HandleTableList.Flink")?;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn traverse_unloadeddrivers(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||
let mut result: Vec<Value> = Vec::new();
|
||||
let ntosbase = driver.get_kernel_base();
|
||||
let unload_array_ptr = ntosbase.clone() + driver.pdb_store.get_offset_r("MmUnloadedDrivers")?;
|
||||
let num_unload_ptr =
|
||||
ntosbase.clone() + driver.pdb_store.get_offset_r("MmLastUnloadedDriver")?;
|
||||
|
||||
let unload_array = driver.deref_addr_new::<u64>(unload_array_ptr.address());
|
||||
if unload_array == 0 {
|
||||
return Err("The unload driver list pointer is null".into());
|
||||
}
|
||||
|
||||
// by reversing MmLocateUnloadedDriver
|
||||
let num_unload = driver.deref_addr_new::<u32>(num_unload_ptr.address()) as u64;
|
||||
let bound = if num_unload > 0x32 { 0x32 } else { num_unload };
|
||||
let drivers = (0..bound).map(|i| Address::from_base(unload_array + (i * 0x28)));
|
||||
|
||||
for driver_addr in drivers {
|
||||
let name = driver
|
||||
.get_unicode_string(driver_addr.address())
|
||||
.unwrap_or("".to_string());
|
||||
let start_addr: u64 = driver.decompose(&driver_addr, "_UNLOADED_DRIVERS.StartAddress")?;
|
||||
let end_addr: u64 = driver.decompose(&driver_addr, "_UNLOADED_DRIVERS.EndAddress")?;
|
||||
let current_time: u64 = driver.decompose(&driver_addr, "_UNLOADED_DRIVERS.CurrentTime")?;
|
||||
let time = to_epoch(current_time);
|
||||
|
||||
result.push(json!({
|
||||
"address": format!("0x{:x}", driver_addr.address()),
|
||||
"type": "_UNLOADED_DRIVERS",
|
||||
"name": name,
|
||||
"start_addr": format!("0x{:x}", start_addr),
|
||||
"end_addr": format!("0x{:x}", end_addr),
|
||||
"time_unix": time.timestamp(),
|
||||
"time_rfc2822": time.to_rfc2822()
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn ssdt_table(driver: &DriverState) -> BoxResult<Vec<u64>> {
|
||||
// https://github.com/volatilityfoundation/volatility3/blob/master/volatility/framework/plugins/windows/ssdt.py
|
||||
let ntosbase = driver.get_kernel_base();
|
||||
let servicetable = ntosbase.clone() + driver.pdb_store.get_offset_r("KiServiceTable")?;
|
||||
let servicelimit_ptr = ntosbase.clone() + driver.pdb_store.get_offset_r("KiServiceLimit")?;
|
||||
|
||||
let servicelimit = driver.deref_addr_new::<u32>(servicelimit_ptr.address()) as u64;
|
||||
let ssdt: Vec<u64> = driver
|
||||
.deref_array::<i32>(&servicetable, servicelimit)
|
||||
.iter()
|
||||
.map(|entry| {
|
||||
// the entry can be negative, we need to do calculation using signed int
|
||||
// and convert back to unsigned int for address
|
||||
((servicetable.address() as i64) + ((*entry >> 4) as i64)) as u64
|
||||
})
|
||||
.collect();
|
||||
Ok(ssdt)
|
||||
}
|
||||
|
290
src/object.rs
Normal file
290
src/object.rs
Normal file
@ -0,0 +1,290 @@
|
||||
use crate::address::Address;
|
||||
use crate::driver_state::DriverState;
|
||||
use crate::{get_device_type, to_epoch};
|
||||
use serde_json::{json, Value};
|
||||
use std::error::Error;
|
||||
use std::str::from_utf8;
|
||||
|
||||
type BoxResult<T> = Result<T, Box<dyn Error>>;
|
||||
|
||||
pub fn make_list_entry(d: &DriverState, a: Address, next: &str) -> BoxResult<Vec<Address>> {
|
||||
// `a` is the address to the _LIST_ENTRY
|
||||
// `next` is the _LIST_ENTRY field in the object
|
||||
// return a list of address for object
|
||||
let mut result: Vec<Address> = Vec::new();
|
||||
let list_offset = d.pdb_store.get_offset_r(next)?;
|
||||
|
||||
let mut ptr: u64 = d.deref_addr_new(a.address());
|
||||
while ptr != a.address() {
|
||||
let obj_ptr = Address::from_base(ptr - list_offset);
|
||||
ptr = d.decompose(&obj_ptr, &format!("{}.Flink", next))?;
|
||||
result.push(obj_ptr);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn make_eprocess(d: &DriverState, a: &Address) -> BoxResult<Value> {
|
||||
let createtime: u64 = d.decompose(a, "_EPROCESS.CreateTime")?;
|
||||
let exittime: u64 = d.decompose(a, "_EPROCESS.ExitTime")?;
|
||||
let pid: u64 = d.decompose(a, "_EPROCESS.UniqueProcessId")?;
|
||||
let ppid: u64 = d.decompose(a, "_EPROCESS.InheritedFromUniqueProcessId")?;
|
||||
let image_name: Vec<u8> = d.decompose_array(a, "_EPROCESS.ImageFileName", 15)?;
|
||||
let filename_ptr = d
|
||||
.address_of(a, "_EPROCESS.ImageFilePointer.FileName")
|
||||
.unwrap_or(0); // ImageFilePointer is after Windows 10 Anniversary
|
||||
|
||||
let eprocess_name = if let Ok(name) = from_utf8(&image_name) {
|
||||
name.to_string().trim_end_matches(char::from(0)).to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
let binary_path = d.get_unicode_string(filename_ptr).unwrap_or("".to_string());
|
||||
|
||||
let thread_head = d.address_of(a, "_EPROCESS.ThreadListHead")?;
|
||||
let threads: Vec<Value> = make_list_entry(
|
||||
d,
|
||||
Address::from_base(thread_head),
|
||||
"_ETHREAD.ThreadListEntry",
|
||||
)
|
||||
.unwrap_or(Vec::new())
|
||||
.iter()
|
||||
.map(|thread_addr| {
|
||||
make_ethread(d, thread_addr).unwrap_or(json!({})) // unlikely
|
||||
})
|
||||
.collect();
|
||||
|
||||
let c_t = to_epoch(createtime);
|
||||
let e_t = to_epoch(exittime);
|
||||
|
||||
Ok(json!({
|
||||
"address": format!("0x{:x}", a.address()),
|
||||
"type": "_EPROCESS",
|
||||
"pid": pid,
|
||||
"ppid": ppid,
|
||||
"name": eprocess_name,
|
||||
"path": binary_path,
|
||||
"threads": threads,
|
||||
"createtime": {
|
||||
"unix": c_t.timestamp(),
|
||||
"rfc2822": c_t.to_rfc2822()
|
||||
},
|
||||
"exittime": {
|
||||
"unix": e_t.timestamp(),
|
||||
"rfc2822": e_t.to_rfc2822(),
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn make_ethread(d: &DriverState, a: &Address) -> BoxResult<Value> {
|
||||
// let createtime: u64 = d.decompose(a, "_ETHREAD.CreateTime")?;
|
||||
// let exittime: u64 = d.decompose(a, "_ETHREAD.ExitTime")?;
|
||||
let pid: u64 = d.decompose(a, "_ETHREAD.Cid.UniqueProcess")?;
|
||||
let tid: u64 = d.decompose(a, "_ETHREAD.Cid.UniqueThread")?;
|
||||
let eprocess: u64 = d.decompose(a, "_ETHREAD.Tcb.Process")?;
|
||||
let flags: u32 = d.decompose(a, "_ETHREAD.CrossThreadFlags")?;
|
||||
let state = match d.decompose::<u8>(a, "_ETHREAD.Tcb.State")? {
|
||||
0 => "Initialized",
|
||||
1 => "Ready",
|
||||
2 => "Running",
|
||||
3 => "Standby",
|
||||
4 => "Terminated",
|
||||
5 => "Waiting",
|
||||
6 => "Transition",
|
||||
7 => "DeferredReady",
|
||||
8 => "GateWait",
|
||||
_ => "Unknown",
|
||||
};
|
||||
let wait = match d.decompose::<u8>(a, "_ETHREAD.Tcb.WaitReason")? {
|
||||
0 => "Executive",
|
||||
1 => "FreePage",
|
||||
2 => "PageIn",
|
||||
3 => "PoolAllocation",
|
||||
4 => "DelayExecution",
|
||||
5 => "Suspended",
|
||||
6 => "UserRequest",
|
||||
7 => "WrExecutive",
|
||||
8 => "WrFreePage",
|
||||
9 => "WrPageIn",
|
||||
10 => "WrPoolAllocation",
|
||||
11 => "WrDelayExecution",
|
||||
12 => "WrSuspended",
|
||||
13 => "WrUserRequest",
|
||||
14 => "WrEventPair",
|
||||
15 => "WrQueue",
|
||||
16 => "WrLpcReceive",
|
||||
17 => "WrLpcReply",
|
||||
18 => "WrVirtualMemory",
|
||||
19 => "WrPageOut",
|
||||
20 => "WrRendezvous",
|
||||
21 => "Spare2",
|
||||
22 => "Spare3",
|
||||
23 => "Spare4",
|
||||
24 => "Spare5",
|
||||
25 => "Spare6",
|
||||
26 => "WrKernel",
|
||||
27 => "WrResource",
|
||||
28 => "WrPushLock",
|
||||
29 => "WrMutex",
|
||||
30 => "WrQuantumEnd",
|
||||
31 => "WrDispatchInt",
|
||||
32 => "WrPreempted",
|
||||
33 => "WrYieldExecution",
|
||||
34 => "WrFastMutex",
|
||||
35 => "WrGuardedMutex",
|
||||
36 => "WrRundown",
|
||||
37 => "MaximumWaitReason",
|
||||
_ => "Unknown",
|
||||
};
|
||||
let name_ptr: u64 = d.address_of(a, "_ETHREAD.ThreadName").unwrap_or(0); // ThreadName is after Windows 10 Anniversary
|
||||
|
||||
let thread_name = if let Ok(name) = d.get_unicode_string(name_ptr) {
|
||||
name
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
// let c_t = to_epoch(createtime);
|
||||
// let e_t = to_epoch(exittime);
|
||||
|
||||
Ok(json!({
|
||||
"address": format!("0x{:x}", a.address()),
|
||||
"type": "_ETHREAD",
|
||||
"tid": tid,
|
||||
"pid": pid,
|
||||
"name": thread_name,
|
||||
"eprocess": format!("0x{:x}", eprocess),
|
||||
"state": state,
|
||||
"wait_reason": wait,
|
||||
"flags": {
|
||||
"raw": format!("0x{:x}", flags),
|
||||
"PS_CROSS_THREAD_FLAGS_TERMINATED": flags & 1 != 0,
|
||||
"PS_CROSS_THREAD_FLAGS_DEADTHREAD": flags & 2 != 0,
|
||||
"PS_CROSS_THREAD_FLAGS_HIDEFROMDBG": flags & 3 != 0,
|
||||
"PS_CROSS_THREAD_FLAGS_IMPERSONATING": flags & 4 != 0,
|
||||
"PS_CROSS_THREAD_FLAGS_SYSTEM": flags & 5 != 0,
|
||||
"PS_CROSS_THREAD_FLAGS_HARD_ERRORS_DISABLED": flags & 6 != 0,
|
||||
"PS_CROSS_THREAD_FLAGS_BREAK_ON_TERMINATION": flags & 7 != 0,
|
||||
"PS_CROSS_THREAD_FLAGS_SKIP_CREATION_MSG": flags & 8 != 0,
|
||||
"PS_CROSS_THREAD_FLAGS_SKIP_TERMINATION_MSG": flags & 9 != 0,
|
||||
},
|
||||
// "createtime": {
|
||||
// "unix": c_t.timestamp(),
|
||||
// "rfc2822": c_t.to_rfc2822()
|
||||
// },
|
||||
// "exittime": {
|
||||
// "unix": e_t.timestamp(),
|
||||
// "rfc2822": e_t.to_rfc2822(),
|
||||
// }
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn make_driver(d: &DriverState, a: &Address) -> BoxResult<Value> {
|
||||
let devicename_ptr = d.address_of(a, "_DRIVER_OBJECT.DriverName")?;
|
||||
let servicekey_ptr = d.address_of(a, "_DRIVER_OBJECT.DriverExtension.ServiceKeyName")?;
|
||||
let hardware_ptr: u64 = d.decompose(a, "_DRIVER_OBJECT.HardwareDatabase")?;
|
||||
let major_function: Vec<u64> = d.decompose_array(a, "_DRIVER_OBJECT.MajorFunction", 28)?;
|
||||
let start: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverStart")?;
|
||||
let init: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverInit")?;
|
||||
let unload: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverUnload")?;
|
||||
let size: u64 = d.decompose(a, "_DRIVER_OBJECT.DriverSize")?;
|
||||
|
||||
let devicename = d
|
||||
.get_unicode_string(devicename_ptr)
|
||||
.unwrap_or("".to_string());
|
||||
let hardware = d.get_unicode_string(hardware_ptr).unwrap_or("".to_string());
|
||||
let servicekey = d
|
||||
.get_unicode_string(servicekey_ptr)
|
||||
.unwrap_or("".to_string());
|
||||
|
||||
// device tree walk
|
||||
let devices = {
|
||||
let mut driver_devices: Vec<Value> = Vec::new();
|
||||
let mut device_ptr: u64 = d.decompose(a, "_DRIVER_OBJECT.DeviceObject")?;
|
||||
while device_ptr != 0 {
|
||||
let addr = Address::from_base(device_ptr);
|
||||
let device_type: u32 = d.decompose(&addr, "_DEVICE_OBJECT.DeviceType")?;
|
||||
|
||||
// get attached devices
|
||||
let mut attached_ptr: u64 = d.decompose(&addr, "_DEVICE_OBJECT.AttachedDevice")?;
|
||||
let mut attached_devices: Vec<Value> = Vec::new();
|
||||
while attached_ptr != 0 {
|
||||
let attached = Address::from_base(attached_ptr);
|
||||
let attached_device_type: u32 =
|
||||
d.decompose(&attached, "_DEVICE_OBJECT.DeviceType")?;
|
||||
attached_devices.push(json!({
|
||||
"address": format!("0x{:x}", attached_ptr),
|
||||
"type": "_DEVICE_OBJECT",
|
||||
"devicetype": get_device_type(attached_device_type)
|
||||
}));
|
||||
attached_ptr = d.decompose(&attached, "_DEVICE_OBJECT.AttachedDevice")?;
|
||||
}
|
||||
driver_devices.push(json!({
|
||||
"address": format!("0x{:x}", device_ptr),
|
||||
"type": "_DEVICE_OBJECT",
|
||||
"devicetype": get_device_type(device_type),
|
||||
"attached": attached_devices
|
||||
}));
|
||||
device_ptr = d.decompose(&addr, "_DEVICE_OBJECT.NextDevice")?;
|
||||
}
|
||||
driver_devices
|
||||
};
|
||||
|
||||
Ok(json!({
|
||||
"address": format!("0x{:x}", a.address()),
|
||||
"type": "_DRIVER_OBJECT",
|
||||
"device": devicename,
|
||||
"hardware": hardware,
|
||||
"major_function": major_function.into_iter()
|
||||
.map(|func| format!("0x{:x}", func))
|
||||
.collect::<Vec<String>>(),
|
||||
"servicekey": servicekey,
|
||||
"start": format!("0x{:x}", start),
|
||||
"init": format!("0x{:x}", init),
|
||||
"unload": format!("0x{:x}", unload),
|
||||
"size": format!("0x{:x}", size),
|
||||
"devicetree": devices
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn make_ldr(d: &DriverState, a: &Address) -> BoxResult<Value> {
|
||||
let dllbase: u64 = d.decompose(a, "_LDR_DATA_TABLE_ENTRY.DllBase")?;
|
||||
let entry: u64 = d.decompose(a, "_LDR_DATA_TABLE_ENTRY.EntryPoint")?;
|
||||
let size: u64 = d.decompose(a, "_LDR_DATA_TABLE_ENTRY.SizeOfImage")?;
|
||||
let fullname_ptr = d.address_of(a, "_LDR_DATA_TABLE_ENTRY.FullDllName")?;
|
||||
let basename_ptr = d.address_of(a, "_LDR_DATA_TABLE_ENTRY.BaseDllName")?;
|
||||
|
||||
let fullname = d.get_unicode_string(fullname_ptr).unwrap_or("".to_string());
|
||||
let basename = d.get_unicode_string(basename_ptr).unwrap_or("".to_string());
|
||||
|
||||
let ldr_load: Vec<String> =
|
||||
make_list_entry(d, a.clone(), "_LDR_DATA_TABLE_ENTRY.InLoadOrderLinks")?
|
||||
.iter()
|
||||
.map(|x| format!("0x{:x}", x.address()))
|
||||
.collect();
|
||||
let ldr_mem: Vec<String> =
|
||||
make_list_entry(d, a.clone(), "_LDR_DATA_TABLE_ENTRY.InMemoryOrderLinks")?
|
||||
.iter()
|
||||
.map(|x| format!("0x{:x}", x.address()))
|
||||
.collect();
|
||||
let ldr_init: Vec<String> = make_list_entry(
|
||||
d,
|
||||
a.clone(),
|
||||
"_LDR_DATA_TABLE_ENTRY.InInitializationOrderLinks",
|
||||
)?
|
||||
.iter()
|
||||
.map(|x| format!("0x{:x}", x.address()))
|
||||
.collect();
|
||||
|
||||
Ok(json!({
|
||||
"address": format!("0x{:x}", a.address()),
|
||||
"type": "_LDR_DATA_TABLE_ENTRY",
|
||||
"dllbase": format!("0x{:x}", dllbase),
|
||||
"entry": format!("0x{:x}", entry),
|
||||
"size": format!("0x{:x}", size),
|
||||
"FullName": fullname,
|
||||
"BaseName": basename,
|
||||
"ldr_load": ldr_load,
|
||||
"ldr_mem": ldr_mem,
|
||||
"ldr_init": ldr_init
|
||||
}))
|
||||
}
|
443
src/pdb_store.rs
443
src/pdb_store.rs
@ -1,18 +1,18 @@
|
||||
use std::error::Error;
|
||||
use std::io;
|
||||
use std::io::{Read};
|
||||
use std::path::{PathBuf};
|
||||
use std::fs::File;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use app_dirs::{app_dir, AppDataType};
|
||||
use pdb::{
|
||||
PDB, SymbolData, TypeData, ClassType, ModifierType, Rva,
|
||||
FallibleIterator, TypeFinder, TypeIndex
|
||||
ClassType, FallibleIterator, ModifierType, Rva, SymbolData, TypeData, TypeFinder, TypeIndex,
|
||||
PDB,
|
||||
};
|
||||
|
||||
use app_dirs::{AppInfo, AppDataType, app_dir};
|
||||
|
||||
const APP_INFO: AppInfo = AppInfo { name: "lpus", author: "nganhkhoa" };
|
||||
use crate::address::Address;
|
||||
use crate::APP_INFO;
|
||||
|
||||
const KERNEL_PDB_NAME: &str = "ntkrnlmp.pdb";
|
||||
const NTOSKRNL_PATH: &str = "C:\\Windows\\System32\\ntoskrnl.exe";
|
||||
@ -25,7 +25,7 @@ type StructStore = HashMap<String, HashMap<String, (String, u64)>>;
|
||||
|
||||
pub struct PdbStore {
|
||||
pub symbols: SymbolStore,
|
||||
pub structs: StructStore
|
||||
pub structs: StructStore,
|
||||
}
|
||||
|
||||
impl PdbStore {
|
||||
@ -38,25 +38,22 @@ impl PdbStore {
|
||||
if name.contains(".") {
|
||||
let v: Vec<&str> = name.split_terminator('.').collect();
|
||||
match self.structs.get(v[0]) {
|
||||
Some(member_info) => {
|
||||
match member_info.get(v[1]) {
|
||||
Some(member_info) => match member_info.get(v[1]) {
|
||||
Some((_memtype, offset)) => Some(*offset),
|
||||
None => None
|
||||
}
|
||||
None => None,
|
||||
},
|
||||
None => None
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
match self.symbols.get(name) {
|
||||
Some(offset) => Some(*offset),
|
||||
None => None
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn addr_decompose(&self, addr: u64, full_name: &str) -> BoxResult<u64>{
|
||||
pub fn addr_decompose(&self, addr: u64, full_name: &str) -> BoxResult<u64> {
|
||||
if !full_name.contains(".") {
|
||||
return Err("Not decomposable".into());
|
||||
}
|
||||
@ -64,79 +61,143 @@ impl PdbStore {
|
||||
let mut name_part: Vec<&str> = full_name.split_terminator('.').collect();
|
||||
let mut next: Vec<_> = name_part.drain(2..).collect();
|
||||
match self.structs.get(name_part[0]) {
|
||||
Some(member_info) => {
|
||||
match member_info.get(name_part[1]) {
|
||||
Some(member_info) => match member_info.get(name_part[1]) {
|
||||
Some((memtype, offset)) => {
|
||||
if next.len() != 0 {
|
||||
if memtype.contains("*") {
|
||||
return Err(format!("Cannot dereference pointer at {} {}", memtype, name_part[1]).into());
|
||||
return Err(format!(
|
||||
"Cannot dereference pointer at {} {}",
|
||||
memtype, name_part[1]
|
||||
)
|
||||
.into());
|
||||
}
|
||||
next.insert(0, memtype);
|
||||
self.addr_decompose(addr + *offset, &next.join("."))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Ok(addr + *offset)
|
||||
}
|
||||
},
|
||||
None => Err(format!("Not found member {}", name_part[1]).into())
|
||||
}
|
||||
None => Err(format!("Not found member {}", name_part[1]).into()),
|
||||
},
|
||||
None => Err(format!("Struct {} not found", name_part[0]).into())
|
||||
None => Err(format!("Struct {} not found", name_part[0]).into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decompose(&self, source: &Address, full_name: &str) -> BoxResult<Address> {
|
||||
// println!("decompose {}", full_name);
|
||||
if !full_name.contains(".") {
|
||||
return Err("Not decomposable".into());
|
||||
}
|
||||
|
||||
let mut name_part: Vec<&str> = full_name.split_terminator('.').collect();
|
||||
let mut next: Vec<_> = name_part.drain(2..).collect();
|
||||
let member_info = self
|
||||
.structs
|
||||
.get(name_part[0])
|
||||
.ok_or(format!("No struct {}", name_part[0]))?;
|
||||
let (memtype, offset) = member_info
|
||||
.get(name_part[1])
|
||||
.ok_or(format!("No member {} in {}", name_part[1], name_part[0]))?;
|
||||
|
||||
if next.len() == 0 {
|
||||
return Ok(source.clone() + *offset);
|
||||
}
|
||||
if memtype.contains("*") {
|
||||
let mut t = memtype.clone(); // remove *
|
||||
t.pop();
|
||||
next.insert(0, &t);
|
||||
let p = Address::from_ptr(source.clone() + *offset);
|
||||
self.decompose(&p, &next.join("."))
|
||||
} else {
|
||||
next.insert(0, memtype);
|
||||
self.decompose(&(source.clone() + *offset), &next.join("."))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print_default_information(&self) {
|
||||
let need_symbols = [
|
||||
"PsLoadedModuleList", "PsActiveProcessHead", "KeNumberNodes",
|
||||
"PoolBigPageTable", "PoolBigPageTableSize",
|
||||
"PsLoadedModuleList",
|
||||
"PsActiveProcessHead",
|
||||
"KeNumberNodes",
|
||||
"PoolBigPageTable",
|
||||
"PoolBigPageTableSize",
|
||||
// "PoolVector", "ExpNumberOfNonPagedPools",
|
||||
"KdDebuggerDataBlock", "MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP
|
||||
"MiNonPagedPoolStartAligned", "MiNonPagedPoolEnd", "MiNonPagedPoolBitMap", // Windows 7, 8
|
||||
"MiNonPagedPoolBitMap", "MiNonPagedPoolVaBitMap",
|
||||
"MiState" // Windows 10
|
||||
"KdDebuggerDataBlock",
|
||||
"MmNonPagedPoolStart",
|
||||
"MmNonPagedPoolEnd", // Windows XP
|
||||
"MiNonPagedPoolStartAligned",
|
||||
"MiNonPagedPoolEnd",
|
||||
"MiNonPagedPoolBitMap", // Windows 7, 8
|
||||
"MiNonPagedPoolBitMap",
|
||||
"MiNonPagedPoolVaBitMap",
|
||||
"MiState", // Windows 10
|
||||
];
|
||||
|
||||
let mut need_structs = HashMap::new();
|
||||
need_structs.insert("_POOL_HEADER", vec![
|
||||
"struct_size",
|
||||
"PoolType", "BlockSize", "PoolTag"
|
||||
]);
|
||||
need_structs.insert(
|
||||
"_POOL_HEADER",
|
||||
vec!["struct_size", "PoolType", "BlockSize", "PoolTag"],
|
||||
);
|
||||
need_structs.insert("_PEB", vec![]);
|
||||
need_structs.insert("_LIST_ENTRY", vec![
|
||||
"Flink", "Blink"
|
||||
]);
|
||||
need_structs.insert("_FILE_OBJECT", vec![
|
||||
"FileName"
|
||||
]);
|
||||
need_structs.insert("_EPROCESS", vec![
|
||||
need_structs.insert("_LIST_ENTRY", vec!["Flink", "Blink"]);
|
||||
need_structs.insert("_FILE_OBJECT", vec!["FileName"]);
|
||||
need_structs.insert(
|
||||
"_EPROCESS",
|
||||
vec![
|
||||
"struct_size",
|
||||
"UniqueProcessId", "ActiveProcessLinks", "CreateTime",
|
||||
"Peb", "ImageFilePointer", "ImageFileName", "ThreadListHead"
|
||||
]);
|
||||
need_structs.insert("_KDDEBUGGER_DATA64", vec![
|
||||
"MmNonPagedPoolStart", "MmNonPagedPoolEnd", // Windows XP
|
||||
]);
|
||||
"UniqueProcessId",
|
||||
"ActiveProcessLinks",
|
||||
"CreateTime",
|
||||
"Peb",
|
||||
"ImageFilePointer",
|
||||
"ImageFileName",
|
||||
"ThreadListHead",
|
||||
],
|
||||
);
|
||||
need_structs.insert(
|
||||
"_KDDEBUGGER_DATA64",
|
||||
vec![
|
||||
"MmNonPagedPoolStart",
|
||||
"MmNonPagedPoolEnd", // Windows XP
|
||||
],
|
||||
);
|
||||
need_structs.insert("_POOL_TRACKER_BIG_PAGES", vec![]);
|
||||
|
||||
// these struct supports finding NonPagedPool{First,Last}Va in windows 10
|
||||
need_structs.insert("_MI_SYSTEM_INFORMATION", vec![
|
||||
need_structs.insert(
|
||||
"_MI_SYSTEM_INFORMATION",
|
||||
vec![
|
||||
"Hardware", // windows 10 2016+
|
||||
"SystemNodeInformation" // windows 10 2015
|
||||
]);
|
||||
need_structs.insert("_MI_HARDWARE_STATE", vec![
|
||||
"SystemNodeInformation", // windows 10 2015
|
||||
],
|
||||
);
|
||||
need_structs.insert(
|
||||
"_MI_HARDWARE_STATE",
|
||||
vec![
|
||||
"SystemNodeInformation", // till windows 10 1900
|
||||
"SystemNodeNonPagedPool" // windows insider, 2020
|
||||
]);
|
||||
need_structs.insert("_MI_SYSTEM_NODE_INFORMATION", vec![ // till windows 10 1900
|
||||
"NonPagedPoolFirstVa", "NonPagedPoolLastVa",
|
||||
"SystemNodeNonPagedPool", // windows insider, 2020
|
||||
],
|
||||
);
|
||||
need_structs.insert(
|
||||
"_MI_SYSTEM_NODE_INFORMATION",
|
||||
vec![
|
||||
// till windows 10 1900
|
||||
"NonPagedPoolFirstVa",
|
||||
"NonPagedPoolLastVa",
|
||||
"NonPagedBitMap", // missing on windows 10 1900+
|
||||
"DynamicBitMapNonPagedPool" // some weird field
|
||||
]);
|
||||
need_structs.insert("_MI_SYSTEM_NODE_NONPAGED_POOL", vec![ // windows insider, 2020
|
||||
"NonPagedPoolFirstVa", "NonPagedPoolLastVa",
|
||||
"DynamicBitMapNonPagedPool" // some weird field
|
||||
]);
|
||||
"DynamicBitMapNonPagedPool", // some weird field
|
||||
],
|
||||
);
|
||||
need_structs.insert(
|
||||
"_MI_SYSTEM_NODE_NONPAGED_POOL",
|
||||
vec![
|
||||
// windows insider, 2020
|
||||
"NonPagedPoolFirstVa",
|
||||
"NonPagedPoolLastVa",
|
||||
"DynamicBitMapNonPagedPool", // some weird field
|
||||
],
|
||||
);
|
||||
need_structs.insert("_MI_DYNAMIC_BITMAP", vec![]);
|
||||
need_structs.insert("_RTL_BITMAP", vec![]); // windows 10 until 2020
|
||||
need_structs.insert("_RTL_BITMAP_EX", vec![]); // windows insider, 2020
|
||||
@ -153,36 +214,60 @@ impl PdbStore {
|
||||
Some(member_info) => {
|
||||
for &member in members {
|
||||
match member_info.get(member) {
|
||||
Some((memtype, offset)) =>
|
||||
println!("0x{:x} {} {}.{}", offset, memtype, struct_name, member),
|
||||
Some((memtype, offset)) => {
|
||||
println!("0x{:x} {} {}.{}", offset, memtype, struct_name, member)
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dt(&self, struct_name: &str) -> BoxResult<()> {
|
||||
let member_info = self
|
||||
.structs
|
||||
.get(struct_name)
|
||||
.ok_or(format!("no struct named {}", struct_name))?;
|
||||
let (_, struct_size) = member_info.get("struct_size").ok_or("")?;
|
||||
println!("// 0x{:x} bytes", struct_size);
|
||||
println!("struct {} {{", struct_name);
|
||||
|
||||
// Vec<(offset, type, name)>
|
||||
let mut members: Vec<(u64, String, String)> = Vec::new();
|
||||
for (name, (t, offset)) in member_info.iter() {
|
||||
if name != "struct_size" {
|
||||
members.push((*offset, t.to_string(), name.to_string()));
|
||||
}
|
||||
}
|
||||
members.sort_by(|(o1, _, _), (o2, _, _)| o1.partial_cmp(o2).unwrap());
|
||||
|
||||
for (offset, memtype, member) in members.iter() {
|
||||
println!(" +0x{:x} {} {};", offset, memtype, member);
|
||||
}
|
||||
|
||||
println!("}} // {}", struct_name);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String {
|
||||
match type_finder.find(*typ).unwrap().parse().unwrap() {
|
||||
TypeData::Class(ct) => {
|
||||
format!("{}", ct.name.to_string())
|
||||
},
|
||||
TypeData::Primitive(pt) => {
|
||||
format!("{:?}", pt.kind)
|
||||
},
|
||||
TypeData::Pointer(pt) => {
|
||||
format!("{}*", get_type_as_str(type_finder, &pt.underlying_type))
|
||||
},
|
||||
TypeData::Class(ct) => format!("{}", ct.name.to_string()),
|
||||
TypeData::Primitive(pt) => format!("{:?}", pt.kind),
|
||||
TypeData::Pointer(pt) => format!("{}*", get_type_as_str(type_finder, &pt.underlying_type)),
|
||||
TypeData::StaticMember(st) => {
|
||||
format!("static {}", get_type_as_str(type_finder, &st.field_type))
|
||||
},
|
||||
}
|
||||
TypeData::Array(at) => {
|
||||
format!("{}{:?}",
|
||||
get_type_as_str(type_finder, &at.element_type), /* get_type_as_str(type_finder, &at.indexing_type), */ at.dimensions)
|
||||
},
|
||||
format!(
|
||||
"{}{:?}",
|
||||
get_type_as_str(type_finder, &at.element_type),
|
||||
/* get_type_as_str(type_finder, &at.indexing_type), */ at.dimensions
|
||||
)
|
||||
}
|
||||
// TypeData::Enumeration(et) => {
|
||||
// format!("enumeration")
|
||||
// },
|
||||
@ -210,28 +295,82 @@ fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String {
|
||||
TypeData::Procedure(pt) => {
|
||||
let rettype = match pt.return_type {
|
||||
Some(rt) => get_type_as_str(type_finder, &rt),
|
||||
_ => "UNKNOWN".to_string()
|
||||
_ => "UNKNOWN".to_string(),
|
||||
};
|
||||
format!("{}({})", rettype, get_type_as_str(type_finder, &pt.argument_list))
|
||||
},
|
||||
TypeData::Modifier(mt) => {
|
||||
match mt {
|
||||
ModifierType { constant: true, volatile: true, unaligned: true, .. } =>
|
||||
format!("const volatile unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: true, volatile: true, unaligned: false, .. } =>
|
||||
format!("const volatile {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: true, volatile: false, unaligned: true, .. } =>
|
||||
format!("const unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: false, volatile: true, unaligned: true, .. } =>
|
||||
format!("volatile unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: true, volatile: false, unaligned: false, .. } =>
|
||||
format!("const {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: false, volatile: true, unaligned: false, .. } =>
|
||||
format!("volatile {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
ModifierType { constant: false, volatile: false, unaligned: true, .. } =>
|
||||
format!("unaligned {}", get_type_as_str(type_finder, &mt.underlying_type)),
|
||||
_ => format!("modifier {}", get_type_as_str(type_finder, &mt.underlying_type))
|
||||
format!(
|
||||
"{}({})",
|
||||
rettype,
|
||||
get_type_as_str(type_finder, &pt.argument_list)
|
||||
)
|
||||
}
|
||||
TypeData::Modifier(mt) => match mt {
|
||||
ModifierType {
|
||||
constant: true,
|
||||
volatile: true,
|
||||
unaligned: true,
|
||||
..
|
||||
} => format!(
|
||||
"const volatile unaligned {}",
|
||||
get_type_as_str(type_finder, &mt.underlying_type)
|
||||
),
|
||||
ModifierType {
|
||||
constant: true,
|
||||
volatile: true,
|
||||
unaligned: false,
|
||||
..
|
||||
} => format!(
|
||||
"const volatile {}",
|
||||
get_type_as_str(type_finder, &mt.underlying_type)
|
||||
),
|
||||
ModifierType {
|
||||
constant: true,
|
||||
volatile: false,
|
||||
unaligned: true,
|
||||
..
|
||||
} => format!(
|
||||
"const unaligned {}",
|
||||
get_type_as_str(type_finder, &mt.underlying_type)
|
||||
),
|
||||
ModifierType {
|
||||
constant: false,
|
||||
volatile: true,
|
||||
unaligned: true,
|
||||
..
|
||||
} => format!(
|
||||
"volatile unaligned {}",
|
||||
get_type_as_str(type_finder, &mt.underlying_type)
|
||||
),
|
||||
ModifierType {
|
||||
constant: true,
|
||||
volatile: false,
|
||||
unaligned: false,
|
||||
..
|
||||
} => format!(
|
||||
"const {}",
|
||||
get_type_as_str(type_finder, &mt.underlying_type)
|
||||
),
|
||||
ModifierType {
|
||||
constant: false,
|
||||
volatile: true,
|
||||
unaligned: false,
|
||||
..
|
||||
} => format!(
|
||||
"volatile {}",
|
||||
get_type_as_str(type_finder, &mt.underlying_type)
|
||||
),
|
||||
ModifierType {
|
||||
constant: false,
|
||||
volatile: false,
|
||||
unaligned: true,
|
||||
..
|
||||
} => format!(
|
||||
"unaligned {}",
|
||||
get_type_as_str(type_finder, &mt.underlying_type)
|
||||
),
|
||||
_ => format!(
|
||||
"modifier {}",
|
||||
get_type_as_str(type_finder, &mt.underlying_type)
|
||||
),
|
||||
},
|
||||
// TypeData::Union(ut) => {
|
||||
// format!("union")
|
||||
@ -239,25 +378,21 @@ fn get_type_as_str(type_finder: &TypeFinder, typ: &TypeIndex) -> String {
|
||||
// TypeData::Bitfield(bft) => {
|
||||
// format!("bitfield")
|
||||
// },
|
||||
TypeData::FieldList(_flt) => {
|
||||
format!("fieldlist")
|
||||
},
|
||||
TypeData::FieldList(_flt) => format!("fieldlist"),
|
||||
// TypeData::ArgumentList(alt) => {
|
||||
// format!("arglist")
|
||||
// },
|
||||
// TypeData::MethodList(mlt) => {
|
||||
// format!("methodlist")
|
||||
// },
|
||||
unk => {
|
||||
match unk.name() {
|
||||
unk => match unk.name() {
|
||||
Some(s) => format!("{}", s.to_string()),
|
||||
_ => "UNNOWN".to_string()
|
||||
}
|
||||
}
|
||||
_ => "UNNOWN".to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn get_guid_age(exe_file: &str) -> BoxResult<(String, u32)>{
|
||||
fn get_guid_age(exe_file: &str) -> BoxResult<(String, u32)> {
|
||||
// TODO: Check file existance
|
||||
let mut file = File::open(exe_file)?;
|
||||
|
||||
@ -275,22 +410,36 @@ fn get_guid_age(exe_file: &str) -> BoxResult<(String, u32)>{
|
||||
buffiter.next().unwrap(),
|
||||
buffiter.next().unwrap(),
|
||||
buffiter.next().unwrap(),
|
||||
].concat();
|
||||
]
|
||||
.concat();
|
||||
|
||||
// guid to hex string
|
||||
let guid = (vec![
|
||||
raw_guid[3], raw_guid[2], raw_guid[1], raw_guid[0],
|
||||
raw_guid[5], raw_guid[4],
|
||||
raw_guid[7], raw_guid[6],
|
||||
raw_guid[8], raw_guid[9], raw_guid[10], raw_guid[11],
|
||||
raw_guid[12], raw_guid[13], raw_guid[14], raw_guid[15],
|
||||
].iter().map(|b| format!("{:02X}", b)).collect::<Vec<String>>()).join("");
|
||||
raw_guid[3],
|
||||
raw_guid[2],
|
||||
raw_guid[1],
|
||||
raw_guid[0],
|
||||
raw_guid[5],
|
||||
raw_guid[4],
|
||||
raw_guid[7],
|
||||
raw_guid[6],
|
||||
raw_guid[8],
|
||||
raw_guid[9],
|
||||
raw_guid[10],
|
||||
raw_guid[11],
|
||||
raw_guid[12],
|
||||
raw_guid[13],
|
||||
raw_guid[14],
|
||||
raw_guid[15],
|
||||
]
|
||||
.iter()
|
||||
.map(|b| format!("{:02X}", b))
|
||||
.collect::<Vec<String>>())
|
||||
.join("");
|
||||
|
||||
// next 4 bytes is age, in little endian
|
||||
let raw_age = buffiter.next().unwrap();
|
||||
let age = u32::from_le_bytes([
|
||||
raw_age[0], raw_age[1], raw_age[2], raw_age[3]
|
||||
]);
|
||||
let age = u32::from_le_bytes([raw_age[0], raw_age[1], raw_age[2], raw_age[3]]);
|
||||
|
||||
Ok((guid, age))
|
||||
}
|
||||
@ -304,14 +453,20 @@ fn pdb_exists(pdbname: &str, guid: &str, age: u32) -> BoxResult<(bool, PathBuf)>
|
||||
// |--file.pdb
|
||||
// |--|--GUID
|
||||
// |--|--|--file.pdb
|
||||
let mut pdb_location = app_dir(AppDataType::UserData, &APP_INFO,
|
||||
&format!("{}/{}/{}", pdbname, guid, age))?;
|
||||
let mut pdb_location = app_dir(
|
||||
AppDataType::UserData,
|
||||
&APP_INFO,
|
||||
&format!("{}/{}/{}", pdbname, guid, age),
|
||||
)?;
|
||||
pdb_location.push(pdbname);
|
||||
Ok((pdb_location.exists(), pdb_location))
|
||||
}
|
||||
|
||||
fn download_pdb(pdbname: &str, guid: &str, age: u32, outfile: &PathBuf) -> BoxResult<()> {
|
||||
let downloadurl = format!("{}/{}/{}{:X}/{}", PDB_SERVER_PATH, pdbname, guid, age, pdbname);
|
||||
let downloadurl = format!(
|
||||
"{}/{}/{}{:X}/{}",
|
||||
PDB_SERVER_PATH, pdbname, guid, age, pdbname
|
||||
);
|
||||
println!("{}", downloadurl);
|
||||
|
||||
let mut resp = reqwest::blocking::get(&downloadurl)?;
|
||||
@ -336,8 +491,12 @@ pub fn parse_pdb() -> BoxResult<PdbStore> {
|
||||
|
||||
let info = pdb.pdb_information()?;
|
||||
let dbi = pdb.debug_information()?;
|
||||
println!("PDB for {}, guid: {}, age: {}\n",
|
||||
dbi.machine_type().unwrap(), info.guid, dbi.age().unwrap_or(0));
|
||||
println!(
|
||||
"PDB for {}, guid: {}, age: {}\n",
|
||||
dbi.machine_type().unwrap(),
|
||||
info.guid,
|
||||
dbi.age().unwrap_or(0)
|
||||
);
|
||||
|
||||
let type_information = pdb.type_information()?;
|
||||
let mut type_finder = type_information.type_finder();
|
||||
@ -356,9 +515,8 @@ pub fn parse_pdb() -> BoxResult<PdbStore> {
|
||||
let name = symbol.name().unwrap().to_string();
|
||||
let Rva(rva) = data.offset.to_rva(&addr_map).unwrap_or_default();
|
||||
symbol_extracted.insert(format!("{}", name), rva as u64);
|
||||
},
|
||||
_ => {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,29 +524,50 @@ pub fn parse_pdb() -> BoxResult<PdbStore> {
|
||||
iter = type_information.iter();
|
||||
while let Some(typ) = iter.next().unwrap() {
|
||||
match typ.parse() {
|
||||
Ok(TypeData::Class(ClassType {name, fields: Some(fields), size, ..})) => {
|
||||
Ok(TypeData::Class(ClassType {
|
||||
name,
|
||||
fields: Some(fields),
|
||||
size,
|
||||
..
|
||||
})) => {
|
||||
let mut struct_fields = HashMap::new();
|
||||
struct_fields.insert("struct_size".to_string(), ("u32".to_string(), size as u64));
|
||||
struct_fields.insert("struct_size".to_string(), ("U32".to_string(), size as u64));
|
||||
match type_finder.find(fields).unwrap().parse().unwrap() {
|
||||
TypeData::FieldList(list) => {
|
||||
for field in list.fields {
|
||||
if let TypeData::Member(member) = field {
|
||||
let mem_typ = get_type_as_str(&type_finder, &member.field_type);
|
||||
struct_fields.insert(
|
||||
format!("{}", member.name), (mem_typ, member.offset as u64));
|
||||
format!("{}", member.name),
|
||||
(mem_typ, member.offset as u64),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
struct_extracted.insert(format!("{}", name), struct_fields);
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// https://github.com/Zer0Mem0ry/ntoskrnl/blob/master/Include/mm.h#L1107
|
||||
let mut unload_driver_member = HashMap::new();
|
||||
unload_driver_member.insert("struct_size".to_string(), ("U32".to_string(), 0x30));
|
||||
unload_driver_member.insert("Name".to_string(), ("_UNICODE_STRING".to_string(), 0));
|
||||
unload_driver_member.insert("StartAddress".to_string(), ("PVOID".to_string(), 0x10));
|
||||
unload_driver_member.insert("EndAddress".to_string(), ("PVOID".to_string(), 0x18));
|
||||
unload_driver_member.insert(
|
||||
"CurrentTime".to_string(),
|
||||
("_LARGE_INTEGER".to_string(), 0x20),
|
||||
);
|
||||
struct_extracted.insert("_UNLOADED_DRIVERS".to_string(), unload_driver_member);
|
||||
}
|
||||
|
||||
Ok(PdbStore {
|
||||
symbols: symbol_extracted,
|
||||
structs: struct_extracted
|
||||
structs: struct_extracted,
|
||||
})
|
||||
}
|
||||
|
243
src/windows.rs
243
src/windows.rs
@ -1,42 +1,66 @@
|
||||
use std::ffi::{c_void, CString};
|
||||
use std::mem::{transmute, size_of_val};
|
||||
use std::mem::{size_of_val, transmute};
|
||||
use std::ptr::null_mut;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use app_dirs::{app_dir, AppDataType};
|
||||
use widestring::U16CString;
|
||||
|
||||
use winapi::shared::ntdef::*;
|
||||
use crate::APP_INFO;
|
||||
|
||||
use winapi::shared::minwindef::{DWORD, HKEY, HMODULE};
|
||||
use winapi::shared::ntdef::*;
|
||||
use winapi::um::winnt::{
|
||||
SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, TOKEN_ADJUST_PRIVILEGES, LUID_AND_ATTRIBUTES,
|
||||
REG_DWORD, REG_SZ, REG_OPTION_NON_VOLATILE, KEY_WRITE,
|
||||
PRTL_OSVERSIONINFOW, OSVERSIONINFOW,
|
||||
FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE
|
||||
FILE_ATTRIBUTE_NORMAL, GENERIC_READ, GENERIC_WRITE, KEY_WRITE, LUID_AND_ATTRIBUTES,
|
||||
OSVERSIONINFOW, PRTL_OSVERSIONINFOW, REG_DWORD, REG_OPTION_NON_VOLATILE, REG_SZ,
|
||||
SE_PRIVILEGE_ENABLED, TOKEN_ADJUST_PRIVILEGES, TOKEN_PRIVILEGES,
|
||||
};
|
||||
|
||||
use winapi::um::ioapiset::{DeviceIoControl};
|
||||
use winapi::um::errhandlingapi::{GetLastError};
|
||||
use winapi::um::errhandlingapi::GetLastError;
|
||||
use winapi::um::fileapi::{CreateFileA, CREATE_ALWAYS};
|
||||
use winapi::um::handleapi::{INVALID_HANDLE_VALUE, CloseHandle};
|
||||
use winapi::um::libloaderapi::{LoadLibraryA, GetProcAddress};
|
||||
use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
|
||||
use winapi::um::ioapiset::DeviceIoControl;
|
||||
use winapi::um::libloaderapi::{GetProcAddress, LoadLibraryA};
|
||||
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken};
|
||||
use winapi::um::sysinfoapi::{GetTickCount64};
|
||||
use winapi::um::securitybaseapi::{AdjustTokenPrivileges};
|
||||
use winapi::um::winbase::{LookupPrivilegeValueA};
|
||||
use winapi::um::winreg::{RegCreateKeyExA, RegSetValueExA, RegCloseKey, HKEY_LOCAL_MACHINE};
|
||||
use winapi::um::securitybaseapi::AdjustTokenPrivileges;
|
||||
use winapi::um::sysinfoapi::GetTickCount64;
|
||||
use winapi::um::winbase::LookupPrivilegeValueA;
|
||||
use winapi::um::winreg::{RegCloseKey, RegCreateKeyExA, RegSetValueExA, HKEY_LOCAL_MACHINE};
|
||||
|
||||
const STR_DRIVER_REGISTRY_PATH: &str = "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\lpus";
|
||||
const STR_DRIVER_REGISTRY_PATH: &str =
|
||||
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\lpus";
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
|
||||
pub enum WindowsVersion {
|
||||
Windows7,
|
||||
Windows8,
|
||||
Windows10Legacy,
|
||||
Windows10_2015,
|
||||
Windows10_2016,
|
||||
Windows10_2017,
|
||||
Windows10_2018,
|
||||
Windows10_2019,
|
||||
Windows10_2020,
|
||||
Windows10FastRing,
|
||||
Windows10VersionUnknown
|
||||
WindowsFastRing,
|
||||
WindowsUnknown,
|
||||
}
|
||||
|
||||
impl WindowsVersion {
|
||||
pub fn not_supported(self) -> bool {
|
||||
match self {
|
||||
WindowsVersion::Windows10Legacy
|
||||
| WindowsVersion::Windows10_2015
|
||||
| WindowsVersion::Windows10_2016
|
||||
| WindowsVersion::Windows10_2017
|
||||
| WindowsVersion::Windows8
|
||||
| WindowsVersion::WindowsUnknown => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
pub fn is_supported(self) -> bool {
|
||||
!self.not_supported()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -60,8 +84,17 @@ impl WindowsFFI {
|
||||
let str_rtl_init_unicode_str = CString::new("RtlInitUnicodeString").unwrap();
|
||||
let str_rtl_get_version = CString::new("RtlGetVersion").unwrap();
|
||||
let str_se_load_driver_privilege = CString::new("SeLoadDriverPrivilege").unwrap();
|
||||
|
||||
let str_driver_path = CString::new("\\SystemRoot\\System32\\DRIVERS\\lpus.sys").unwrap();
|
||||
let str_driver_path = {
|
||||
let mut driver_location =
|
||||
app_dir(AppDataType::UserData, &APP_INFO, &format!("driver")).unwrap();
|
||||
driver_location.push("lpus.sys");
|
||||
if driver_location.is_file() {
|
||||
let p = driver_location.to_str().unwrap();
|
||||
CString::new(format!("\\??\\{}", p)).unwrap()
|
||||
} else {
|
||||
CString::new("\\SystemRoot\\System32\\DRIVERS\\lpus.sys").unwrap()
|
||||
}
|
||||
};
|
||||
let str_registry_path = CString::new("System\\CurrentControlSet\\Services\\lpus").unwrap();
|
||||
let str_type = CString::new("Type").unwrap();
|
||||
let str_error_control = CString::new("ErrorControl").unwrap();
|
||||
@ -99,25 +132,43 @@ impl WindowsFFI {
|
||||
// setup registry
|
||||
let mut registry_key: HKEY = null_mut();
|
||||
RegCreateKeyExA(
|
||||
HKEY_LOCAL_MACHINE, str_registry_path.as_ptr(),
|
||||
0, null_mut(),
|
||||
REG_OPTION_NON_VOLATILE, KEY_WRITE,
|
||||
null_mut(), &mut registry_key, null_mut()
|
||||
HKEY_LOCAL_MACHINE,
|
||||
str_registry_path.as_ptr(),
|
||||
0,
|
||||
null_mut(),
|
||||
REG_OPTION_NON_VOLATILE,
|
||||
KEY_WRITE,
|
||||
null_mut(),
|
||||
&mut registry_key,
|
||||
null_mut(),
|
||||
);
|
||||
let type_value: [u8; 4] = 1u32.to_le_bytes();
|
||||
let error_control_value: [u8; 4] = 1u32.to_le_bytes();
|
||||
let start_value: [u8; 4] = 3u32.to_le_bytes();
|
||||
let registry_values = [
|
||||
(str_type.as_ptr(), REG_DWORD, type_value.as_ptr(), 4),
|
||||
(str_error_control.as_ptr(), REG_DWORD, error_control_value.as_ptr(), 4),
|
||||
(
|
||||
str_error_control.as_ptr(),
|
||||
REG_DWORD,
|
||||
error_control_value.as_ptr(),
|
||||
4,
|
||||
),
|
||||
(str_start.as_ptr(), REG_DWORD, start_value.as_ptr(), 4),
|
||||
(str_image_path.as_ptr(), REG_SZ,
|
||||
str_driver_path.as_ptr() as *const u8, str_driver_path.to_bytes().len() + 1)
|
||||
(
|
||||
str_image_path.as_ptr(),
|
||||
REG_SZ,
|
||||
str_driver_path.as_ptr() as *const u8,
|
||||
str_driver_path.to_bytes().len() + 1,
|
||||
),
|
||||
];
|
||||
for &(key, keytype, value_ptr, size_in_bytes) in ®istry_values {
|
||||
RegSetValueExA(
|
||||
registry_key, key, 0,
|
||||
keytype, value_ptr, size_in_bytes as u32
|
||||
registry_key,
|
||||
key,
|
||||
0,
|
||||
keytype,
|
||||
value_ptr,
|
||||
size_in_bytes as u32,
|
||||
);
|
||||
}
|
||||
RegCloseKey(registry_key);
|
||||
@ -125,28 +176,46 @@ impl WindowsFFI {
|
||||
// Setup privilege SeLoadDriverPrivilege
|
||||
let mut token_handle: HANDLE = null_mut();
|
||||
let mut luid = LUID::default();
|
||||
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &mut token_handle);
|
||||
OpenProcessToken(
|
||||
GetCurrentProcess(),
|
||||
TOKEN_ADJUST_PRIVILEGES,
|
||||
&mut token_handle,
|
||||
);
|
||||
LookupPrivilegeValueA(null_mut(), str_se_load_driver_privilege.as_ptr(), &mut luid);
|
||||
let mut new_token_state = TOKEN_PRIVILEGES {
|
||||
PrivilegeCount: 1,
|
||||
Privileges: [LUID_AND_ATTRIBUTES {
|
||||
Luid: luid,
|
||||
Attributes: SE_PRIVILEGE_ENABLED
|
||||
}]
|
||||
Attributes: SE_PRIVILEGE_ENABLED,
|
||||
}],
|
||||
};
|
||||
AdjustTokenPrivileges(
|
||||
token_handle, 0, &mut new_token_state, 16, null_mut(), null_mut());
|
||||
token_handle,
|
||||
0,
|
||||
&mut new_token_state,
|
||||
16,
|
||||
null_mut(),
|
||||
null_mut(),
|
||||
);
|
||||
CloseHandle(token_handle);
|
||||
}
|
||||
|
||||
rtl_get_version(&mut version_info);
|
||||
|
||||
let short_version = match version_info.dwBuildNumber {
|
||||
// 2600 => WindowsVersion::WindowsXP,
|
||||
// 6000 | 6001 | 6002 => WindowsVersion::WindowsVista,
|
||||
7600 | 7601 => WindowsVersion::Windows7,
|
||||
9200 | 9600 => WindowsVersion::Windows8,
|
||||
10240 => WindowsVersion::Windows10Legacy,
|
||||
10586 => WindowsVersion::Windows10_2015,
|
||||
14393 => WindowsVersion::Windows10_2016,
|
||||
15063 | 16299 => WindowsVersion::Windows10_2017,
|
||||
17134 | 17763 => WindowsVersion::Windows10_2018,
|
||||
18362 | 18363 => WindowsVersion::Windows10_2019,
|
||||
18363 | 18362 => WindowsVersion::Windows10_2019,
|
||||
19041 => WindowsVersion::Windows10_2020,
|
||||
_ if version_info.dwBuildNumber >= 19536 => WindowsVersion::Windows10FastRing,
|
||||
_ => WindowsVersion::Windows10VersionUnknown
|
||||
x if x >= 19536 => WindowsVersion::WindowsFastRing,
|
||||
_ => WindowsVersion::WindowsUnknown,
|
||||
};
|
||||
|
||||
Self {
|
||||
@ -157,36 +226,47 @@ impl WindowsFFI {
|
||||
nt_load_driver,
|
||||
nt_unload_driver,
|
||||
rtl_init_unicode_str,
|
||||
rtl_get_version
|
||||
rtl_get_version,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn driver_loaded(self) -> bool {
|
||||
pub fn driver_loaded(&self) -> bool {
|
||||
self.driver_handle != INVALID_HANDLE_VALUE
|
||||
}
|
||||
|
||||
pub fn file_connect(&mut self) {
|
||||
let filename = CString::new("\\\\.\\poolscanner").unwrap();
|
||||
let driver_file_handle: HANDLE = unsafe {
|
||||
CreateFileA(
|
||||
filename.as_ptr(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
null_mut(),
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
null_mut(),
|
||||
)
|
||||
};
|
||||
|
||||
if driver_file_handle == INVALID_HANDLE_VALUE {
|
||||
println!("Driver CreateFileA failed");
|
||||
} else {
|
||||
self.driver_handle = driver_file_handle;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_driver(&mut self) -> NTSTATUS {
|
||||
// TODO: Move this to new()
|
||||
// If we move this function to new(), self.driver_handle will be init, and thus no mut here
|
||||
let str_driver_reg = U16CString::from_str(STR_DRIVER_REGISTRY_PATH).unwrap();
|
||||
let mut str_driver_reg_unicode = UNICODE_STRING::default();
|
||||
(self.rtl_init_unicode_str)(&mut str_driver_reg_unicode, str_driver_reg.as_ptr() as *const u16);
|
||||
(self.rtl_init_unicode_str)(
|
||||
&mut str_driver_reg_unicode,
|
||||
str_driver_reg.as_ptr() as *const u16,
|
||||
);
|
||||
let status = (self.nt_load_driver)(&mut str_driver_reg_unicode);
|
||||
|
||||
let filename = CString::new("\\\\.\\poolscanner").unwrap();
|
||||
let driver_file_handle: HANDLE = unsafe {
|
||||
CreateFileA(filename.as_ptr(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0, null_mut(), CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, null_mut())
|
||||
};
|
||||
|
||||
if driver_file_handle == INVALID_HANDLE_VALUE {
|
||||
println!("Driver CreateFileA failed");
|
||||
}
|
||||
else {
|
||||
self.driver_handle = driver_file_handle;
|
||||
}
|
||||
self.file_connect();
|
||||
status
|
||||
}
|
||||
|
||||
@ -204,7 +284,8 @@ impl WindowsFFI {
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print_version(&self) {
|
||||
println!("Windows version: {}.{}.{} {:?}",
|
||||
println!(
|
||||
"Windows version: {}.{}.{} {:?}",
|
||||
self.version_info.dwMajorVersion,
|
||||
self.version_info.dwMinorVersion,
|
||||
self.version_info.dwBuildNumber,
|
||||
@ -212,6 +293,15 @@ impl WindowsFFI {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn to_epoch(&self, filetime: u64) -> u64 {
|
||||
let windows_epoch_diff = 11644473600000 * 10000;
|
||||
if filetime < windows_epoch_diff {
|
||||
return 0;
|
||||
}
|
||||
let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
|
||||
process_time_epoch
|
||||
}
|
||||
|
||||
pub fn valid_process_time(&self, filetime: u64) -> bool {
|
||||
// https://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/
|
||||
let windows_epoch_diff = 11644473600000 * 10000;
|
||||
@ -219,9 +309,13 @@ impl WindowsFFI {
|
||||
return false;
|
||||
}
|
||||
let system_up_time_ms = unsafe { GetTickCount64() };
|
||||
let process_time_epoch = (filetime - windows_epoch_diff) / 10000;
|
||||
let now_ms = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis() as u64;
|
||||
let system_start_up_time_ms = now_ms - system_up_time_ms;
|
||||
let process_time_epoch = (filetime - windows_epoch_diff) / 10000; // in milisecond
|
||||
let now_ms = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Time went backwards")
|
||||
.as_millis() as u64;
|
||||
let system_start_up_time_ms =
|
||||
now_ms - system_up_time_ms - (10 * 3600 * 1000/* 10 minutes penalty */);
|
||||
|
||||
if process_time_epoch < system_start_up_time_ms {
|
||||
false
|
||||
@ -233,21 +327,36 @@ impl WindowsFFI {
|
||||
}
|
||||
|
||||
pub fn device_io<T, E>(&self, code: DWORD, inbuf: &mut T, outbuf: &mut E) -> DWORD {
|
||||
self.device_io_raw(code,
|
||||
inbuf as *mut _ as *mut c_void, size_of_val(inbuf) as DWORD,
|
||||
outbuf as *mut _ as *mut c_void, size_of_val(outbuf) as DWORD)
|
||||
self.device_io_raw(
|
||||
code,
|
||||
inbuf as *mut _ as *mut c_void,
|
||||
size_of_val(inbuf) as DWORD,
|
||||
outbuf as *mut _ as *mut c_void,
|
||||
size_of_val(outbuf) as DWORD,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn device_io_raw(&self, code: DWORD,
|
||||
input_ptr: *mut c_void, input_len: DWORD,
|
||||
output_ptr: *mut c_void, output_len: DWORD) -> DWORD {
|
||||
pub fn device_io_raw(
|
||||
&self,
|
||||
code: DWORD,
|
||||
input_ptr: *mut c_void,
|
||||
input_len: DWORD,
|
||||
output_ptr: *mut c_void,
|
||||
output_len: DWORD,
|
||||
) -> DWORD {
|
||||
// println!("driver loaded: {}; device_io_code: {}", self.driver_loaded(), code);
|
||||
let mut bytes_returned: DWORD = 0;
|
||||
unsafe {
|
||||
let status = DeviceIoControl(self.driver_handle, code,
|
||||
input_ptr, input_len,
|
||||
output_ptr, output_len,
|
||||
&mut bytes_returned, null_mut());
|
||||
let status = DeviceIoControl(
|
||||
self.driver_handle,
|
||||
code,
|
||||
input_ptr,
|
||||
input_len,
|
||||
output_ptr,
|
||||
output_len,
|
||||
&mut bytes_returned,
|
||||
null_mut(),
|
||||
);
|
||||
if status == 0 {
|
||||
println!("device io failed: last error {}", GetLastError());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user