Conversation
smda 4.5.0 moved ESCAPER_DOWNWARD_COMPATIBILITY from 1.13.16 to 4.4.5, so samples hashed under smda 4.4.4 or older are reported stale once this floor is installed, which is accurate: the Intel escaper changed output in 4.4.5. The database-free suite passes unchanged under 4.8.0.
…mples smda 4.4.5 changed where CIL blocks end, which no recalculation from a stored report can repair, and a sample without a recorded minhash_smda_version is stale whatever hashed it.
produceIdaReport() opens a copy of the sample in a temporary directory so IDA database files never land beside the original, registers the headless backend as the IdaInterface singleton that IdaExporter resolves through, and restamps the resulting report from the on-disk file. selectCandidateSigs() narrows a signature bundle to the sigs that can plausibly match a binary's format, architecture and toolchain, and applySigs() reverts any signature that stays below the match threshold.
An unconditional continue after the progress print made the submission branch unreachable, turning --mode recursive into a dry run.
mcrit client submit --disassembler ida routes files through a headless IDA Pro instead of SMDA, optionally applying a FLIRT signature bundle via --ida-sigs/--ida-sig-min-matches. Since the headless IDA library holds a single database per process, bulk modes are forced into worker mode so each file is disassembled in its own subprocess; that subprocess is now started with sys.executable, as a python on PATH may lack the optional IDA dependencies.
Running a directory through IDA against a live server showed three problems. --server and --apitoken were appended after the submit subcommand, which only the client parser accepts, so each worker died with a usage error. A worker past its timeout was reported but left running. And IDA loads a file of no known format as a raw binary, which produced an empty sample; such a report is now skipped. Also coerces two optional IDA return values to str.
Signature probing: a planned signature that could not be located afterwards was left applied, bypassing the match threshold; it is now undone. Windows signatures are selected by architecture suffix (38 candidates down to at most 10 per sample), and 32-bit ARM ELF files also get the bundle's -arm signatures. The sample is hashed without reading it into memory a second time. Console: --force_update is forwarded to workers, an empty family or version derived in recursive mode is forwarded as such, --ida-sig-min-matches is rejected below 1 and no longer compared against its own default, and a missing ida-domain package stops the run once instead of once per file. Kept signatures are logged rather than printed, and the console shows that logger. Tests drop a module stub that never took effect, patch the name the console actually calls, and cover several signatures in sequence.
r0ny123
added a commit
to r0ny123/mcrit
that referenced
this pull request
Sep 23, 2026
The sixteen clean mcrit merges test-run and passing, and familiary#204. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011EAW1DRkBwmjZtGzQ5pgDA
# Conflicts: # CHANGELOG.md
# Conflicts: # CHANGELOG.md
tests/testSmdaFloor.py holds three assumptions of the floor as tests, so a later smda release that breaks one fails the suite instead of a corpus: - Every function of the smda 1.5.12 and 4.2.16 reports under tests/ carries the fields smda's SmdaFunction.fromDict requires (REQUIRED_FUNCTION_FIELDS, REQUIRED_FUNCTION_METADATA) and loads under the installed smda. - recalculateAllPicHashes and repairMinHashes decide staleness by a single number, smda's ESCAPER_DOWNWARD_COMPATIBILITY, still 4.4.5 in 4.8.0. That only works while it is at least as new as each per-architecture pic_hash escape gate smda applies itself (AArch64 4.2.0, Intel 4.3.5, CIL 4.3.8, Dalvik 4.4.2); a test asserts it. - A sample carrying the "MCRIT4IDA cli via SMDA <version>" string the IDA producer writes is taken as current by recalculateAllPicHashes, with the same sample under its original smda 1.5.12 version as the control. The producer's comment now names the method that parses that string, and the CHANGELOG entry for the floor states the findings and the measured counts: 300 database-free tests and the full suite of 456 pass under smda 4.8.0.
…oor test IdaReportVersionTest read the last LOGGER.info call of recalculateAllPicHashes and expected it to be the "Found N outdated samples" summary, so any info line logged after the summary would fail both tests without the behaviour changing. It now picks the summary out of every info call and asserts there is exactly one.
Collaborator
Author
|
Merged
On smda 4.8.0 the full suite passes on the merged head (522 tests). |
This branch has not been deployed
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.
Closes #83.
Problem
mcrit client submitalways disassembles with SMDA. The IDA plugin can instead upload IDA's own analysis, including the function names FLIRT recovers, but only for the single database open in the GUI. There was no way to run a folder of samples through IDA and get the same result.My earlier assessment on the issue was that this needed IDA batch tooling outside this repository's dependencies. That no longer holds: smda ships a headless IDA backend (
IdaInterface.fromPath, viaida-domain) behind its optionalidaextra, so the work reduces to an optional extra here plus a producer for the report.Fix
--disassembler idaswaps only the step that produces theSmdaReport. The sample is copied to a temporary directory, opened in a headless IDA database, and exported withDisassembler(backend="IDA"), which is the same call the plugin makes.sha256,filenameandbinary_sizeare then taken from the file on disk, because the buffer SMDA sees is IDA's reassembled segment image and its hash is not the sample's. Everything after that is the existing submit path, so skipping known samples,--force_update,--outputand the family/version derivation of each mode behave as they do with SMDA.--ida-sigs DIRpoints at an unpacked Hex-Rays FLIRT Signature Bundle. Bundles are not applied by IDA on its own, and the current one holds about 4,500 signatures, so candidates are first narrowed by file format, architecture and Go/Rust detection. Each candidate is applied behind an undo point and kept only if it names at least--ida-sig-min-matchesfunctions (default 10); otherwise it is undone. The threshold exists because a few coincidental hits would otherwise reach MCRIT as wrong function labels.windows/**/*_<x64|x86|arm64|arm>.sig, at most 10linux/**/*-<debian arch>.sig: about 60 for x86, x64 and AArch64, 116 for 32-bit ARM (armhf,armelandarmtogether)golang/stdlibs/golang_std_<pc|arm|arm64>_*.sigrust/rust_bundle_<triple>.sigmatching architecture and OSOne subprocess per file. The headless IDA library holds a single database per process, and one malformed sample must not end a batch, so
--workeris switched on automatically for thedir,recursiveandmalpediamodes. A missingida-domainpackage stops the run once, with an install hint, before any file is touched.Reports carry
smda_versionMCRIT4IDA cli via SMDA <version>.MongoDbStoragealready recognises that prefix and reads the last token as the smda version, so the string has to end with it; a test pins that.Bugs found on the way
Running a directory through IDA against a live server exposed defects in the existing submit code. Each has its own changelog entry and test.
continuein_handle_submit_recursive--mode recursiveprinted every file and submitted none--server/--apitokenappended aftersubmitin the worker command--force_updatenot forwarded to workers--workeridasmda 4.8.0
The floor moves from
>=4.2.13to>=4.8.0, as its own commit. smda 4.5.0 movedESCAPER_DOWNWARD_COMPATIBILITYfrom1.13.16to4.4.5, so samples hashed under smda 4.4.4 or older are reported stale after upgrading. That report is accurate, andrepair_minhashesbrings them current..NET samples are the exception. smda 4.4.5 ends CIL blocks at
throw,rethrow,endfinallyandendfilter, which changes the stored report's structure rather than its escaping. No recalculation from a stored report repairs that; affected samples have to be submitted again. The changelog entry says so.Limits
FLIRT results reach MCRIT only as function names, which the server stores as function labels attributed to the submitting user. There is no per-function library flag:
is_librarystays a per-sample property, and changing that would need a schema change in SMDA and in both storage backends. Filename base-address suffixes are ignored underida, since IDA's loader decides the base address. IDA older than 9.1 is not supported.Reproduce
Checked against IDA Pro 9.3 on macOS with a server on memory storage: a directory of two PE files and one file of random bytes took about 20 seconds. Both PE files were stored under their on-disk sha256, the random file was skipped, no IDA database files appeared beside the samples, and a second run skipped everything. Re-running with
-uand a different family updated the stored samples through the workers. Undo of a rejected signature was confirmed separately inside a headless session: the signature count went from 2 to 3 on apply and back to 2 on undo.Not measured: a sample where the bundle adds names beyond IDA's stock signatures. The two PE files were small launchers the stock signatures already name completely (225 of 251 functions), so the one signature that passed the threshold,
Microsoft.Win10SDK_x64.sigwith 18 matches, changed no names. No large binary and no ELF, Go or Rust sample was run.Tests
ruff format,ruff checkandty checkare clean, andpytest -m 'not mongo'passes (235). The new tests need neither IDA nor a database: signature selection runs against a fake bundle tree, signature application against stub IDA modules (including keep, drop, keep in sequence), and the console tests patch the report producer. The suite also passes withida-domainuninstalled, which is the CI situation.