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 <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(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 //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 DWORD* nameRVAs = (DWORD*)(funcNamesListRVA + (ULONG_PTR)modulePtr);
88 SIZE_T i = 0;
89 for (i = 0; i < namesCount; i++) {
90 DWORD nameRVA = nameRVAs[i];
91 if (!nameRVA) continue;
92 LPSTR name = (LPSTR)(nameRVA + (BYTE*) modulePtr);
93 if (peconv::is_bad_read_ptr(name, 1)) break; // this should not happen. maybe the PE file is corrupt?
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, LPCSTR 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#ifdef _DEBUG
143 std::cerr << "Function not found!" << std::endl;
144#endif
145 return NULL;
146}
147
148FARPROC peconv::export_based_resolver::resolve_func(LPCSTR lib_name, LPCSTR func_name)
149{
150 HMODULE libBasePtr = LoadLibraryA(lib_name);
151 if (libBasePtr == NULL) {
152 std::cerr << "Could not load the library!" << std::endl;
153 return NULL;
154 }
155
156 FARPROC hProc = get_exported_func(libBasePtr, func_name);
157
158 if (hProc == NULL) {
159#ifdef _DEBUG
160 if (!peconv::is_bad_read_ptr(func_name, 1)) {
161 std::cerr << "[!] Cound not get the function: "<< func_name <<" from exports!" << std::endl;
162 } else {
163 std::cerr << "[!] Cound not get the function: "<< MASK_TO_DWORD((ULONG_PTR)func_name) <<" from exports!" << std::endl;
164 }
165 std::cerr << "[!] Falling back to the default resolver..." <<std::endl;
166#endif
167 hProc = default_func_resolver::resolve_func(lib_name, func_name);
168 if (hProc == NULL) {
169 std::cerr << "[-] Loading function from " << lib_name << " failed!" << std::endl;
170 }
171 }
172#ifdef _DEBUG
173 FARPROC defaultProc = default_func_resolver::resolve_func(lib_name, func_name);
174 if (hProc != defaultProc) {
175 std::cerr << "[-] Loaded proc is not matching the default one!" << std::endl;
176 }
177#endif
178 return hProc;
179}
180
181LPSTR peconv::read_dll_name(HMODULE modulePtr)
182{
183 IMAGE_EXPORT_DIRECTORY* exp = get_export_directory(modulePtr);
184 if (exp == NULL) {
185 return NULL;
186 }
187 LPSTR module_name = (char*)((ULONGLONG)modulePtr + exp->Name);
188 if (peconv::is_bad_read_ptr(module_name, 1)) {
189 return NULL;
190 }
191 size_t len = peconv::forwarder_name_len((BYTE*) module_name);
192 if (len > 1) {
193 return module_name;
194 }
195 return NULL;
196}
#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.
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, LPCSTR 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)
Miscellaneous utility functions.