libPeConv
A library to load, manipulate, dump PE files.
Loading...
Searching...
No Matches
exports_lookup.cpp
Go to the documentation of this file.
2#include "peconv/util.h"
3
4#include "peconv/logger.h"
5
6/*
7typedef struct _IMAGE_EXPORT_DIRECTORY {
8 DWORD Characteristics;
9 DWORD TimeDateStamp;
10 WORD MajorVersion;
11 WORD MinorVersion;
12 DWORD Name;
13 DWORD Base;
14 DWORD NumberOfFunctions;
15 DWORD NumberOfNames;
16 DWORD AddressOfFunctions; // RVA from base of image
17 DWORD AddressOfNames; // RVA from base of image
18 DWORD AddressOfNameOrdinals; // RVA from base of image
19} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
20*/
21
22#ifndef TO_LOWERCASE
23#define TO_LOWERCASE(c1) c1 = (c1 <= 'Z' && c1 >= 'A') ? c1 = (c1 - 'A') + 'a': c1;
24#endif
25
26namespace {
27
28 bool is_wanted_func(LPCSTR curr_name, LPCSTR wanted_name)
29 {
30 if (curr_name == NULL || wanted_name == NULL) return false;
31
32 size_t wanted_name_len = strlen(wanted_name);
33 size_t curr_name_len = strlen(curr_name);
34
35 if (curr_name_len != wanted_name_len) return false;
36
37 for (size_t i = 0; i < wanted_name_len; i++) {
38 char c1 = curr_name[i];
39 char c2 = wanted_name[i];
40 TO_LOWERCASE(c1);
41 TO_LOWERCASE(c2);
42 if (c1 != c2) return false;
43 }
44 return true;
45 }
46
47 bool is_ordinal(IMAGE_EXPORT_DIRECTORY* exp, LPCSTR func_name)
48 {
49 ULONGLONG base = exp->Base;
50 ULONGLONG max_ord = base + exp->NumberOfFunctions;
51 ULONGLONG name_ptr_val = (ULONGLONG)func_name;
52 if (name_ptr_val >= base && name_ptr_val < max_ord) {
53 return true;
54 }
55 return false;
56 }
57
58 FARPROC get_export_by_ord(LPVOID modulePtr, IMAGE_EXPORT_DIRECTORY* exp, DWORD wanted_ordinal)
59 {
60 SIZE_T functCount = exp->NumberOfFunctions;
61 DWORD funcsListRVA = exp->AddressOfFunctions;
62 DWORD ordBase = exp->Base;
63
64 const size_t modSize = peconv::get_image_size((BYTE*)modulePtr);
65
66 //go through names:
67 for (DWORD i = 0; i < functCount; i++) {
68 DWORD ordinal = ordBase + i;
69 if (ordinal != wanted_ordinal) continue;
70
71 DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*)modulePtr + i * sizeof(DWORD));
72 if (!peconv::validate_ptr((LPVOID)modulePtr, modSize, funcRVA, sizeof(DWORD))) {
73 LOG_ERROR("Invalid RVA of exported function");
74 return NULL;
75 }
76 BYTE* fPtr = (BYTE*)modulePtr + (*funcRVA); //pointer to the function
77 if (!peconv::validate_ptr((LPVOID)modulePtr, modSize, fPtr, 1)) {
78 LOG_ERROR("Invalid pointer to exported function");
79 return NULL;
80 }
81 if (peconv::is_valid_string(modulePtr, modSize, fPtr) && peconv::forwarder_name_len(fPtr) > 1) {
82 LOG_WARNING("Forwarded function: [%lu -> %p] cannot be resolved.", wanted_ordinal, fPtr);
83 return NULL; // this function is forwarded, cannot be resolved
84 }
85 return (FARPROC)fPtr; //return the pointer to the found function
86 }
87 return NULL;
88 }
89};
90
91size_t peconv::get_exported_names(LPVOID modulePtr, std::vector<std::string> &names_list)
92{
93 const size_t modSize = peconv::get_image_size((const BYTE*)modulePtr);
94 if (!modSize) return 0;
95
96 IMAGE_EXPORT_DIRECTORY* exp = peconv::get_export_directory((HMODULE) modulePtr);
97 if (!exp || !validate_ptr(modulePtr, modSize, exp, sizeof(IMAGE_EXPORT_DIRECTORY))) {
98 return 0;
99 }
100
101 SIZE_T namesCount = exp->NumberOfNames;
102 DWORD funcNamesListRVA = exp->AddressOfNames;
103
104 //go through names:
105 DWORD* nameRVAs = (DWORD*)(funcNamesListRVA + (ULONG_PTR)modulePtr);
106 SIZE_T i = 0;
107 for (i = 0; i < namesCount; i++) {
108 if (!validate_ptr(modulePtr, modSize, &nameRVAs[i], sizeof(DWORD))) {
109 break;// this should not happen. maybe the PE file is corrupt?
110 }
111 DWORD nameRVA = nameRVAs[i];
112 if (!nameRVA) {
113 continue;
114 }
115 LPSTR name = (LPSTR)(nameRVA + (BYTE*) modulePtr);
116 if (!is_valid_string(modulePtr, modSize, name)) {
117 break;// this should not happen. maybe the PE file is corrupt?
118 }
119 names_list.push_back(name);
120 }
121 return i;
122}
123
124//WARNING: doesn't work for the forwarded functions.
125FARPROC peconv::get_exported_func(LPVOID modulePtr, LPCSTR wanted_name)
126{
127 const size_t modSize = peconv::get_image_size((const BYTE*)modulePtr);
128 if (!modSize) return nullptr;
129
130 IMAGE_EXPORT_DIRECTORY* exp = peconv::get_export_directory((HMODULE) modulePtr);
131 if (!exp || !validate_ptr(modulePtr, modSize, exp, sizeof(IMAGE_EXPORT_DIRECTORY))) {
132 return nullptr;
133 }
134
135 SIZE_T namesCount = exp->NumberOfNames;
136
137 DWORD funcsListRVA = exp->AddressOfFunctions;
138 DWORD funcNamesListRVA = exp->AddressOfNames;
139 DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals;
140
141 if (is_ordinal(exp, wanted_name)) {
142 LOG_DEBUG("Getting function by ordinal.");
143 const DWORD ordinal = MASK_TO_DWORD((ULONG_PTR)wanted_name);
144 return get_export_by_ord(modulePtr, exp, ordinal);
145 }
146 if (peconv::is_bad_read_ptr(wanted_name, 1)) { // wanted_name is not in supplied module, so we can't check it against the module bounds
147 LOG_ERROR("Invalid pointer to the name.");
148 return nullptr;
149 }
150 //go through names:
151 for (SIZE_T i = 0; i < namesCount; i++) {
152 DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
153 WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*) modulePtr + i * sizeof(WORD));
154 if (!validate_ptr(modulePtr, modSize, nameRVA, sizeof(DWORD))
155 || !validate_ptr(modulePtr, modSize, nameIndex, sizeof(WORD)))
156 {
157 LOG_ERROR("Invalid pointer to exported name RVA or index");
158 return nullptr;
159 }
160 DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + (*nameIndex) * sizeof(DWORD));
161 if (!validate_ptr(modulePtr, modSize, funcRVA, sizeof(DWORD))) {
162 LOG_ERROR("Invalid pointer to exported function RVA");
163 return nullptr;
164 }
165 LPSTR name = (LPSTR)(*nameRVA + (BYTE*) modulePtr);
166 if (!peconv::validate_ptr(modulePtr, modSize, name, 1)) {
167 LOG_ERROR("Invalid pointer to exported function name");
168 return nullptr;
169 }
170 if (!is_wanted_func(name, wanted_name)) {
171 continue; //this is not the function we are looking for
172 }
173 BYTE* fPtr = (BYTE*)modulePtr + (*funcRVA); //pointer to the function
174 if (!peconv::validate_ptr(modulePtr, modSize, (LPVOID)fPtr, 1)) {
175 LOG_ERROR("Invalid pointer to exported function");
176 return NULL;
177 }
178 if (is_valid_string(modulePtr, modSize, fPtr) && forwarder_name_len(fPtr) > 1) {
179 LOG_WARNING("Forwarded function: [%s -> %p] cannot be resolved.", name, fPtr);
180 return nullptr; // this function is forwarded, cannot be resolved
181 }
182 return (FARPROC) fPtr; //return the pointer to the found function
183 }
184 //function not found
185 LOG_WARNING("Function not found.");
186 return nullptr;
187}
188
189FARPROC peconv::export_based_resolver::resolve_func(LPCSTR lib_name, LPCSTR func_name)
190{
191 HMODULE libBasePtr = load_library(lib_name);
192 if (libBasePtr == NULL) {
193 LOG_ERROR("Could not load the library.");
194 return NULL;
195 }
196
197 FARPROC hProc = get_exported_func(libBasePtr, func_name);
198 if (!hProc) {
199 LOG_WARNING("Could could not get function from exports. Falling back to the default resolver.");
200 hProc = default_func_resolver::resolve_func(lib_name, func_name);
201 if (!hProc) {
202 LOG_ERROR("Loading function from %s failed.", lib_name);
203 }
204 }
205 return hProc;
206}
207
208LPSTR peconv::read_dll_name(HMODULE modulePtr)
209{
210 const size_t modSize = peconv::get_image_size((const BYTE*)modulePtr);
211 if (!modSize) {
212 return nullptr;
213 }
214 IMAGE_EXPORT_DIRECTORY* exp = get_export_directory(modulePtr);
215 if (!exp || !validate_ptr(modulePtr, modSize, exp, sizeof(IMAGE_EXPORT_DIRECTORY))) {
216 return nullptr;
217 }
218 const LPSTR module_name = (char*)((ULONGLONG)modulePtr + exp->Name);
219 if (is_valid_string(modulePtr, modSize, module_name) && forwarder_name_len((BYTE*)module_name) > 1) {
220 return module_name;
221 }
222 return nullptr;
223}
#define MASK_TO_DWORD(val)
Definition: buffer_util.h:12
virtual FARPROC resolve_func(LPCSTR lib_name, LPCSTR func_name)
virtual HMODULE load_library(LPCSTR lib_name)
virtual FARPROC resolve_func(LPCSTR lib_name, LPCSTR func_name)
#define TO_LOWERCASE(c1)
Searching specific functions in PE's Exports Table.
Compile-time configurable logging macros for peconv.
#define LOG_DEBUG(fmt,...)
Definition: logger.h:80
#define LOG_ERROR(fmt,...)
Definition: logger.h:60
#define LOG_WARNING(fmt,...)
Definition: logger.h:68
bool is_valid_string(LPVOID modulePtr, const size_t moduleSize, const CHAR_T *name_ptr, const size_t max_len=260)
Definition: util.h:61
LPSTR read_dll_name(HMODULE modulePtr)
size_t forwarder_name_len(BYTE *fPtr)
bool validate_ptr(IN const void *buffer_bgn, IN size_t buffer_size, IN const void *field_bgn, IN size_t field_size)
Definition: buffer_util.cpp:9
DWORD get_image_size(IN const BYTE *payload)
FARPROC get_exported_func(LPVOID modulePtr, LPCSTR wanted_name)
bool is_bad_read_ptr(LPCVOID areaStart, SIZE_T areaSize)
Definition: util.cpp:156
size_t get_exported_names(LPVOID modulePtr, std::vector< std::string > &names_list)
IMAGE_EXPORT_DIRECTORY * get_export_directory(IN HMODULE modulePtr)
Miscellaneous utility functions.