-
-
Save LloydLabs/d4e0ffba3ba6ccce17fafc08d9118385 to your computer and use it in GitHub Desktop.
This file contains 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
import sys | |
from typing import Dict, List | |
import malduck | |
import pefile | |
import yara | |
from capstone import CS_ARCH_X86, CS_MODE_64, Cs | |
from capstone.x86 import X86_INS_RET | |
from qiling import * | |
from qiling.const import QL_VERBOSE | |
from unicorn.x86_const import UC_X86_REG_RCX, UC_X86_REG_RDX | |
def _emotet_end_emu(ql: Qiling, address: int, size: int) -> None: | |
buf = ql.mem.read(address, size) | |
md = Cs(CS_ARCH_X86, CS_MODE_64) | |
md.detail = True | |
for _ in filter(lambda x: x.id == X86_INS_RET, md.disasm(buf, address)): | |
ql.stop() | |
def _emotet_get_c2_pair(addr: int) -> Dict: | |
ip_buf = ql.mem.map_anywhere(0x4) | |
port_buf = ql.mem.map_anywhere(0x4) | |
ql.reg.write(UC_X86_REG_RCX, ip_buf) | |
ql.reg.write(UC_X86_REG_RDX, port_buf) | |
ql.hook_code(_emotet_end_emu) | |
ql.run(begin=addr) | |
c2_port = malduck.u16(ql.mem.read(port_buf, 4), offset=2) | |
c2_ip = malduck.ipv4(bytes(ql.mem.read(ip_buf, 4))) | |
if c2_ip == "0.0.0.0": | |
return | |
return {"ip": c2_ip, "port": c2_port} | |
def _emotet_get_c2s(ql: Qiling, path: str) -> List: | |
with open(path, 'rb') as f: | |
data = f.read() | |
addresses = [] | |
pe = pefile.PE(data=data) | |
rule = yara.compile(source="rule load {strings: $load = {48 8D 05 ?? ?? ?? ?? 48 89 81 ?? ?? 00} condition: $load}") | |
matches = rule.match(data=data) | |
for off, _, _ in matches[0].strings: | |
addr = ((pe.get_rva_from_offset(off) + malduck.int32(data, offset=off + 3)) + 7) + pe.OPTIONAL_HEADER.ImageBase | |
if pair := _emotet_get_c2_pair(addr): | |
addresses.append(pair) | |
return addresses | |
if __name__ == "__main__": | |
if len(sys.argv) != 2: | |
print("emo_x64_dump.py <name>") | |
sys.exit(0) | |
ql = Qiling([sys.argv[1]], "rootfs/x8664_windows", verbose=QL_VERBOSE.DISABLED) | |
print(_emotet_get_c2s(ql, sys.argv[1])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I see, thanks for the feedback! In my analysis I could clearly see those were Emotet, but was surprised none of the usual sandboxes seemed to have picked it up (at least on VT)...
Another very interesting example is
e17d5db1856c406f8fa55b0ec282959cf8eda1c9b697f85d47b329d4d80f4cea
with only 9 detections on VT, but again it seems to me that this is clearly Emotet. I wish I had the RE skills to understand why it doesn't get picked up, what does it do so differently etc 🥲🤷🏻♂️