Skip to content

Commit 6adafd5

Browse files
committed
Unify heap API hooks, address debug CRT init issues
1 parent 92cd2d4 commit 6adafd5

File tree

2 files changed

+119
-99
lines changed

2 files changed

+119
-99
lines changed

qiling/os/windows/dlls/kernel32/heapapi.py

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ def hook_HeapCreate(ql: Qiling, address: int, params):
4949

5050
return ql.os.heap.alloc(dwInitialSize)
5151

52+
def _HeapAlloc(ql: Qiling, address: int, params):
53+
dwFlags = params["dwFlags"]
54+
dwBytes = params["dwBytes"]
55+
56+
ptr = ql.os.heap.alloc(dwBytes)
57+
58+
if ptr and (dwFlags & HEAP_ZERO_MEMORY):
59+
__zero_mem(ql.mem, ptr, dwBytes)
60+
61+
return ptr
62+
5263
# DECLSPEC_ALLOCATOR LPVOID HeapAlloc(
5364
# HANDLE hHeap,
5465
# DWORD dwFlags,
@@ -60,15 +71,7 @@ def hook_HeapCreate(ql: Qiling, address: int, params):
6071
'dwBytes' : SIZE_T
6172
})
6273
def hook_HeapAlloc(ql: Qiling, address: int, params):
63-
dwFlags = params["dwFlags"]
64-
dwBytes = params["dwBytes"]
65-
66-
ptr = ql.os.heap.alloc(dwBytes)
67-
68-
if ptr and (dwFlags & HEAP_ZERO_MEMORY):
69-
__zero_mem(ql.mem, ptr, dwBytes)
70-
71-
return ptr
74+
return _HeapAlloc(ql, address, params)
7275

7376
# DECLSPEC_ALLOCATOR LPVOID HeapReAlloc(
7477
# HANDLE hHeap,
@@ -86,6 +89,14 @@ def hook_HeapReAlloc(ql: Qiling, address: int, params):
8689
base = params["lpMem"]
8790
newSize = params["dwBytes"]
8891

92+
if not base:
93+
return _HeapAlloc(ql, address, params)
94+
95+
if newSize == 0:
96+
ql.os.heap.free(base)
97+
98+
return 0
99+
89100
oldSize = ql.os.heap.size(base)
90101
oldData = bytes(ql.mem.read(base, oldSize))
91102

@@ -150,3 +161,29 @@ def hook_HeapSetInformation(ql: Qiling, address: int, params):
150161
@winsdkapi(cc=STDCALL, params={})
151162
def hook_GetProcessHeap(ql: Qiling, address: int, params):
152163
return ql.os.heap.start_address
164+
165+
# BOOL HeapValidate(
166+
# HANDLE hHeap,
167+
# DWORD dwFlags,
168+
# LPCVOID lpMem
169+
# );
170+
@winsdkapi(cc=STDCALL, params={
171+
'hHeap': PVOID,
172+
'dwFlags': DWORD,
173+
'lpMem': PVOID
174+
})
175+
def hook_HeapValidate(ql: Qiling, address: int, params):
176+
hHeap = params['hHeap']
177+
lpMem = params['lpMem']
178+
179+
if not hHeap:
180+
return 0
181+
182+
# TODO: Maybe _find is a heap manager implementation
183+
# detail, in which case we shouldn't rely on it.
184+
chunk = ql.os.heap._find(lpMem)
185+
186+
if not chunk:
187+
return 0
188+
189+
return chunk.inuse

qiling/os/windows/dlls/msvcrt.py

Lines changed: 73 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,9 @@ def hook__controlfp(ql: Qiling, address: int, params):
135135
# );
136136
@winsdkapi(cc=CDECL, params={
137137
'func' : POINTER
138-
})
138+
}, passthru=True)
139139
def hook_atexit(ql: Qiling, address: int, params):
140-
ret = 0
141-
return ret
140+
return
142141

143142
# char*** __p__environ(void)
144143
@winsdkapi(cc=CDECL, params={})
@@ -211,20 +210,12 @@ def hook___p___argc(ql: Qiling, address: int, params):
211210
return ret
212211

213212
# TODO: this one belongs to ucrtbase.dll
214-
@winsdkapi(cc=CDECL, params={})
213+
@winsdkapi(cc=CDECL, params={}, passthru=True)
215214
def hook__get_initial_narrow_environment(ql: Qiling, address: int, params):
216-
ret = 0
217-
218-
for i, (k, v) in enumerate(ql.env.items()):
219-
entry = bytes(f'{k}={v}', 'ascii') + b'\x00'
220-
p_entry = ql.os.heap.alloc(len(entry))
221-
222-
ql.mem.write(p_entry, entry)
223-
224-
if i == 0:
225-
ret = p_entry
226-
227-
return ret
215+
# If the native version of this function does not
216+
# get to run, then debug versions of the CRT DLLs can fail
217+
# their initialization.
218+
return
228219

229220
# int sprintf ( char * str, const char * format, ... );
230221
@winsdkapi(cc=CDECL, params={
@@ -339,6 +330,18 @@ def __stdio_common_vsprintf(ql: Qiling, address: int, params, wstring: bool):
339330
def hook___stdio_common_vsprintf(ql: Qiling, address: int, params):
340331
return __stdio_common_vsprintf(ql, address, params, False)
341332

333+
@winsdkapi(cc=CDECL, params={
334+
'_Options' : PARAM_INT64,
335+
'_Buffer' : POINTER,
336+
'_BufferCount' : SIZE_T,
337+
'_MaxCount' : SIZE_T,
338+
'_Format' : STRING,
339+
'_Locale' : DWORD,
340+
'_ArgList' : POINTER
341+
})
342+
def hook___stdio_common_vsnprintf(ql: Qiling, address: int, params):
343+
return __stdio_common_vsprintf(ql, address, params, False)
344+
342345
@winsdkapi(cc=CDECL, params={
343346
'_Options' : PARAM_INT64,
344347
'_Buffer' : POINTER,
@@ -350,6 +353,18 @@ def hook___stdio_common_vsprintf(ql: Qiling, address: int, params):
350353
def hook___stdio_common_vswprintf(ql: Qiling, address: int, params):
351354
return __stdio_common_vsprintf(ql, address, params, True)
352355

356+
@winsdkapi(cc=CDECL, params={
357+
'_Options' : PARAM_INT64,
358+
'_Buffer' : POINTER,
359+
'_BufferCount' : SIZE_T,
360+
'_MaxCount' : SIZE_T,
361+
'_Format' : WSTRING,
362+
'_Locale' : DWORD,
363+
'_ArgList' : POINTER
364+
})
365+
def hook___stdio_common_vsnwprintf(ql: Qiling, address: int, params):
366+
return __stdio_common_vsprintf(ql, address, params, True)
367+
353368
# all the "_s" versions are aliases to their non-"_s" counterparts
354369

355370
@winsdkapi(cc=CDECL, params={
@@ -383,6 +398,18 @@ def hook___stdio_common_vfwprintf_s(ql: Qiling, address: int, params):
383398
def hook___stdio_common_vsprintf_s(ql: Qiling, address: int, params):
384399
return hook___stdio_common_vsprintf.__wrapped__(ql, address, params)
385400

401+
@winsdkapi(cc=CDECL, params={
402+
'_Options' : PARAM_INT64,
403+
'_Buffer' : POINTER,
404+
'_BufferCount' : SIZE_T,
405+
'_MaxCount' : SIZE_T,
406+
'_Format' : STRING,
407+
'_Locale' : DWORD,
408+
'_ArgList' : POINTER
409+
})
410+
def hook___stdio_common_vsnprintf_s(ql: Qiling, address: int, params):
411+
return hook___stdio_common_vsnprintf.__wrapped__(ql, address, params)
412+
386413
@winsdkapi(cc=CDECL, params={
387414
'_Options' : PARAM_INT64,
388415
'_Buffer' : POINTER,
@@ -394,6 +421,18 @@ def hook___stdio_common_vsprintf_s(ql: Qiling, address: int, params):
394421
def hook___stdio_common_vswprintf_s(ql: Qiling, address: int, params):
395422
return hook___stdio_common_vswprintf.__wrapped__(ql, address, params)
396423

424+
@winsdkapi(cc=CDECL, params={
425+
'_Options' : PARAM_INT64,
426+
'_Buffer' : POINTER,
427+
'_BufferCount' : SIZE_T,
428+
'_MaxCount' : SIZE_T,
429+
'_Format' : WSTRING,
430+
'_Locale' : DWORD,
431+
'_ArgList' : POINTER
432+
})
433+
def hook___stdio_common_vsnwprintf_s(ql: Qiling, address: int, params):
434+
return hook___stdio_common_vsnwprintf.__wrapped__(ql, address, params)
435+
397436
@winsdkapi(cc=CDECL, params={})
398437
def hook___lconv_init(ql: Qiling, address: int, params):
399438
return 0
@@ -449,50 +488,18 @@ def hook_strncmp(ql: Qiling, address: int, params):
449488

450489
return result
451490

452-
def __malloc(ql: Qiling, address: int, params):
453-
size = params['size']
454-
455-
return ql.os.heap.alloc(size)
456-
457491
@winsdkapi(cc=CDECL, params={
458492
'size' : UINT
459-
})
493+
}, passthru=True)
460494
def hook__malloc_base(ql: Qiling, address: int, params):
461-
return __malloc(ql, address, params)
495+
return
462496

463497
# void* malloc(unsigned int size)
464498
@winsdkapi(cc=CDECL, params={
465499
'size' : UINT
466-
})
500+
}, passthru=True)
467501
def hook_malloc(ql: Qiling, address: int, params):
468-
size = params['size']
469-
470-
return ql.os.heap.alloc(size)
471-
472-
def __realloc(ql: Qiling, address: int, params):
473-
block = params['block']
474-
size = params['size']
475-
476-
if not block:
477-
return ql.os.heap.alloc(size)
478-
479-
if size == 0:
480-
ql.os.heap.free(block)
481-
return 0
482-
483-
oldSize = ql.os.heap.size(block)
484-
oldData = bytes(ql.mem.read(block, size))
485-
ql.os.heap.free(block)
486-
487-
if size < oldSize:
488-
oldData = oldData[0:size]
489-
490-
newBase = ql.os.heap.alloc(size)
491-
492-
if newBase:
493-
ql.mem.write(newBase, oldData)
494-
495-
return newBase
502+
return
496503

497504
# void* __cdecl _realloc_base(
498505
# void* const block,
@@ -501,27 +508,22 @@ def __realloc(ql: Qiling, address: int, params):
501508
@winsdkapi(cc=CDECL, params={
502509
'block' : POINTER,
503510
'size' : UINT
504-
})
511+
}, passthru=True)
505512
def hook__realloc_base(ql: Qiling, address: int, params):
506-
return __realloc(ql, address, params)
507-
508-
def __free(ql: Qiling, address: int, params):
509-
address = params['address']
510-
511-
ql.os.heap.free(address)
513+
return
512514

513515
@winsdkapi(cc=CDECL, params={
514516
'address': POINTER
515-
})
517+
}, passthru=True)
516518
def hook__free_base(ql: Qiling, address: int, params):
517-
return __free(ql, address, params)
519+
return
518520

519521
# void* free(void *address)
520522
@winsdkapi(cc=CDECL, params={
521523
'address': POINTER
522-
})
524+
}, passthru=True)
523525
def hook_free(ql: Qiling, address: int, params):
524-
return __free(ql, address, params)
526+
return
525527

526528
# _onexit_t _onexit(
527529
# _onexit_t function
@@ -546,32 +548,16 @@ def hook__onexit(ql: Qiling, address: int, params):
546548
'dest' : POINTER,
547549
'c' : INT,
548550
'count' : SIZE_T
549-
})
551+
}, passthru=True)
550552
def hook_memset(ql: Qiling, address: int, params):
551-
dest = params["dest"]
552-
c = params["c"]
553-
count = params["count"]
554-
555-
ql.mem.write(dest, bytes([c] * count))
556-
557-
return dest
558-
559-
def __calloc(ql: Qiling, address: int, params):
560-
num = params['num']
561-
size = params['size']
562-
563-
count = num * size
564-
ret = ql.os.heap.alloc(count)
565-
ql.mem.write(ret, bytes([0] * count))
566-
567-
return ret
553+
return
568554

569555
@winsdkapi(cc=CDECL, params={
570556
'num' : SIZE_T,
571557
'size' : SIZE_T
572-
})
558+
}, passthru=True)
573559
def hook__calloc_base(ql: Qiling, address: int, params):
574-
return __calloc(ql, address, params)
560+
return
575561

576562
# void *calloc(
577563
# size_t num,
@@ -580,9 +566,9 @@ def hook__calloc_base(ql: Qiling, address: int, params):
580566
@winsdkapi(cc=CDECL, params={
581567
'num' : SIZE_T,
582568
'size' : SIZE_T
583-
})
569+
}, passthru=True)
584570
def hook_calloc(ql: Qiling, address: int, params):
585-
return __calloc(ql, address, params)
571+
return
586572

587573
# void * memmove(
588574
# void *dest,
@@ -593,12 +579,9 @@ def hook_calloc(ql: Qiling, address: int, params):
593579
'dest' : POINTER,
594580
'src' : POINTER,
595581
'num' : SIZE_T
596-
})
582+
}, passthru=True)
597583
def hook_memmove(ql: Qiling, address: int, params):
598-
data = ql.mem.read(params['src'], params['num'])
599-
ql.mem.write(params['dest'], bytes(data))
600-
601-
return params['dest']
584+
return
602585

603586
# int _ismbblead(
604587
# unsigned int c

0 commit comments

Comments
 (0)