libPeConv
A library to load, manipulate, dump PE files.
exports_lookup.cpp
Go to the documentation of this file.
2#include "peconv/util.h"
3
4#include <iostream>
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(LPSTR curr_name, LPSTR 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, LPSTR 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 //go through names:
63 for (DWORD i = 0; i < functCount; i++) {
64 DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
65 BYTE* fPtr = (BYTE*) modulePtr + (*funcRVA); //pointer to the function
66 DWORD ordinal = ordBase + i;
67 if (ordinal == wanted_ordinal) {
68 if (peconv::forwarder_name_len(fPtr) > 1) {
69 std::cerr << "[!] Forwarded function: ["<< wanted_ordinal << " -> "<< fPtr << "] cannot be resolved!" << std::endl;
70 return NULL; // this function is forwarded, cannot be resolved
71 }
72 return (FARPROC) fPtr; //return the pointer to the found function
73 }
74 }
75 return NULL;
76}
77
78size_t peconv::get_exported_names(PVOID modulePtr, std::vector<std::string> &names_list)
79{
80 IMAGE_EXPORT_DIRECTORY* exp = peconv::get_export_directory((HMODULE) modulePtr);
81 if (exp == 0) return 0;
82
83 SIZE_T namesCount = exp->NumberOfNames;
84 DWORD funcNamesListRVA = exp->AddressOfNames;
85
86 //go through names:
87 SIZE_T i = 0;
88 for (i = 0; i < namesCount; i++) {
89 DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
90
91 LPSTR name = (LPSTR)(*nameRVA + (BYTE*) modulePtr);
92 if (peconv::is_bad_read_ptr(name, 1)) break; // this shoudld not happen. maybe the PE file is corrupt?
93
94 names_list.push_back(name);
95 }
96 return i;
97}
98
99//WARNING: doesn't work for the forwarded functions.
100FARPROC peconv::get_exported_func(PVOID modulePtr, LPSTR wanted_name)
101{
102 IMAGE_EXPORT_DIRECTORY* exp = peconv::get_export_directory((HMODULE) modulePtr);
103 if (exp == NULL) return NULL;
104
105 SIZE_T namesCount = exp->NumberOfNames;
106
107 DWORD funcsListRVA = exp->AddressOfFunctions;
108 DWORD funcNamesListRVA = exp->AddressOfNames;
109 DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals;
110
111 if (is_ordinal(exp, wanted_name)) {
112#ifdef _DEBUG
113 std::cerr << "[*] Getting function by ordinal" << std::endl;
114#endif
115 const DWORD ordinal = MASK_TO_DWORD((ULONG_PTR)wanted_name);
116 return get_export_by_ord(modulePtr, exp, ordinal);
117 }
118 if (peconv::is_bad_read_ptr(wanted_name, 1)) {
119 std::cerr << "[-] Invalid pointer to the name" << std::endl;
120 return NULL;
121 }
122
123 //go through names:
124 for (SIZE_T i = 0; i < namesCount; i++) {
125 DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
126 WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*) modulePtr + i * sizeof(WORD));
127 DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + (*nameIndex) * sizeof(DWORD));
128
129 LPSTR name = (LPSTR)(*nameRVA + (BYTE*) modulePtr);
130 BYTE* fPtr = (BYTE*) modulePtr + (*funcRVA); //pointer to the function
131
132 if (!is_wanted_func(name, wanted_name)) {
133 continue; //this is not the function we are looking for
134 }
135 if (forwarder_name_len(fPtr) > 1) {
136 std::cerr << "[!] Forwarded function: ["<< name << " -> "<< fPtr << "] cannot be resolved!" << std::endl;
137 return NULL; // this function is forwarded, cannot be resolved
138 }
139 return (FARPROC) fPtr; //return the pointer to the found function
140 }
141 //function not found
142 std::cerr << "Function not found!" << std::endl;
143 return NULL;
144}
145
146FARPROC peconv::export_based_resolver::resolve_func(LPSTR lib_name, LPSTR func_name)
147{
148 HMODULE libBasePtr = LoadLibraryA(lib_name);
149 if (libBasePtr == NULL) {
150 std::cerr << "Could not load the library!" << std::endl;
151 return NULL;
152 }
153
154 FARPROC hProc = get_exported_func(libBasePtr, func_name);
155
156 if (hProc == NULL) {
157#ifdef _DEBUG
158 if (!peconv::is_bad_read_ptr(func_name, 1)) {
159 std::cerr << "[!] Cound not get the function: "<< func_name <<" from exports!" << std::endl;
160 } else {
161 std::cerr << "[!] Cound not get the function: "<< MASK_TO_DWORD((ULONG_PTR)func_name) <<" from exports!" << std::endl;
162 }
163 std::cerr << "[!] Falling back to the default resolver..." <<std::endl;
164#endif
165 hProc = default_func_resolver::resolve_func(lib_name, func_name);
166 if (hProc == NULL) {
167 std::cerr << "[-] Loading function from " << lib_name << " failed!" << std::endl;
168 }
169 }
170#ifdef _DEBUG
171 FARPROC defaultProc = default_func_resolver::resolve_func(lib_name, func_name);
172 if (hProc != defaultProc) {
173 std::cerr << "[-] Loaded proc is not matching the default one!" << std::endl;
174 }
175#endif
176 return hProc;
177}
178
179LPSTR peconv::read_dll_name(HMODULE modulePtr)
180{
181 IMAGE_EXPORT_DIRECTORY* exp = get_export_directory(modulePtr);
182 if (exp == NULL) {
183 return NULL;
184 }
185 LPSTR module_name = (char*)((ULONGLONG)modulePtr + exp->Name);
186 if (peconv::is_bad_read_ptr(module_name, 1)) {
187 return NULL;
188 }
189 size_t len = peconv::forwarder_name_len((BYTE*) module_name);
190 if (len > 1) {
191 return module_name;
192 }
193 return NULL;
194}
virtual FARPROC resolve_func(LPSTR lib_name, LPSTR func_name)
virtual FARPROC resolve_func(LPSTR lib_name, LPSTR func_name)
bool is_wanted_func(LPSTR curr_name, LPSTR wanted_name)
FARPROC get_export_by_ord(PVOID modulePtr, IMAGE_EXPORT_DIRECTORY *exp, DWORD wanted_ordinal)
bool is_ordinal(IMAGE_EXPORT_DIRECTORY *exp, LPSTR func_name)
#define TO_LOWERCASE(c1)
Searching specific functions in PE's Exports Table.
LPSTR read_dll_name(HMODULE modulePtr)
size_t forwarder_name_len(BYTE *fPtr)
size_t get_exported_names(PVOID modulePtr, std::vector< std::string > &names_list)
FARPROC get_exported_func(PVOID modulePtr, LPSTR wanted_name)
bool is_bad_read_ptr(LPCVOID areaStart, SIZE_T areaSize)
Definition: util.cpp:150
IMAGE_EXPORT_DIRECTORY * get_export_directory(IN HMODULE modulePtr)
#define MASK_TO_DWORD(val)
Miscellaneous utility functions.