fix hasher/matcher bugs that show up with SMDA 4 and mcrit - #3
Open
r0ny123 wants to merge 4 commits into
Open
Conversation
calculateBlockhash always went through IntelInstructionEscaper, even for AArch64 functions mcrit stores via getBlockhashesForFunction. Matcher percentages mixed unique (hash, size) coverage with instance-weighted block_bytes. processFile treated any path containing "dump" as a raw buffer, and baseaddress=0 was ignored. Pin smda>=4.2.13 (same floor as mcrit), add pytest coverage, and a CI job that boots Mongo + mcrit against SMDA's cutwail fixture.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A handful of these have been sitting in the hasher/matcher for a while. They started to actually hurt once mcrit began indexing SMDA 4 reports (including AArch64).
Intel-only PIC hashes
picblocks/blockhasher.pycalculateBlockhashalways did:SMDA 4.x has
SmdaReport.getInstructionEscaper()/SmdaFunction._escaper(intel / aarch64 / cil / dalvik). mcritMemoryStorage/MongoDbStoragecallgetBlockhashesForFunction(..., hash_size=8)on every add, so non-Intel functions were stored under Intel-style escaping.The hasher now uses the function/report escaper (checking
smda_function._escaper,report.getInstructionEscaper(), orSmdaFunction.getInstructionEscaper(architecture)) and only falls back to Intel if nothing else is available. The SHA-256 prefix is unpacked little-endian (<I/<Q) so the integer is the same as SMDA 4.x on a big-endian host.Matcher percentages vs
block_bytesextractBlockhashesaddsblock_sizetoblock_bytesfor every hashed block.match()credited each family once per (hash, size) (thefamily_idsset was reset per hash+size, then reused across query fids).A sample with the same 16-byte matching block in 10 functions plus 16 unmatched bytes scored
16/176instead of160/176. The family loop now credits once per query fid.While I was in there:
unmatched_hasheswas initialized to 0 and never written, and a hash hit / size miss bumpedunmatched_scorebut notunmatched_blocks.saveDb()also ensures parent directories are created (os.makedirs) if saving to a new directory path, andload()handles missing filenames and empty blockhashes safely.Dump vs PE routing
processFileused"dump" in filepath, so/data/dumps/malware.exewent throughdisassembleBuffer. It now matches Malpedia-style names (dump_0x.../dump7_0x...) on the basename.processBufferstill treats_0xin the filename, or an explicitbaseaddress(including0), as a mapped buffer.baseaddress=0used to be falsy and dropped the override, so the PE mapper ran instead.Dump regexes and base/bitness parsers also support 5–6 digit hex base addresses (such as
dump_0x400000) and standard architecture identifiers (x86,i386,amd64,win32,win64).Smaller things
status="error",xcfg is Noneon 1.12.7) no longer crash hashingnum_functions_hashedwas incremented next tonum_blocksinside the per-block loophash_malpedia.pyskipped 9/10 files (file_index % 10 != 0), reade_lfanewas a WORD at 0x3C (now DWORD), andPool(cpu_count() - 2)dies on 1–2 CPUs._identifyPythonnow covers Python 3.10+ DLLs (python310.dll,python311.dll, etc.), and path extraction handles both/and\separators.utils/import_picblocksdb_to_mongo.pyrefactored intoimport_db()with fastinsert_manybatch insertion and guarded CLI execution.setup.pyhad unpinned"smda"whilerequirements.txtpinned 1.12.7 — both nowsmda>=4.2.13(mcrit's floor)block_bintoreport.html; default DB timestamp was%Y-%d-%d; hidden bitness radiovalue="0"won over the 32-bit control; added HTML escaping for family links;/statsfalls back todb/stats.jsonif Mongo is offline;/blocksand/api/blocksvalidate payloads (returning 400 on empty API requests and acceptingbitness/baseaddressparameters).python -m blocks.blockhashmatcherandpython -m utils.make_stats.py; Makefile pointed atnose/ packageblocksTooling, Typing & CI
pyproject.tomlconfiguringruffand Astralty. Codebase is formatted and passes bothruff check/ruff formatandty checkwith zero diagnostics.lintjob (ruff+ty), unit tests, and a second job that starts Mongo 7 +mcrit server/worker, checks out SMDA's xored fixtures, and submits cutwail / aarch64_static / bashlite through the samegetBlockhashesForFunctionpath mcrit uses.requestsis guarded intest_mcrit_live.pyso unit test discovery doesn't fail when running offline.actions/checkout@3d3c42e...,actions/setup-python@5fda3b9...),persist-credentials: false, andpermissions: contents: read.