mirror of
https://github.com/wavestone-cdt/EDRSandblast.git
synced 2026-06-08 16:37:12 +00:00
Merge pull request #1 from zeronounours/master
Make extraction of offsets compatible with Linux
This commit is contained in:
+33
-24
@@ -1,13 +1,13 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import csv
|
import csv
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
from requests import get
|
from requests import get
|
||||||
from gzip import decompress
|
from gzip import decompress
|
||||||
from json import loads, dumps
|
from json import loads, dumps
|
||||||
from subprocess import run
|
import subprocess
|
||||||
|
|
||||||
import win32api
|
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
import threading
|
import threading
|
||||||
CSVLock = threading.Lock()
|
CSVLock = threading.Lock()
|
||||||
@@ -16,6 +16,13 @@ machineType = dict(x86=332, x64=34404)
|
|||||||
knownImageVersions = dict(ntoskrnl=list(), wdigest=list())
|
knownImageVersions = dict(ntoskrnl=list(), wdigest=list())
|
||||||
extensions_by_mode = dict(ntoskrnl="exe", wdigest="dll")
|
extensions_by_mode = dict(ntoskrnl="exe", wdigest="dll")
|
||||||
|
|
||||||
|
def run(args, **kargs):
|
||||||
|
"""Wrap subprocess.run to works on Windows and Linux"""
|
||||||
|
# Windows needs shell to be True, to locate binary automatically
|
||||||
|
# On Linux, shell needs to be False to manage lists in args
|
||||||
|
shell = sys.platform in ["win32"]
|
||||||
|
return subprocess.run(args, shell=shell, **kargs)
|
||||||
|
|
||||||
def downloadSpecificFile(entry, pe_basename, pe_ext, knownPEVersions, output_folder):
|
def downloadSpecificFile(entry, pe_basename, pe_ext, knownPEVersions, output_folder):
|
||||||
pe_name = f'{pe_basename}.{pe_ext}'
|
pe_name = f'{pe_basename}.{pe_ext}'
|
||||||
|
|
||||||
@@ -97,17 +104,21 @@ def get_field_offset(symbols_info, field_name):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
def get_file_version(path):
|
def get_file_version(path):
|
||||||
info = win32api.GetFileVersionInfo(path, '\\')
|
# dump version number using r2
|
||||||
ms = info['FileVersionMS']
|
r = run(["r2", "-c", "iV", "-qq", path], capture_output=True)
|
||||||
ls = info['FileVersionLS']
|
for line in r.stdout.decode().splitlines():
|
||||||
return (win32api.HIWORD(ms), win32api.LOWORD(ms),
|
line = line.strip()
|
||||||
win32api.HIWORD(ls), win32api.LOWORD(ls))
|
if line.startswith("FileVersion:"):
|
||||||
|
return [int(frag) for frag in line.split(" ")[-1].split(".")]
|
||||||
|
|
||||||
|
print(f'[!] ERROR : failed to extract version from {path}.')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
def extractOffsets(input_file, output_file, mode):
|
def extractOffsets(input_file, output_file, mode):
|
||||||
if os.path.isfile(input_file):
|
if os.path.isfile(input_file):
|
||||||
try:
|
try:
|
||||||
# check image type (ntoskrnl, wdigest, etc.)
|
# check image type (ntoskrnl, wdigest, etc.)
|
||||||
r = run(["r2", "-c", "iE", "-qq", input_file], shell=True, capture_output=True)
|
r = run(["r2", "-c", "iE", "-qq", input_file], capture_output=True)
|
||||||
for line in r.stdout.decode().splitlines():
|
for line in r.stdout.decode().splitlines():
|
||||||
if "ntoskrnl.exe" in line:
|
if "ntoskrnl.exe" in line:
|
||||||
imageType = "ntoskrnl"
|
imageType = "ntoskrnl"
|
||||||
@@ -123,17 +134,6 @@ def extractOffsets(input_file, output_file, mode):
|
|||||||
if mode != imageType:
|
if mode != imageType:
|
||||||
print(f"[*] Skipping {input_file} since we are in {mode} mode")
|
print(f"[*] Skipping {input_file} since we are in {mode} mode")
|
||||||
return
|
return
|
||||||
# dump version number
|
|
||||||
"""
|
|
||||||
r = run(["r2", "-c", "iV", "-qq", input_file], shell=True, capture_output=True)
|
|
||||||
for line in r.stdout.decode().splitlines():
|
|
||||||
line = line.strip()
|
|
||||||
if line.startswith("FileVersion:"):
|
|
||||||
full_version = [int(frag) for frag in line.split(" ")[-1].split(".")]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
assert(False)
|
|
||||||
"""
|
|
||||||
if os.path.sep not in input_file:
|
if os.path.sep not in input_file:
|
||||||
input_file = "." + os.path.sep + input_file
|
input_file = "." + os.path.sep + input_file
|
||||||
full_version = get_file_version(input_file)
|
full_version = get_file_version(input_file)
|
||||||
@@ -149,9 +149,9 @@ def extractOffsets(input_file, output_file, mode):
|
|||||||
|
|
||||||
print(f'[*] Processing {imageType} version {imageVersion} (file: {input_file})')
|
print(f'[*] Processing {imageType} version {imageVersion} (file: {input_file})')
|
||||||
# download the PDB if needed
|
# download the PDB if needed
|
||||||
r = run(["r2", "-c", "idpd", "-qq", input_file], shell=True, capture_output=True)
|
r = run(["r2", "-c", "idpd", "-qq", input_file], capture_output=True)
|
||||||
# dump all symbols
|
# dump all symbols
|
||||||
r = run(["r2", "-c", "idpi", "-qq", '-B', '0', input_file], shell=True, capture_output=True)
|
r = run(["r2", "-c", "idpi", "-qq", '-B', '0', input_file], capture_output=True)
|
||||||
all_symbols_info = [line.strip() for line in r.stdout.decode().splitlines()]
|
all_symbols_info = [line.strip() for line in r.stdout.decode().splitlines()]
|
||||||
|
|
||||||
if imageType == "ntoskrnl":
|
if imageType == "ntoskrnl":
|
||||||
@@ -231,12 +231,21 @@ if __name__ == '__main__':
|
|||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
# check R2 version
|
# check R2 version
|
||||||
output = run(["r2", "-V"], shell=True, capture_output=True).stdout.decode()
|
output = run(["r2", "-V"], capture_output=True).stdout.decode()
|
||||||
ma,me,mi = map(int, output.splitlines()[0].split(" ")[0].split("."))
|
ma,me,mi = map(int, output.splitlines()[0].split(" ")[0].split("."))
|
||||||
if (ma, me, mi) < (5,4,3):
|
if (ma, me, mi) < (5,0,0):
|
||||||
print("WARNING : This script has been tested with radare2 5.4.3 (works) and 4.3.1 (does NOT work)")
|
print("WARNING : This script has been tested with radare2 5.0.0 (works) and 4.3.1 (does NOT work)")
|
||||||
print(f"You have version {ma}.{me}.{mi}, if is does not work correctly, meaning most of the offsets are not found (i.e. 0), check radare2's 'idpi' command output and modify get_symbol_offset() & get_field_offset() to parse symbols correctly")
|
print(f"You have version {ma}.{me}.{mi}, if is does not work correctly, meaning most of the offsets are not found (i.e. 0), check radare2's 'idpi' command output and modify get_symbol_offset() & get_field_offset() to parse symbols correctly")
|
||||||
input("Press enter to continue")
|
input("Press enter to continue")
|
||||||
|
if sys.platform in ["linux"]:
|
||||||
|
# check that cabextract is insalled
|
||||||
|
try:
|
||||||
|
run(["cabextract", "-v"], check=True, capture_output=True)
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||||
|
print('[!] ERROR : On Linux systems, radare2 needs cabextract to be installed to work with PDB.')
|
||||||
|
exit(1)
|
||||||
|
if "R2_CURL" not in os.environ:
|
||||||
|
print("WARNING : On Linux systems, radare2 may have trouble to download PDB files. If offsets are reported as 0, export R2_CURL=1 prior to running the script.")
|
||||||
|
|
||||||
|
|
||||||
# If the output file exists, load the already analyzed image versions.
|
# If the output file exists, load the already analyzed image versions.
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
requests
|
requests
|
||||||
pywin32
|
|
||||||
Reference in New Issue
Block a user