Nice troll post for a repo on the eve of dying.
aiooord/mim — "Morse Code in Malware Analysis": a review
Repo:
https://github.com/aiooord/mim
I pulled the repo. Here's the demolition.
The code is 30 lines and two lookup tables
Excluding the alphabet maps, the entire "research" is: a
for loop that concatenates map lookups, and a
while (stream >> word) loop that concatenates map lookups in reverse. That's it.
The README is roughly 700 words of prose about "in-depth exploration", "research implications" and "advancing cybersecurity defenses", attached to a program a first-semester student writes as a homework exercise. The ratio of grandiosity to substance here is the single most damning thing in the repo.
The premise is wrong
Morse is not obfuscation. It's a public, keyless, fixed substitution over a two-symbol alphabet. There is no secret. Anyone who sees
^.-.. ^.... ^.- knows immediately what it is.
And it's actively
worse than doing nothing. A binary containing long runs of
. - / ^ and spaces is a statistical scream. Plaintext strings at least drown in the millions of plaintext strings every binary contains; base64 blobs are ordinary background noise. A Morse-alphabet run is a fingerprint you could match with a two-line regex at essentially zero false-positive rate across all legitimate software.
This scheme loses to plaintext, loses to base64, and loses to single-byte XOR — the laziest technique in existence — on size, on conspicuousness, and on having a key.
Then it ships the key inside the binary
usage/morse_decoder.h embeds
g_ReverseMorseCodeMap as a static array of literal
".-",
"-...",
"--.-" strings in the data section.
The README claims this "bypass[es] many static analysis tools." Your own second program refutes your first program's thesis: a reverse engineer sees the complete decode table before they see anything else. You handed them the answer key and stapled it to the test.
The README describes features that don't exist
Quote:
|
Allows for customization of Morse code representations.
|
There is no customization. The map is a
const global initialized inline in a header. Changing it means hand-editing two files and manually keeping them in sync. No key, no flag, no config, no seed. That bullet point is simply false.
Quote:
|
Binary Integration Demonstrator... demonstrates how the malware remains functional.
|
It is a
main() that prints the author's name. No payload, no API resolution, no C2 string, no dynamic imports:
Code:
int main(int argc, char* argv[])
{
std::string name = "-- ^.. ^.-.. ^.- ^-.. / ...";
std::cout << MorseCodeToPlaintext(name) << std::endl;
return 0;
}
Naming that a "Demonstrator" is résumé inflation.
Actual bugs
- Silent, destructive data loss. The encoder map has zero punctuation. Encode http://evil.com/a.php or C:\Users\x and it silently drops : / . \ and hands back corrupted garbage — no error, no return code. The exact strings this tool exists to hide are the ones it destroys. decode(encode(x)) != x for essentially every realistic input.
- Infinite loop on EOF. ./encoder < /dev/null spins forever: getline fails, input stays empty, != "exit" is true, print, repeat. The only exit path is typing the literal word "exit".
- Two independently hardcoded copies of the alphabet, one per direction, with nothing generating one from the other and no round-trip test. You couldn't keep two tables in sync in a 30-line project.
- const map at namespace scope in a header — internal linkage, so a separate dynamically-allocated unordered_map is constructed at static-init time in every translation unit that includes it. Invisible at this size; a real bug at any other.
- find() then .at() — double hash lookup. Twice. In both halves of a 30-line codebase.
- Neither header includes <string>; both rely on transitive includes. exit(0) skipping destructors. Unused argc/argv. No CLI mode, so it can't be scripted into a build — the only way you'd actually use it.
Engineering hygiene
Windows-only
.sln/
.vcxproj for code that is pure ISO C++ with no platform dependency. No CMake, no Makefile.
.vcxproj.user files — per-developer local state — committed to version control, while the
.gitignore is an untouched generic template covering
*.o and
*.mod (Fortran, in a C++ repo) but not
.vs/,
Debug/, or the
.user files actually present.
No tests, no CI, no releases. Apache-2.0 on thirty lines.
It isn't research
No methodology. No experiment. No detection-rate measurement against any scanner. No comparison to any other encoding. No threat model.
Not a single number appears anywhere in the repository.
And it never cites the 2021 Morse-encoded phishing campaign that is the entire reason anyone briefly cared about this technique — "research" that doesn't cite the incident it's studying is a blog post with delusions.
The README's cadence — "delves into", "sheds light on", triadic bullets, a Conclusion section for a program with two functions — reads as machine-generated filler. That's the real problem: someone spent more effort generating prose
about the artifact than building the artifact, and the prose makes claims the artifact contradicts.