File size: 5,740 Bytes
ce847d4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""
Disassemble the actual BCrypt crypto operations at 0x18015ba45+ 
and map all indirect calls to IAT entries.
"""
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}")
    print(f"{'='*100}")
    for insn in md.disasm(code, va_start):
        foff = rva_to_file(insn.address - IMAGE_BASE)
        line = f"  {insn.address - IMAGE_BASE:08x} ({foff:08x}): {insn.bytes.hex():<40s} {insn.mnemonic:<14s} {insn.op_str}"
        # Annotate indirect calls
        if insn.mnemonic == 'call' and insn.bytes[0] == 0xFF and insn.bytes[1] == 0x15:
            disp = struct.unpack_from('<i', bytes(insn.bytes), 2)[0]
            target_rva = (insn.address - IMAGE_BASE) + insn.size + disp
            line += f"  ; IAT@0x{target_rva:08x}"
        print(line)

# First, let's identify ALL BCrypt IAT entries
# From previous analysis:
# BCryptOpenAlgorithmProvider → IAT 0x0081a5e0
# BCryptGetProperty → IAT 0x0081a5d0 
# BCryptSetProperty → IAT 0x0081a608
# Let's find the rest by looking at the import section

# Parse PE to find BCrypt imports
print("="*100)
print("FINDING ALL BCRYPT IAT ENTRIES")
print("="*100)

# Parse PE headers
e_lfanew = struct.unpack_from('<I', dll_data, 0x3c)[0]
opt_hdr_off = e_lfanew + 24
import_dir_rva = struct.unpack_from('<I', dll_data, opt_hdr_off + 120)[0]  # Import RVA
import_dir_size = struct.unpack_from('<I', dll_data, opt_hdr_off + 124)[0]

# Find sections for RVA to file offset mapping
num_sections = struct.unpack_from('<H', dll_data, e_lfanew + 6)[0]
sections_off = e_lfanew + 24 + struct.unpack_from('<H', dll_data, e_lfanew + 20)[0]

sections = []
for i in range(num_sections):
    sec_off = sections_off + i * 40
    name = dll_data[sec_off:sec_off+8].rstrip(b'\x00').decode('ascii', errors='replace')
    vsize = struct.unpack_from('<I', dll_data, sec_off + 8)[0]
    vrva = struct.unpack_from('<I', dll_data, sec_off + 12)[0]
    rawsize = struct.unpack_from('<I', dll_data, sec_off + 16)[0]
    rawoff = struct.unpack_from('<I', dll_data, sec_off + 20)[0]
    sections.append((name, vrva, vsize, rawoff, rawsize))
    
def rva_to_foff(rva):
    for name, vrva, vsize, rawoff, rawsize in sections:
        if vrva <= rva < vrva + vsize:
            return rawoff + (rva - vrva)
    return None

if import_dir_rva:
    ioff = rva_to_foff(import_dir_rva)
    if ioff:
        idx = 0
        while True:
            desc_off = ioff + idx * 20
            ilt_rva = struct.unpack_from('<I', dll_data, desc_off)[0]
            name_rva = struct.unpack_from('<I', dll_data, desc_off + 12)[0]
            iat_rva = struct.unpack_from('<I', dll_data, desc_off + 16)[0]
            if ilt_rva == 0 and name_rva == 0:
                break
            name_off = rva_to_foff(name_rva)
            if name_off:
                dname = dll_data[name_off:name_off+64].split(b'\x00')[0].decode('ascii', errors='replace')
                if 'bcrypt' in dname.lower():
                    print(f"\nDLL: {dname}, ILT RVA: 0x{ilt_rva:08x}, IAT RVA: 0x{iat_rva:08x}")
                    # Walk the ILT to find function names
                    ilt_off = rva_to_foff(ilt_rva)
                    iat_entry_rva = iat_rva
                    j = 0
                    while ilt_off:
                        entry = struct.unpack_from('<Q', dll_data, ilt_off + j * 8)[0]
                        if entry == 0:
                            break
                        if entry & (1 << 63):
                            ordinal = entry & 0xFFFF
                            print(f"  IAT 0x{iat_entry_rva:08x}: Ordinal {ordinal}")
                        else:
                            hint_rva = entry & 0x7FFFFFFF
                            hint_off = rva_to_foff(hint_rva)
                            if hint_off:
                                hint = struct.unpack_from('<H', dll_data, hint_off)[0]
                                fname = dll_data[hint_off+2:hint_off+66].split(b'\x00')[0].decode('ascii', errors='replace')
                                print(f"  IAT 0x{iat_entry_rva:08x}: {fname} (hint {hint})")
                        iat_entry_rva += 8
                        j += 1
            idx += 1

# Now disassemble the actual BCrypt crypto operation block
# This is at RVA 0x0015ba45 = file 0x0015ae45
disasm_region(
    "BCrypt crypto operations (key gen + decrypt)",
    0x0015ae45, 0x0015b200
)

# Find all indirect calls in extended range
print("\n" + "="*100)
print("ALL INDIRECT CALLS (ff 15) in range 0x0015ae00-0x0015c200")
print("="*100)

for i in range(0x0015ae00, 0x0015c200):
    if dll_data[i] == 0xFF and dll_data[i+1] == 0x15:
        rva = file_to_rva(i)
        disp = struct.unpack_from('<i', dll_data, i + 2)[0]
        target_rva = rva + 6 + disp
        print(f"  File 0x{i:08x} (RVA 0x{rva:08x}): call [rip+0x{disp:x}] -> IAT@0x{target_rva:08x}")

# Also disassemble the function at 0x18015abd0 (called to process data when r14b=true)
# RVA 0x0015abd0, file 0x00159fd0
disasm_region(
    "Function at 0x18015abd0 (called on data when r14b=true)",
    0x00159fd0, 0x0015a0c0
)