Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
chivay committed May 12, 2021
1 parent 85af884 commit 3a62538
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 5 deletions.
4 changes: 4 additions & 0 deletions drakcore/drakcore/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ def get_dumps(self, output_file):
""" Download memory dumps """
return self.minio.fget_object(self.bucket, f"{self.uid}/dumps.zip", output_file.name)

def get_ipt(self, output_file):
""" Download memory dumps """
return self.minio.fget_object(self.bucket, f"{self.uid}/ipt.zip", output_file.name)

def get_graph(self, output_file):
""" Download ProcDOT graph """
return self.minio.fget_object(self.bucket, f"{self.uid}/graph.dot", output_file.name)
Expand Down
53 changes: 53 additions & 0 deletions drakcore/drakcore/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import os
import re
import pathlib
import subprocess
import contextlib
from tempfile import NamedTemporaryFile, TemporaryDirectory
from zipfile import ZipFile, ZIP_DEFLATED

Expand Down Expand Up @@ -212,6 +214,57 @@ def graph(task_uid):
def metadata(task_uid):
return jsonify(get_analysis_metadata(task_uid))

def find_pid_cr3(fileobj, pid: int):
# Find process CR3
for line in fileobj:
entry = json.loads(line)
if entry["PID"] == pid:
return int(entry["CR3"], 16)
return None


from drakcore.ipt_disasm import get_executed_blocks

@contextlib.contextmanager
def open_temporary(*args, **kwargs):
file = open(*args, **kwargs)
try:
yield file
finally:
file.close()
os.remove(file.name)

@app.route("/ipt/<analysis_uid>/<int:pid>")
def ipt(analysis_uid, pid):
analysis = AnalysisProxy(minio, analysis_uid)

with NamedTemporaryFile() as ipt_zip, \
TemporaryDirectory() as analysis_dir, \
open_temporary(pathlib.Path(analysis_dir) / "codemon.log", "wb") as codemon_log:
analysis_dir = pathlib.Path(analysis_dir)
ipt_dir = analysis_dir / "ipt"
# Get IPT artifacts
analysis.get_log("codemon", codemon_log)

with open(codemon_log.name) as f:
cr3 = find_pid_cr3(f, pid)
if not cr3:
return "PID not found", 404

analysis.get_ipt(ipt_zip)
subprocess.run(["unzip", ipt_zip.name, "-d", analysis_dir])

blocks = set()
for cpu in ipt_dir.glob("ipt_stream_*"):
for block in get_executed_blocks(pathlib.Path(analysis_dir), cr3, cpu, use_blocks=False):
#print(hex(block))
blocks.add(block)

l = list(blocks)
l.sort()
res = list(map(hex, l))
return json.dumps(res)


@app.route("/status/<task_uid>")
def status(task_uid):
Expand Down
48 changes: 44 additions & 4 deletions drakcore/drakcore/ipt_disasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def match_frames(page_faults, frames, foreign_frames):
return results


def get_ptxed_cmdline(analysis_dir, cr3_value, vcpu, use_blocks=False):
def get_ptxed_cmdline(analysis_dir, cr3_value, pt_stream, use_blocks=False):
log.debug("Analysis directory: %s", analysis_dir)
log.debug("CR3: %#x", cr3_value)

Expand Down Expand Up @@ -114,19 +114,59 @@ def get_ptxed_cmdline(analysis_dir, cr3_value, vcpu, use_blocks=False):
for addr, fname in mappings:
name = Path(fname).name
fpath = analysis_dir / "ipt" / "dumps" / name
if fpath.stat().st_size == 0x1000:
if not fpath.exists():
log.warning(f"Missing {fpath}")
continue
if fpath.name != "(null)" and fpath.stat().st_size == 0x1000:
pages.append("--raw")
pages.append(f"{fpath}:0x{addr:x}")

binary = ["ptxed", "--block-decoder"]
binary = ["ptxed", "--block-decoder", "--block:show-blocks"]

if use_blocks:
binary = ["drak-ipt-blocks", "--cr3", hex(cr3_value)]

ptxed_cmdline = binary + pages
ptxed_cmdline = binary + pages + ["--pt", pt_stream]
log.info("IPT: Succesfully generated ptxed command line")
return ptxed_cmdline

def generate_ipt_blocks(process):
for line in process.stdout:
entry = json.loads(line)
if entry["event"] == "block_executed":
yield int(entry["data"], 16)

def generate_ptxed(process):
prev_block = False

for line in process.stdout:
if prev_block and all(map(lambda c: c in "0123456789abcdef", line[:16].decode())):
yield int(line[:16], 16)
prev_block = False

if line.startswith(b"[cbr"):
continue
if line.startswith(b"[ptwrite"):
continue
if line.startswith(b"[enabled"):
continue
if line.startswith(b"[disabled"):
continue
if line.startswith(b"[resumed"):
continue
if line.startswith(b"[exec mode"):
continue
if line.strip().decode() == "[block]":
prev_block = True
continue

def get_executed_blocks(analysis_dir, cr3_value, pt_stream, use_blocks=False):
current = get_ptxed_cmdline(analysis_dir, cr3_value, pt_stream, use_blocks)
proc = subprocess.Popen(current, stdout=subprocess.PIPE)
if use_blocks:
yield from generate_ipt_blocks(proc)
else:
yield from generate_ptxed(proc)

def cmdline_main():
parser = argparse.ArgumentParser()
Expand Down
2 changes: 1 addition & 1 deletion drakcore/drakcore/tools/ipt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ cmake_minimum_required(VERSION 3.2)
project(drak-ipt-tools CXX)

add_executable(drak-ipt-blocks drak-ipt-blocks.cpp)
target_link_libraries(drak-ipt-blocks ipt json-c spdlog fmt)
target_link_libraries(drak-ipt-blocks ipt json-c fmt)
set_property(TARGET drak-ipt-blocks PROPERTY CXX_STANDARD 17)
install(TARGETS drak-ipt-blocks RUNTIME DESTINATION bin)

0 comments on commit 3a62538

Please sign in to comment.