Skip to content

Instantly share code, notes, and snippets.

@sysopfb
Created April 23, 2025 22:48
Show Gist options
  • Save sysopfb/2c21f05a554fa570e4f73863381ead79 to your computer and use it in GitHub Desktop.
Save sysopfb/2c21f05a554fa570e4f73863381ead79 to your computer and use it in GitHub Desktop.
Amos standalone decoder for new variant
#Saw RussianPandas ida script after I got it to the custom base64 - was easy to verify my work after finding their IDA script
# Prior work ref: https://github.com/RussianPanda95/IDAPython/blob/main/Atomic%20Stealer/amos_config_extract_idapython-3-2025.py
# created a standalone decoder based on the x64 opcodes
import re
import sys
import yara
import struct
import binascii
import base64
rule_source = '''
rule amos
{
strings:
$a1 = {48 8d 35 ?? ?? ?? 00 ba ?? ?? ?? 00 e8}
condition:
all of them
}
'''
#From Graham Austin
def yara_scan(raw_data, rule_name):
xor_keys = []
yara_rules = yara.compile(source=rule_source)
matches = yara_rules.match(data=raw_data)
for match in matches:
if match.rule == 'amos':
for item in match.strings:
if item.identifier == rule_name and len(item.instances) > 0:
xor_keys += (item.instances)
return xor_keys
def add_base64_padding(data):
return data + b'=' * (-len(data) % 4)
def custom_b64(encoded_data, custom_alphabet):
std_base64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
translated_data = encoded_data.translate(str.maketrans(custom_alphabet, std_base64chars)).encode()
return(base64.b64decode(add_base64_padding(translated_data)))
data = open(sys.argv[1], 'rb').read()
tet = yara_scan(data, '$a1')
key_struct = None
blobs = []
#To get memory address you do the offset from opcode + yara match .offset + instruction opcode count in this case 7
while len(tet) > 0:
(dc, dc, dc, offset_a, dc, a_length) = struct.unpack_from('<BBBIBI', tet[0].matched_data)
offset_a += tet[0].offset
offset_a += 7
(dc, dc, dc, offset_c, dc, c_length) = struct.unpack_from('<BBBIBI', tet[1].matched_data)
offset_c += tet[1].offset
offset_c += 7
(dc, dc, dc, offset_d, dc, d_length) = struct.unpack_from('<BBBIBI', tet[2].matched_data)
offset_d += tet[2].offset
offset_d += 7
if a_length == 0x200:
key_struct = {'a_off': offset_a, 'a_len': a_length, 'c_off': offset_c, 'c_len': c_length, 'd_off': offset_d, 'd_len': d_length}
else:
obj_struct = {'a_off': offset_a, 'a_len': a_length, 'c_off': offset_c, 'c_len': c_length, 'd_off': offset_d, 'd_len': d_length}
blobs.append(obj_struct)
tet = tet[3:]
if key_struct:
out = ""
a_data = data[key_struct['a_off']:key_struct['a_off']+key_struct['a_len']]
d_data = data[key_struct['d_off']:key_struct['d_off']+key_struct['d_len']]
c_data = data[key_struct['c_off']:key_struct['c_off']+key_struct['c_len']]
for i in range(0x80):
a = struct.unpack_from('<I', a_data[i*4:])[0]
d = struct.unpack_from('<I', d_data[i*4:])[0]
c = struct.unpack_from('<I', c_data[i*4:])[0]
a = (a - d) & 0xffffffff
a ^= c
out += chr(a)
key = binascii.unhexlify(out)
dump = b''
for blob in blobs:
out = ""
a_data = data[blob['a_off']:blob['a_off']+blob['a_len']]
d_data = data[blob['d_off']:blob['d_off']+blob['d_len']]
c_data = data[blob['c_off']:blob['c_off']+blob['c_len']]
for i in range(int(blob['a_len']/4)):
a = struct.unpack_from('<I', a_data[i*4:])[0]
d = struct.unpack_from('<I', d_data[i*4:])[0]
c = struct.unpack_from('<I', c_data[i*4:])[0]
a = (a - d) & 0xffffffff
a ^= c
out += chr(a)
temp = binascii.unhexlify(out)
decoded = custom_b64(temp.decode('ascii'), key.decode('ascii'))
dump += decoded+b'\n'
open(sys.argv[1]+'.dumped', 'wb').write(dump)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment