0
# Ordinal Lookups
1
2
Database of ordinal to symbol name mappings for common Windows DLLs. The ordlookup package provides resolution of function names from ordinal numbers when symbolic information is not available.
3
4
## Capabilities
5
6
### Ordinal Resolution
7
8
Look up function names from ordinal numbers for supported DLLs.
9
10
```python { .api }
11
def ordLookup(libname, ord_val, make_name=False):
12
"""
13
Look up symbol name for given ordinal in specified library.
14
15
Args:
16
libname (bytes): DLL name (case-insensitive)
17
ord_val (int): Ordinal number to look up
18
make_name (bool): If True, generate formatted name when lookup fails
19
20
Returns:
21
bytes: Function name if found, formatted ordinal if make_name=True,
22
or None if not found and make_name=False
23
"""
24
25
def formatOrdString(ord_val):
26
"""
27
Format ordinal number as standardized string.
28
29
Args:
30
ord_val (int): Ordinal number
31
32
Returns:
33
bytes: Formatted ordinal string (e.g., b"ord123")
34
"""
35
```
36
37
### Supported Libraries
38
39
The ordlookup package includes mappings for these common Windows DLLs:
40
41
- **oleaut32.dll**: OLE Automation functions
42
- **ws2_32.dll**: Winsock 2 networking functions
43
- **wsock32.dll**: Legacy Winsock networking functions
44
45
## Usage Examples
46
47
### Basic Ordinal Lookup
48
49
```python
50
import ordlookup
51
52
# Look up function names by ordinal
53
dll_name = b"oleaut32.dll"
54
ordinal = 2
55
56
function_name = ordlookup.ordLookup(dll_name, ordinal)
57
if function_name:
58
print(f"Ordinal {ordinal} in {dll_name.decode()}: {function_name.decode()}")
59
else:
60
print(f"Ordinal {ordinal} not found in {dll_name.decode()}")
61
62
# Generate formatted name if lookup fails
63
formatted_name = ordlookup.ordLookup(dll_name, 9999, make_name=True)
64
print(f"Unknown ordinal formatted: {formatted_name.decode()}")
65
```
66
67
### Integration with PE Import Analysis
68
69
```python
70
import pefile
71
import ordlookup
72
73
def resolve_import_ordinals(pe):
74
"""Resolve ordinal imports using ordlookup database."""
75
if not hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
76
return
77
78
print("Import Analysis with Ordinal Resolution:")
79
print("-" * 50)
80
81
for entry in pe.DIRECTORY_ENTRY_IMPORT:
82
dll_name = entry.dll
83
print(f"\nDLL: {dll_name.decode('utf-8')}")
84
85
for imp in entry.imports:
86
if imp.import_by_ordinal:
87
# Try to resolve ordinal to function name
88
resolved_name = ordlookup.ordLookup(dll_name, imp.ordinal)
89
90
if resolved_name:
91
print(f" Ordinal {imp.ordinal}: {resolved_name.decode('utf-8')}")
92
else:
93
print(f" Ordinal {imp.ordinal}: <unknown>")
94
else:
95
# Regular named import
96
if imp.name:
97
print(f" Function: {imp.name.decode('utf-8')}")
98
99
# Usage
100
with pefile.PE('executable.exe') as pe:
101
resolve_import_ordinals(pe)
102
```
103
104
### Ordinal Database Exploration
105
106
```python
107
import ordlookup
108
109
def explore_ordinal_database():
110
"""Explore available ordinal mappings."""
111
print("Available Ordinal Databases:")
112
print("=" * 40)
113
114
for dll_name, ord_dict in ordlookup.ords.items():
115
dll_str = dll_name.decode('utf-8')
116
print(f"\n{dll_str}:")
117
print(f" Functions: {len(ord_dict)}")
118
119
# Show ordinal range
120
if ord_dict:
121
min_ord = min(ord_dict.keys())
122
max_ord = max(ord_dict.keys())
123
print(f" Ordinal range: {min_ord} - {max_ord}")
124
125
# Show first few functions
126
print(" Sample functions:")
127
for ord_num in sorted(ord_dict.keys())[:5]:
128
func_name = ord_dict[ord_num].decode('utf-8')
129
print(f" {ord_num}: {func_name}")
130
131
if len(ord_dict) > 5:
132
print(f" ... and {len(ord_dict) - 5} more")
133
134
# Usage
135
explore_ordinal_database()
136
```
137
138
### Custom Ordinal Resolution
139
140
```python
141
import ordlookup
142
143
def resolve_with_fallback(dll_name, ordinal):
144
"""Resolve ordinal with multiple fallback strategies."""
145
# Try direct lookup
146
result = ordlookup.ordLookup(dll_name, ordinal)
147
if result:
148
return result.decode('utf-8'), 'database'
149
150
# Check case variations of DLL name
151
dll_variations = [
152
dll_name.lower(),
153
dll_name.upper(),
154
dll_name.lower().replace(b'.dll', b'') + b'.dll'
155
]
156
157
for dll_var in dll_variations:
158
result = ordlookup.ordLookup(dll_var, ordinal)
159
if result:
160
return result.decode('utf-8'), 'case_variant'
161
162
# Generate formatted ordinal as fallback
163
formatted = ordlookup.formatOrdString(ordinal)
164
return formatted.decode('utf-8'), 'generated'
165
166
# Usage example
167
test_cases = [
168
(b"oleaut32.dll", 2), # Known mapping
169
(b"OLEAUT32.DLL", 2), # Case variation
170
(b"kernel32.dll", 1), # Unknown DLL
171
(b"ws2_32.dll", 999) # Unknown ordinal
172
]
173
174
print("Ordinal Resolution with Fallback:")
175
print("-" * 40)
176
177
for dll, ordinal in test_cases:
178
result, method = resolve_with_fallback(dll, ordinal)
179
print(f"{dll.decode():<15} ord {ordinal:<3}: {result:<20} ({method})")
180
```
181
182
### PE File Analysis with Complete Ordinal Resolution
183
184
```python
185
import pefile
186
import ordlookup
187
188
def complete_import_analysis(pe_file):
189
"""Complete import analysis with ordinal resolution."""
190
print(f"Complete Import Analysis: {pe_file}")
191
print("=" * 60)
192
193
with pefile.PE(pe_file) as pe:
194
if not hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
195
print("No imports found")
196
return
197
198
total_imports = 0
199
resolved_ordinals = 0
200
201
for entry in pe.DIRECTORY_ENTRY_IMPORT:
202
dll_name = entry.dll
203
dll_str = dll_name.decode('utf-8')
204
205
print(f"\n{dll_str}:")
206
print("-" * len(dll_str))
207
208
dll_imports = 0
209
dll_resolved = 0
210
211
for imp in entry.imports:
212
dll_imports += 1
213
total_imports += 1
214
215
if imp.import_by_ordinal:
216
# Try to resolve ordinal
217
resolved_name = ordlookup.ordLookup(dll_name, imp.ordinal)
218
219
if resolved_name:
220
function_name = resolved_name.decode('utf-8')
221
resolved_ordinals += 1
222
dll_resolved += 1
223
status = "✓"
224
else:
225
function_name = f"<unknown ordinal {imp.ordinal}>"
226
status = "✗"
227
228
print(f" {status} Ordinal {imp.ordinal:3d}: {function_name}")
229
else:
230
# Named import
231
if imp.name:
232
function_name = imp.name.decode('utf-8')
233
print(f" ○ Function: {function_name}")
234
else:
235
print(f" ? Import at 0x{imp.address:08x}")
236
237
print(f" Summary: {dll_imports} imports, {dll_resolved} ordinals resolved")
238
239
# Overall statistics
240
print(f"\nOverall Statistics:")
241
print("-" * 20)
242
print(f"Total imports: {total_imports}")
243
print(f"Resolved ordinals: {resolved_ordinals}")
244
245
if total_imports > 0:
246
resolution_rate = (resolved_ordinals / total_imports) * 100
247
print(f"Resolution rate: {resolution_rate:.1f}%")
248
249
# Usage
250
complete_import_analysis('executable.exe')
251
```
252
253
### Extending the Ordinal Database
254
255
```python
256
import ordlookup
257
258
# Example of how to extend the database (conceptual)
259
def add_custom_ordinals():
260
"""Example of extending ordinal database with custom mappings."""
261
262
# This shows how you could add custom ordinal mappings
263
# Note: This modifies the runtime database, not persistent storage
264
265
custom_dll = b"custom.dll"
266
custom_mappings = {
267
1: b"CustomFunction1",
268
2: b"CustomFunction2",
269
100: b"SpecialExport"
270
}
271
272
# Add to ordlookup database
273
ordlookup.ords[custom_dll] = custom_mappings
274
275
print("Added custom ordinal mappings")
276
277
# Test the new mappings
278
for ordinal, expected_name in custom_mappings.items():
279
resolved = ordlookup.ordLookup(custom_dll, ordinal)
280
if resolved == expected_name:
281
print(f"✓ Custom ordinal {ordinal}: {resolved.decode()}")
282
else:
283
print(f"✗ Failed to resolve custom ordinal {ordinal}")
284
285
# Note: This is for demonstration - actual extension would require
286
# modifying the ordlookup package files or creating a custom lookup system
287
```