|
|
""" |
|
|
Full disassembly of the Cipher function from AES setup through BCryptDecrypt. |
|
|
Based on findings: |
|
|
- SHA256 provider at file 0x0015a3e2 (RVA 0x0015afe2) |
|
|
- AES provider at file 0x0015a702 (RVA 0x0015b302) |
|
|
- ChainingModeCFB at file 0x0015a7cd (RVA 0x0015b3cd) |
|
|
- MessageBlockLength at file 0x0015a7fc (RVA 0x0015b3fc) |
|
|
- BCryptGenerateSymmetricKey import at ~0x027ef0a2 |
|
|
- Need to find: key handling, IV passing, BCryptDecrypt call |
|
|
""" |
|
|
import struct |
|
|
from capstone import Cs, CS_ARCH_X86, CS_MODE_64 |
|
|
|
|
|
DLL_PATH = r"c:\Users\MattyMroz\Desktop\PROJECTS\ONEOCR\ocr_data\oneocr.dll" |
|
|
IMAGE_BASE = 0x180000000 |
|
|
TEXT_VA = 0x1000 |
|
|
TEXT_FILE_OFFSET = 0x400 |
|
|
|
|
|
def rva_to_file(rva): |
|
|
return rva - TEXT_VA + TEXT_FILE_OFFSET |
|
|
|
|
|
def file_to_rva(foff): |
|
|
return foff - TEXT_FILE_OFFSET + TEXT_VA |
|
|
|
|
|
with open(DLL_PATH, "rb") as f: |
|
|
dll_data = f.read() |
|
|
|
|
|
md = Cs(CS_ARCH_X86, CS_MODE_64) |
|
|
md.detail = False |
|
|
|
|
|
def disasm_region(name, file_start, file_end): |
|
|
rva_start = file_to_rva(file_start) |
|
|
va_start = IMAGE_BASE + rva_start |
|
|
code = dll_data[file_start:file_end] |
|
|
print(f"\n{'='*100}") |
|
|
print(f"{name}") |
|
|
print(f"File: 0x{file_start:08x}-0x{file_end:08x}, RVA: 0x{rva_start:08x}, VA: 0x{va_start:016x}") |
|
|
print(f"{'='*100}") |
|
|
for insn in md.disasm(code, va_start): |
|
|
foff = rva_to_file(insn.address - IMAGE_BASE) |
|
|
print(f" {insn.address - IMAGE_BASE:08x} ({foff:08x}): {insn.bytes.hex():<40s} {insn.mnemonic:<14s} {insn.op_str}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("\n" + "="*100) |
|
|
print("SCANNING FOR FUNCTION PROLOGUE before AES setup (file 0x0015a702)") |
|
|
print("="*100) |
|
|
|
|
|
|
|
|
search_start = 0x0015a500 |
|
|
search_end = 0x0015a710 |
|
|
search_region = dll_data[search_start:search_end] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for i in range(len(search_region) - 4): |
|
|
b = search_region[i:i+8] |
|
|
foff = search_start + i |
|
|
rva = file_to_rva(foff) |
|
|
|
|
|
|
|
|
if b[:5] == bytes([0x48, 0x89, 0x5C, 0x24, 0x08]): |
|
|
print(f" Possible prologue at file 0x{foff:08x} (RVA 0x{rva:08x}): mov [rsp+8], rbx") |
|
|
elif b[:2] == bytes([0x40, 0x55]): |
|
|
print(f" Possible prologue at file 0x{foff:08x} (RVA 0x{rva:08x}): REX push rbp") |
|
|
elif b[:1] == bytes([0x55]) and (i == 0 or search_region[i-1] in (0xC3, 0xCC, 0x90)): |
|
|
print(f" Possible prologue at file 0x{foff:08x} (RVA 0x{rva:08x}): push rbp (after ret/nop/int3)") |
|
|
elif b[:4] == bytes([0x48, 0x83, 0xEC, 0x28]): |
|
|
print(f" Possible prologue at file 0x{foff:08x} (RVA 0x{rva:08x}): sub rsp, 0x28") |
|
|
elif b[:3] == bytes([0x48, 0x81, 0xEC]): |
|
|
val = struct.unpack_from('<I', b, 3)[0] |
|
|
print(f" Possible prologue at file 0x{foff:08x} (RVA 0x{rva:08x}): sub rsp, 0x{val:X}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
disasm_region( |
|
|
"Cipher function part 1: prologue to AES provider", |
|
|
0x0015a500, 0x0015a720 |
|
|
) |
|
|
|
|
|
|
|
|
disasm_region( |
|
|
"Cipher function part 2: AES provider, ChainingModeCFB, MessageBlockLength", |
|
|
0x0015a720, 0x0015a880 |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
disasm_region( |
|
|
"Cipher function part 3: key gen and decrypt (extended)", |
|
|
0x0015abd0, 0x0015ae00 |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("\n" + "="*100) |
|
|
print("ALL INDIRECT CALLS (ff 15) in Cipher function region 0x0015a500-0x0015ae00") |
|
|
print("="*100) |
|
|
|
|
|
search_start = 0x0015a500 |
|
|
search_end = 0x0015ae00 |
|
|
for i in range(search_end - search_start - 6): |
|
|
foff = search_start + i |
|
|
if dll_data[foff] == 0xFF and dll_data[foff+1] == 0x15: |
|
|
rva = file_to_rva(foff) |
|
|
disp = struct.unpack_from('<i', dll_data, foff + 2)[0] |
|
|
target_rva = rva + 6 + disp |
|
|
target_foff = rva_to_file(target_rva) |
|
|
|
|
|
iat_value = struct.unpack_from('<Q', dll_data, target_foff)[0] if target_foff + 8 <= len(dll_data) else 0 |
|
|
print(f" File 0x{foff:08x} (RVA 0x{rva:08x}): call [rip+0x{disp:x}] -> IAT at RVA 0x{target_rva:08x}") |
|
|
|
|
|
|
|
|
|
|
|
disasm_region( |
|
|
"Cipher function part 4: from end of IV path to function cleanup", |
|
|
0x0015ac00, 0x0015ae00 |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
disasm_region( |
|
|
"Pre-magic-check function caller", |
|
|
0x0015a0c0, 0x0015a170 |
|
|
) |
|
|
|