mirror of
https://github.com/dobin/avred
synced 2026-06-08 13:54:13 +00:00
274 lines
11 KiB
Python
274 lines
11 KiB
Python
from copy import deepcopy
|
|
from model.model_verification import FillType
|
|
import logging
|
|
from typing import List
|
|
|
|
from model.model_data import Match
|
|
from model.model_verification import *
|
|
from model.file_model import BaseFile
|
|
|
|
|
|
# Middle: 8
|
|
# Thirds: 4 * 2
|
|
MATCH_SIZE_CUTOFF = 16
|
|
|
|
def toTestEntry(scanIndex, result):
|
|
scanResult = ScanResult.NOT_SCANNED
|
|
if not result:
|
|
scanResult = ScanResult.NOT_DETECTED
|
|
else:
|
|
scanResult = ScanResult.DETECTED
|
|
|
|
testEntry = MatchTest(scanIndex, scanResult)
|
|
return testEntry
|
|
|
|
|
|
def getMatchTestsFor(verifications: List[VerificationEntry], matchOrder: TestMatchOrder, matchModify: TestMatchModify):
|
|
for verification in verifications:
|
|
if verification.info == matchOrder and verification.type == matchModify:
|
|
return verification.matchTests
|
|
return None
|
|
|
|
|
|
def verify(file: BaseFile, matches: List[Match], scanner) -> Verification:
|
|
"""Verify matches in file with scanner, and return the result"""
|
|
verifications = runVerifications(file, matches, scanner)
|
|
matchConclusions = verificationAnalyzer(verifications)
|
|
verify = Verification(verifications, matchConclusions)
|
|
return verify
|
|
|
|
|
|
def verificationAnalyzer(verifications: List[VerificationEntry]) -> MatchConclusion:
|
|
"""Do some analysis on the verifications, and return the result"""
|
|
verifyResults = []
|
|
if len(verifications) == 0:
|
|
matchConclusion = MatchConclusion(verifyResults)
|
|
return matchConclusion
|
|
|
|
# check if robust:
|
|
# no ISOLATED.FULL not detected
|
|
hasDominant = False
|
|
matchTests = getMatchTestsFor(verifications, TestMatchOrder.ISOLATED, TestMatchModify.FULL)
|
|
for matchTest in matchTests:
|
|
if matchTest.scanResult == ScanResult.NOT_DETECTED:
|
|
hasDominant = True
|
|
break
|
|
if not hasDominant:
|
|
# set all to ROBUST
|
|
for _ in verifications[0].matchTests: # just iterate through it
|
|
res = VerifyStatus.ROBUST
|
|
verifyResults.append(res)
|
|
matchConclusion = MatchConclusion(verifyResults)
|
|
return matchConclusion
|
|
|
|
matchCount = len(verifications[0].matchTests)
|
|
idx = 0
|
|
while idx < matchCount:
|
|
middleRes = getMatchTestsFor(verifications, TestMatchOrder.ISOLATED, TestMatchModify.MIDDLE8)[idx].scanResult
|
|
thirdsRes = getMatchTestsFor(verifications, TestMatchOrder.ISOLATED, TestMatchModify.THIRDS4)[idx].scanResult
|
|
fullRes = getMatchTestsFor(verifications, TestMatchOrder.ISOLATED, TestMatchModify.FULL)[idx].scanResult
|
|
|
|
# very weak signature
|
|
if middleRes == ScanResult.NOT_DETECTED and thirdsRes == ScanResult.NOT_DETECTED:
|
|
res = VerifyStatus.DOMINANT
|
|
|
|
# for small signatures, ignore MIDDLE/THIRDS and just make result depend on FULL
|
|
elif fullRes == ScanResult.NOT_DETECTED:
|
|
res = VerifyStatus.DOMINANT
|
|
|
|
# incremental and stuff, just everything in between
|
|
else:
|
|
res = VerifyStatus.IRRELEVANT
|
|
|
|
|
|
verifyResults.append(res)
|
|
idx += 1
|
|
|
|
matchConclusion = MatchConclusion(verifyResults)
|
|
return matchConclusion
|
|
|
|
|
|
def runVerifications(file: BaseFile, matches: List[Match], scanner) -> List[VerificationEntry]:
|
|
"""Perform modifications on file from matches, scan with scanner and return those results"""
|
|
verificationRuns: List[VerificationEntry] = []
|
|
if len(matches) == 0:
|
|
return verificationRuns
|
|
|
|
logging.info(f"Verify {len(matches)} matches")
|
|
|
|
# Independant, Middle
|
|
verificationRun = VerificationEntry(
|
|
index=len(verificationRuns),
|
|
matchOrder=TestMatchOrder.ISOLATED,
|
|
matchModify=TestMatchModify.MIDDLE8)
|
|
for match in matches:
|
|
if match.size < MATCH_SIZE_CUTOFF:
|
|
verificationRun.matchTests.append(MatchTest('', ScanResult.NOT_SCANNED))
|
|
continue
|
|
fileCopy = deepcopy(file)
|
|
offset = match.fileOffset + int((match.size) // 2) - 4
|
|
fileCopy.Data().hidePart(offset, 8, fillType=FillType.lowentropy)
|
|
result = scanner.scannerDetectsBytes(fileCopy.DataAsBytes(), file.filename)
|
|
verificationRun.matchTests.append(toTestEntry('', result))
|
|
logging.info("Verification run: {}".format(verificationRun))
|
|
verificationRuns.append(verificationRun)
|
|
|
|
# Independant, Thirds
|
|
verificationRun = VerificationEntry(
|
|
index=len(verificationRuns),
|
|
matchOrder=TestMatchOrder.ISOLATED,
|
|
matchModify=TestMatchModify.THIRDS4)
|
|
for match in matches:
|
|
if match.size < MATCH_SIZE_CUTOFF:
|
|
verificationRun.matchTests.append(MatchTest('', ScanResult.NOT_SCANNED))
|
|
continue
|
|
fileCopy = deepcopy(file)
|
|
offset1 = match.fileOffset + int( (match.size // 3) * 1) - 2
|
|
offset2 = match.fileOffset + int( (match.size // 3) * 2) - 2
|
|
fileCopy.Data().hidePart(offset1, 4, fillType=FillType.lowentropy)
|
|
fileCopy.Data().hidePart(offset2, 4, fillType=FillType.lowentropy)
|
|
result = scanner.scannerDetectsBytes(fileCopy.DataAsBytes(), file.filename)
|
|
verificationRun.matchTests.append(toTestEntry('', result))
|
|
verificationRuns.append(verificationRun)
|
|
logging.info("Verification run: {}".format(verificationRun))
|
|
|
|
# Independant, Full
|
|
verificationRun = VerificationEntry(
|
|
index=len(verificationRuns),
|
|
matchOrder=TestMatchOrder.ISOLATED,
|
|
matchModify=TestMatchModify.FULL
|
|
)
|
|
for match in matches:
|
|
fileCopy = deepcopy(file)
|
|
fileCopy.Data().hidePart(match.fileOffset, match.size, fillType=FillType.lowentropy)
|
|
result = scanner.scannerDetectsBytes(fileCopy.DataAsBytes(), file.filename)
|
|
verificationRun.matchTests.append(toTestEntry('', result))
|
|
verificationRuns.append(verificationRun)
|
|
logging.info("Verification run: {}".format(verificationRun))
|
|
|
|
# Independant, Full B
|
|
verificationRun = VerificationEntry(
|
|
index=len(verificationRuns),
|
|
matchOrder=TestMatchOrder.ISOLATED,
|
|
matchModify=TestMatchModify.FULLB
|
|
)
|
|
for match in matches:
|
|
fileCopy = deepcopy(file)
|
|
fileCopy.Data().hidePart(match.fileOffset, match.size, fillType=FillType.highentropy)
|
|
result = scanner.scannerDetectsBytes(fileCopy.DataAsBytes(), file.filename)
|
|
verificationRun.matchTests.append(toTestEntry('', result))
|
|
verificationRuns.append(verificationRun)
|
|
logging.info("Verification run: {}".format(verificationRun))
|
|
|
|
if len(matches) == 1:
|
|
return verificationRuns
|
|
|
|
# Incremental, Middle
|
|
verificationRun = VerificationEntry(
|
|
index=len(verificationRuns),
|
|
matchOrder=TestMatchOrder.INCREMENTAL,
|
|
matchModify=TestMatchModify.MIDDLE8,
|
|
)
|
|
fileCopy = deepcopy(file)
|
|
for match in matches:
|
|
if match.size < MATCH_SIZE_CUTOFF:
|
|
verificationRun.matchTests.append(MatchTest('', ScanResult.NOT_SCANNED))
|
|
continue
|
|
offset = match.fileOffset + int((match.size) // 2) - 4
|
|
fileCopy.Data().hidePart(offset, 8, fillType=FillType.lowentropy)
|
|
result = scanner.scannerDetectsBytes(fileCopy.DataAsBytes(), file.filename)
|
|
verificationRun.matchTests.append(toTestEntry(match.idx, result))
|
|
verificationRuns.append(verificationRun)
|
|
logging.info("Verification run: {}".format(verificationRun))
|
|
|
|
# Incremental, Full
|
|
verificationRun = VerificationEntry(
|
|
index=len(verificationRuns),
|
|
matchOrder=TestMatchOrder.INCREMENTAL,
|
|
matchModify=TestMatchModify.FULL)
|
|
fileCopy = deepcopy(file)
|
|
for match in matches:
|
|
fileCopy.Data().hidePart(match.fileOffset, match.size, fillType=FillType.lowentropy)
|
|
result = scanner.scannerDetectsBytes(fileCopy.DataAsBytes(), file.filename)
|
|
verificationRun.matchTests.append(toTestEntry(match.idx, result))
|
|
verificationRuns.append(verificationRun)
|
|
logging.info("Verification run: {}".format(verificationRun))
|
|
|
|
# Decremental, Full
|
|
verificationRun = VerificationEntry(
|
|
index=len(verificationRuns),
|
|
matchOrder=TestMatchOrder.DECREMENTAL,
|
|
matchModify=TestMatchModify.FULL)
|
|
fileCopy = deepcopy(file)
|
|
n = 0
|
|
for match in reversed(matches):
|
|
fileCopy.Data().hidePart(match.fileOffset, match.size, fillType=FillType.lowentropy)
|
|
result = scanner.scannerDetectsBytes(fileCopy.DataAsBytes(), file.filename)
|
|
verificationRun.matchTests.append(toTestEntry(n, result))
|
|
n += 1
|
|
verificationRun.matchTests = list(reversed(verificationRun.matchTests))
|
|
verificationRuns.append(verificationRun)
|
|
logging.info("Verification run: {}".format(verificationRun))
|
|
|
|
# All, Middle
|
|
verificationRun = VerificationEntry(
|
|
index=len(verificationRuns),
|
|
matchOrder=TestMatchOrder.ALL,
|
|
matchModify=TestMatchModify.MIDDLE8)
|
|
fileCopy = deepcopy(file)
|
|
for match in matches:
|
|
if match.size < MATCH_SIZE_CUTOFF:
|
|
# no need to a matchTest, as it is done later
|
|
continue
|
|
offset = match.fileOffset + int((match.size) // 2) - 4
|
|
fileCopy.Data().hidePart(offset, 8, fillType=FillType.lowentropy)
|
|
result = scanner.scannerDetectsBytes(fileCopy.DataAsBytes(), file.filename)
|
|
for match in matches:
|
|
if match.size < MATCH_SIZE_CUTOFF:
|
|
verificationRun.matchTests.append(MatchTest('', ScanResult.NOT_SCANNED))
|
|
else:
|
|
verificationRun.matchTests.append(toTestEntry(0, result))
|
|
verificationRun.matchTests = list(reversed(verificationRun.matchTests))
|
|
verificationRuns.append(verificationRun)
|
|
logging.info("Verification run: {}".format(verificationRun))
|
|
|
|
# All, Thirds
|
|
verificationRun = VerificationEntry(
|
|
index=len(verificationRuns),
|
|
matchOrder=TestMatchOrder.ALL,
|
|
matchModify=TestMatchModify.THIRDS4)
|
|
fileCopy = deepcopy(file)
|
|
for match in matches:
|
|
if match.size < MATCH_SIZE_CUTOFF:
|
|
# no need to a matchTest, as it is done in the end
|
|
continue
|
|
offset1 = match.fileOffset + int( (match.size // 3) * 1) - 2
|
|
offset2 = match.fileOffset + int( (match.size // 3) * 2) - 2
|
|
fileCopy.Data().hidePart(offset1, 4, fillType=FillType.lowentropy)
|
|
fileCopy.Data().hidePart(offset2, 4, fillType=FillType.lowentropy)
|
|
result = scanner.scannerDetectsBytes(fileCopy.DataAsBytes(), file.filename)
|
|
for match in matches:
|
|
if match.size < MATCH_SIZE_CUTOFF:
|
|
verificationRun.matchTests.append(MatchTest('', ScanResult.NOT_SCANNED))
|
|
else:
|
|
verificationRun.matchTests.append(toTestEntry(0, result))
|
|
verificationRun.matchTests = list(reversed(verificationRun.matchTests))
|
|
verificationRuns.append(verificationRun)
|
|
logging.info("Verification run: {}".format(verificationRun))
|
|
|
|
# All, Full
|
|
verificationRun = VerificationEntry(
|
|
index=len(verificationRuns),
|
|
matchOrder=TestMatchOrder.ALL,
|
|
matchModify=TestMatchModify.FULL)
|
|
fileCopy = deepcopy(file)
|
|
for match in matches:
|
|
fileCopy.Data().hidePart(match.fileOffset, match.size, fillType=FillType.lowentropy)
|
|
result = scanner.scannerDetectsBytes(fileCopy.DataAsBytes(), file.filename)
|
|
for match in matches:
|
|
verificationRun.matchTests.append(toTestEntry(0, result))
|
|
verificationRun.matchTests = list(reversed(verificationRun.matchTests))
|
|
verificationRuns.append(verificationRun)
|
|
logging.info("Verification run: {}".format(verificationRun))
|
|
|
|
return verificationRuns |