Merge pull request #1 from zeronounours/master

Make extraction of offsets compatible with Linux
This commit is contained in:
Qazeer
2021-12-08 14:52:44 +01:00
committed by GitHub
2 changed files with 33 additions and 25 deletions
+33 -24
View File
@@ -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
View File
@@ -1,2 +1 @@
requests requests
pywin32