-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathutils.cpp
More file actions
179 lines (152 loc) · 4.95 KB
/
utils.cpp
File metadata and controls
179 lines (152 loc) · 4.95 KB
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <ntifs.h>
#include <windef.h>
#include <ntimage.h>
#include "shared.h"
#include "utils.h"
#include <cstdint>
/**
* \brief Get base address of kernel module
* \param moduleName Name of the module (ex. storport.sys)
* \return Address of the module or null pointer if failed
*/
PVOID Utils::GetModuleBase(const char* moduleName)
{
PVOID address = nullptr;
ULONG size = 0;
auto status = ZwQuerySystemInformation(SystemModuleInformation, &size, 0, &size);
if (status != STATUS_INFO_LENGTH_MISMATCH)
return nullptr;
auto* moduleList = static_cast<PSYSTEM_MODULE_INFORMATION>(ExAllocatePoolWithTag(NonPagedPool, size, POOL_TAG));
if (!moduleList)
return nullptr;
status = ZwQuerySystemInformation(SystemModuleInformation, moduleList, size, nullptr);
if (!NT_SUCCESS(status))
goto end;
for (auto i = 0; i < moduleList->ulModuleCount; i++)
{
auto module = moduleList->Modules[i];
if (strstr(module.ImageName, moduleName))
{
address = module.Base;
break;
}
}
end:
ExFreePool(moduleList);
return address;
}
int CustomStrCmp(const char* str1, const char* str2)
{
while (*str1 && (*str1 == *str2))
{
str1++;
str2++;
}
return *(const unsigned char*)str1 - *(const unsigned char*)str2;
}
UINT64 Utils::GetExport(void* base, const char* functionName)
{
PIMAGE_DOS_HEADER dosHeader = static_cast<PIMAGE_DOS_HEADER>(base);
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
return 0;
PIMAGE_NT_HEADERS64 ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS64>(reinterpret_cast<UINT64>(base) + dosHeader->e_lfanew);
UINT32 exportsRva = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
if (!exportsRva)
return 0;
PIMAGE_EXPORT_DIRECTORY exports = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(reinterpret_cast<UINT64>(base) + exportsRva);
UINT32* nameRva = reinterpret_cast<UINT32*>(reinterpret_cast<UINT64>(base) + exports->AddressOfNames);
for (UINT32 i = 0; i < exports->NumberOfNames; ++i)
{
char* func = reinterpret_cast<char*>(reinterpret_cast<UINT64>(base) + nameRva[i]);
if (CustomStrCmp(func, functionName) == 0)
{
UINT32* funcRva = reinterpret_cast<UINT32*>(reinterpret_cast<UINT64>(base) + exports->AddressOfFunctions);
UINT16* ordinalRva = reinterpret_cast<UINT16*>(reinterpret_cast<UINT64>(base) + exports->AddressOfNameOrdinals);
return reinterpret_cast<UINT64>(base) + funcRva[ordinalRva[i]];
}
}
return 0;
}
/**
* \brief Checks if buffer at the location of base parameter
* matches pattern and mask
* \param base Address to check
* \param pattern Byte pattern to match
* \param mask Mask containing unknown bytes
* \return
*/
bool Utils::CheckMask(const char* base, const char* pattern, const char* mask)
{
for (; *mask; ++base, ++pattern, ++mask)
{
if ('x' == *mask && *base != *pattern)
{
return false;
}
}
return true;
}
/**
* \brief Find byte pattern in given buffer
* \param base Address to start searching in
* \param length Maximum length
* \param pattern Byte pattern to match
* \param mask Mask containing unknown bytes
* \return Pointer to matching memory
*/
PVOID Utils::FindPattern(PVOID base, int length, const char* pattern, const char* mask)
{
length -= static_cast<int>(strlen(mask));
for (auto i = 0; i <= length; ++i)
{
const auto* data = static_cast<char*>(base);
const auto* address = &data[i];
if (CheckMask(address, pattern, mask))
return PVOID(address);
}
return nullptr;
}
/**
* \brief Find byte pattern in given module/image ".text" and "PAGE" sections
* \param base Base address of the kernel module
* \param pattern Byte pattern to match
* \param mask Mask containing unknown bytes
* \return Pointer to matching memory
*/
PVOID Utils::FindPatternImage(PVOID base, const char* pattern, const char* mask)
{
PVOID match = nullptr;
auto* headers = reinterpret_cast<PIMAGE_NT_HEADERS>(static_cast<char*>(base) + static_cast<PIMAGE_DOS_HEADER>(base)->e_lfanew);
auto* sections = IMAGE_FIRST_SECTION(headers);
for (auto i = 0; i < headers->FileHeader.NumberOfSections; ++i)
{
auto* section = §ions[i];
if ('EGAP' == *reinterpret_cast<PINT>(section->Name) || memcmp(section->Name, ".text", 5) == 0)
{
match = FindPattern(static_cast<char*>(base) + section->VirtualAddress, section->Misc.VirtualSize, pattern, mask);
if (match)
break;
}
}
return match;
}
/**
* \brief Generate pseudo-random text into given buffer
* \param text Pointer to text
* \param length Desired length
*/
void Utils::RandomText(char* text, const int length)
{
if (!text)
return;
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
auto seed = KeQueryTimeIncrement();
for (auto n = 0; n <= length; n++)
{
auto key = RtlRandomEx(&seed) % static_cast<int>(sizeof(alphanum) - 1);
text[n] = alphanum[key];
}
}