mirror of
https://github.com/dobin/avred
synced 2026-06-08 13:54:13 +00:00
172 lines
4.9 KiB
Python
172 lines
4.9 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import base64
|
|
from dataclasses import dataclass
|
|
from typing import List, Set, Dict, Tuple, Optional
|
|
from dataclasses import dataclass
|
|
import logging
|
|
import random
|
|
|
|
from model.model_verification import FillType
|
|
from model.model_code import AsmInstruction, SectionType, UiDisasmLine, Section
|
|
|
|
|
|
# All Input: bytes
|
|
# All Output: bytes
|
|
# All Internal: bytearray
|
|
class Data():
|
|
def __init__(self, data: bytes):
|
|
self._data: bytearray = bytearray(data)
|
|
|
|
|
|
def getBytes(self) -> bytes:
|
|
return bytes(self._data)
|
|
|
|
|
|
def getBytesRange(self, start: int, end: int) -> bytes:
|
|
data = self._data[start:end]
|
|
return bytes(data)
|
|
|
|
|
|
def getLength(self) -> int:
|
|
return len(self._data)
|
|
|
|
|
|
def hideMatch(self, match: Match):
|
|
self.hidePart(match.fileOffset, match.size)
|
|
|
|
|
|
def hideMatches(self, matches: List[Match]):
|
|
for match in matches:
|
|
self.hidePart(match.fileOffset, match.size)
|
|
|
|
|
|
def hidePart(self, offset: int, size: int, fillType: FillType=FillType.null):
|
|
"""Overwrites size bytes at base with fillType"""
|
|
self.patchDataFill(offset, size, fillType)
|
|
|
|
|
|
def patchDataFill(self, offset: int, size: int, fillType: FillType=FillType.null):
|
|
origLen = len(self._data)
|
|
|
|
fill = None # has to be exactly <size> bytes
|
|
if fillType is FillType.null:
|
|
fill = b"\x00" * size
|
|
elif fillType is FillType.space:
|
|
fill = b" " * size
|
|
elif fillType is FillType.highentropy:
|
|
random.seed(offset) # make it deterministic
|
|
fill = randbytes(size)
|
|
elif fillType is FillType.lowentropy:
|
|
random.seed(offset) # make it deterministic
|
|
temp = randbytes(size)
|
|
temp = base64.b64encode(temp)
|
|
fill = temp[:size]
|
|
|
|
self.patchData(offset, fill)
|
|
if len(self._data) != origLen:
|
|
raise Exception("patchData cant patch, different size: {} {}".format(origLen, len(self._data)))
|
|
|
|
|
|
def patchData(self, offset: int, replace: bytes) -> bytes:
|
|
self._data[offset:offset+len(replace)] = replace
|
|
|
|
|
|
def swapData(self, offset_a, size_a, offset_b, size_b):
|
|
data_a = self._data[offset_a:offset_a+size_a]
|
|
data_b = self._data[offset_b:offset_b+size_b]
|
|
|
|
self._data[offset_a:offset_a + size_b] = data_b
|
|
self._data[offset_a + size_b:offset_a + size_b + size_a] = data_a
|
|
|
|
|
|
|
|
def randbytes(n):
|
|
#temp = random.randbytes(size) # 3.9..
|
|
random_bytes = bytes([random.getrandbits(8) for _ in range(0, n)])
|
|
return random_bytes
|
|
|
|
|
|
class Match():
|
|
def __init__(self, idx: int, fileOffset:int , size: int, iteration: int = 0):
|
|
self.idx: int = idx
|
|
self.fileOffset: int = fileOffset
|
|
self.size: int = size
|
|
self.iteration = iteration
|
|
|
|
# set by augmentation
|
|
self.rva: int = 0
|
|
self.data: bytes = b''
|
|
self.dataHexdump: str = ''
|
|
self.sectionInfo: str = '' # info about the section the match is in
|
|
self.sectionDetail: str = '' # more detailed info
|
|
|
|
self.section: Section = Section('', 0, 0, 0, False) # init with empty section
|
|
self.sectionType: SectionType = SectionType.UNKNOWN
|
|
self.disasmLines: List[UiDisasmLine] = []
|
|
self.asmInstructions: List[AsmInstruction] = []
|
|
|
|
def start(self):
|
|
return self.fileOffset
|
|
|
|
def end(self):
|
|
return self.fileOffset + self.size
|
|
|
|
def setRva(self, rva: int):
|
|
self.rva = rva
|
|
|
|
def setData(self, data):
|
|
self.data = data
|
|
|
|
def setDataHexdump(self, dataHexdump):
|
|
self.dataHexdump = dataHexdump
|
|
|
|
def setSectionInfo(self, info):
|
|
self.sectionInfo = info
|
|
|
|
def setSectionDetail(self, detail):
|
|
self.sectionDetail = detail
|
|
|
|
def getSectionInfo(self):
|
|
return self.sectionInfo
|
|
|
|
def setSection(self, section: Section):
|
|
self.section = section
|
|
|
|
def getSection(self):
|
|
return self.section
|
|
|
|
def setDisasmLines(self, disasmLines):
|
|
self.disasmLines = disasmLines
|
|
|
|
def getDisasmLines(self):
|
|
return self.disasmLines
|
|
|
|
def setAsmInstructions(self, asminstruction):
|
|
self.asmInstructions = asminstruction
|
|
|
|
def getAsmInstructions(self):
|
|
return self.asmInstructions
|
|
|
|
def __str__(self):
|
|
s = ""
|
|
s += "id:{} offset:{} len:{}\n".format(self.idx, self.fileOffset, self.size)
|
|
if self.sectionInfo is not None:
|
|
s += " Section: {}\n".format(self.sectionInfo)
|
|
#if self.disasmLines is not None:
|
|
# s += " DisasmLines: {}\n".format(self.disasmLines)
|
|
if self.dataHexdump is not None:
|
|
s += " Hexdump: \n{}\n".format(self.dataHexdump)
|
|
s += '\n'
|
|
return s
|
|
|
|
def __eq__(self, other: Match):
|
|
# TODO: Size too?
|
|
return self.fileOffset == other.fileOffset
|
|
|
|
def __lt__(self, other: Match):
|
|
return self.fileOffset < other.fileOffset
|
|
|
|
|