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