XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
"""Read only thread registers and module addresses from a local diagnostic minidump."""
import argparse,json,struct
from pathlib import Path
from inspect_minidump import inspect
p=argparse.ArgumentParser(description=__doc__);p.add_argument('dump',type=Path);p.add_argument('--output',type=Path,required=True);a=p.parse_args()
d=a.dump.read_bytes()
def u(fmt,at):return struct.unpack_from('<'+fmt,d,at)
count,directory=u('II',8);streams={u('III',directory+i*12)[0]:u('III',directory+i*12)[1:] for i in range(count)}
metadata=inspect(a.dump)
memory=[]
if 5 in streams:
    at=streams[5][1];n=u('I',at)[0]
    memory.extend(u('QII',at+4+i*16) for i in range(n))
if 9 in streams:
    at=streams[9][1];n,file_rva=u('QQ',at)
    for i in range(n):
        address,size=u('QQ',at+16+i*16);memory.append((address,size,file_rva));file_rva+=size

def read_pointer(address):
    for base,size,file_rva in memory:
        if base<=address and address+8<=base+size:return u('Q',file_rva+address-base)[0]
    return None
def location(address):
    for m in metadata['modules']:
        base=int(m['base'],16)
        if base<=address<base+int(m['size'],16):return {'module':Path(m['name']).name,'rva':hex(address-base)}
    return {'address':hex(address)}
times={}
if 17 in streams:
    at=streams[17][1];header,size,n=u('III',at)
    for i in range(n):
        row=at+header+i*size;tid=u('I',row)[0];times[tid]={'kernelSeconds':u('Q',row+32)[0]/1e7,'userSeconds':u('Q',row+40)[0]/1e7}
rows=[]
if 3 in streams:
    at=streams[3][1];n=u('I',at)[0]
    for i in range(n):
        row=at+4+i*48;tid=u('I',row)[0];stack,size,stack_rva=u('QII',row+24);context_size,context=u('II',row+40)
        if context_size<256:continue
        rsp=u('Q',context+0x98)[0];rip=u('Q',context+0xf8)[0]
        candidates=[]
        for offset in range(0,min(max(0,stack+size-rsp),2048),8):
            pointer=read_pointer(rsp+offset)
            if pointer is None and stack_rva and stack<=rsp+offset<stack+size:pointer=u('Q',stack_rva+rsp+offset-stack)[0]
            if pointer is None:continue
            where=location(pointer)
            if where.get('module','').lower().endswith(('elitedangerous64.exe','dinput8.dll','dbghelp.dll')):candidates.append({'offset':offset,**where})
        rows.append({'thread':tid,**times.get(tid,{}),'instruction':location(rip),'rsp':hex(rsp),'stackCandidates':candidates[:20]})
rows.sort(key=lambda r:r.get('kernelSeconds',0)+r.get('userSeconds',0),reverse=True)
result={'scope':'Address candidates only; stack entries are not an unwind','threads':rows}
with a.output.open('x',encoding='utf-8') as out:json.dump(result,out,indent=2)
print(json.dumps({'scope':result['scope'],'threads':rows[:5]},indent=2))