Skip to content

Instantly share code, notes, and snippets.

@FZKiritsugu
Forked from X-Junior/Statc_Stealer.py
Created August 19, 2023 03:34
Show Gist options
  • Save FZKiritsugu/6f5074d0828fff1af79595d041e2f350 to your computer and use it in GitHub Desktop.
Save FZKiritsugu/6f5074d0828fff1af79595d041e2f350 to your computer and use it in GitHub Desktop.
Statc Stealer String Decryptor
import struct , sys , pefile , validators , re , base64
from capstone import *
from capstone.x86 import *
'''
Author: Mohamed Ashraf (@X__Junior)
Usage:
python3 Statc_Stealer.py path_to_sample
'''
def xor_decryption(encoded_string , xor_key):
encoded_string = base64.b64decode(encoded_string)
decoded_str = ""
for i in range(len(encoded_string)):
decoded_str += chr(encoded_string[i] ^ xor_key[i%len(xor_key)])
return decoded_str
def sub_decryption(encdata, sub_byte):
try:
if encdata != []:
out = bytearray((ord(encdata[j]) - sub_byte) %
256 for j in range(len(encdata)))
return out.decode()
except Exception as e :
return 0
def add_decryption(encdata, add_byte):
try:
if encdata != []:
out = bytearray((ord(encdata[j]) + add_byte) %
256 for j in range(len(encdata)))
return out.decode()
except Exception as e :
return 0
def extract_xor_key_xmm(md , text , text_addr , file_data , pe):
'''
e68649a91df324229a6f33685a5ba3827767c8105bcd3c6808ac9e06a4a76045
movdqa xmm0, cs:xmmword_7FF6049D5D50
movdqu [rbp+57h+var_A8], xmm0
mov [rbp+57h+var_98], 'QT
'''
xor_key = b''
regex_address = 0
instruction_offset = 0
regex = b'\x4C\x89\x6D[\x00-\xff]\x4C\x8B\x67[\x00-\xff]\x48\x8B\xF7\x48\x83\x7F[\x00-\xff]{2}\x72[\x00-\xff]\x48\x8B\x37'
for match in re.finditer(regex, text.get_data()):
regex_address = match.start()
text_addr += regex_address - 50
inst = list(md.disasm(text.get_data()[regex_address-50:regex_address], text_addr))
for i in range(len(inst)):
if 'movd' not in inst[i].mnemonic :
instruction_offset+= inst[i].size
if 'movd' in inst[i].mnemonic :
break
text_addr += instruction_offset
inst = list(md.disasm(text.get_data()[regex_address-50+instruction_offset:regex_address], text_addr))
for i in range(len(inst)):
try :
if 'movd' in inst[i].mnemonic :
last_4_bytes_inst = inst[i].operands[1].value.mem.disp
instruction_size = inst[i].size
instruction_addr = inst[i].address
xor_key_rva = instruction_addr + instruction_size + last_4_bytes_inst
for s in pe.sections:
if b'.rdata' in s.Name:
xor_key_offset = xor_key_rva - s.VirtualAddress + s.PointerToRawData - pe.OPTIONAL_HEADER.ImageBase
temp_xor_key = file_data[xor_key_offset:xor_key_offset+30].split(b'\x00')[0]
temp_xor_key = temp_xor_key.split(b'\xff')[0].decode()
if temp_xor_key != "":
xor_key = bytes(temp_xor_key,"utf-8")
except Exception as e :
continue
return xor_key
def extract_xor_key_stack_string(md , text , text_addr):
'''
f4d60dde0ba2d06e34adb688c135613077659b2b7c0770b09a083b25168048f1
mov [rbp+57h+var_A0], 61304055h
mov [rbp+57h+var_9C], 72456D7Dh
mov [rbp+57h+var_98], 543C5158h
'''
regex = b'\x4C\x89\x6D[\x00-\xff]\x4C\x8B\x67[\x00-\xff]\x48\x8B\xF7\x48\x83\x7F[\x00-\xff]{2}\x72[\x00-\xff]\x48\x8B\x37'
regex_address = 0
for match in re.finditer(regex, text.get_data()):
regex_address = match.start()
xor_key = b''
for inst in md.disasm(text.get_data()[regex_address-50:regex_address], text_addr):
if inst.mnemonic == 'mov' and inst.operands[0].type == X86_OP_MEM and inst.operands[1].type == X86_OP_IMM :
xor_key += struct.pack('<I',inst.operands[1].value.imm)
return xor_key.replace(b'\x00',b'')
def extract_xor_key(binary_path):
xor_key = b''
file_data = open(binary_path,'rb').read()
pe = pefile.PE(binary_path)
md = Cs(CS_ARCH_X86, CS_MODE_64)
md.skipdata = True
md.detail = True
text = pe.sections[0]
text_addr = pe.OPTIONAL_HEADER.ImageBase + text.VirtualAddress
xor_key += extract_xor_key_xmm(md , text , text_addr , file_data , pe)
xor_key += extract_xor_key_stack_string(md , text , text_addr)
return xor_key.replace(b'\x00',b'')
def extract_dec_byte(binary_path):
regex = b'\x44\x0F\xB6\x0E\x41\x80[\x00-\xff]{2}\x48\x8B\x4B[\x00-\xff]\x48\x8B\x53[\x00-\xff]\x48\x3B\xCA\x73[\x00-\xff]\x48\x8D\x41[\x00-\xff]\x48\x89\x43'
file_data = open(binary_path,'rb').read()
regex_address = 0
pe = pefile.PE(binary_path)
md = Cs(CS_ARCH_X86, CS_MODE_64)
md.skipdata = True
md.detail = True
text = pe.sections[0]
text_addr = pe.OPTIONAL_HEADER.ImageBase + text.VirtualAddress
for match in re.finditer(regex, text.get_data()):
regex_address = match.start()
for inst in md.disasm(text.get_data()[regex_address:regex_address + 50], text_addr):
if (inst.mnemonic == 'sub'):
return inst.operands[1].value.imm , 0
if (inst.mnemonic == 'add'):
return inst.operands[1].value.imm , 1
return 0 , 0
def main(binary_path , dec_byte , dec_option , xor_key):
file_data = open(binary_path,'rb').read()
pe = pefile.PE(data=file_data)
potential_c2 = []
all_hardcoded_strings = []
for section in pe.sections:
if b"rdata" in section.Name:
all_hardcoded_strings = section.get_data().split(b'\x00')
for data in all_hardcoded_strings:
try:
decoded_string = xor_decryption(data, xor_key)
if dec_option == 0:
decoded_string = sub_decryption(decoded_string ,dec_byte)
else:
decoded_string = add_decryption(decoded_string ,dec_byte)
if decoded_string != "":
if validators.url(decoded_string) or validators.ipv4(decoded_string):
potential_c2.append(decoded_string)
print(decoded_string)
except:
continue
if potential_c2 != []:
print("C2 : ")
for c2 in potential_c2:
print(c2)
if __name__ == "__main__":
binary_path = sys.argv[1]
dec_byte , dec_option = extract_dec_byte(binary_path)
xor_key = extract_xor_key(binary_path)
print("Decryption Byte = " ,dec_byte)
print("Xor Key = ",xor_key )
if dec_byte != 0 and xor_key != b'':
main(binary_path,dec_byte,dec_option,xor_key)
else:
print("Couldn't extract decryption keys")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment