mirror of
https://github.com/dobin/avred
synced 2026-06-08 13:54:13 +00:00
238 lines
9.7 KiB
Python
238 lines
9.7 KiB
Python
from intervaltree import Interval, IntervalTree
|
|
import logging
|
|
from typing import List, Tuple, Set
|
|
|
|
from plugins.dotnet.file_dotnet import FilePeDotnet
|
|
from plugins.dotnet.dncilparser import DncilParser, IlMethod
|
|
from plugins.dotnet.dotnet_data import DotnetData, DotnetDataEntry
|
|
|
|
from myutils import *
|
|
from config import MAX_DISASM_SIZE
|
|
|
|
from dotnetfile import DotNetPE
|
|
from dotnetfile.structures import DOTNET_CLR_HEADER
|
|
from dotnetfile.parser import DOTNET_STREAM_HEADER
|
|
from dotnetfile.util import BinaryStructureField, FileLocation
|
|
|
|
from model.model_data import Match
|
|
from model.model_code import AsmInstruction, UiDisasmLine, SectionType
|
|
|
|
|
|
def augmentFileDotnet(filePeDotnet: FilePeDotnet, matches: List[Match]) -> str:
|
|
"""Correlates file offsets in matches with the disassembles filePe methods"""
|
|
dncilParser = DncilParser(filePeDotnet.filepath)
|
|
dotNetData = DotnetData(filePeDotnet.filepath)
|
|
dotNetData.init()
|
|
|
|
for match in matches:
|
|
matchDisasmLines: List[UiDisasmLine] = []
|
|
matchAsmInstructions: List[AsmInstruction] = []
|
|
matchBytes: bytes = filePeDotnet.Data().getBytesRange(start=match.start(), end=match.end())
|
|
matchHexdump = hexdmp(matchBytes, offset=match.start())
|
|
|
|
detail = ''
|
|
info = filePeDotnet.peSectionsBag.getSectionByPhysAddr(match.start()).name # should always work
|
|
# May have more information in dotnet sections
|
|
dotnetSection = filePeDotnet.dotnetSectionsBag.getSectionByPhysAddr(match.start())
|
|
if dotnetSection is not None:
|
|
info += " " + dotnetSection.name
|
|
# Even more info with regions
|
|
regions = filePeDotnet.regionsBag.getSectionsForPhysRange(match.start(), match.end())
|
|
info += ' '.join(s.name for s in regions)
|
|
|
|
matchPeSection = filePeDotnet.peSectionsBag.getSectionByPhysAddr(match.fileOffset)
|
|
if matchPeSection is not None and matchPeSection.name == ".text":
|
|
# .text has most of DotNet, check if its methods
|
|
matchDotnetSection = filePeDotnet.dotnetSectionsBag.getSectionByPhysAddr(match.fileOffset)
|
|
if matchDotnetSection is not None and matchDotnetSection.name == "methods":
|
|
match.sectionType = SectionType.CODE
|
|
if match.size < MAX_DISASM_SIZE:
|
|
# only disassemble if the match is reasonably small. same for function names
|
|
matchAsmInstructions, matchDisasmLines, methodNames = disassembleDotNet(match.start(), match.size, dncilParser)
|
|
detail += " " + " ".join(methodNames)
|
|
else:
|
|
match.sectionType = SectionType.DATA
|
|
results: List[DotnetDataEntry] = dotNetData.findBy(match.start(), match.end())
|
|
|
|
infoAdd: Set[str] = set()
|
|
uidl: List[UiDisasmLine] = []
|
|
for res in results:
|
|
u = UiDisasmLine(
|
|
res.offset,
|
|
0,
|
|
True,
|
|
res.tableName + res.data,
|
|
res.tableName + res.data)
|
|
uidl.append(u)
|
|
infoAdd.add(res.tableName)
|
|
matchDisasmLines += uidl
|
|
detail += " ".join(list(infoAdd))
|
|
else:
|
|
match.sectionType = SectionType.DATA
|
|
|
|
# take dotnet section
|
|
relevantSection = filePeDotnet.dotnetSectionsBag.getSectionByPhysAddr(match.fileOffset)
|
|
#if relevantSection is None:
|
|
# # or pe section if not in dotnet section
|
|
# relevantSection = filePe.peSectionsBag.getSectionByPhysAddr(match.fileOffset)
|
|
#if relevantSection is None:
|
|
# # should never be reached
|
|
# relevantSection = "unknown?"
|
|
|
|
match.setSection(relevantSection)
|
|
match.setData(matchBytes)
|
|
match.setDataHexdump(matchHexdump)
|
|
match.setSectionInfo(info)
|
|
match.setSectionDetail(detail)
|
|
match.setDisasmLines(matchDisasmLines)
|
|
match.setAsmInstructions(matchAsmInstructions)
|
|
|
|
s = ''
|
|
for section in filePeDotnet.peSectionsBag.sections:
|
|
s += "{0:<24}: File Offset: {1:<7} Virtual Addr: {2:<6} size {3:<6} scan:{4}\n".format(
|
|
section.name, section.physaddr, section.virtaddr, section.size, section.scan)
|
|
return s
|
|
|
|
|
|
def disassembleDotNet(offset: int, size: int, dncilParser: DncilParser) -> Tuple[List[AsmInstruction], List[UiDisasmLine], Set[str]]:
|
|
"""Get section-info & disassembly as UiDisasmLine's with dncilParser for range offset/+size"""
|
|
uiDisasmLines: List[UiDisasmLine] = []
|
|
asmInstructions: List[AsmInstruction] = []
|
|
methodNames: Set[str] = set()
|
|
|
|
ilMethods = dncilParser.getMethods(offset, offset+size)
|
|
if ilMethods is None or len(ilMethods) == 0:
|
|
#logging.debug("No disassembly found for {:X}", offset)
|
|
return [], [], ''
|
|
logging.info("Match physical {}/0x{:X}, method disassemblies found: {}".format(
|
|
offset, offset, len(ilMethods)))
|
|
|
|
# all relevant instructions
|
|
addrTightStart = offset
|
|
addrTightEnd = offset + size
|
|
|
|
# provide some more context
|
|
addrWideStart = addrTightStart - 16
|
|
addrWideEnd = addrTightEnd + 16
|
|
|
|
intervalMatch = Interval(offset, offset+size)
|
|
# check each disassembled function if it contains instructions for our offset
|
|
ilMethod: IlMethod
|
|
for ilMethod in sorted(ilMethods):
|
|
intervalMethod = Interval(ilMethod.getOffset(), ilMethod.getOffset() + ilMethod.getSize())
|
|
# check if this method contains part of the data
|
|
if not intervalMatch.overlaps(intervalMethod):
|
|
continue
|
|
|
|
# the method contains some of the data.
|
|
# * add method metadata
|
|
# * add the relevant instructions
|
|
isPart = False
|
|
if ilMethod.getOffset() >= addrTightStart and ilMethod.getOffset() <= addrTightEnd:
|
|
isPart = True
|
|
uiDisasmLine = UiDisasmLine(
|
|
ilMethod.getOffset(),
|
|
ilMethod.getRva(),
|
|
isPart,
|
|
"Function: {}".format(ilMethod.getName()),
|
|
"Function: {}".format(ilMethod.getName())
|
|
)
|
|
uiDisasmLines.append(uiDisasmLine)
|
|
|
|
# find all instructions of method which are part of the match
|
|
for asmInstruction in ilMethod.instructions:
|
|
addrOff = asmInstruction.offset
|
|
|
|
if addrOff > addrWideStart and addrOff < addrWideEnd:
|
|
isPart = False
|
|
if addrOff >= addrTightStart and addrOff <= addrTightEnd:
|
|
asmInstructions.append(asmInstruction)
|
|
isPart = True
|
|
|
|
text = ' '
|
|
text += f"{' '.join('{:02x}'.format(b) for b in asmInstruction.rawBytes) : <20}"
|
|
text += asmInstruction.disasm
|
|
uiDisasmLine = UiDisasmLine(
|
|
asmInstruction.offset,
|
|
asmInstruction.rva,
|
|
isPart,
|
|
text,
|
|
text
|
|
)
|
|
uiDisasmLines.append(uiDisasmLine)
|
|
|
|
methodNames.add(ilMethod.getName())
|
|
|
|
return asmInstructions, uiDisasmLines, methodNames
|
|
|
|
|
|
def getDotNetDisassemblyHeader(filePeDotnet: FilePeDotnet, offset: int, size: int,) -> List[UiDisasmLine]:
|
|
uiDisasmLines: List[UiDisasmLine] = [] # all diasassmbled IL
|
|
dotnet_file = DotNetPE(filePeDotnet.filepath)
|
|
|
|
textSection = filePeDotnet.peSectionsBag.getSectionByName('.text')
|
|
addrOffset = textSection.virtaddr - textSection.physaddr
|
|
|
|
# DotNet header / CLI header / CLR header
|
|
clrHeader: DOTNET_CLR_HEADER = dotnet_file.clr_header
|
|
for entry in clrHeader.structure_fields:
|
|
hdrFileOffset = entry.address
|
|
hdrSize = entry.size
|
|
if hdrFileOffset >= offset and hdrFileOffset + hdrSize <= offset + size:
|
|
text = "{:18} CLR Header: {}: {}".format(
|
|
hexstr(filePeDotnet.DataAsBytes(), hdrFileOffset, hdrSize),
|
|
entry.display_name,
|
|
entry.value)
|
|
uiDisasmLine = UiDisasmLine(
|
|
hdrFileOffset,
|
|
entry.address,
|
|
True,
|
|
text,
|
|
text
|
|
)
|
|
uiDisasmLines.append(uiDisasmLine)
|
|
|
|
# metadata header
|
|
entry: BinaryStructureField
|
|
for entry in dotnet_file.dotnet_metadata_header.structure_fields:
|
|
hdrFileOffset = entry.address - addrOffset
|
|
hdrSize = entry.size
|
|
if hdrFileOffset >= offset and hdrFileOffset + hdrSize <= offset + size:
|
|
text = "{:18} Metadata Header: {}: {}".format(
|
|
hexstr(filePeDotnet.DataAsBytes(), hdrFileOffset, hdrSize),
|
|
entry.display_name,
|
|
entry.value)
|
|
uiDisasmLine = UiDisasmLine(
|
|
hdrFileOffset,
|
|
entry.address,
|
|
True,
|
|
text,
|
|
text
|
|
)
|
|
uiDisasmLines.append(uiDisasmLine)
|
|
|
|
# all 5 stream headers
|
|
streamHeader: DOTNET_STREAM_HEADER
|
|
for streamHeader in dotnet_file.dotnet_stream_headers:
|
|
hdrFileOffset = streamHeader.address - addrOffset
|
|
hdrSize = streamHeader.size
|
|
|
|
for entry in streamHeader.structure_fields:
|
|
entryFileOffset = entry.address - addrOffset
|
|
entrySize = entry.size
|
|
if entryFileOffset >= offset and entryFileOffset + entrySize <= offset + size:
|
|
text = "{:18} Stream Header: {}: {}".format(
|
|
hexstr(filePeDotnet.DataAsBytes(), entryFileOffset, entrySize),
|
|
entry.display_name,
|
|
entry.value)
|
|
uiDisasmLine = UiDisasmLine(
|
|
hdrFileOffset,
|
|
entry.address,
|
|
True,
|
|
text,
|
|
text
|
|
)
|
|
uiDisasmLines.append(uiDisasmLine)
|
|
|
|
return uiDisasmLines
|