Created
April 23, 2025 22:48
-
-
Save sysopfb/2c21f05a554fa570e4f73863381ead79 to your computer and use it in GitHub Desktop.
Amos standalone decoder for new variant
This file contains hidden or 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
#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