1 /**
2 * @file libc.cpp
3 * @author created by: Peter Hlavaty
4 */
5
6 #include "libc.h"
7 #include <memory>
8 #include <Ntintsafe.h>
9
10 #pragma warning(push)
11 #pragma warning (disable : 4565)
12
13 #ifndef _LIBC_POOL_TAG
14 #define _LIBC_POOL_TAG 'colM'
15 #endif
16
17 // very nice for debug forensics!
18 struct MEMBLOCK
19 {
20 size_t size;
21 #pragma warning(push)
22 #pragma warning (disable : 4200)
23 char data[0];
24 #pragma warning(pop)
25 };
26
27 EXTERN_C
__drv_allocatesMem(pBlock)28 __drv_when(return!=0, __drv_allocatesMem(pBlock))
29 __checkReturn
30 __drv_maxIRQL(DISPATCH_LEVEL)
31 __bcount_opt(size)
32 void*
33 __cdecl malloc(
34 __in size_t size
35 )
36 {
37 /* A specially crafted size value can trigger the overflow.
38 If the sum in a value that overflows or underflows the capacity of the type,
39 the function returns nullptr. */
40 size_t number_of_bytes = 0;
41 if (!NT_SUCCESS(RtlSizeTAdd(size, sizeof(MEMBLOCK), &number_of_bytes))){
42 return nullptr;
43 }
44 MEMBLOCK *pBlock = static_cast<MEMBLOCK*>(
45 ExAllocatePoolWithTag(
46 NonPagedPoolNxCacheAligned,
47 number_of_bytes,
48 _LIBC_POOL_TAG));
49
50 if (nullptr == pBlock)
51 return nullptr;
52
53 pBlock->size = size;
54 return pBlock->data;
55 }
56
57 EXTERN_C
__drv_allocatesMem(p)58 __drv_when(return != 0, __drv_allocatesMem(p))
59 __checkReturn
60 __drv_maxIRQL(DISPATCH_LEVEL)
61 __bcount_opt(size * n)
62 void*
63 __cdecl calloc(size_t n, size_t size)
64 {
65 size_t total = n * size;
66 void *p = malloc(total);
67
68 if (!p) return NULL;
69
70 return memset(p, 0, total);
71 }
72
73 EXTERN_C
__drv_allocatesMem(inblock)74 __drv_when(return!=0, __drv_allocatesMem(inblock))
75 __checkReturn
76 __drv_maxIRQL(DISPATCH_LEVEL)
77 __bcount_opt(size)
78 void*
79 __cdecl realloc(
80 __in_opt void* ptr,
81 __in size_t size
82 )
83 {
84 if (!ptr)
85 return malloc(size);
86
87 std::unique_ptr<unsigned char> inblock = std::unique_ptr<unsigned char>(static_cast<unsigned char*>(ptr));
88
89 // alloc new block
90 void* mem = malloc(size);
91 if (!mem)
92 return nullptr;
93
94 // copy from old one, not overflow ..
95 memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data)->size, size));
96 return mem;
97 }
98
99 EXTERN_C
__drv_maxIRQL(DISPATCH_LEVEL)100 __drv_maxIRQL(DISPATCH_LEVEL)
101 void
102 __cdecl free(
103 __inout_opt __drv_freesMem(Mem) void* ptr
104 )
105 {
106 if (ptr)
107 ExFreePoolWithTag(CONTAINING_RECORD(ptr, MEMBLOCK, data), _LIBC_POOL_TAG);
108 }
109
110 #pragma warning(pop)
111
__drv_allocatesMem(ptr)112 __drv_when(return!=0, __drv_allocatesMem(ptr))
113 __checkReturn
114 __drv_maxIRQL(DISPATCH_LEVEL)
115 __bcount_opt(size)
116 void*
117 __cdecl operator new(
118 __in size_t size
119 )
120 {
121 return malloc(size);
122 }
123
__drv_maxIRQL(DISPATCH_LEVEL)124 __drv_maxIRQL(DISPATCH_LEVEL)
125 void
126 __cdecl operator delete(
127 __inout void* ptr
128 )
129 {
130 free(ptr);
131 }
132
133 int
vsnprintf(char * buffer,size_t count,const char * format,va_list argptr)134 __cdecl vsnprintf(
135 char *buffer,
136 size_t count,
137 const char *format,
138 va_list argptr
139 )
140 {
141 return vsprintf_s(buffer, count, format, argptr);
142 }
143