PE-sieve
Scans all running processes. Recognizes and dumps a variety of potentially malicious implants (replaced/implanted PEs, shellcodes, hooks, in-memory patches).
Loading...
Searching...
No Matches
iat_block.cpp
Go to the documentation of this file.
1#include "iat_block.h"
2#include <peconv.h>
3
4namespace pesieve {
5 size_t get_longest_func_name(std::map<ULONGLONG, std::set<peconv::ExportedFunc>> &addrToFunc)
6 {
7 size_t max_len = 0;
8 std::map<ULONGLONG, std::set<peconv::ExportedFunc>>::iterator itr;
9 for (itr = addrToFunc.begin(); itr != addrToFunc.end(); ++itr) {
10 std::set<peconv::ExportedFunc> &expSet = itr->second;
11 const peconv::ExportedFunc& exp = *(expSet.begin());
12 if (exp.isByOrdinal) {
13 continue;
14 }
15 if (exp.funcName.length() > max_len) {
16 max_len = exp.funcName.length();
17 }
18 }
19 return max_len;
20 }
21};
22
23//---
24
25bool pesieve::IATThunksSeries::makeCoverage(IN const peconv::ExportsMapper* exportsMap)
26{
27 delete cov; //delete previous
28 cov = new peconv::ImportedDllCoverage(funcAddresses, *exportsMap);
29 if (!cov->findCoveringDll()) {
30 // DLL not found
31 return false;
32 }
33 size_t covered_count = cov->mapAddressesToFunctions(cov->dllName);
34 this->dllFullName = exportsMap->get_dll_fullname(cov->dllName);
35 this->covered = (covered_count == this->funcAddresses.size());
36 return this->covered;
37}
38
39bool pesieve::IATThunksSeries::fillNamesSpace(const BYTE* buf_start, size_t buf_size, DWORD bufRVA, bool is64b)
40{
41 if (!buf_start || !this->cov) return false;
42
43 if (!this->cov->isMappingComplete()) {
44 return false; //TODO: make a workaround for this case
45 }
46
47 const size_t longest_name = get_longest_func_name(this->cov->addrToFunc);
48 const size_t field_size = is64b ? sizeof(ULONGLONG) : sizeof(DWORD);
49
50 const size_t thunks_count = this->cov->addrToFunc.size();
51 const size_t thunks_area_size = (thunks_count * field_size) + field_size;
52
53 size_t names_rva = bufRVA + thunks_area_size;
54
55 //fill thunks:
56 BYTE *buf = const_cast<BYTE*>(buf_start);
57 const BYTE *buf_end = buf_start + buf_size;
58 std::map<ULONGLONG, std::set<peconv::ExportedFunc>>::iterator itr;
59 for (itr = this->cov->addrToFunc.begin(); itr != cov->addrToFunc.end() && buf < buf_end; ++itr) {
60
61 std::set<peconv::ExportedFunc> &expSet = itr->second;
62 const peconv::ExportedFunc& exp = *(expSet.begin());
63 if (is64b) {
64 ULONGLONG *val = (ULONGLONG*)buf;
65 *val = names_rva;
66 }
67 else {
68 DWORD *val = (DWORD*)buf;
69 *val = MASK_TO_DWORD(names_rva);
70 }
71 //no need to fill names, they will be autofilled during dumping
72 buf += field_size;
73 names_rva += sizeof(IMAGE_IMPORT_BY_NAME) + longest_name;
74 }
75 return true;
76}
77
79{
80 if (!cov) return 0;
81
82 size_t space_size = 0;
83 if (!this->cov->isMappingComplete()) {
84 return 0; //TODO: make a workaround for this case
85 }
86 const size_t longest_name = get_longest_func_name(this->cov->addrToFunc);
87 const size_t field_size = is64b ? sizeof(ULONGLONG) : sizeof(DWORD);
88 std::map<ULONGLONG, std::set<peconv::ExportedFunc>>::iterator itr;
89 for (itr = this->cov->addrToFunc.begin(); itr != cov->addrToFunc.end(); ++itr) {
90 std::set<peconv::ExportedFunc> &expSet = itr->second;
91 const peconv::ExportedFunc& exp = *(expSet.begin());
92 space_size += field_size;
93 space_size += sizeof(IMAGE_IMPORT_BY_NAME) + longest_name;
94 }
95 if (space_size > 0) {
96 space_size += sizeof(field_size);
97 }
98 return space_size;
99}
100
102{
103 return this->dllFullName;
104}
105
106//---
107
108bool pesieve::IATBlock::makeCoverage(IN const peconv::ExportsMapper* exportsMap)
109{
110 if (!exportsMap) return false;
111
112 IATThunksSeriesSet::iterator itr;
113 std::set<IATThunksSeries*>to_split;
114
115 for (itr = this->thunkSeries.begin(); itr != thunkSeries.end(); ++itr) {
116 IATThunksSeries* series = *itr;
117 if (!series->makeCoverage(exportsMap)) {
118 to_split.insert(series);
119 }
120 }
121
122 std::set<IATThunksSeries*>::iterator sItr;
123 for (sItr = to_split.begin(); sItr != to_split.end(); ++sItr) {
124 IATThunksSeries *series = *sItr;
125 IATThunksSeriesSet splitted = splitSeries(series, *exportsMap);
126 if (!splitted.size()) {
127 continue;
128 }
129#ifdef _DEBUG
130 std::cout << "Uncovered series splitted into: " << splitted.size() << " series\n";
131#endif
132 this->thunkSeries.erase(series);
133 this->thunkSeries.insert(splitted.begin(), splitted.end());
134
135 delete series; // delete the series that have been splitted
136 }
137
138 size_t covered_count = 0;
139 for (itr = this->thunkSeries.begin(); itr != thunkSeries.end(); ++itr) {
140 IATThunksSeries* series = *itr;
141
142 if (series->isCovered() || series ->makeCoverage(exportsMap)) {
143 covered_count++;
144 }
145 }
146
147 isCoverageComplete = (covered_count == this->thunkSeries.size());
148 return isCoverageComplete;
149}
150
151pesieve::IATThunksSeriesSet pesieve::IATBlock::splitSeries(IN IATThunksSeries* series, IN const peconv::ExportsMapper &exportsMap)
152{
153 IATThunksSeriesSet splitted;
154 if (!series) return splitted;
155
156 std::map<DWORD, ULONGLONG> addresses = series->getRvaToFuncMap();
157
158 IATThunksSeries *new_series = nullptr;
159 std::map<DWORD, ULONGLONG>::iterator itr;
160 std::string last_dll = "";
161
162 for (itr = addresses.begin(); itr != addresses.end(); ++itr) {
163 ULONGLONG func_addr = itr->second;
164 DWORD offset = itr->first;
165 const peconv::ExportedFunc *func = exportsMap.find_export_by_va(func_addr);
166 if (new_series && (!func || func->libName != last_dll)) {
167 //close series
168 splitted.insert(new_series);
169 new_series = nullptr;
170 last_dll = "";
171 }
172 if (!func) continue;
173
174 if (!new_series) {
175 new_series = new IATThunksSeries(offset);
176 last_dll = func->libName;
177#ifdef _DEBUG
178 std::cout << std::hex << "addr: " << offset << " set DLL: " << last_dll << "\n";
179#endif
180 }
181 new_series->insert(offset, func_addr);
182 }
183 if (new_series) {
184 splitted.insert(new_series);
185 }
186 return splitted;
187}
188
190{
191 size_t max_size = 0;
192 IATThunksSeriesSet::iterator itr;
193 for (itr = this->thunkSeries.begin(); itr != thunkSeries.end(); ++itr) {
194 IATThunksSeries* series = *itr;
195 size_t curr_size = series->getDllName().length() + 1;
196 if (curr_size > max_size) max_size = curr_size;
197 }
198 return max_size;
199}
200
202{
203 const size_t max_len = maxDllLen();
204 return max_len * (thunkSeries.size() + 1);
205}
206
208{
209 std::stringstream stream;
210 stream << "---\nIAT at: " << std::hex << iatOffset << ", size: " << iatSize << ", thunks: "
211 << countThunks() << ", is_terminated: " << isTerminated << ", in_main: " << isInMain << "\n";
212
213 if (this->importTableOffset) {
214 stream << "ImportTable: " << std::hex << importTableOffset << "\n";
215 }
216 stream << "---\n";
217 std::map<ULONGLONG, const peconv::ExportedFunc*>::const_iterator itr;
218 for (itr = functions.begin(); itr != functions.end(); ++itr) {
219 ULONGLONG offset = itr->first;
220 const peconv::ExportedFunc* exp = itr->second;
221
222 stream << std::hex << offset << "," << addrToFunctionVA[offset] << "," << exp->toString() << "\n";
223 }
224 return stream.str();
225}
std::string toString()
size_t sizeOfDllsSpace()
bool makeCoverage(IN const peconv::ExportsMapper *exportsMap)
IATThunksSeriesSet splitSeries(IN IATThunksSeries *notCoveredSeries, IN const peconv::ExportsMapper &exportsMap)
bool makeCoverage(IN const peconv::ExportsMapper *exportsMap)
Definition iat_block.cpp:25
bool insert(DWORD rva, ULONGLONG funcAddr)
Definition iat_block.h:29
size_t sizeOfNamesSpace(bool is64b)
Definition iat_block.cpp:78
bool fillNamesSpace(const BYTE *buf_start, size_t buf_size, DWORD bufRVA, bool is64b)
Definition iat_block.cpp:39
std::map< DWORD, ULONGLONG > getRvaToFuncMap()
Definition iat_block.h:51
#define MASK_TO_DWORD(val)
Definition iat_finder.h:9
size_t get_longest_func_name(std::map< ULONGLONG, std::set< peconv::ExportedFunc > > &addrToFunc)
Definition iat_block.cpp:5
std::set< IATThunksSeries *, IATThunksSeriesPtrCompare > IATThunksSeriesSet
Definition iat_block.h:76