Latrodectus
Extracting new AES encrypted strings from this RAT
Overview
Latrodectus is a RAT that has been linked to the development of IcedID. It provides host information collection capabilities as well as the ability to download and launch additional payloads.
Sample
5cecb26a3f33c24b92a0c8f6f5175da0664b21d7c4216a41694e4a4cad233ca8
UnpacMe
References
Analysis
The focus of our analysis will be to extract the new AES encrypted strings.
We are going to use the pemulator.py lib to assist with emulation.
from pemulator import Emulator
file_path = '/tmp/5cecb26a3f33c24b92a0c8f6f5175da0664b21d7c4216a41694e4a4cad233ca8'
file_data = open(file_path, 'rb').read()
from unicorn import *
from unicorn.x86_const import *
import struct
emu = Emulator(file_data, mode=64, trace=False)
scratch_start = emu.get_memory_upper_bound() + 0x1000
emu.emu.mem_map(scratch_start, 0x1000)
buff = scratch_start
image_base = emu._pe.OPTIONAL_HEADER.ImageBase
data_addr = 0x01400110A8
dec_fn = 0x014000C1E4
# Move buff into rdx
emu.emu.reg_write(UC_X86_REG_RDX, buff)
# Move enc string into
emu.emu.reg_write(UC_X86_REG_RCX, data_addr)
# address to end emulation
kill_addr = 0xdeadbeef
kill_addr_data = struct.pack('<I', kill_addr)
esp = emu.emu.reg_read(UC_X86_REG_RSP)
emu.emu.mem_write(esp, kill_addr_data)
emu.emu.emu_start(dec_fn, kill_addr)
tmp_string = emu.emu.mem_read(buff, 0x1000).replace(b'\x00',b'')
print(tmp_string)
def decrypt(data_addr):
emu = Emulator(file_data, mode=64, trace=False)
scratch_start = emu.get_memory_upper_bound() + 0x1000
emu.emu.mem_map(scratch_start, 0x1000)
buff = scratch_start
image_base = emu._pe.OPTIONAL_HEADER.ImageBase
#data_addr = 0x01400110A8
dec_fn = 0x014000C1E4
# Move buff into rdx
emu.emu.reg_write(UC_X86_REG_RDX, buff)
# Move enc string into
emu.emu.reg_write(UC_X86_REG_RCX, data_addr)
# address to end emulation
kill_addr = 0xdeadbeef
kill_addr_data = struct.pack('<I', kill_addr)
esp = emu.emu.reg_read(UC_X86_REG_RSP)
emu.emu.mem_write(esp, kill_addr_data)
emu.emu.emu_start(dec_fn, kill_addr)
tmp_string = emu.emu.mem_read(buff, 0x1000).replace(b'\x00',b'')
return tmp_string
decrypt(0x01400110A8)
import re
tmp_emu = Emulator(file_data, mode=64, trace=False)
# Find all refs to the enc strings
#
# .text:0000000140005E19 48 8D 94 24 80 00 00 00 lea rdx, [rsp+188h+var_108]
# .text:0000000140005E21 48 8D 0D 80 B2 00 00 lea rcx, word_1400110A8
# .text:0000000140005E28 E8 B7 63 00 00 call latro_str_decryption_main
#
# .text:0000000140007A83 48 8D 54 24 40 lea rdx, [rsp+88h+var_48]
# .text:0000000140007A88 48 8D 0D 91 A1 00 00 lea rcx, word_140011C20
# .text:0000000140007A8F E8 50 47 00 00 call latro_str_decryption_main
egg = rb'\x48\x8D.{3,6}\x48\x8D\x0D(....)\xE8'
for match in re.finditer(egg, file_data):
match_len = len(match.group())
if match_len == 13:
# Smaller offset
image_base = tmp_emu._pe.OPTIONAL_HEADER.ImageBase
start_address = tmp_emu._pe.get_rva_from_offset(match.start()) + image_base
data_addr = struct.unpack('<I', match.group(1))[0] + 12 + start_address
else:
image_base = tmp_emu._pe.OPTIONAL_HEADER.ImageBase
start_address = tmp_emu._pe.get_rva_from_offset(match.start()) + image_base
data_addr = struct.unpack('<I', match.group(1))[0] + 15 + start_address
#print(f"{hex(start_address)}: STRING: {hex(data_addr)}")
try:
tmp_string = decrypt(data_addr)
if tmp_string.isascii():
out = tmp_string.decode('utf-8')
print(f"{hex(data_addr)}: {out}")
else:
print(f"{hex(data_addr)}: -------> {tmp_string}")
except:
print(f"{hex(data_addr)}: ***ERROR - no string")
hex(0x0140007A8F + 0xa191)