Sample
bazaar.abuse.ch — aa1b1384dbf123607f6f63132f355e7486ccd67a0e03d3af2db40a333b70797b
from pathlib import Path
WORKING_DIR = Path('/path/to/rhadamanthys/')
SAMPLE_PATH = WORKING_DIR.joinpath('aa1b1384dbf123607f6f63132f355e7486ccd67a0e03d3af2db40a333b70797b.exe')
DB_PATH = WORKING_DIR.joinpath('rdm-testing.bndb')
view = binaryninja.open_view(SAMPLE_PATH)
view.create_database(DB_PATH)
Helpers
# Search type libraries for matching name, return prototype.
def search_type_libraries(fname: str, view: BinaryView):
# not super efficient to search every single time...
for typelib in view.type_libraries:
for name, obj in typelib.named_objects.items():
if not isinstance(obj, FunctionType):
continue
if fname == name:
return obj
def name_and_type_next_data_var(view: BinaryView, v: Variable, address: int, name: str, new_type: Type):
mlil = view.get_functions_containing(address)[0].mlil
for op in mlil.get_var_uses(v):
if isinstance(op, MediumLevelILStore) and isinstance(op.dest, MediumLevelILConstPtr):
data_var = view.get_data_var_at(op.dest.constant)
data_var.name = name
data_var.type = new_type
Adding a type library:
x = typelibrary.TypeLibrary.from_name(bv.arch, 'amsi.dll')
bv.add_type_library(x)
ResolveModule (0x14000d520)
Prototype: HANDLE rdm_ResolveModule(module_ref*)
struct module_ref {
uint64_t string_len;
uint64_t unknown;
char module_name[0x8];
};
Loop over xrefs, set the data var passed in as our struct, decode the module name, then load the matching type library and rename the call’s output variable.
# Create the struct
rdm_string_builder = StructureBuilder.create(
members=[(IntegerType.create(8, False), 'len'),
(IntegerType.create(8, False), 'unknown'),
(ArrayType.create(CharType.create(), 16), 'string')])
view.define_user_type('rdm_string', rdm_string_builder)
# Iterate over all calls to rdm_ResolveModule.
# Re-type the data var passed to rdm_string.
# Extract the module name from the newly typed struct.
# Rename the output variable.
runtime_loaded_modules = []
target_func = view.get_function_at(0x14000d520)
target_func.name = 'rdm_ResolveModule'
rdm_string = view.get_type_by_name('rdm_string')
for xref in target_func.caller_sites:
if isinstance(xref.mlil, MediumLevelILCall):
param = xref.mlil.params[0]
if isinstance(param, MediumLevelILConstPtr):
v = view.get_data_var_at(param.constant)
v.type = rdm_string
module_name = v.value['string'][:v.value['len']].decode()
v.name = module_name
if module_name not in runtime_loaded_modules:
runtime_loaded_modules.append(module_name)
dest_var = xref.mlil.output[0]
var_name = f'h_{module_name}'
dest_var.name = var_name
name_and_type_next_data_var(view, dest_var, xref.address, var_name, view.get_type_by_name('HMODULE'))
Recovered modules: kernel32.dll, ole32, oleaut32, mscoree.
# load the appropriate type lib for each module
for module in runtime_loaded_modules:
if module[-4:] != '.dll':
module = f'{module}.dll'
type_lib = typelibrary.TypeLibrary.from_name(view.arch, module)
if type_lib:
view.add_type_library(type_lib)
else:
display(f'No type library for {module}')
ResolveFunction (0x14000d880)
target_func = view.get_function_at(0x14000d880)
target_func.name = 'rdm_ResolveFunction'
for xref in target_func.caller_sites:
if isinstance(xref.mlil, MediumLevelILCall):
variable = xref.mlil.output[0]
# 2nd param: rdm_ResolveFunc(HMODULE, string function name)
func_name = xref.mlil.params[1].string[0]
variable.name = func_name
proto = search_type_libraries(func_name, view)
if proto is not None:
proto_pointer = PointerType.create(view.arch, proto)
variable.type = proto_pointer
name_and_type_next_data_var(view, variable, xref.address, func_name, proto_pointer)
Names recovered include OpenProcess, WideCharToMultiByte, GetThreadContext, AddVectoredExceptionHandler, HeapCreate, CLRCreateInstance, CreateToolhelp32Snapshot, etc.
ConvertUTF8toUTF16 (0x14000f5d0)
target_func = view.get_function_at(0x14000f5d0)
target_func.name = 'rdm_ConvertUTF8toUTF16'
rdm_string = view.get_type_by_name('rdm_string')
for xref in target_func.caller_sites:
if isinstance(xref.mlil, MediumLevelILCall):
param = xref.mlil.params[0]
if isinstance(param, MediumLevelILConstPtr):
v = view.get_data_var_at(param.constant)
v.type = rdm_string
module_name = v.value['string'][:v.value['len']].decode()
v.name = module_name
if module_name not in runtime_loaded_modules:
runtime_loaded_modules.append(module_name)
dest_var = xref.mlil.output[0]
var_name = f'h_{module_name}'
dest_var.name = var_name
This pulls additional ntdll.dll and kernel32.dll references out of the UTF-8/UTF-16 conversion path.
ResolveFunction2 (0x14001a490)
target_func = view.get_function_at(0x14001a490)
target_func.name = 'rdm_ResolveFunction2'
for xref in target_func.caller_sites:
if isinstance(xref.mlil, MediumLevelILCall):
variable = xref.mlil.output[0]
# 2nd param: rdm_ResolveFunc(HMODULE, string function name)
func_name = xref.mlil.params[1].string[0]
variable.name = func_name
proto = search_type_libraries(func_name, view)
if proto is not None:
proto_pointer = PointerType.create(view.arch, proto)
variable.type = proto_pointer
name_and_type_next_data_var(view, variable, xref.address, func_name, proto_pointer)
A second resolver covers VirtualProtect, GetProcAddress, GetModuleHandleA, LoadLibraryA, CreateFileW, GetModuleFileNameW, and the rest of the runtime API surface.
view.update_analysis_and_wait()
view.save_auto_snapshot()