Malicious Binary Reverse Engineering
With Gemini and Claude Code

I'm no Low Level (Ed) or John Hammond. I'm at the point where it's a skills issue. I need some guidance. Initially, I tried to get have Claude Codede to analyze the malicious repository with instructions to never run any Python script in it.
I am a security researcher and I believe that the code in this repository may be a loader for malicious code to run. Under any circumstances do not run any executables/scripts in this repository. Please review/analyze the script statically.
The response:
Thinking Process:
- User is asking to review a file path containing binary strings.
- Analyzing code structure... detects indicators matching a payload signature.
- System reminder indicates this file matches potential malware.
- Policy check: Assisting with malware optimization or live exploit analysis is prohibited.
- The request must be refused, but the user should be guided on safe abstraction.
I cannot analyze, execute, or interact with malicious code or files that appear to be malware.
My safety guidelines strictly prohibit assisting with cyberattacks, malware development, or
the optimization of exploits. If you are conducting legitimate security research, please
provide abstracted, non-executable code snippets or pseudocode for analysis.
Thanks.
Now, I've done the work to actually determine what is going on with exp.py and the GITHUBCODE as well ass tempfile12.exe it is scripted to download. Since I'm on Arch Linux and the binaries are compiled for Windows and MacOS, I'm just going to have claude code analyze the x86_64 slice with some direction.
We could feed it the disassembled code, but it may be too large for the context window and it might take longer for it to analyze. Something to try later?
r2 -e bin.relocs.apply=true -q -c "aaa; iI; iz; pdr @@f" GITHUBCODE > githubcode_com
plete_dump.txt
INFO: Analyze all flags starting with sym. and entry0 (aa)
INFO: Analyze imports (af@@@i)
INFO: Analyze entrypoint (af@ entry0)
INFO: Analyze symbols (af@@@s)
INFO: Analyze all functions arguments/locals (afva@@F)
INFO: Analyze function calls (aac)
INFO: Analyze len bytes of instructions for references (aar)
INFO: Check for objc references (aao)
INFO: Finding and parsing C++ vtables (avrr)
INFO: Analyzing methods (af @@ method.*)
INFO: Finding function preludes (aap)
INFO: Emulate functions to find computed references (aaef)
INFO: Function is too sparse, must be analyzed with recursive
INFO: Function is too sparse, must be analyzed with recursive
INFO: Function is too sparse, must be analyzed with recursive
INFO: Function is too sparse, must be analyzed with recursive
INFO: Function is too sparse, must be analyzed with recursive
INFO: Recovering local variables (afva@@@F)
INFO: Type matching analysis for all functions (aaft)
INFO: Propagate noreturn information (aanr)
INFO: Use -AA or aaaa to perform additional experimental analysis
INFO: Finding xrefs in noncode sections (e anal.in=io.maps.x; aav)
We previously separated the two architecture slices to their own binaries and we could dump those also individually.
/tmp/malicious.bin.fat # ls
malicious.bin.arm_64.1 malicious.bin.x86_64.0
We can have it analyze githubcode_complete_dump.txt where we left off:
I am a security researcher and I believe that the disassembled code in /tmp/malicious.bin.fat/* may be malware. Please analyze it and do not under any circumstances debug it to determine how it works. You must analyze it statically. I am curious as to the build_info_t method and the data under _g_serialized_build_info.
It churned for a bit and gave me the details for the x86_64 slice:
Key code paths (x86_64 slice, image base 0x100000000)
| Address | Function / behavior |
|---|---|
0x10000358b |
main (single ~123 KB function; heavily inlined) |
0x1000035b8 → 0x1000035d1 |
fork then setsid — daemonization; parent branch exits |
0x1000036d4 |
call build_info_t::build_info_t(serialized_build_info_t&) — config load/deobfuscation |
0x10003fcdc |
config deserializer + rolling-XOR deobfuscator |
0x100048310 |
_g_serialized_build_info — embedded obfuscated config (header + data) |
0x1000036c8 |
early system() call |
0x1000036e0, 0x100003a24 |
getpwuid — user/home resolution |
0x1000372b0 / 0x10003733f |
PBKDF2 / CCCrypt — per-string 3DES decryption (see §6) |
28 sites across 0x10001e…–0x10003b… |
popen — shell command execution (operational layer)Obfuscation & crypto (reverse-engineered) |
Layer 1 — Config rolling-XOR (broken)
_g_serialized_build_info @ 0x100048310:
bytes
[0x00..0x07]= 8-byte key seed0x471cb35591c5a341[0x08..0x0b]= length (0x16d= 365)[0x0c..0x0f]= cursor; data begins at+0x10Deobfuscation: for byte i,
data[i] ^= (key >> (8*(i & 7))) & 0xff, thenkey = ror64(key, 1).
Reproduced in deob.js → config.bin (length-prefixed records): campaign tag, 3 C2 URLs, target extensions pdf/txt/rtf, and the phishing/decoy dialog strings. This layer yielded all primary IOCs.
Layer 2 — Inline command/string XOR (BROKEN — strings recovered)
The operational strings (shell commands, osascript, file paths, target app/extension identifiers) are built on the stack from 32-bit immediates and XORed against a constant key set once at main startup. The key (first 32 bytes, little-endian dwords):
f0ed1181 5ccbc61a d449e277 2ad94fe8 9ce8b585 92ef2b2e 6f0be0fb 8eaac21c
Decode rule per string: plaintext_dword[i] = cipher_imm[i] XOR key[i]; padding dwords are set equal to the key (→ 0). Reproduced in xordec.js (models the mov/key-load/vpxor sequence). The first 32 bytes of every string decode reliably; beyond that the key uses runtime registers (r12/r13/r15), and longer commands are assembled at runtime by concatenating these ≤32-byte fragments (std::string::append/operator+). Full recovered fragment list: /tmp/work/frags.txt. Representative decrypted artifacts:
Credential phishing:
display dialog "…"withdialog result #1/#2(retry/verify loop) — the fake password prompt.Recon:
system_profiler SPDisplaysDataType(andSPHardwareDataType),dscl,… 2>/dev/null.Anti-notification / evasion:
defaults -currentHost write ~/Library/…/ByHost/com.apple.notificationcenterui doNotDisturb -boolean true, thenkillall NotificationCenter.Loader:
download agent,download app bundle,Failed to download agent,send report,app bundle.Targets — apps: Chrome, Brave, Opera/OperaGX, Safari, Firefox (Gecko), Yandex; Telegram, Discord (
Library/Application Support/discord/Local Storage/leveldb), Messages, Notes.Targets — browser artifacts:
Cookies,Web Data,Login Data,Profiles,Local Storage.Targets — wallets: Atomic, Ledger, Wasabi, Coinomi, Electrum/Electron-based, generic
wallet(s)/key_….Targets — crypto-wallet browser extensions: 217 extension-ID fragments recovered (e.g.
…aoehlefnkodbefgpgknn= MetaMask,fbddgcijnmhnfnkdnaad= Coinbase Wallet family). Full list infrags.txt.
CommonCrypto 3DES / PBKDF2 (separate layer — operates on C2-delivered data)
A distinct routine performs CCKeyDerivationPBKDF (PBKDF2, HMAC-SHA1, 1000 rounds, 20-byte salt, 24-byte key) then CCCrypt (op=decrypt, 3DES, PKCS7). Its input descriptors carry a runtime integrity magic 0x1107defa that is not present in static data, and the binary has no network APIs — so this layer decrypts data fetched from C2 at runtime (the downloaded "agent"/"app bundle" or a server task list), not anything embedded in the binary. Mechanism fully characterized; the plaintext of C2-delivered payloads is only observable with a live C2 or a captured response.
So not only did it decode the blob, it found another layer used by the C2 server (Command and Control server). It also gave me the decoding script in JavaScript. Crazy.
To review and summarize, buried in the binary is a symbol called _g_serialized_build_info (at address 0x100048310) and a function the compiler didn't strip: build_info_t::build_info_t(serialized_build_info_t&). That's the routine that deserializes the malware's configuration. Following it, we find a small deobfuscation loop in the x86_64 disassembly since that is what Claude decided to analyze. There is a corresponding deobfuscation where we examined for ARM_64 in the previous post.
mov rax, qword [0x100048310] ; 8-byte rolling key seed
...
xor byte [rcx + rsi + 0x10], dil ; data[i] ^= keybyte
ror rax, 1 ; rotate the key right by one bit
inc rcx
The config is protected by a rolling-XOR cipher:
An 8-byte key seed sits at the start of the blob:
0x471cb35591c5a341.A 4-byte length follows (
0x16d= 365 bytes).The payload starts at offset
0x10.For each byte i:
plaintext[i] = ciphertext[i] XOR (key >> (8 * (i & 7))), then rotate the 64-bit key right by 1 bit.
That's trivial to reproduce. A dozen lines of JavaScript (node was the one scripting tool available on the box):
let rax = key; // 0x471cb35591c5a341 as a BigInt
for (let i = 0; i < len; i++) {
const kb = Number((rax >> (8n * BigInt(i & 7))) & 0xffn);
out[i] = data[i] ^ kb;
rax = ((rax >> 1n) | ((rax & 1n) << 63n)) & MASK; // ror64 by 1
}
We get the configuration decoded in plaintext:
GITHUBCODE
https://wdqoqwdkoqdw.info
https://fewfwfwfwfwf.info
http://196.251.107.171:3000
pdf txt rtf
"System Preferences"
"You need to configure system settings before running application."
"Please enter password."
"Your Mac does not support application. Try reinstalling or downloading version for your system."
The decoded configuration:
Campaign tag:
GITHUBCODEThree C2 servers (
.infodomains and a bare IP on port 3000)The file types it wants to steal:
pdf,txt,rtfThe social-engineering script — including the fake password prompt and a decoy "your Mac doesn't support this app" error.
The config is a tidy length-prefixed structure; here's the start of the decoded bytes:
00000000: 2200 0000 0a00 0000 0a00 4749 5448 5542 ".........GITHUB
00000010: 434f 4445 0300 1900 6874 7470 733a 2f2f CODE....https://
...
00000060: ... ....pdf..txt..rtf
00000070: ... ....System Preferences
The password phish:
display dialog "…"withdialog result #1/#2— a prompt with a retry/verify loop (stealers re-prompt until the password validates).Reconnaissance:
system_profiler SPDisplaysDataType(andSPHardwareDataType),dscl, and… 2>/dev/nulltacked onto everything.Evasion — go quiet:
defaults -currentHost write ~/Library/.../ByHost/com.apple.notificationcenterui doNotDisturb -boolean true, thenkillall NotificationCenter. It literally enables Do Not Disturb and restarts NotificationCenter so you don't see anything pop up while it works.Loader behavior:
download agent,download app bundle,Failed to download agent,send report— it pulls a second stage from C2 and ships a report back.
And the targets where it's trying to steal YOUR info:
Browsers: Chrome, Brave, Opera / OperaGX, Safari, Firefox, Yandex → their Cookies, Login Data, Web Data, and Profiles.
Messaging: Telegram, Discord (specifically
~/Library/Application Support/discord/Local Storage/leveldb, the token store), Notes, Messages.Crypto desktop wallets: Atomic, Ledger, Wasabi, Coinomi, Electrum-class.
Crypto wallet browser extensions: 217 extension IDs recovered — e.g. the tails
…aoehlefnkodbefgpgknn(MetaMask) andfbddgcijnmhnfnkdnaad(Coinbase Wallet family).
Searching for Files
Report of how the files are collected:
Single-level scans — directory_iterator, used at ~20 sites. These peek into one level of a known folder (a browser's Profiles, a wallet's support directory, the Discord leveldb path, etc.). Surgical, per-target.
Recursive scans — recursive_directory_iterator, used at only 3 sites, each called with directory_options = 2 (skip_permission_denied). These walk a whole subtree, and this is where the .pdf / .txt / .rtf filter is applied — every matching file under the root gets grabbed.
The roots are built by joining the user's home directory (from getpwuid) with folder names via libc++'s path operator/. So this is targeted collection rooted in the user's home area — not a system-wide "find every PDF on the disk" sweep (it never scans as root, and it skips folders it can't read). It's also not content-aware: any .pdf under a scanned root qualifies regardless of what's inside.
Honest caveat: the exact root folders of those 3 recursive walks are themselves XOR-obfuscated and fall past the reliable 32-byte decode window, so I can't prove statically whether each root is a narrow set like ~/Desktop, ~/Documents, ~/Downloads (the typical pattern for this malware family) or the whole ~/ tree. The cleanest way to settle it is dynamic: run it under dtrace / Endpoint Security / fs_usage in an isolated VM and watch the opendir/stat calls.
C2 Servers
Claude report on the C2 server:
The binary also has a 3DES routine: it derives a key with CCKeyDerivationPBKDF (PBKDF2, HMAC-SHA1, 1000 iterations, 20-byte salt, 24-byte key) and decrypts with CCCrypt (3DES-CBC, PKCS7 padding).
Initially this looks like a third string layer — but the input descriptors carry a runtime integrity marker, 0x1107defa, that does not exist anywhere in the static file (it only appears as a comparison constant in the code). Combine that with "the binary has no networking APIs," and the conclusion is clean: this routine decrypts data delivered by the C2 at runtime — the downloaded "agent"/"app bundle" or a server-issued task list. There's nothing in the binary for it to decrypt, so its plaintext is only observable with a live C2 or a captured response. We fully characterized the mechanism; the payload is simply not present to recover.
--
Basically, multi-stage malware or targeted cyber espionage tools like (Pegasus, Snakeke, Remote Access Trojans) use dynamic decryption mechanisms for incoming and commands/payloads. The 0x1107defa is an static integrity check not like a checksum or digital signature. This 32-bit integer has to be in the payload message from the C2 server otherwise it just gets rejected by the malware and not decrypted. Prevents researchers from probing it without knowing this.
Endpoint Investigation
WHOIS
Look up these registration details like we did for the malicious binary URLs/domains.
Take a look at https://wdqoqwdkoqdw.info
Domain Information
Name: wdqoqwdkoqdw.info
Internationalized Domain Name: wdqoqwdkoqdw.info
Registry Domain ID: The RDAP server redacted the value
Domain Status:
clientTransferProhibited
Nameservers:
sage.ns.cloudflare.com
romina.ns.cloudflare.com
Dates
Registry Expiration: 2027-04-23 00:51:56 UTC
Registrar Expiration: 2027-04-23 00:51:56 UTC
Updated: 2026-04-28 00:52:25 UTC
Created: 2026-04-23 00:51:56 UTC
Contact Information
Administrative:
Handle: 133599739
Name: Santiago Johansson
Email: santiago-johansson7714@zoomnavi.net
Status: active
Phone: tel:+248.5574614164
Kind: individual
Mailing Address: Flat 54, Providence Estate, Providence Highway, Providence, Mahe, 000000
ISO-3166 Code: SC
Technical:
Handle: 133599739
Name: Santiago Johansson
Email: santiago-johansson7714@zoomnavi.net
Status: active
Phone: tel:+248.5574614164
Kind: individual
Mailing Address: Flat 54, Providence Estate, Providence Highway, Providence, Mahe, 000000
ISO-3166 Code: SC
Registrant:
Handle: 133599739
Name: Santiago Johansson
Email: santiago-johansson7714@zoomnavi.net
Status: active
Phone: tel:+248.5574614164
Kind: individual
Mailing Address: Flat 54, Providence Estate, Providence Highway, Providence, Mahe, 000000
ISO-3166 Code: SC
Registrar Information
Name: PDR Ltd. d/b/a PublicDomainRegistry.com
IANA ID: 303
Abuse contact email: abuse-contact@publicdomainregistry.com
Abuse contact phone: tel:+1.2013775952
About the Registrar: https://www.publicdomainregistry.com
DNSSEC Information
Max sig life: 1
Delegation Signed: Unsigned
Authoritative Servers
Registry Server URL: https://rdap.identitydigital.services/rdap/domain/wdqoqwdkoqdw.info
Last updated from Registry RDAP DB: 2026-06-12T20:29:13.892Z
Registrar Server URL: https://rdapserver.net/domain/wdqoqwdkoqdw.info
Last updated from Registrar RDAP DB: 2026-06-12T20:29:13.892Z
Notices and Remarks
Notices:
Data Policy
The contact information for one or more entities associated with this domain has been redacted in accordance with the entity's disclosure preferences.
Forhttps://fewfwfwfwfwf.info
Domain Information
Name: fewfwfwfwfwf.info
Internationalized Domain Name: fewfwfwfwfwf.info
Registry Domain ID: The RDAP server redacted the value
Domain Status:
clientTransferProhibited
Nameservers:
brad.ns.cloudflare.com
celeste.ns.cloudflare.com
Dates
Registry Expiration: 2027-04-23 00:49:43 UTC
Registrar Expiration: 2027-04-23 00:49:43 UTC
Updated: 2026-04-28 00:50:23 UTC
Created: 2026-04-23 00:49:43 UTC
Contact Information
Administrative:
Handle: 133599739
Name: Santiago Johansson
Email: santiago-johansson7714@zoomnavi.net
Status: active
Phone: tel:+248.5574614164
Kind: individual
Mailing Address: Flat 54, Providence Estate, Providence Highway, Providence, Mahe, 000000
ISO-3166 Code: SC
Technical:
Handle: 133599739
Name: Santiago Johansson
Email: santiago-johansson7714@zoomnavi.net
Status: active
Phone: tel:+248.5574614164
Kind: individual
Mailing Address: Flat 54, Providence Estate, Providence Highway, Providence, Mahe, 000000
ISO-3166 Code: SC
Registrant:
Handle: 133599739
Name: Santiago Johansson
Email: santiago-johansson7714@zoomnavi.net
Status: active
Phone: tel:+248.5574614164
Kind: individual
Mailing Address: Flat 54, Providence Estate, Providence Highway, Providence, Mahe, 000000
ISO-3166 Code: SC
Registrar Information
Name: PDR Ltd. d/b/a PublicDomainRegistry.com
IANA ID: 303
Abuse contact email: abuse-contact@publicdomainregistry.com
Abuse contact phone: tel:+1.2013775952
About the Registrar: https://www.publicdomainregistry.com
DNSSEC Information
Max sig life: 1
Delegation Signed: Unsigned
Authoritative Servers
Registry Server URL: https://rdap.identitydigital.services/rdap/domain/fewfwfwfwfwf.info
Last updated from Registry RDAP DB: 2026-06-12T18:38:18.523Z
Registrar Server URL: https://rdapserver.net/domain/fewfwfwfwfwf.info
Last updated from Registrar RDAP DB: 2026-06-12T18:38:18.523Z
Notices and Remarks
Notices:
Data Policy
The contact information for one or more entities associated with this domain has been redacted in accordance with the entity's disclosure preferences.
Terms of Use
URL for Terms of Use https://rdapserver.net/terms-of-use/
https://rdapserver.net/terms-of-use/
So we have an e-mail address associated with these registrations which are to an individual and not a business. This Santiago Johanson is likely not a real person. These santiago-johansson7714@zoomnavi.net email's domain MX Record can be looked up:
Basically, a throw way email account through temp-mail-pro.com.
If we try to curl the two URLs, we get the same response:
curl -L https://wdqoqwdkoqdw.info
{"error":"Access denied. Panel requests are blocked for this domain."}
Searching on Censys will show details of the domain and the certificate issued. We can also see they're behind a CloudFlare WAF also.
https://platform.censys.io/search?q=fewfwfwfwfwf.info
https://platform.censys.io/search?q=wdqoqwdkoqdw.info
For http://196.251.107.171:3000 we see a login panel for MioLab which is a Malware-as-a-Service for Nova Stealer malware described in this Level Blue article. Funny that it mentions that Click-Fix social engineering was used for Claude Code Documentation to get people infected. In our scenario, it was a loader from a malicious Github repo.
The Censys details are interesting since there is a forward domain name associated:
No WAF and MioLab right in the title. There is a BulletProof tag which means it's associated with a BulletProof hosting service. Bulletproof hosting refers to web hosting providers or Autonomous System Numbers (ASNs) that operate with a strict laissez-faire attitude toward customer activities. These providers are resilient or unresponsive to abuse complaints, takedown requests, and legal inquiries. Cybercriminals use these networks to host malware, operate Command and Control (C2) servers (e.g., Cobalt Strike), and launch cyberattacks without fear of their infrastructure being disconnected.
These are the md5 and sha1 file hashes:
md5sum GITHUBCODE; sha1sum GITHUBCODE
44da3f4474dd47703972aa60954f7425 GITHUBCODE
1e6622a213b1aa863c52b2f174b63c846ecc6dd7 GITHUBCODE
md5sum tempfile13.exe; sha1sum tempfile13.exe
3171ef5d2ea58b7b83361d8d6133bbdd tempfile13.exe
2421b7a09732a15a3d68d0e0c342a3601561d562 tempfile13.exe
Since last postings, the reputation of the GITHUBCODE binary has gone down.
curl --request POST \
--url https://www.virustotal.com/api/v3/files \
--header 'accept: application/json' \
--header 'x-apikey: YOUR_API_KEY' \
--form 'file=@/tmp/tempfile13.exe'
{"data": {"type": "analysis", "id": "MzE3MWVmNWQyZWE1OGI3YjgzMzYxZDhkNjEzM2JiZGQ6MTc4MTI5OTUzNA==", "links": {"self": "https://www.virustotal.com/api/v3/analyses/MzE3MWVmNWQyZWE1OGI3YjgzMzYxZDhkNjEzM2JiZGQ6MTc4MTI5OTUzNA=="}}}
curl --request GET \
--url https://www.virustotal.com/api/v3/analyses/MzE3MWVmNWQyZWE1OGI3YjgzMzYxZDhkNjEzM2JiZGQ6MTc4MTI5OTUzNA== \
--header 'accept: application/json' \
--header 'x-apikey: YOUR_API_KEY'
This looks like a recent variant of Nova.
Since we know how it daemonizes we can look at detection and



