Skip to content

Instantly share code, notes, and snippets.

@X-Junior
Created April 18, 2024 19:47
Show Gist options
  • Save X-Junior/31e8fccf159631ccbe1bdf8d1f8dd781 to your computer and use it in GitHub Desktop.
Save X-Junior/31e8fccf159631ccbe1bdf8d1f8dd781 to your computer and use it in GitHub Desktop.
Wineloader Static String Decryptor
from Crypto.Cipher import ARC4
from capstone import *
from capstone.x86 import *
import pefile , sys , os
'''
Author: Mohamed Ashraf (@X__Junior)
make sure you are passing wineloader and not the loader of wineloader, if you suspect it's the loader then use https://raw.githubusercontent.com/tccontre/KnowledgeBase/main/malware_re_tools/wineloader_dll_side_load/wineloader_extractor.py , to extract the shellcode
tested samples:
27c0935a22862475bb3fd516f93bd466f8021f77727e83f53d67d76978b439ee
1f123f8e82310161e2e0ebf0420d3b5f3dd932f26b93eedb2b01f5abe77450d7
f5cb3234eff0dbbd653d5cdce1d4b1026fa9574ebeaf16aaae3d4e921b6a7f9d
'''
def extract_strings(encrypted_strings_table):
flag = 0
counter = 0
extracted_strings = []
string_length = encrypted_strings_table[0]
while counter < len(encrypted_strings_table):
if encrypted_strings_table[counter] == 0:
counter += 1
elif encrypted_strings_table[counter] != 0 and flag == 0:
string_length = encrypted_strings_table[counter]
counter += 1
flag = 1
elif encrypted_strings_table[counter] != 0 and flag == 1:
encrypted_string = encrypted_strings_table[counter : counter + string_length]
extracted_strings.append(encrypted_string)
flag = 0
counter += string_length
return extracted_strings
def decrypt_strings(encrypted_strings , rc4_key):
for encrypted_string in encrypted_strings:
try:
cipher = ARC4.new(rc4_key)
decrypted_string = cipher.decrypt(encrypted_string)
print(decrypted_string.decode())
except:
continue
def extract_rc4_key (md ,text_addr ,pe ,file_data ,text):
inst = list(md.disasm(text.get_data(), text_addr))
for i in range(len(inst)):
try :
if inst[i].mnemonic == "xor" and inst[i+1].mnemonic == "mov" and inst[i+2].mnemonic == "mov" and inst[i+3].mnemonic == "lea" and inst[i+4].mnemonic == "mov" and inst[i+5].mnemonic == "xor":
last_4_bytes_inst = inst[i+3].operands[1].value.mem.disp
instruction_size = inst[i+3].size
instruction_addr = inst[i+3].address
rc4_key_rva = instruction_addr + instruction_size + last_4_bytes_inst
break
except:
continue
for s in pe.sections:
if b'.text' in s.Name:
rc4_key_offset = rc4_key_rva - s.VirtualAddress + s.PointerToRawData - pe.OPTIONAL_HEADER.ImageBase
rc4_key = file_data[rc4_key_offset : rc4_key_offset + 0x100]
return rc4_key , rc4_key_offset
def main():
# Check if the correct number of arguments are provided
if len(sys.argv) != 2:
# python3 WineLoader_String_Decryptor.py WineLoader.dll(WineLoader_Shellcode)
print("Usage: python WineLoader_String_Decryptor.py [filename]")
exit()
# Check if the file exists
if not os.path.isfile(sys.argv[1]):
print(f"The file {sys.argv[1]} does not exist.")
exit()
else:
file_data = open(sys.argv[1], "rb").read()
try:
pe = pefile.PE(sys.argv[1])
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
rc4_key , rc4_key_offset = extract_rc4_key(md , text_addr , pe , file_data , text)
encrypted_strings_table = file_data[rc4_key_offset + 0x100: rc4_key_offset + 0x1100]
except:
# if only the shellcode is passed
# Use splunk wineloader shellcode extractor : https://raw.githubusercontent.com/tccontre/KnowledgeBase/main/malware_re_tools/wineloader_dll_side_load/wineloader_extractor.py
rc4_key = file_data[0x20:0x120]
encrypted_strings_table = file_data[0x120:0x1000]
extracted_strings = extract_strings(encrypted_strings_table)
decrypt_strings(extracted_strings , rc4_key)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment