cobf
PE imports obfuscator
load.cpp
Go to the documentation of this file.
1 
9 #ifndef LOAD_CPP
10 #define LOAD_CPP
11 
12  // The includes.
13 #include <cobf.hpp>
14 #include <time.h>
15 
16 // Load the specified PE from disk.
18 {
19  // Check if already loaded.
20  if (!this->pe_rawf.empty()) return cobf_error::COBF_PE_LOADED;
21 
22  // Get an access to the file.
23  cobf_error ret_err = cobf_error::COBF_NO_ERROR;
24  HANDLE h_file = CreateFileA(
25  this->pe_path.c_str(), // The PE file path.
26  GENERIC_READ, // Access options.
27  FILE_SHARE_READ, // The share mode.
28  NULL, // Security attributes.
29  OPEN_EXISTING, // Disposition.
30  FILE_ATTRIBUTE_NORMAL, // File attributes.
31  NULL // The template handle.
32  );
33 
34  // Check the return.
35  if (h_file == INVALID_HANDLE_VALUE)
36  {
37  // Cannot open the specified file.
38  return cobf_error::COBF_CANNOT_OPEN_FILE;
39  };
40 
41  // Needed local variables.
42  PIMAGE_DOS_HEADER dos_hdr;
43  PIMAGE_NT_HEADERS nt_hdrs;
44  PIMAGE_IMPORT_DESCRIPTOR p_imports;
45  size_t imports_size;
46 
47  // Getting the size.
48  LARGE_INTEGER f_size;
49  if (!GetFileSizeEx(h_file, &f_size))
50  {
51  // Cannot get the file size.
52  ret_err = cobf_error::COBF_CANNOT_GET_SIZE;
53  goto LOAD_FINISH;
54  };
55 
56  // Resizing the raw file array.
57  this->pe_rawf.resize((size_t)f_size.QuadPart);
58 
59  // Reading the file.
60  DWORD r_size;
61  if (!ReadFile(
62  h_file, // The PE file handle.
63  this->pe_rawf.data(), // The data of the vector.
64  (DWORD)this->pe_rawf.size(),// Size to read.
65  &r_size, // Read bytes.
66  NULL // Overlapped struct.
67  ))
68  {
69  // Cannot read.
70  ret_err = cobf_error::COBF_CANNOT_READ_FILE;
71  goto LOAD_FINISH;
72  };
73 
74  // Get the dos header.
75  if (!this->get_dos_header(dos_hdr))
76  {
77  // Invalid dos header.
78  ret_err = cobf_error::COBF_INVALID_DOS_HDR;
79  goto LOAD_FINISH;
80  };
81 
82  // Get the dos header.
83  if (!this->get_nt_headers(dos_hdr, nt_hdrs))
84  {
85  // Invalid dos header.
86  ret_err = cobf_error::COBF_INVALID_NT_HDRS;
87  goto LOAD_FINISH;
88  };
89 
90  // Verify the arch.
91  if (!this->verify_machine(nt_hdrs))
92  {
93  // Invalid dos header.
94  ret_err = cobf_error::COBF_UNSUPPORTED_PE;
95  goto LOAD_FINISH;
96  };
97 
98  // Verify the sections.
99  if (!this->verify_sections(dos_hdr, nt_hdrs))
100  {
101  // Invalid sections header.
102  ret_err = cobf_error::COBF_INVALID_SECTION_HDR;
103  goto LOAD_FINISH;
104  };
105 
106  // Get the imports directory.
107  if (!this->get_data_table(IMAGE_DIRECTORY_ENTRY_IMPORT, (PVOID*)&p_imports, imports_size))
108  {
109  // Invalid imports directory.
110  ret_err = cobf_error::COBF_INVALID_IMPORTS_DIR;
111  goto LOAD_FINISH;
112  };
113 
114  // Getting the import directory.
115  if (p_imports && !this->parse_imports(p_imports, imports_size))
116  {
117  // Invalid imports.
118  ret_err = cobf_error::COBF_CANNOT_PARSE_IMPORTS;
119  goto LOAD_FINISH;
120  };
121 
122 LOAD_FINISH:
123 
124  // Clearing.
125  if (ret_err != cobf_error::COBF_NO_ERROR)
126  {
127  // Removing the symbols and the loaded module.
128  this->pe_rawf.clear();
129  this->pe_mods.clear();
130  };
131 
132  // Closing the handle.
133  if (!CloseHandle(h_file)) return cobf_error::COBF_CANNOT_CLEAR;
134  return ret_err;
135 };
136 
137 // Unload the specified PE from memory.
139 {
140  // Check if already unloaded.
141  if (this->pe_rawf.empty()) return cobf_error::COBF_PE_UNLOADED;
142 
143  // Clear everything.
144  this->pe_rawf.clear();
145  this->pe_mods.clear();
146  return cobf_error::COBF_NO_ERROR;
147 };
148 
149 // Get the attributes for the a data table.
150 BOOL cobf::get_data_table(size_t data_entry, PVOID* p_table_ptr, size_t& table_size)
151 {
152  // Get the headers.
153  PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER)this->pe_rawf.data();
154  PIMAGE_NT_HEADERS nt_hdrs = (PIMAGE_NT_HEADERS)&this->pe_rawf[dos_hdr->e_lfanew];
155 
156  // Check if the index is valid.
157  if (data_entry >= nt_hdrs->OptionalHeader.NumberOfRvaAndSizes) return FALSE;
158 
159  // Check the table itself.
160  DWORD table_rva = nt_hdrs->OptionalHeader.DataDirectory[data_entry].VirtualAddress;
161  table_size = nt_hdrs->OptionalHeader.DataDirectory[data_entry].Size;
162 
163  // Check if zero.
164  if (!table_rva)
165  {
166  // Zero both of them.
167  *p_table_ptr = NULL;
168  table_size = 0;
169  return TRUE;
170  };
171 
172  // Convert it to offset.
173  DWORD table_offset;
174  if (!this->rva_to_offset(table_rva, table_offset)) return FALSE;
175  if (table_offset + table_size > this->pe_rawf.size()) return FALSE;
176 
177  // Fill the pointer.
178  *p_table_ptr = (PVOID)&this->pe_rawf[table_offset];
179  return TRUE;
180 };
181 
182 // Get the section of some rva.
183 BOOL cobf::section_of_rva(DWORD rva, PIMAGE_SECTION_HEADER& sec)
184 {
185  // Get the sections.
186  PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER)this->pe_rawf.data();
187  PIMAGE_NT_HEADERS nt_hdrs = (PIMAGE_NT_HEADERS)&this->pe_rawf[dos_hdr->e_lfanew];
188  PIMAGE_SECTION_HEADER c_sec = (PIMAGE_SECTION_HEADER)&this->pe_rawf[dos_hdr->e_lfanew +
189  sizeof(nt_hdrs->Signature) + sizeof(nt_hdrs->FileHeader) +
190  nt_hdrs->FileHeader.SizeOfOptionalHeader];
191 
192  // Loop on the sections.
193  WORD n_secs = nt_hdrs->FileHeader.NumberOfSections;
194  while (n_secs--)
195  {
196  // Check if not contained.
197  if (rva < (size_t)c_sec->VirtualAddress || rva >= (size_t)c_sec->VirtualAddress +
198  c_sec->Misc.VirtualSize)
199  {
200  // Move to the next one.
201  c_sec++;
202  continue;
203  };
204 
205  // Found.
206  sec = c_sec;
207  return TRUE;
208  };
209 
210  // Not found.
211  return FALSE;
212 };
213 
214 // Verify and get the dos header.
215 BOOL cobf::get_dos_header(PIMAGE_DOS_HEADER& dos_hdr)
216 {
217  // Verifing the dos header.
218  dos_hdr = (PIMAGE_DOS_HEADER)this->pe_rawf.data();
219  if (sizeof(*dos_hdr) > this->pe_rawf.size() ||
220  dos_hdr->e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
221  return TRUE;
222 };
223 
224 // Verify and get the nt headers.
225 BOOL cobf::get_nt_headers(PIMAGE_DOS_HEADER dos_hdr, PIMAGE_NT_HEADERS& nt_hdrs)
226 {
227  // Verifing the nt headers.
228  nt_hdrs = (PIMAGE_NT_HEADERS)&this->pe_rawf[dos_hdr->e_lfanew];
229  if (sizeof(*nt_hdrs) + dos_hdr->e_lfanew > this->pe_rawf.size() ||
230  nt_hdrs->Signature != IMAGE_NT_SIGNATURE) return FALSE;
231  return TRUE;
232 };
233 
234 // Verify the archeticture.
235 BOOL cobf::verify_machine(PIMAGE_NT_HEADERS nt_hdrs)
236 {
237  // Verify the machine.
238 #ifdef _M_IX86
239  return nt_hdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_I386;
240 #else
241  return nt_hdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64 ||
242  nt_hdrs->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64;
243 #endif
244 };
245 
246 // Verify the sections.
247 BOOL cobf::verify_sections(PIMAGE_DOS_HEADER dos_hdr, PIMAGE_NT_HEADERS nt_hdrs)
248 {
249  // Verify the sections header.
250  return dos_hdr->e_lfanew + sizeof(*nt_hdrs) + nt_hdrs->FileHeader.NumberOfSections
251  * sizeof(IMAGE_SECTION_HEADER) <= this->pe_rawf.size() &&
252  nt_hdrs->FileHeader.NumberOfSections;
253 };
254 
255 // Parse the imported symbols.
256 BOOL cobf::parse_imports(PIMAGE_IMPORT_DESCRIPTOR p_imports, size_t imports_size)
257 {
258  // Filling up the imported modules array.
259  while (imports_size >= sizeof(IMAGE_IMPORT_DESCRIPTOR) && p_imports->Name)
260  {
261  // Getting the thunk array offset.
262  DWORD dll_name = p_imports->Name;
263  DWORD orig_th = p_imports->OriginalFirstThunk;
264  DWORD first_th = p_imports->FirstThunk;
265  PSIZE_T p_orig_th, p_first_th;
266  PCHAR p_dll_name; size_t sym_idx = 0;
267 
268  // Convert the pointers.
269  if ((orig_th && !this->rva_to_ptr(orig_th, (PVOID*)&p_orig_th))
270  || !this->rva_to_ptr(first_th, (PVOID*)&p_first_th)
271  || !this->rva_to_ptr(dll_name, (PVOID*)&p_dll_name))
272  {
273  // Cannot get the thunks or the name.
274  return FALSE;
275  };
276 
277  // Get the dll name.
278  this->pe_mods.push_back({ p_dll_name });
279  auto& dll_mod = this->pe_mods.back();
280  transform(dll_mod.dll_name.begin(), dll_mod.dll_name.end(),
281  dll_mod.dll_name.begin(), ::toupper);
282 
283  // Loop the imports.
284  PSIZE_T p_thunk = orig_th ? p_orig_th : p_first_th;
285  while (*p_thunk)
286  {
287  // Needed attributes.
288  DWORD fth_rva = first_th + (DWORD)sym_idx * sizeof(size_t);
289  DWORD oth_off = (DWORD)((PBYTE)p_thunk - this->pe_rawf.data());
290 
291  // Try to insert it.
292  if (!this->insert_import(this->pe_mods.back(), dll_name, *p_thunk, fth_rva, oth_off))
293  return FALSE;
294 
295  // Calculate the next one.
296  p_thunk++;
297  sym_idx++;
298  };
299 
300  // Move to the next module.
301  imports_size -= sizeof(IMAGE_IMPORT_DESCRIPTOR);
302  p_imports++;
303  };
304 
305  // Done.
306  return TRUE;
307 };
308 
309 // Insert a parsed import.
310 BOOL cobf::insert_import(cmod& dll_mod, DWORD dll_off, size_t th_sym, DWORD fth_rva, DWORD oth_off)
311 {
312  // Check if imported by ordinal.
313  if (IMAGE_SNAP_BY_ORDINAL(th_sym))
314  {
315  // Inserting the import.
316  dll_mod.mod_syms.push_back(csym(IMAGE_ORDINAL(th_sym), dll_off, fth_rva, oth_off));
317  return TRUE;
318  };
319 
320  // Imported by name.
321  PCHAR p_name;
322  if (!this->rva_to_ptr((DWORD)th_sym, (PVOID*)&p_name))
323  {
324  // Invalid rva.
325  return FALSE;
326  };
327 
328  // Inserting the import.
329  p_name += sizeof(IMAGE_IMPORT_BY_NAME::Hint);
330 
331  // Inserting the import.
332  dll_mod.mod_syms.push_back(csym(p_name, dll_off, fth_rva, oth_off,
333  (DWORD)((PBYTE)p_name - this->pe_rawf.data())));
334  return TRUE;
335 };
336 
337 // Convert RVA to pointer after checking it.
338 BOOL cobf::rva_to_ptr(DWORD ptr_rva, PVOID* p_ptr)
339 {
340  if (!this->rva_to_offset(ptr_rva, ptr_rva) ||
341  ptr_rva >= this->pe_rawf.size()) return FALSE;
342  *p_ptr = (PVOID)&this->pe_rawf[ptr_rva];
343  return TRUE;
344 };
345 
346 // Convert RVA to offset.
347 BOOL cobf::rva_to_offset(DWORD rva, DWORD& offset)
348 {
349  // Get the section.
350  PIMAGE_SECTION_HEADER sec;
351  if (this->section_of_rva(rva, sec))
352  {
353  // Convert.
354  offset = sec->PointerToRawData + (rva - sec->VirtualAddress);
355  return TRUE;
356  };
357 
358  // Not Converted.
359  return FALSE;
360 };
361 
362 // Constructor for the obfuscation module.
363 cobf::cobf(string pe_path) : pe_path(pe_path)
364 {
365  // Seed.
366  srand((DWORD)time(NULL));
367 };
368 
369 #endif // !LOAD_CPP.
cobf::unload_pe
cobf_error unload_pe()
Unload the specified PE from memory.
Definition: load.cpp:138
cobf::load_pe
cobf_error load_pe()
Load the specified PE from disk.
Definition: load.cpp:17
cobf::cobf
cobf(string pe_path)
Constructor for the obfuscation module.
Definition: load.cpp:363
cobf.hpp
cobf_error
cobf_error
Definition: utils.hpp:15