Skip to content

Instantly share code, notes, and snippets.

@adelmas
Last active September 28, 2021 03:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save adelmas/8c864315648a21ddabbd6bc7e0b64119 to your computer and use it in GitHub Desktop.
Save adelmas/8c864315648a21ddabbd6bc7e0b64119 to your computer and use it in GitHub Desktop.
IDAPython script to deobfuscate statically the bot32 payload of the banking malware FlokiBot. Imports are fully resolved, hooks are identified and named and strings are decrypted and added in comments, without using any debugger. May take a few minutes to resolve imports. Works with FlokiBot dropper with some small changes.
# coding: utf-8
# ====================================================== #
# #
# FLOKIBOT BOT32 DEOBFUSCATION IDA SCRIPT #
# #
# http://adelmas.com/blog/flokibot.php #
# #
# ====================================================== #
# IDAPython script to deobfuscate statically the bot32 payload of the banking malware FlokiBot.
# Imports are fully resolved, hooks are identified and named and strings are decrypted and added in comments, without using any debugger.
# May take a few minutes to resolve imports.
# Works with FlokiBot dropper with some small changes.
import sys
# sys.path.append("/usr/local/lib/python2.7/dist-packages")
# idaapi.enable_extlang_python(True)
import pefile
# RunPlugin("python", 3)
CRC_POLY = 0xEDB88320 # Depending on sample
XOR_KEY = 0x34ED # Depending on sample
ARRAY_ADDR = 0x41B350 # Depending on sample
ARRAY_ITER = 12 # Size of a triplet (3*sizeof(DWORD))
i = 0
# ----------------------------------------------------
# Generating CRC polynoms
# ----------------------------------------------------
poly = []
while i < 256:
size = 8
b = i
while size != 0:
if b & 1:
b = (b >> 1) ^ CRC_POLY
else:
b >>= 1
size -= 1
poly.insert(i, b)
i += 1
# ----------------------------------------------------
# FlokiBot CRC32
# ----------------------------------------------------
def crc32(name):
name_len = len(name)
i = 0
crc = 0xFFFFFFFF
while i < name_len:
crc = poly[(crc ^ ord(name[i])) & 0xFF] ^ (crc >> 8)
i += 1
crc = (~crc) & 0xFFFFFFFF
return crc
# ----------------------------------------------------
# DEOBFUSCATING API CALLS
# ----------------------------------------------------
array_dll = ['ntdll', 'kernel32', 'wininet', 'ws2_32', 'advapi32', 'secur32', 'crypt32',
'shlwapi', 'ole32', 'gdi32', 'shell32', 'user32', 'urlmon' #, 'nss3', 'nspr4', 'chrome'
]
dll_hash = {}
for dll in array_dll:
h = crc32(dll + '.dll') ^ XOR_KEY
dll_hash[h] = dll
print "[+] %s.dll (%X) : Parsing..." % (dll, h)
pe = pefile.PE("C:\\Windows\\System32\\" + dll + ".dll")
api_hash = {}
pe.parse_data_directories()
for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:
if exp.name:
api_crc = crc32(exp.name) ^ XOR_KEY
api_hash[api_crc] = exp.name
nb = 0
for i in range(0, 287):
ea_name = (ARRAY_ADDR + i*ARRAY_ITER)
ea_func = Dword(ea_name)
ea_crc = ea_name + 4
MakeDword(ea_crc)
crc = Dword(ea_crc)
if crc in api_hash:
if MakeName(ea_func, api_hash[crc]+"_wrap"):
nb += 1
print "[+] %s : Resolved %d API names" % (dll, nb)
# ----------------------------------------------------
# PARSING HOOK STRUCT
# ----------------------------------------------------
sid = AddStruc(-1, 'HOOKWINAPI')
AddStrucMember(sid, 'functionForHook', 0, FF_DWRD|FF_DATA, -1, 4)
AddStrucMember(sid, 'hookerFunction', 4, FF_DWRD|FF_DATA, -1, 4)
AddStrucMember(sid, 'originalFunction', 8, FF_DWRD|FF_DATA, -1, 4)
AddStrucMember(sid, 'originalFunctionSize', 12, FF_DWRD|FF_DATA, -1, 4)
AddStrucMember(sid, 'dllHash', 16, FF_DWRD|FF_DATA, -1, 4)
AddStrucMember(sid, 'apiHash', 20, FF_DWRD|FF_DATA, -1, 4)
HOOKWINAPI_EA = 0x41B000
HOOKWINAPI_SIZE = 0x18
ea = HOOKWINAPI_EA
MakeName(HOOKWINAPI_EA, "hookWinApi_array")
print "Parsing hook table @ 0x%X" % HOOKWINAPI_EA
for i in range(0, 25):
for field in range(0, 6):
MakeDword(ea+4*field)
fn_name = Name(Dword(ea))
hook_ea = Dword(ea+4)
MakeName(hook_ea, "hook_" + fn_name)
hook_name = Name(Dword(ea+4))
ori_ea = ea+8
MakeName(ori_ea, "ori_" + fn_name)
print "[+] Hook on %s \t--> %s" % (fn_name, hook_name)
ea += HOOKWINAPI_SIZE
# ----------------------------------------------------
# STRING DEOBFUSCATION
# ----------------------------------------------------
DECRYPT_FN_EA = 0x403948 # Depending on sample
ENCRYPTED_STRINGS_EA = 0x402278 # Depending on sample
DECRYPT_FN = "decrypt_string"
ENCRYPTED_STRINGS = "encrypted_strings"
ARRAY_SIZE = 0x77 # Depending on sample
decrypted_strings = {}
def backwardSearch(ea, instr):
while True:
ea = PrevHead(ea)
if GetMnem(ea) == instr:
return ea
def decrypt_string(index, ea_encrypted):
string = ""
if index == -1:
string = "Invalid index"
return string
encr_array = LocByName(ea_encrypted)
if encr_array == 0xFFFFFFFF:
string = "Invalid array for encrypted strings"
return string
ea_item = encr_array + index*2*4
xor_k = Byte(ea_item)
size = Word(ea_item+2)
ptr_string = Dword(ea_item + 4)
MakeByte(ptr_string)
MakeArray(ptr_string, size)
#print "[%d] %X %X %X" % (index, xor_k, size, ptr_string)
i = 0
if size <= 0:
string = "Size <= 0"
return string
while i < size:
ichr = i
string += str(unichr((i ^ xor_k ^ Byte(ptr_string + i)) & 0xFF))
i += 1
MakeComm(ptr_string, string) # Add comments with decrypted strings in the array
return string
# ----------------------------------------------------
# Decrypting and commenting whole array
# ----------------------------------------------------
MakeName(DECRYPT_FN_EA, DECRYPT_FN)
MakeName(ENCRYPTED_STRINGS_EA, ENCRYPTED_STRINGS)
i = 0
loc = LocByName(DECRYPT_FN)
for ea in range(loc, loc+ARRAY_SIZE):
decrypted_strings[i] = decrypt_string(i, ENCRYPTED_STRINGS)
i += 1
print "[+] Decrypted %d strings :" % (i)
print decrypted_strings
# ----------------------------------------------------
# Commenting calls to decryption function with decrypted strings
# ----------------------------------------------------
i = 0
for xref in XrefsTo(LocByName(DECRYPT_FN)):
ea = xref.frm
mnem = GetMnem(PrevHead(ea))
index = 0
if mnem == "xor":
index = 0
elif mnem == "pop":
ea = backwardSearch(ea, "push")
index = GetOperandValue(ea, 0)
elif mnem == "inc":
index = 1
elif mnem == "mov":
index = GetOperandValue(ea, 1)
#print "Index : 0x%X" % (index)
if index in decrypted_strings:
MakeComm(xref.frm, decrypted_strings[index])
i += 1
print "[+] Commented %d strings with decrypted values" % (i)
print "[+] Script is done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment