Compare commits
5 Commits
v0.3-alpha
...
repl
Author | SHA1 | Date | |
---|---|---|---|
21a1a58447 | |||
1707b301ff | |||
060f222c0a | |||
72a947ccd7 | |||
8c642f6ba0 |
2
.cargo/config
Normal file
2
.cargo/config
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[target.x86_64-pc-windows-msvc]
|
||||||
|
rustflags = ["-Ctarget-feature=+crt-static"]
|
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -218,11 +218,6 @@ dependencies = [
|
|||||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -354,10 +349,10 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
|
||||||
"pdb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pdb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"reqwest 0.10.1 (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)",
|
"serde_json 1.0.55 (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)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -764,7 +759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.48"
|
version = "1.0.55"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -988,7 +983,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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 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)",
|
"wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1080,7 +1075,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "widestring"
|
name = "widestring"
|
||||||
version = "0.4.0"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1166,7 +1161,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum h2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9433d71e471c1736fd5a61b671fc0b148d7a2992f666c958d03cd8feb3b88d1"
|
"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 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 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 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 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"
|
"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
|
||||||
@ -1226,7 +1220,7 @@ 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 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 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 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 serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
|
||||||
"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c"
|
"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 slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||||
@ -1263,7 +1257,7 @@ 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 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 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 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.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 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-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||||
|
@ -12,9 +12,9 @@ doctest = false
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
app_dirs = "1.2.1"
|
app_dirs = "1.2.1"
|
||||||
hex = "0.4.2"
|
|
||||||
pdb = "0.5.0"
|
pdb = "0.5.0"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
widestring = "0.4.0"
|
widestring = "0.4.0"
|
||||||
winapi = { version = "0.3.8", features = ["libloaderapi", "processthreadsapi", "winbase", "securitybaseapi", "handleapi", "winnt", "winreg", "fileapi", "ioapiset", "winioctl", "errhandlingapi", "sysinfoapi"] }
|
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"] }
|
reqwest = { version = "0.10.1", features = ["blocking"] }
|
||||||
|
serde_json = "1.0.55"
|
||||||
|
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
|
177
src/address.rs
Normal file
177
src/address.rs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
use std::ops::{Add, AddAssign, Sub, SubAssign};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
write!(f, "0x{:x} + 0x{:x}", self.base, self.offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Address {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Address {
|
||||||
|
base: self.base,
|
||||||
|
pointer: self.pointer.clone(),
|
||||||
|
offset: self.offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
src/bin/driver_scan.rs
Normal file
21
src/bin/driver_scan.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use lpus::{
|
||||||
|
driver_state::{DriverState},
|
||||||
|
scan_driver
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut driver = DriverState::new();
|
||||||
|
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,89 +1,19 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::str::{from_utf8};
|
|
||||||
use chrono::Utc;
|
|
||||||
use chrono::{DateTime};
|
|
||||||
use std::time::{UNIX_EPOCH, Duration};
|
|
||||||
|
|
||||||
use lpus::{
|
use lpus::{
|
||||||
driver_state::{DriverState /* , EprocessPoolChunk */}
|
driver_state::{DriverState},
|
||||||
|
scan_eprocess
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn to_str_time(time_ms: u64) -> String {
|
|
||||||
if time_ms == 0 {
|
|
||||||
return "".to_string();
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// for windows admin require
|
|
||||||
// https://github.com/nabijaczleweli/rust-embed-resource
|
|
||||||
|
|
||||||
let mut driver = DriverState::new();
|
let mut driver = DriverState::new();
|
||||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||||
|
|
||||||
// let eprocess_scan_head = driver.scan_active_head(ntosbase)?;
|
let result = scan_eprocess(&driver).unwrap_or(Vec::new());
|
||||||
// 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 eprocess_size = driver.pdb_store.get_offset_r("_EPROCESS.struct_size")?;
|
for r in result.iter() {
|
||||||
let eprocess_name_offset = driver.pdb_store.get_offset_r("_EPROCESS.ImageFileName")?;
|
println!("{:#}", r.to_string());
|
||||||
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;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
// });
|
|
||||||
})?;
|
|
||||||
|
|
||||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,54 +1,19 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use lpus::{
|
use lpus::{
|
||||||
driver_state::{DriverState}
|
driver_state::{DriverState},
|
||||||
|
scan_file
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let mut driver = DriverState::new();
|
let mut driver = DriverState::new();
|
||||||
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
println!("NtLoadDriver() -> 0x{:x}", driver.startup());
|
||||||
|
|
||||||
driver.scan_pool(b"File", |pool_addr, header, data_addr| {
|
let result = scan_file(&driver).unwrap_or(Vec::new());
|
||||||
let chunk_size = (header[2] as u64) * 16u64;
|
|
||||||
|
|
||||||
let fob_size = driver.pdb_store.get_offset_r("_FILE_OBJECT.struct_size")?;
|
for r in result.iter() {
|
||||||
let fob_size_offset = driver.pdb_store.get_offset_r("_FILE_OBJECT.Size")?;
|
println!("{:#}", r.to_string());
|
||||||
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;
|
|
||||||
}
|
|
||||||
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]");
|
|
||||||
}
|
|
||||||
else if let Ok(filename) = driver.get_unicode_string(fob_addr + fob_filename_offset, true) {
|
|
||||||
println!(" {}", filename);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
println!(" [NOT A VALID _UNICODE_STRING]");
|
|
||||||
}
|
|
||||||
Ok(true)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
println!("NtUnloadDriver() -> 0x{:x}", driver.shutdown());
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use lpus::{
|
use lpus::{
|
||||||
driver_state::{DriverState}
|
driver_state::{DriverState},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
26
src/bin/thread_scan.rs
Normal file
26
src/bin/thread_scan.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use lpus::{
|
||||||
|
driver_state::{DriverState},
|
||||||
|
scan_ethread, /* scan_mutant */
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut driver = DriverState::new();
|
||||||
|
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,3 +1,5 @@
|
|||||||
|
use std::default::Default;
|
||||||
|
use std::clone::Clone;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
// use std::io::{Error, ErrorKind};
|
// use std::io::{Error, ErrorKind};
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
@ -10,6 +12,7 @@ use winapi::um::winioctl::{
|
|||||||
METHOD_IN_DIRECT, METHOD_OUT_DIRECT, /* METHOD_BUFFERED, */ METHOD_NEITHER
|
METHOD_IN_DIRECT, METHOD_OUT_DIRECT, /* METHOD_BUFFERED, */ METHOD_NEITHER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::address::Address;
|
||||||
use crate::pdb_store::{PdbStore, parse_pdb};
|
use crate::pdb_store::{PdbStore, parse_pdb};
|
||||||
use crate::windows::{WindowsFFI, WindowsVersion};
|
use crate::windows::{WindowsFFI, WindowsVersion};
|
||||||
use crate::ioctl_protocol::{
|
use crate::ioctl_protocol::{
|
||||||
@ -100,79 +103,84 @@ impl DriverState {
|
|||||||
self.windows_ffi.unload_driver()
|
self.windows_ffi.unload_driver()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_kernel_base(&self) -> u64 {
|
pub fn get_kernel_base(&self) -> Address {
|
||||||
let mut ntosbase = 0u64;
|
let mut ntosbase = 0u64;
|
||||||
self.windows_ffi.device_io(DriverAction::GetKernelBase.get_code(),
|
self.windows_ffi.device_io(DriverAction::GetKernelBase.get_code(),
|
||||||
&mut Nothing, &mut ntosbase);
|
&mut Nothing, &mut ntosbase);
|
||||||
// println!("ntosbase: 0x{:x}", self.ntosbase);
|
Address::from_base(ntosbase)
|
||||||
ntosbase
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scan_active_head(&self) -> BoxResult<Vec<EprocessPoolChunk>> {
|
// pub fn scan_active_head(&self) -> BoxResult<Vec<EprocessPoolChunk>> {
|
||||||
let ntosbase = self.get_kernel_base();
|
// let ntosbase = self.get_kernel_base();
|
||||||
let ps_active_head = ntosbase + self.pdb_store.get_offset_r("PsActiveProcessHead")?;
|
// 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 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_link_offset = self.pdb_store.get_offset_r("_EPROCESS.ActiveProcessLinks")?;
|
||||||
let eprocess_name_offset = self.pdb_store.get_offset_r("_EPROCESS.ImageFileName")?;
|
// let eprocess_name_offset = self.pdb_store.get_offset_r("_EPROCESS.ImageFileName")?;
|
||||||
|
//
|
||||||
|
// let mut ptr = ps_active_head;
|
||||||
|
// self.deref_addr((ptr + flink_offset).get(), &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
|
||||||
|
//
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// _ => {}
|
||||||
|
// };
|
||||||
|
// self.deref_addr(ptr + flink_offset, &mut ptr);
|
||||||
|
// }
|
||||||
|
// Ok(result)
|
||||||
|
// }
|
||||||
|
|
||||||
let mut ptr = ps_active_head;
|
pub fn scan_pool<F>(&self, tag: &[u8; 4], expected_struct: &str, mut handler: F) -> BoxResult<bool>
|
||||||
self.deref_addr(ptr + flink_offset, &mut ptr);
|
where F: FnMut(Address, &[u8], Address) -> BoxResult<bool>
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
});
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
self.deref_addr(ptr + flink_offset, &mut ptr);
|
|
||||||
}
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
// F(Pool Address, Pool Header Data, Pool Data Address)
|
||||||
// TODO: Pool Header as a real struct
|
// TODO: Pool Header as a real struct
|
||||||
{
|
{
|
||||||
let ntosbase = self.get_kernel_base();
|
// 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 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 code = DriverAction::ScanPoolRemote.get_code();
|
||||||
let range = self.get_nonpaged_range(ntosbase)?;
|
let ntosbase = self.get_kernel_base();
|
||||||
let start_address = range[0];
|
let [start_address, end_address] = self.get_nonpaged_range(&ntosbase)?;
|
||||||
let end_address = range[1];
|
|
||||||
|
println!("kernel base: {}; non-paged pool (start, end): ({}, {})", ntosbase, start_address, end_address);
|
||||||
|
|
||||||
let mut ptr = start_address;
|
let mut ptr = start_address;
|
||||||
while ptr < end_address {
|
while ptr < end_address {
|
||||||
|
let mut next_found = 0u64;
|
||||||
let mut input = InputData {
|
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);
|
self.windows_ffi.device_io(code, &mut input, &mut next_found);
|
||||||
// println!("found: 0x{:x}", ptr);
|
ptr = Address::from_base(next_found);
|
||||||
if ptr >= end_address {
|
if ptr >= end_address {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pool_addr = ptr;
|
let pool_addr = Address::from_base(ptr.address());
|
||||||
let mut header = vec![0u8; pool_header_size as usize];
|
let header: Vec<u8> = self.deref_array(&pool_addr, pool_header_size);
|
||||||
self.deref_addr_ptr(pool_addr, header.as_mut_ptr(), pool_header_size);
|
|
||||||
let chunk_size = (header[2] as u64) * 16u64;
|
let chunk_size = (header[2] as u64) * 16u64;
|
||||||
|
|
||||||
if pool_addr + chunk_size > end_address {
|
if pool_addr.address() + chunk_size > end_address.address() {
|
||||||
// the chunk found is not a valid chunk for sure
|
// the chunk surpasses the non page pool range
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,10 +190,11 @@ impl DriverState {
|
|||||||
continue;
|
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)?;
|
||||||
if success {
|
if success {
|
||||||
ptr += chunk_size; /* pass this chunk */
|
ptr += chunk_size; /* skip this chunk */
|
||||||
// ptr += 0x4;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ptr += 0x4; /* search next */
|
ptr += 0x4; /* search next */
|
||||||
@ -194,27 +203,42 @@ impl DriverState {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_minimum_block_size(&self, tag: &[u8; 4]) -> BoxResult<u64> {
|
pub fn address_of(&self, addr: &Address, name: &str) -> BoxResult<u64> {
|
||||||
// Proc -> _EPROCESS
|
let resolver = |p| { self.deref_addr_new(p) };
|
||||||
// Thre -> _KTHREAD
|
let r = self.pdb_store.decompose(&addr, &name)?;
|
||||||
let pool_header_size = self.pdb_store.get_offset_r("_POOL_HEADER.struct_size")?;
|
Ok(r.get(&resolver))
|
||||||
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 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];
|
||||||
|
self.deref_addr_ptr(addr.get(&resolver), r.as_mut_ptr(), len);
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[deprecated(note="use deref_addr_new<T>")]
|
||||||
pub fn deref_addr<T>(&self, addr: u64, outbuf: &mut 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 code = DriverAction::DereferenceAddress.get_code();
|
||||||
let size: usize = size_of_val(outbuf);
|
let size: usize = size_of_val(outbuf);
|
||||||
let mut input = InputData {
|
let mut input = InputData {
|
||||||
@ -223,10 +247,10 @@ impl DriverState {
|
|||||||
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);
|
self.windows_ffi.device_io(code, &mut input, outbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #[deprecated(note="use deref_array<T>")]
|
||||||
pub fn deref_addr_ptr<T>(&self, addr: u64, outptr: *mut T, output_len: u64) {
|
pub fn deref_addr_ptr<T>(&self, addr: u64, outptr: *mut T, output_len: u64) {
|
||||||
let code = DriverAction::DereferenceAddress.get_code();
|
let code = DriverAction::DereferenceAddress.get_code();
|
||||||
let mut input = InputData {
|
let mut input = InputData {
|
||||||
@ -241,6 +265,10 @@ impl DriverState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_unicode_string(&self, unicode_str_addr: u64, deref: bool) -> BoxResult<String> {
|
pub fn get_unicode_string(&self, unicode_str_addr: u64, deref: bool) -> BoxResult<String> {
|
||||||
|
if unicode_str_addr == 0 {
|
||||||
|
return Err("Not a valid address".into());
|
||||||
|
}
|
||||||
|
|
||||||
let mut strlen = 0u16;
|
let mut strlen = 0u16;
|
||||||
let mut capacity = 0u16;
|
let mut capacity = 0u16;
|
||||||
let mut bufaddr = 0u64;
|
let mut bufaddr = 0u64;
|
||||||
@ -251,7 +279,6 @@ impl DriverState {
|
|||||||
self.deref_addr(capacity_addr, &mut capacity);
|
self.deref_addr(capacity_addr, &mut capacity);
|
||||||
self.deref_addr(buffer_ptr, &mut bufaddr);
|
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 {
|
if bufaddr == 0 || strlen > capacity || strlen == 0 || strlen % 2 != 0 {
|
||||||
return Err("Unicode string is empty".into());
|
return Err("Unicode string is empty".into());
|
||||||
}
|
}
|
||||||
@ -262,53 +289,53 @@ impl DriverState {
|
|||||||
|
|
||||||
let mut buf = vec![0u16; (strlen / 2) as usize];
|
let mut buf = vec![0u16; (strlen / 2) as usize];
|
||||||
self.deref_addr_ptr(bufaddr, buf.as_mut_ptr(), strlen as u64);
|
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)?)
|
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
|
// TODO: Add support for other Windows version here
|
||||||
match self.windows_ffi.short_version {
|
match self.windows_ffi.short_version {
|
||||||
WindowsVersion::Windows10FastRing => {
|
WindowsVersion::Windows10FastRing => {
|
||||||
let mistate = ntosbase + self.pdb_store.get_offset_r("MiState")?;
|
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
|
||||||
let system_node_ptr = self.pdb_store.addr_decompose(
|
let path_first_va: String = vec![
|
||||||
mistate, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeNonPagedPool")?;
|
"_MI_SYSTEM_INFORMATION",
|
||||||
let mut system_node_addr = 0u64;
|
"Hardware",
|
||||||
self.deref_addr(system_node_ptr, &mut system_node_addr);
|
"SystemNodeNonPagedPool",
|
||||||
|
"NonPagedPoolFirstVa"
|
||||||
let mut first_va = 0u64;
|
].join(".");
|
||||||
let mut last_va = 0u64;
|
let path_last_va: String = vec![
|
||||||
self.deref_addr(
|
"_MI_SYSTEM_INFORMATION",
|
||||||
system_node_addr
|
"Hardware",
|
||||||
+ self.pdb_store.get_offset_r("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolFirstVa")?,
|
"SystemNodeNonPagedPool",
|
||||||
&mut first_va);
|
"NonPagedPoolLastVa"
|
||||||
|
].join(".");
|
||||||
self.deref_addr(
|
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
|
||||||
system_node_addr
|
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
|
||||||
+ self.pdb_store.get_offset_r("_MI_SYSTEM_NODE_NONPAGED_POOL.NonPagedPoolLastVa")?,
|
|
||||||
&mut last_va);
|
|
||||||
|
|
||||||
Ok([first_va, last_va])
|
Ok([first_va, last_va])
|
||||||
},
|
},
|
||||||
WindowsVersion::Windows10_2019 => {
|
WindowsVersion::Windows10_2019 |
|
||||||
let mistate = ntosbase + self.pdb_store.get_offset_r("MiState")?;
|
WindowsVersion::Windows10_2018 => {
|
||||||
let system_node_ptr = self.pdb_store.addr_decompose(
|
let mistate = ntosbase.clone() + self.pdb_store.get_offset_r("MiState")?;
|
||||||
mistate, "_MI_SYSTEM_INFORMATION.Hardware.SystemNodeInformation")?;
|
let path_first_va: String = vec![
|
||||||
let mut system_node_addr = 0u64;
|
"_MI_SYSTEM_INFORMATION",
|
||||||
self.deref_addr(system_node_ptr, &mut system_node_addr);
|
"Hardware",
|
||||||
|
"SystemNodeInformation",
|
||||||
let mut first_va = 0u64;
|
"NonPagedPoolFirstVa"
|
||||||
let mut last_va = 0u64;
|
].join(".");
|
||||||
self.deref_addr(
|
let path_last_va: String = vec![
|
||||||
system_node_addr
|
"_MI_SYSTEM_INFORMATION",
|
||||||
+ self.pdb_store.get_offset_r("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolFirstVa")?,
|
"Hardware",
|
||||||
&mut first_va);
|
"SystemNodeInformation",
|
||||||
|
"NonPagedPoolLastVa"
|
||||||
self.deref_addr(
|
].join(".");
|
||||||
system_node_addr
|
let first_va = Address::from_base(self.decompose(&mistate, &path_first_va)?);
|
||||||
+ self.pdb_store.get_offset_r("_MI_SYSTEM_NODE_INFORMATION.NonPagedPoolLastVa")?,
|
let last_va = Address::from_base(self.decompose(&mistate, &path_last_va)?);
|
||||||
&mut last_va);
|
|
||||||
|
|
||||||
Ok([first_va, last_va])
|
Ok([first_va, last_va])
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
280
src/lib.rs
280
src/lib.rs
@ -5,4 +5,284 @@ pub mod pdb_store;
|
|||||||
pub mod windows;
|
pub mod windows;
|
||||||
pub mod ioctl_protocol;
|
pub mod ioctl_protocol;
|
||||||
pub mod driver_state;
|
pub mod driver_state;
|
||||||
|
pub mod address;
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
use std::str::{from_utf8};
|
||||||
|
use serde_json::{json, Value};
|
||||||
|
use driver_state::DriverState;
|
||||||
|
use address::Address;
|
||||||
|
|
||||||
|
type BoxResult<T> = Result<T, Box<dyn Error>>;
|
||||||
|
|
||||||
|
pub fn scan_eprocess(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||||
|
let mut result: Vec<Value> = Vec::new();
|
||||||
|
driver.scan_pool(b"Proc", "_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
let eprocess_ptr = &try_eprocess_ptr;
|
||||||
|
|
||||||
|
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, true)
|
||||||
|
.unwrap_or("".to_string());
|
||||||
|
|
||||||
|
result.push(json!({
|
||||||
|
"pool": format!("0x{:x}", pool_addr.address()),
|
||||||
|
"address": format!("0x{:x}", eprocess_ptr.address()),
|
||||||
|
"type": "_EPROCESS",
|
||||||
|
"pid": pid,
|
||||||
|
"ppid": ppid,
|
||||||
|
"name": eprocess_name,
|
||||||
|
"path": binary_path
|
||||||
|
}));
|
||||||
|
Ok(true)
|
||||||
|
})?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scan_file(driver: &DriverState) -> BoxResult<Vec<Value>> {
|
||||||
|
let mut result: Vec<Value> = Vec::new();
|
||||||
|
|
||||||
|
driver.scan_pool(b"File", "_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, true) {
|
||||||
|
n
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"[NOT A VALID _UNICODE_STRING]".to_string()
|
||||||
|
};
|
||||||
|
let devicename = driver.get_unicode_string(devicename_ptr, true)
|
||||||
|
.unwrap_or("".to_string());
|
||||||
|
let hardware = driver.get_unicode_string(hardware_ptr, true)
|
||||||
|
.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();
|
||||||
|
|
||||||
|
driver.scan_pool(b"Thre", "_ETHREAD", |pool_addr, header, data_addr| {
|
||||||
|
let chunk_size = (header[2] as u64) * 16u64;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ethread_ptr = &try_ethread_ptr;
|
||||||
|
|
||||||
|
let pid: u64 = driver.decompose(ethread_ptr, "_ETHREAD.Cid.UniqueProcess")?;
|
||||||
|
let tid: u64 = driver.decompose(ethread_ptr, "_ETHREAD.Cid.UniqueThread")?;
|
||||||
|
let unicode_str_ptr: u64 = driver.address_of(ethread_ptr, "_ETHREAD.ThreadName")?;
|
||||||
|
|
||||||
|
let thread_name =
|
||||||
|
if let Ok(name) = driver.get_unicode_string(unicode_str_ptr, true) {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
result.push(json!({
|
||||||
|
"pool": format!("0x{:x}", pool_addr.address()),
|
||||||
|
"address": format!("0x{:x}", ethread_ptr.address()),
|
||||||
|
"type": "_ETHREAD",
|
||||||
|
"pid": pid,
|
||||||
|
"tid": tid,
|
||||||
|
"name": thread_name
|
||||||
|
}));
|
||||||
|
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)?;
|
||||||
|
|
||||||
|
driver.scan_pool(b"Muta", "_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, true) {
|
||||||
|
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();
|
||||||
|
|
||||||
|
driver.scan_pool(b"Driv", "_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 ftype: u16 = driver.decompose(&try_ptr, "_DRIVER_OBJECT.Type")?;
|
||||||
|
let size: u16 = driver.decompose(&try_ptr, "_DRIVER_OBJECT.Size")?;
|
||||||
|
if (size as u64) == dob_size /* && ftype == 5u16 */ {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try_ptr += 0x4; // search exhaustively
|
||||||
|
}
|
||||||
|
if try_ptr > valid_end {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
let dob_addr = &try_ptr;
|
||||||
|
|
||||||
|
let devicename_ptr = driver.address_of(dob_addr, "_DRIVER_OBJECT.DriverName")?;
|
||||||
|
let hardware_ptr: u64 = driver.decompose(dob_addr, "_DRIVER_OBJECT.HardwareDatabase")?;
|
||||||
|
|
||||||
|
let devicename = driver.get_unicode_string(devicename_ptr, true)
|
||||||
|
.unwrap_or("".to_string());
|
||||||
|
let hardware = driver.get_unicode_string(hardware_ptr, true)
|
||||||
|
.unwrap_or("".to_string());
|
||||||
|
result.push(json!({
|
||||||
|
"pool": format!("0x{:x}", pool_addr.address()),
|
||||||
|
"address": format!("0x{:x}", dob_addr.address()),
|
||||||
|
"type": "_DRIVER_OBJECT",
|
||||||
|
"device": devicename,
|
||||||
|
"hardware": hardware
|
||||||
|
}));
|
||||||
|
Ok(true)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
@ -9,9 +9,10 @@ use pdb::{
|
|||||||
PDB, SymbolData, TypeData, ClassType, ModifierType, Rva,
|
PDB, SymbolData, TypeData, ClassType, ModifierType, Rva,
|
||||||
FallibleIterator, TypeFinder, TypeIndex
|
FallibleIterator, TypeFinder, TypeIndex
|
||||||
};
|
};
|
||||||
|
|
||||||
use app_dirs::{AppInfo, AppDataType, app_dir};
|
use app_dirs::{AppInfo, AppDataType, app_dir};
|
||||||
|
|
||||||
|
use crate::address::Address;
|
||||||
|
|
||||||
const APP_INFO: AppInfo = AppInfo { name: "lpus", author: "nganhkhoa" };
|
const APP_INFO: AppInfo = AppInfo { name: "lpus", author: "nganhkhoa" };
|
||||||
|
|
||||||
const KERNEL_PDB_NAME: &str = "ntkrnlmp.pdb";
|
const KERNEL_PDB_NAME: &str = "ntkrnlmp.pdb";
|
||||||
@ -85,6 +86,36 @@ impl PdbStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)]
|
#[allow(dead_code)]
|
||||||
pub fn print_default_information(&self) {
|
pub fn print_default_information(&self) {
|
||||||
let need_symbols = [
|
let need_symbols = [
|
||||||
|
581
src/repl/eval.rs
Normal file
581
src/repl/eval.rs
Normal file
@ -0,0 +1,581 @@
|
|||||||
|
use crate::{
|
||||||
|
error::{BlisprError, BlisprResult},
|
||||||
|
lenv::Lenv,
|
||||||
|
lval::{
|
||||||
|
lval_add, lval_join, lval_lambda, lval_num, lval_pop, lval_qexpr, lval_sexpr, Lval, LvalFun,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use log::debug;
|
||||||
|
use std::{collections::HashMap, ops::{Add, Div, Mul, Rem, Sub}};
|
||||||
|
|
||||||
|
// macro to shorten code for applying a binary operation to two Lvals
|
||||||
|
macro_rules! apply_binop {
|
||||||
|
( $op:ident, $x:ident, $y:ident ) => {
|
||||||
|
match (*$x, *$y) {
|
||||||
|
(Lval::Num(x_num), Lval::Num(y_num)) => {
|
||||||
|
$x = lval_num(x_num.$op(y_num));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => return Err(BlisprError::NotANumber),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply a binary operation {+ - * / ^ % min max} to a list of arguments in succession
|
||||||
|
fn builtin_op(mut v: &mut Lval, func: &str) -> BlisprResult {
|
||||||
|
let mut child_count;
|
||||||
|
match *v {
|
||||||
|
Lval::Sexpr(ref children) => {
|
||||||
|
child_count = children.len();
|
||||||
|
}
|
||||||
|
_ => return Ok(Box::new(v.clone())),
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut x = lval_pop(&mut v, 0)?;
|
||||||
|
|
||||||
|
// If no args given and we're doing subtraction, perform unary negation
|
||||||
|
if (func == "-" || func == "sub") && child_count == 1 {
|
||||||
|
debug!("builtin_op: Unary negation on {}", x);
|
||||||
|
let x_num = x.as_num()?;
|
||||||
|
return Ok(lval_num(-x_num));
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume the children until empty
|
||||||
|
// and operate on x
|
||||||
|
while child_count > 1 {
|
||||||
|
let y = lval_pop(&mut v, 0)?;
|
||||||
|
child_count -= 1;
|
||||||
|
match func {
|
||||||
|
"+" | "add" => {
|
||||||
|
debug!("builtin_op: Add {} and {}", x, y);
|
||||||
|
apply_binop!(add, x, y)
|
||||||
|
}
|
||||||
|
"-" | "sub" => {
|
||||||
|
debug!("builtin_op: Subtract {} and {}", x, y);
|
||||||
|
apply_binop!(sub, x, y)
|
||||||
|
}
|
||||||
|
"*" | "mul" => {
|
||||||
|
debug!("builtin_op: Multiply {} and {}", x, y);
|
||||||
|
apply_binop!(mul, x, y)
|
||||||
|
}
|
||||||
|
"/" | "div" => {
|
||||||
|
if y.as_num()? == 0 {
|
||||||
|
debug!("builtin_op: Failed divide {} by {}", x, y);
|
||||||
|
return Err(BlisprError::DivideByZero);
|
||||||
|
} else {
|
||||||
|
debug!("builtin_op: Divide {} by {}", x, y);
|
||||||
|
apply_binop!(div, x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"%" | "rem" => {
|
||||||
|
debug!("builtin_op: {} % {}", x, y);
|
||||||
|
apply_binop!(rem, x, y)
|
||||||
|
}
|
||||||
|
"^" | "pow" => {
|
||||||
|
debug!("builtin_op: Raise {} to the {} power", x, y);
|
||||||
|
let y_num = y.as_num()?;
|
||||||
|
let x_num = x.as_num()?;
|
||||||
|
let mut coll = 1;
|
||||||
|
for _ in 0..y_num {
|
||||||
|
coll *= x_num;
|
||||||
|
}
|
||||||
|
x = lval_num(coll);
|
||||||
|
}
|
||||||
|
"min" => {
|
||||||
|
debug!("builtin_op: Min {} and {}", x, y);
|
||||||
|
let x_num = x.as_num()?;
|
||||||
|
let y_num = y.as_num()?;
|
||||||
|
if x_num < y_num {
|
||||||
|
x = lval_num(x_num);
|
||||||
|
} else {
|
||||||
|
x = lval_num(y_num);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"max" => {
|
||||||
|
debug!("builtin_op: Max {} and {}", x, y);
|
||||||
|
let x_num = x.as_num()?;
|
||||||
|
let y_num = y.as_num()?;
|
||||||
|
if x_num > y_num {
|
||||||
|
x = lval_num(x_num);
|
||||||
|
} else {
|
||||||
|
x = lval_num(y_num);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operator aliases, function pointers will be stored in env
|
||||||
|
// TODO macro?? create_builtin!(a, &str)
|
||||||
|
pub fn builtin_add(a: &mut Lval) -> BlisprResult {
|
||||||
|
builtin_op(a, "+")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin_sub(a: &mut Lval) -> BlisprResult {
|
||||||
|
builtin_op(a, "-")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin_mul(a: &mut Lval) -> BlisprResult {
|
||||||
|
builtin_op(a, "*")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin_div(a: &mut Lval) -> BlisprResult {
|
||||||
|
builtin_op(a, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin_pow(a: &mut Lval) -> BlisprResult {
|
||||||
|
builtin_op(a, "^")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin_rem(a: &mut Lval) -> BlisprResult {
|
||||||
|
builtin_op(a, "%")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin_max(a: &mut Lval) -> BlisprResult {
|
||||||
|
builtin_op(a, "max")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin_min(a: &mut Lval) -> BlisprResult {
|
||||||
|
builtin_op(a, "min")
|
||||||
|
}
|
||||||
|
|
||||||
|
// define a list of values
|
||||||
|
// if "def" define in global env
|
||||||
|
// if "=" define in local env
|
||||||
|
fn builtin_var(e: &mut Lenv, a: &mut Lval, func: &str) -> BlisprResult {
|
||||||
|
let args = lval_pop(a, 0)?;
|
||||||
|
match *args {
|
||||||
|
Lval::Qexpr(names) => {
|
||||||
|
// grab the rest of the vals
|
||||||
|
let mut vals = Vec::new();
|
||||||
|
for _ in 0..a.len()? {
|
||||||
|
vals.push(lval_pop(a, 0)?);
|
||||||
|
}
|
||||||
|
let names_len = names.len();
|
||||||
|
let vals_len = vals.len();
|
||||||
|
// TODO assert all symbols?
|
||||||
|
if vals_len != names_len {
|
||||||
|
Err(BlisprError::NumArguments(names_len, vals_len))
|
||||||
|
} else {
|
||||||
|
for (k, v) in names.iter().zip(vals.iter()) {
|
||||||
|
let scope = if func == "def" { "global" } else { "local" };
|
||||||
|
debug!("adding key, value pair {}, {} to {} env {}", k, v, scope, e);
|
||||||
|
let name = k.clone().as_string()?;
|
||||||
|
if scope == "local" {
|
||||||
|
e.put(name, v.clone());
|
||||||
|
} else {
|
||||||
|
//e.def(name, v.clone())?;
|
||||||
|
debug!("warning: global scope definition unimplemented!");
|
||||||
|
e.put(name, v.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(lval_sexpr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(BlisprError::WrongType(
|
||||||
|
"qexpr".to_string(),
|
||||||
|
format!("{:?}", args),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BROKEN
|
||||||
|
//pub fn builtin_def_stub(_v: &Lval) -> BlisprResult {
|
||||||
|
// Ok(lval_sexpr())
|
||||||
|
//}
|
||||||
|
|
||||||
|
// FOR NOW def IS LOCAL ENV ASSIGN
|
||||||
|
fn builtin_def(e: &mut Lenv, v: &mut Lval) -> BlisprResult {
|
||||||
|
builtin_var(e, v, "def")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin_put_stub(_v: &mut Lval) -> BlisprResult {
|
||||||
|
Ok(lval_sexpr())
|
||||||
|
}
|
||||||
|
|
||||||
|
//BROKEN
|
||||||
|
//fn builtin_put(e: &mut Lenv, v: &Lval) -> BlisprResult {
|
||||||
|
// builtin_var(e, v, "=")
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Attach a value to the front of a qexpr
|
||||||
|
pub fn builtin_cons(v: &mut Lval) -> BlisprResult {
|
||||||
|
let child_count = v.len()?;
|
||||||
|
if child_count != 2 {
|
||||||
|
return Err(BlisprError::NumArguments(2, child_count));
|
||||||
|
}
|
||||||
|
let new_elem = lval_pop(v, 0)?;
|
||||||
|
let qexpr = lval_pop(v, 0)?;
|
||||||
|
match *qexpr {
|
||||||
|
Lval::Qexpr(ref children) => {
|
||||||
|
let mut ret = lval_qexpr();
|
||||||
|
lval_add(&mut ret, &new_elem)?;
|
||||||
|
for c in children {
|
||||||
|
lval_add(&mut ret, &c.clone())?;
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
_ => Err(BlisprError::WrongType(
|
||||||
|
"qexpr".to_string(),
|
||||||
|
format!("{:?}", v),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// correct call dispatched in lval_call
|
||||||
|
pub fn builtin_eval_stub(_v: &mut Lval) -> BlisprResult {
|
||||||
|
Ok(lval_sexpr())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate qexpr as a sexpr
|
||||||
|
pub fn builtin_eval(e: &mut Lenv, v: &mut Lval) -> BlisprResult {
|
||||||
|
let qexpr = lval_pop(v, 0)?;
|
||||||
|
match *qexpr {
|
||||||
|
Lval::Qexpr(ref children) => {
|
||||||
|
let mut new_sexpr = lval_sexpr();
|
||||||
|
for c in children {
|
||||||
|
let cloned = Box::new(*c.clone());
|
||||||
|
lval_add(&mut new_sexpr, &cloned)?;
|
||||||
|
}
|
||||||
|
debug!("builtin_eval: {:?}", new_sexpr);
|
||||||
|
lval_eval(e, &mut new_sexpr)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// add it back
|
||||||
|
lval_add(v, &qexpr)?;
|
||||||
|
lval_eval(e, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// terminate the program (or exit the prompt)
|
||||||
|
pub fn builtin_exit(_v: &mut Lval) -> BlisprResult {
|
||||||
|
// always succeeds
|
||||||
|
println!("Goodbye!");
|
||||||
|
::std::process::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the first element of a qexpr
|
||||||
|
pub fn builtin_head(v: &mut Lval) -> BlisprResult {
|
||||||
|
let mut qexpr = lval_pop(v, 0)?;
|
||||||
|
match *qexpr {
|
||||||
|
Lval::Qexpr(ref mut children) => {
|
||||||
|
if children.is_empty() {
|
||||||
|
return Err(BlisprError::EmptyList);
|
||||||
|
}
|
||||||
|
debug!("builtin_head: Returning the first element");
|
||||||
|
Ok(children[0].clone())
|
||||||
|
}
|
||||||
|
_ => Err(BlisprError::WrongType(
|
||||||
|
"qexpr".to_string(),
|
||||||
|
format!("{:?}", qexpr),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return everything but the last element of a qexpr
|
||||||
|
pub fn builtin_init(v: &mut Lval) -> BlisprResult {
|
||||||
|
let qexpr = lval_pop(v, 0)?;
|
||||||
|
match *qexpr {
|
||||||
|
Lval::Qexpr(ref children) => {
|
||||||
|
let mut ret = lval_qexpr();
|
||||||
|
for item in children.iter().take(children.len() - 1) {
|
||||||
|
lval_add(&mut ret, &item.clone())?;
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
_ => Err(BlisprError::WrongType(
|
||||||
|
"qexpr".to_string(),
|
||||||
|
format!("{:?}", qexpr),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join the children into one qexpr
|
||||||
|
pub fn builtin_join(v: &mut Lval) -> BlisprResult {
|
||||||
|
let mut ret = lval_qexpr();
|
||||||
|
for _ in 0..v.len()? {
|
||||||
|
let next = lval_pop(v, 0)?;
|
||||||
|
match *next {
|
||||||
|
Lval::Qexpr(_) => {
|
||||||
|
lval_join(&mut ret, next)?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(BlisprError::WrongType(
|
||||||
|
"qexpr".to_string(),
|
||||||
|
format!("{:?}", next),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
//builtin_lambda returns a lambda lval from two lists of symbols
|
||||||
|
pub fn builtin_lambda(v: &mut Lval) -> BlisprResult {
|
||||||
|
// ensure there's only two arguments
|
||||||
|
let child_count = v.len()?;
|
||||||
|
if child_count != 2 {
|
||||||
|
return Err(BlisprError::NumArguments(2, child_count));
|
||||||
|
}
|
||||||
|
|
||||||
|
// first qexpr should contain only symbols - lval.as_string().is_ok()
|
||||||
|
let formals = lval_pop(v, 0)?;
|
||||||
|
let formals_ret = formals.clone(); // ewwww but it gets moved on me?! this might be why Rc<> - it doesn't need to mutate
|
||||||
|
let body = lval_pop(v, 0)?;
|
||||||
|
match *formals {
|
||||||
|
Lval::Qexpr(contents) => {
|
||||||
|
for cell in contents {
|
||||||
|
if cell.as_string().is_err() {
|
||||||
|
return Err(BlisprError::WrongType(
|
||||||
|
"Symbol".to_string(),
|
||||||
|
format!("{:?}", cell),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match *body {
|
||||||
|
Lval::Qexpr(_) => Ok(lval_lambda(HashMap::new(), formals_ret, body)),
|
||||||
|
_ => Err(BlisprError::WrongType(
|
||||||
|
"Q-Expression".to_string(),
|
||||||
|
format!("{:?}", body),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(BlisprError::WrongType(
|
||||||
|
"Q-Expression".to_string(),
|
||||||
|
format!("{:?}", formals),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sexpr into a qexpr
|
||||||
|
pub fn builtin_list(v: &mut Lval) -> BlisprResult {
|
||||||
|
match *v {
|
||||||
|
Lval::Sexpr(ref children) => {
|
||||||
|
debug!("builtin_list: Building qexpr from {:?}", children);
|
||||||
|
let mut new_qexpr = lval_qexpr();
|
||||||
|
for c in children {
|
||||||
|
let cloned = Box::new(*c.clone());
|
||||||
|
lval_add(&mut new_qexpr, &cloned)?;
|
||||||
|
}
|
||||||
|
Ok(new_qexpr)
|
||||||
|
}
|
||||||
|
_ => Ok(Box::new(v.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin_len(v: &mut Lval) -> BlisprResult {
|
||||||
|
let child_count = v.len()?;
|
||||||
|
match child_count {
|
||||||
|
1 => {
|
||||||
|
let qexpr = lval_pop(v, 0)?;
|
||||||
|
match *qexpr {
|
||||||
|
Lval::Qexpr(_) => {
|
||||||
|
debug!("Returning length of {:?}", qexpr);
|
||||||
|
Ok(lval_num(qexpr.len()? as i64))
|
||||||
|
}
|
||||||
|
_ => Err(BlisprError::WrongType(
|
||||||
|
"qexpr".to_string(),
|
||||||
|
format!("{:?}", qexpr),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(BlisprError::NumArguments(1, child_count)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin_printenv_stub(_v: &mut Lval) -> BlisprResult {
|
||||||
|
Ok(lval_sexpr())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print all the named variables in the environment
|
||||||
|
pub fn builtin_printenv(e: &mut Lenv) -> BlisprResult {
|
||||||
|
// we don't use the input
|
||||||
|
lval_eval(e, &mut *e.list_all()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn builtin_tail(v: &mut Lval) -> BlisprResult {
|
||||||
|
let mut qexpr = lval_pop(v, 0)?;
|
||||||
|
debug!("Returning tail of {:?}", qexpr);
|
||||||
|
match *qexpr {
|
||||||
|
Lval::Qexpr(ref mut children) => {
|
||||||
|
if children.is_empty() {
|
||||||
|
return Err(BlisprError::EmptyList);
|
||||||
|
}
|
||||||
|
let mut ret = lval_qexpr();
|
||||||
|
for c in &children[1..] {
|
||||||
|
lval_add(&mut ret, &c.clone())?;
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
_ => Err(BlisprError::WrongType(
|
||||||
|
"qexpr".to_string(),
|
||||||
|
format!("{:?}", qexpr),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call a Lval::Fun(f) on an argument list
|
||||||
|
// This will handle both builtins and lambdas
|
||||||
|
pub fn lval_call(e: &mut Lenv, f: Lval, args: &mut Lval) -> BlisprResult {
|
||||||
|
match f {
|
||||||
|
Lval::Fun(func) => {
|
||||||
|
match func {
|
||||||
|
// if its one of the ones that need an environment, intercept and route to the properly typed fn
|
||||||
|
LvalFun::Builtin(name, fp) => match name.as_str() {
|
||||||
|
"eval" => builtin_eval(e, args),
|
||||||
|
"def" => builtin_def(e, args),
|
||||||
|
//"=" => builtin_put(e, args),
|
||||||
|
"printenv" => builtin_printenv(e),
|
||||||
|
// Otherwise, just apply the actual stored function pointer
|
||||||
|
_ => fp(args),
|
||||||
|
},
|
||||||
|
LvalFun::Lambda(env, mut formals, body) => {
|
||||||
|
debug!(
|
||||||
|
"Executing lambda. Environment: {:?}, Formals: {:?}, body: {:?}",
|
||||||
|
env, formals, body
|
||||||
|
);
|
||||||
|
// If it's a Lambda, bind arguments to a new local environment
|
||||||
|
|
||||||
|
// First, build the lookup hashmap
|
||||||
|
let mut new_env: HashMap<String, Box<Lval>> = HashMap::new();
|
||||||
|
// grab the argument and body
|
||||||
|
let given = args.len()?;
|
||||||
|
let total = formals.len()?;
|
||||||
|
|
||||||
|
while args.len()? > 0 {
|
||||||
|
// if we've run out of args to bind, error
|
||||||
|
if formals.len()? == 0 {
|
||||||
|
return Err(BlisprError::NumArguments(total, given));
|
||||||
|
}
|
||||||
|
|
||||||
|
// grab first symbol from formals
|
||||||
|
let sym = lval_pop(&mut formals, 0)?;
|
||||||
|
|
||||||
|
// special case to handle '&'
|
||||||
|
if &sym.as_string()? == "&" {
|
||||||
|
// make sure there's one symbol left
|
||||||
|
if formals.len()? != 1 {
|
||||||
|
return Err(BlisprError::FunctionFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// next formal should be found to remaining args
|
||||||
|
let next_sym = lval_pop(&mut formals, 0)?;
|
||||||
|
let arglist = builtin_list(args)?;
|
||||||
|
let curr = new_env
|
||||||
|
.entry(next_sym.as_string()?)
|
||||||
|
.or_insert(arglist.clone());
|
||||||
|
if *curr != arglist {
|
||||||
|
*curr = arglist.clone();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// grab next argument from list
|
||||||
|
let val = lval_pop(args, 0)?;
|
||||||
|
|
||||||
|
// bind a copy to the function's environment
|
||||||
|
debug!("lval_call: adding {},{} to local fn environment", sym, val);
|
||||||
|
let curr = new_env.entry(sym.as_string()?).or_insert(val.clone());
|
||||||
|
// if we're overwriting, overwrite!
|
||||||
|
if *curr != val {
|
||||||
|
*curr = val.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Use the lookup map to initialize the new child env for evaluation
|
||||||
|
let mut local_env = Lenv::new(Some(new_env.clone()), Some(e));
|
||||||
|
// if all formals have been bound
|
||||||
|
if formals.len()? == 0 {
|
||||||
|
// Evaluate and return
|
||||||
|
// first, apply any held by the lambda.
|
||||||
|
for (k, v) in env {
|
||||||
|
local_env.put(k, v);
|
||||||
|
}
|
||||||
|
let mut ret = lval_sexpr();
|
||||||
|
lval_add(&mut ret, &body)?;
|
||||||
|
debug!("lval_call: evaluating fully applied lambda {}", ret);
|
||||||
|
// evaluate with the environment of the function, which now has the env this was called with as a parent.
|
||||||
|
builtin_eval(&mut local_env, &mut ret)
|
||||||
|
} else {
|
||||||
|
// Otherwise return partially evaluated function
|
||||||
|
// build a new lval for it
|
||||||
|
debug!("Returning partially applied lambda");
|
||||||
|
Ok(lval_lambda(new_env, formals.clone(), body.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(BlisprError::WrongType(
|
||||||
|
"Function".to_string(),
|
||||||
|
format!("{:?}", f),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a slice of boxed Lvals, return a single evaluated sexpr
|
||||||
|
fn eval_cells(e: &mut Lenv, cells: &[Box<Lval>]) -> BlisprResult {
|
||||||
|
cells.iter().fold(Ok(lval_sexpr()), |acc, c| {
|
||||||
|
match acc {
|
||||||
|
Ok(mut lval) => {
|
||||||
|
lval_add(&mut lval, &*lval_eval(e, &mut c.clone())?)?;
|
||||||
|
Ok(lval)
|
||||||
|
}
|
||||||
|
// it's just a Result so we can bubble errors out of the fold
|
||||||
|
Err(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fully evaluate an `Lval`
|
||||||
|
pub fn lval_eval(e: &mut Lenv, v: &mut Lval) -> BlisprResult {
|
||||||
|
let child_count;
|
||||||
|
let mut args_eval;
|
||||||
|
match v {
|
||||||
|
Lval::Blispr(forms) => {
|
||||||
|
// If it's multiple, evaluate each and return the result of the last
|
||||||
|
args_eval = eval_cells(e, forms)?;
|
||||||
|
let forms_len = args_eval.len()?;
|
||||||
|
return Ok(lval_pop(&mut args_eval, forms_len - 1)?);
|
||||||
|
}
|
||||||
|
Lval::Sym(s) => {
|
||||||
|
// If it's a symbol, perform an environment lookup
|
||||||
|
let result = e.get(&s)?;
|
||||||
|
debug!(
|
||||||
|
"lval_eval: Symbol lookup - retrieved {:?} from key {:?}",
|
||||||
|
result, s
|
||||||
|
);
|
||||||
|
// The environment stores Lvals ready to go, we're done
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
Lval::Sexpr(ref mut cells) => {
|
||||||
|
// If it's a Sexpr, we're going to continue past this match
|
||||||
|
// First, though, recursively evaluate each child with lval_eval()
|
||||||
|
debug!("lval_eval: Sexpr, evaluating children");
|
||||||
|
// grab the length and evaluate the children
|
||||||
|
child_count = cells.len();
|
||||||
|
args_eval = eval_cells(e, cells)?;
|
||||||
|
}
|
||||||
|
// if it's not a sexpr, we're done, return as is
|
||||||
|
_ => {
|
||||||
|
debug!("lval_eval: Non-sexpr: {:?}", v);
|
||||||
|
return Ok(Box::new(v.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if child_count == 0 {
|
||||||
|
// It was a Sexpr, but it was empty. We're done, return it
|
||||||
|
Ok(Box::new(v.clone()))
|
||||||
|
} else if child_count == 1 {
|
||||||
|
// Single expression
|
||||||
|
debug!("Single-expression");
|
||||||
|
lval_eval(e, &mut *lval_pop(v, 0)?)
|
||||||
|
} else {
|
||||||
|
// Function call
|
||||||
|
// We'll pop the first element off and attempt to call it on the rest of the elements
|
||||||
|
// lval_call will handle typechecking fp
|
||||||
|
let fp = lval_pop(&mut args_eval, 0)?;
|
||||||
|
debug!("Calling function {:?} on {:?}", fp, v);
|
||||||
|
lval_call(e, *fp, &mut *args_eval)
|
||||||
|
}
|
||||||
|
}
|
19
src/repl/lpus.pest
Normal file
19
src/repl/lpus.pest
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
COMMENT = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" }
|
||||||
|
WHITESPACE = _{ (" " | NEWLINE ) }
|
||||||
|
|
||||||
|
num = @{ int }
|
||||||
|
int = { ("+" | "-")? ~ digit+ }
|
||||||
|
digit = { '0'..'9' }
|
||||||
|
|
||||||
|
symbol = @{ (letter | digit | "_" | arithmetic_ops | "\\" | comparison_ops | "&")+ }
|
||||||
|
letter = { 'a' .. 'z' | 'A' .. 'Z' }
|
||||||
|
arithmetic_ops = { "+" | "-" | "*" | "/" | "%" | "^" }
|
||||||
|
comparison_ops = { "=" | "<" | ">" | "!" }
|
||||||
|
|
||||||
|
sexpr = { "(" ~ expr* ~ ")" }
|
||||||
|
|
||||||
|
qexpr = { "{" ~ expr* ~ "}" }
|
||||||
|
|
||||||
|
expr = { num | symbol | sexpr | qexpr }
|
||||||
|
|
||||||
|
program = { SOI ~ expr* ~ EOI }
|
182
src/repl/lval.rs
Normal file
182
src/repl/lval.rs
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
use std::{collections::HashMap, fmt};
|
||||||
|
|
||||||
|
// The recursive types hold their children in one of these bad boys
|
||||||
|
// TODO Should this be a VecDeque or a LinkedList instead?
|
||||||
|
type LvalChildren = Vec<Box<Lval>>;
|
||||||
|
pub type LBuiltin = fn(&mut Lval) -> ReplResult;
|
||||||
|
|
||||||
|
// There are two types of function - builtin and lambda
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum LvalFun {
|
||||||
|
Builtin(String, LBuiltin), // (name, function pointer)
|
||||||
|
Lambda(HashMap<String, Box<Lval>>, Box<Lval>, Box<Lval>), // (environment(?), formals, body), both should be Qexpr // TODO these should both be Rc<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
// The book has a pointer to an Lenv in the Lambda
|
||||||
|
// I instead just store a plain old hashmap of any extras
|
||||||
|
// it's then applied in lval_call
|
||||||
|
|
||||||
|
// The main type - all possible Blispr values
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Lval {
|
||||||
|
Lpus(LvalChildren),
|
||||||
|
Fun(LvalFun),
|
||||||
|
Num(i64),
|
||||||
|
Sym(String),
|
||||||
|
Sexpr(LvalChildren),
|
||||||
|
Qexpr(LvalChildren),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Lval {
|
||||||
|
pub fn as_num(&self) -> Result<i64> {
|
||||||
|
match *self {
|
||||||
|
Lval::Num(n_num) => Ok(n_num),
|
||||||
|
_ => Err("".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn as_string(&self) -> Result<String> {
|
||||||
|
match self {
|
||||||
|
Lval::Sym(s) => Ok(s.to_string()),
|
||||||
|
_ => Err(BlisprError::WrongType(
|
||||||
|
"symbol".to_string(),
|
||||||
|
format!("{}", self),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn len(&self) -> Result<usize> {
|
||||||
|
match *self {
|
||||||
|
Lval::Sexpr(ref children) | Lval::Qexpr(ref children) | Lval::Blispr(ref children) => {
|
||||||
|
Ok(children.len())
|
||||||
|
}
|
||||||
|
_ => Err(BlisprError::NoChildren),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for LvalFun {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
LvalFun::Builtin(name, _) => write!(f, "Builtin({})", name),
|
||||||
|
LvalFun::Lambda(env, formals, body) => {
|
||||||
|
write!(f, "Lambda({{{:?}}},{{{}}},{{{}}})", env, formals, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for LvalFun {
|
||||||
|
fn eq(&self, other: &LvalFun) -> bool {
|
||||||
|
match self {
|
||||||
|
LvalFun::Builtin(name, _) => match other {
|
||||||
|
LvalFun::Builtin(other_name, _) => name == other_name,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
LvalFun::Lambda(env, formals, body) => match other {
|
||||||
|
LvalFun::Lambda(other_env, other_f, other_b) => {
|
||||||
|
formals == other_f && body == other_b && env == other_env
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Lval {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Lval::Blispr(_cells) => write!(f, "<toplevel>"),
|
||||||
|
Lval::Fun(lf) => match lf {
|
||||||
|
LvalFun::Builtin(name, _) => write!(f, "<builtin: {}>", name),
|
||||||
|
LvalFun::Lambda(_, formals, body) => write!(f, "(\\ {} {})", formals, body),
|
||||||
|
},
|
||||||
|
Lval::Num(n) => write!(f, "{}", n),
|
||||||
|
Lval::Sym(s) => write!(f, "{}", s),
|
||||||
|
Lval::Sexpr(cell) => write!(f, "({})", lval_expr_print(cell)),
|
||||||
|
Lval::Qexpr(cell) => write!(f, "{{{}}}", lval_expr_print(cell)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lval_expr_print(cell: &[Box<Lval>]) -> String {
|
||||||
|
let mut ret = String::new();
|
||||||
|
for i in 0..cell.len() {
|
||||||
|
ret.push_str(&format!("{}", cell[i]));
|
||||||
|
if i < cell.len() - 1 {
|
||||||
|
ret.push_str(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
// Each allocates a brand new boxed Lval
|
||||||
|
// The recursive types start empty
|
||||||
|
|
||||||
|
pub fn lval_blispr() -> Box<Lval> {
|
||||||
|
Box::new(Lval::Blispr(Vec::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lval_builtin(f: LBuiltin, name: &str) -> Box<Lval> {
|
||||||
|
Box::new(Lval::Fun(LvalFun::Builtin(name.to_string(), f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lval_lambda(
|
||||||
|
env: HashMap<String, Box<Lval>>,
|
||||||
|
formals: Box<Lval>,
|
||||||
|
body: Box<Lval>,
|
||||||
|
) -> Box<Lval> {
|
||||||
|
Box::new(Lval::Fun(LvalFun::Lambda(env, formals, body)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lval_num(n: i64) -> Box<Lval> {
|
||||||
|
Box::new(Lval::Num(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lval_sym(s: &str) -> Box<Lval> {
|
||||||
|
Box::new(Lval::Sym(s.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lval_sexpr() -> Box<Lval> {
|
||||||
|
Box::new(Lval::Sexpr(Vec::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lval_qexpr() -> Box<Lval> {
|
||||||
|
Box::new(Lval::Qexpr(Vec::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manipulating children
|
||||||
|
|
||||||
|
// Add lval x to lval::sexpr or lval::qexpr v
|
||||||
|
pub fn lval_add(v: &mut Lval, x: &Lval) -> Result<()> {
|
||||||
|
match *v {
|
||||||
|
Lval::Sexpr(ref mut children)
|
||||||
|
| Lval::Qexpr(ref mut children)
|
||||||
|
| Lval::Blispr(ref mut children) => {
|
||||||
|
children.push(Box::new(x.clone()));
|
||||||
|
}
|
||||||
|
_ => return Err(BlisprError::NoChildren),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract single element of sexpr at index i
|
||||||
|
pub fn lval_pop(v: &mut Lval, i: usize) -> BlisprResult {
|
||||||
|
match *v {
|
||||||
|
Lval::Sexpr(ref mut children)
|
||||||
|
| Lval::Qexpr(ref mut children)
|
||||||
|
| Lval::Blispr(ref mut children) => {
|
||||||
|
let ret = (&children[i]).clone();
|
||||||
|
children.remove(i);
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
_ => Err(BlisprError::NoChildren),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add each cell in y to x
|
||||||
|
pub fn lval_join(x: &mut Lval, mut y: Box<Lval>) -> Result<()> {
|
||||||
|
while y.len()? > 0 {
|
||||||
|
lval_add(x, &*lval_pop(&mut y, 0)?)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
56
src/repl/parser.rs
Normal file
56
src/repl/parser.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use pest::{iterators::Pair, Parser};
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[grammar = "lpus.pest"]
|
||||||
|
pub struct LpusParser;
|
||||||
|
|
||||||
|
fn is_bracket_or_eoi(parsed: &Pair<Rule>) -> bool {
|
||||||
|
if parsed.as_rule() == Rule::EOI {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
let c = parsed.as_str();
|
||||||
|
c == "(" || c == ")" || c == "{" || c == "}"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a rule with children into the given containing Lval
|
||||||
|
fn read_to_lval(mut v: &mut Lval, parsed: Pair<Rule>) -> Result<()> {
|
||||||
|
for child in parsed.into_inner() {
|
||||||
|
if is_bracket_or_eoi(&child) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lval_add(&mut v, &*lval_read(child)?)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lval_read(parsed: Pair<Rule>) -> ReplResult {
|
||||||
|
match parsed.as_rule() {
|
||||||
|
// Rule::program => {
|
||||||
|
// let mut ret = lval_lpus();
|
||||||
|
// read_to_lval(&mut ret, parsed)?;
|
||||||
|
// Ok(ret)
|
||||||
|
// }
|
||||||
|
// Rule::expr => lval_read(parsed.into_inner().next().unwrap()),
|
||||||
|
Rule::sexpr => {
|
||||||
|
let mut ret = lval_sexpr();
|
||||||
|
read_to_lval(&mut ret, parsed)?;
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
// Rule::qexpr => {
|
||||||
|
// let mut ret = lval_qexpr();
|
||||||
|
// read_to_lval(&mut ret, parsed)?;
|
||||||
|
// Ok(ret)
|
||||||
|
// }
|
||||||
|
Rule::num => Ok(lval_num(parsed.as_str().parse::<i64>()?)),
|
||||||
|
Rule::symbol => Ok(lval_sym(parsed.as_str())),
|
||||||
|
_ => unreachable!(), // COMMENT/WHITESPACE etc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eval_str(e: &mut Lenv, s: &str) -> ReplResult {
|
||||||
|
let parsed = LpusParser::parse(Rule::sexpr, s)?.next().unwrap();
|
||||||
|
// debug!("{}", parsed);
|
||||||
|
let mut lval_ptr = lval_read(parsed)?;
|
||||||
|
// debug!("Parsed: {:?}", *lval_ptr);
|
||||||
|
lval_eval(e, &mut *lval_ptr)
|
||||||
|
}
|
44
src/repl/repl.rs
Normal file
44
src/repl/repl.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
use rustyline::error::ReadlineError;
|
||||||
|
use rustyline::Editor;
|
||||||
|
|
||||||
|
fn repl(e: &mut Lenv) -> Result<()> {
|
||||||
|
println!("LPUS v0.0.1");
|
||||||
|
println!("Use exit(), Ctrl-C, or Ctrl-D to exit prompt");
|
||||||
|
|
||||||
|
let mut rl = Editor::<()>::new();
|
||||||
|
if rl.load_history("./.lpus-history.txt").is_err() {
|
||||||
|
println!("No history found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let input = rl.readline("lpus> ");
|
||||||
|
|
||||||
|
match input {
|
||||||
|
Ok(line) => {
|
||||||
|
rl.add_history_entry(line.as_ref());
|
||||||
|
print_eval_result(eval_str(e, &line));
|
||||||
|
}
|
||||||
|
Err(ReadlineError::Interrupted) => {
|
||||||
|
info!("CTRL-C");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(ReadlineError::Eof) => {
|
||||||
|
info!("CTRL-D");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!("Error: {:?}", err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rl.save_history("./.blispr-history.txt")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_eval_result(v: ReplResult) {
|
||||||
|
match v {
|
||||||
|
Ok(res) => println!("{}", res),
|
||||||
|
Err(e) => eprintln!("Error: {}", e),
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user