cobf
PE imports obfuscator
obfuscate.cpp
Go to the documentation of this file.
1 
8 #ifndef OBFUSCATE_CPP
9 #define OBFUSCATE_CPP
10 
11  // The includes.
12 #include <cobf.hpp>
13 
14 // Obfuscate one symbol with another.
15 template <typename t_sym_info, typename t_obf_info>
16 cobf_error cobf::obf_sym_internal(string dll_name, t_sym_info sym_info, t_obf_info obf_info)
17 {
18  // Convert the name.
19  transform(dll_name.begin(), dll_name.end(), dll_name.begin(), ::toupper);
20 
21  // Find the symbol.
22  vector<csym*> symbols;
23  this->find_symbols(dll_name, sym_info, symbols);
24  if (symbols.empty()) return cobf_error::COBF_SYMS_NOT_FOUND;
25 
26  // Obfuscate it.
27  for (auto& symbol : symbols) symbol->obfuscate(obf_info);
28  return cobf_error::COBF_NO_ERROR;
29 };
30 
31 // Obfuscate one symbol (name) with another (name).
32 cobf_error cobf::obf_sym(string dll_name, string sym_name, string obf_name) {
33  return this->obf_sym_internal(dll_name, sym_name, obf_name);
34 };
35 
36 // Obfuscate one symbol (name) with another (ordinal).
37 cobf_error cobf::obf_sym(string dll_name, string sym_name, WORD obf_ord) {
38  return this->obf_sym_internal(dll_name, sym_name, obf_ord);
39 };
40 
41 // Obfuscate one symbol (ordinal) with another (ordinal).
42 cobf_error cobf::obf_sym(string dll_name, WORD sym_ord, WORD obf_ord) {
43  return this->obf_sym_internal(dll_name, sym_ord, obf_ord);
44 };
45 
46 // Obfuscate one symbol (ordinal) with another (name).
47 cobf_error cobf::obf_sym(string dll_name, WORD sym_ord, string obf_name) {
48  return this->obf_sym_internal(dll_name, sym_ord, obf_name);
49 };
50 
51 template <typename t_sym_info>
52 cobf_error cobf::unobf_sym_internal(string dll_name, t_sym_info sym_info)
53 {
54  // Convert the name.
55  transform(dll_name.begin(), dll_name.end(), dll_name.begin(), ::toupper);
56 
57  // Find the symbol.
58  vector<csym*> symbols;
59  this->find_symbols(dll_name, sym_info, symbols);
60  if (symbols.empty()) return cobf_error::COBF_SYMS_NOT_FOUND;
61 
62  // Unobfuscate it.
63  for (auto& symbol : symbols) symbol->unobfuscate();
64  return cobf_error::COBF_NO_ERROR;
65 };
66 
67 // Unobfuscate one symbol (name).
68 cobf_error cobf::unobf_sym(string dll_name, string sym_name) {
69  return this->unobf_sym_internal(dll_name, sym_name);
70 };
71 
72 // Unobfuscate one symbol (ordinal).
73 cobf_error cobf::unobf_sym(string dll_name, WORD sym_ord) {
74  return this->unobf_sym_internal(dll_name, sym_ord);
75 };
76 
77 // Generate the obfuscated PE.
78 cobf_error cobf::generate(string out_file)
79 {
80  // Check if not loaded and getting a copy of the original PE.
81  if (this->pe_rawf.empty()) return cobf_error::COBF_PE_UNLOADED;
82 
83  // Needed locals.
84  cobf_error ret_err = cobf_error::COBF_NO_ERROR;
85  PIMAGE_SECTION_HEADER sh_sec;
86  DWORD stub_entry;
87  DWORD funs_table;
88  DWORD symbols;
89  DWORD written;
90 
91  // Open the file.
92  HANDLE h_file = CreateFileA(
93  out_file.c_str(), // The PE file path.
94  GENERIC_WRITE, // Access options.
95  FILE_SHARE_WRITE, // The share mode.
96  NULL, // Security attributes.
97  CREATE_ALWAYS, // Disposition.
98  FILE_ATTRIBUTE_NORMAL, // File attributes.
99  NULL // The template handle.
100  );
101 
102  // Check the return.
103  if (h_file == INVALID_HANDLE_VALUE)
104  {
105  // Cannot create the specified file.
106  return cobf_error::COBF_CANNOT_CREATE_FILE;
107  };
108 
109  // Save the original copy.
110  auto orig_pe = this->pe_rawf;
111 
112  // Creating the shellcode section.
113  if (!this->create_shellcode_section(sh_sec, funs_table))
114  {
115  // Cannot create the section.
116  ret_err = cobf_error::COBF_CANNOT_CREATE_SECTION;
117  goto OBFUSCATE_FINISH;
118  };
119 
120  // Applying the obfuscations.
121  this->apply_obfuscations(sh_sec, symbols);
122 
123  // Adding the stub for the shellcode.
124  this->add_shellcode_stub(sh_sec, funs_table, symbols, stub_entry);
125 
126  // Add the shellcode entry as a tls callback.
127  if (!this->add_shellcode_entry(sh_sec, stub_entry))
128  {
129  // Cannot do it.
130  ret_err = cobf_error::COBF_CANNOT_ADD_ENTRY;
131  goto OBFUSCATE_FINISH;
132  };
133 
134  // Make it unrelocatable.
135  if (!this->disable_the_relocation())
136  {
137  // Cannot create the section.
138  ret_err = cobf_error::COBF_CANNOT_DISABLE_RELOCS;
139  goto OBFUSCATE_FINISH;
140  };
141 
142  // Make the imports writible.
143  if (!this->make_the_iat_writable())
144  {
145  // Cannot create the section.
146  ret_err = cobf_error::COBF_INVALID_IAT_SECTION;
147  goto OBFUSCATE_FINISH;
148  };
149 
150  // Remove the debug symbols.
151  if (!this->remove_debug_symbols())
152  {
153  // Cannot remove the debug symbols.
154  ret_err = cobf_error::COBF_CANNOT_REMOVE_DBG_SYMS;
155  goto OBFUSCATE_FINISH;
156  };
157 
158  // Finish everything.
159  this->finalize_pe(sh_sec);
160 
161  // Write the PE.
162  if (!WriteFile(
163  h_file, // The PE file handle.
164  this->pe_rawf.data(), // The data of the vector.
165  (DWORD)this->pe_rawf.size(), // Size to read.
166  &written, // Read bytes.
167  NULL // Overlapped struct.
168  ))
169  {
170  // Cannot write.
171  ret_err = cobf_error::COBF_CANNOT_WRITE_FILE;
172  goto OBFUSCATE_FINISH;
173  };
174 
175 OBFUSCATE_FINISH:
176 
177  // Restore the PE.
178  this->pe_rawf = orig_pe;
179 
180  // Test if not successful.
181  if (!CloseHandle(h_file) || (ret_err != cobf_error::COBF_NO_ERROR && !DeleteFileA(out_file.c_str())))
182  ret_err = cobf_error::COBF_CANNOT_CLEAR;
183  return ret_err;
184 };
185 
186 // Find a symbol by dll and info.
187 template <typename t_sym_info>
188 VOID cobf::find_symbols(string dll_name, t_sym_info sym_info, vector<csym*>& p_syms)
189 {
190  // Loop the symbols.
191  for (auto& mod : this->pe_mods)
192  {
193  // Check the module and the symbol.
194  if (!csym::match_wildcard(dll_name.c_str(), mod.dll_name.c_str())) continue;
195  for (auto& sym : mod.mod_syms) if (sym.check_sym(sym_info))
196  p_syms.push_back(&sym);
197  };
198 };
199 
200 // Create a new entry at the sections header.
201 BOOL cobf::create_shellcode_section(PIMAGE_SECTION_HEADER& sh_sec, DWORD& funs_rva)
202 {
203  // Get the sections.
204  PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER)this->pe_rawf.data();
205  PIMAGE_NT_HEADERS nt_hdrs = (PIMAGE_NT_HEADERS)&this->pe_rawf.data()[dos_hdr->e_lfanew];
206 
207  // Verify the existence of a new section.
208  if (nt_hdrs->OptionalHeader.SizeOfHeaders < dos_hdr->e_lfanew + sizeof(nt_hdrs->Signature) +
209  sizeof(nt_hdrs->FileHeader) + nt_hdrs->FileHeader.SizeOfOptionalHeader +
210  ((size_t)nt_hdrs->FileHeader.NumberOfSections + 1) * sizeof(IMAGE_SECTION_HEADER))
211  return FALSE;
212 
213  // Get the section of the shellcode.
214  sh_sec = (PIMAGE_SECTION_HEADER)&this->pe_rawf[dos_hdr->e_lfanew +
215  sizeof(nt_hdrs->Signature) + sizeof(nt_hdrs->FileHeader) +
216  nt_hdrs->FileHeader.SizeOfOptionalHeader + nt_hdrs->FileHeader.NumberOfSections *
217  sizeof(IMAGE_SECTION_HEADER)];
218 
219  // Set the shellcode section properties.
220  PIMAGE_SECTION_HEADER prev_sec = sh_sec - 1;
221  sh_sec->Name[0] = '.'; sh_sec->Name[1] = 'c';
222  sh_sec->Name[2] = 'o'; sh_sec->Name[3] = 'b';
223  sh_sec->Name[4] = 'f'; sh_sec->Name[5] = '\0';
224  sh_sec->Name[6] = '\0'; sh_sec->Name[7] = '\0';
225  sh_sec->NumberOfLinenumbers = 0;
226  sh_sec->NumberOfRelocations = 0;
227  sh_sec->PointerToRelocations = 0;
228  sh_sec->PointerToLinenumbers = 0;
229  sh_sec->Misc.VirtualSize = 0;
230  sh_sec->SizeOfRawData = shellcode::shellcode_size + sizeof(shellcode::shellcodes_funs);
231  sh_sec->PointerToRawData = prev_sec->PointerToRawData + prev_sec->SizeOfRawData;
232  sh_sec->VirtualAddress = prev_sec->VirtualAddress + prev_sec->Misc.VirtualSize +
233  nt_hdrs->OptionalHeader.SectionAlignment - (prev_sec->Misc.VirtualSize %
234  nt_hdrs->OptionalHeader.SectionAlignment);
235  sh_sec->Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
236  nt_hdrs->FileHeader.NumberOfSections++;
237 
238  // Set the section info.
239  DWORD sh_sec_offset = (DWORD)((PBYTE)sh_sec - this->pe_rawf.data());
240 
241  // Resize the whole pe.
242  this->pe_rawf.resize(this->pe_rawf.size() + sh_sec->SizeOfRawData +
244  sh_sec = (PIMAGE_SECTION_HEADER)(this->pe_rawf.data() + sh_sec_offset);
245  funs_rva = sh_sec->VirtualAddress + shellcode::shellcode_size;
246 
247  // Copy the shellcode and the table.
248  memcpy_s(this->pe_rawf.data() + sh_sec->PointerToRawData, sh_sec->SizeOfRawData,
250  memcpy_s(this->pe_rawf.data() + sh_sec->PointerToRawData + shellcode::shellcode_size,
253 
254  // Updating the functions offsets.
255  PDWORD p_sh_funs = (PDWORD)(this->pe_rawf.data() + sh_sec->PointerToRawData + shellcode::shellcode_size);
256  for (size_t idx = 0; idx < sizeof(shellcode::shellcodes_funs) / sizeof(*shellcode::shellcodes_funs); idx++)
257  {
258  // Update the offset.
259  p_sh_funs[idx] += sh_sec->VirtualAddress;
260  };
261 
262  // Done.
263  return TRUE;
264 };
265 
266 // Apply the patches to the PE.
267 VOID cobf::apply_obfuscations(PIMAGE_SECTION_HEADER& sh_sec, DWORD& syms_rva)
268 {
269  // The array of symbols to load.
270  vector<BYTE> strings_of_imports;
271  vector<shellcode::obfuscated_sym> symbols;
272 
273  // Enumerate the obfuscate by name array.
274  DWORD c_rva = sh_sec->VirtualAddress + (DWORD_PTR)sh_sec->SizeOfRawData;
275  for (auto& mod : this->pe_mods) for (auto& sym : mod.mod_syms) sym.apply_obfuscation(
276  this->pe_rawf.data(), c_rva, strings_of_imports, symbols);
277 
278  // Set the section info.
279  symbols.push_back({ 0 });
280  DWORD sh_sec_offset = (DWORD)((PBYTE)sh_sec - this->pe_rawf.data());
281 
282  // Resize the whole pe.
283  size_t size_of_symbols = symbols.size() * sizeof(shellcode::obfuscated_sym);
284  this->pe_rawf.resize(this->pe_rawf.size() + strings_of_imports.size() + size_of_symbols);
285  sh_sec = (PIMAGE_SECTION_HEADER)(this->pe_rawf.data() + sh_sec_offset);
286 
287  // Copy the strings and the symbols.
288  memcpy_s(this->pe_rawf.data() + sh_sec->PointerToRawData + sh_sec->SizeOfRawData,
289  strings_of_imports.size() + size_of_symbols, strings_of_imports.data(),
290  strings_of_imports.size());
291  memcpy_s(this->pe_rawf.data() + sh_sec->PointerToRawData + sh_sec->SizeOfRawData +
292  strings_of_imports.size(), size_of_symbols, symbols.data(), size_of_symbols);
293 
294  // Edit the properties.
295  syms_rva = sh_sec->VirtualAddress + sh_sec->SizeOfRawData + (DWORD)strings_of_imports.size();
296  sh_sec->SizeOfRawData += (DWORD)strings_of_imports.size() + (DWORD)size_of_symbols;
297 };
298 
299 // Add the stub for shellcode.
300 VOID cobf::add_shellcode_stub(PIMAGE_SECTION_HEADER& sh_sec, DWORD funs_offset, DWORD syms_rva, DWORD& entry)
301 {
302  // Building the stub.
303  DWORD shellcode_entry = sh_sec->VirtualAddress + shellcode::shellcode_entry;
304  BYTE shellcode_stub[] =
305  {
306 #ifdef _M_IX86
307  0x83, 0x7c, 0x24, 0x08, 0x01, // cmp dword ptr [esp + 8], 0x1;
308  0x74, 0x03, 0xc2, 0x0c, 0x00, // je $+3; ret;
309  0xc7, 0x44, 0x24, 0x08,
310  ((PBYTE)&funs_offset)[0],
311  ((PBYTE)&funs_offset)[1],
312  ((PBYTE)&funs_offset)[2],
313  ((PBYTE)&funs_offset)[3], // mov dword ptr [esp + 8], functions_rva;
314  0xc7, 0x44, 0x24, 0x0c,
315  ((PBYTE)&syms_rva)[0],
316  ((PBYTE)&syms_rva)[1],
317  ((PBYTE)&syms_rva)[2],
318  ((PBYTE)&syms_rva)[3], // mov dword ptr [esp + 12], symbols_rva;
319  0x8b, 0x44, 0x24, 0x04, // mov eax, dword ptr [esp + 4];
320  0x05,
321  ((PBYTE)&shellcode_entry)[0],
322  ((PBYTE)&shellcode_entry)[1],
323  ((PBYTE)&shellcode_entry)[2],
324  ((PBYTE)&shellcode_entry)[3], // add eax, shellcode_entry;
325  0xff, 0xe0 // jmp eax;
326 #else
327  0x83, 0xfa, 0x01, // cmp edx, 0x1;
328  0x74, 0x01, 0xc3, // je $+1; ret;
329  0x48, 0xc7, 0xc2,
330  ((PBYTE)&funs_offset)[0],
331  ((PBYTE)&funs_offset)[1],
332  ((PBYTE)&funs_offset)[2],
333  ((PBYTE)&funs_offset)[3], // mov rdx, functions_rva;
334  0x41, 0xb8,
335  ((PBYTE)&syms_rva)[0],
336  ((PBYTE)&syms_rva)[1],
337  ((PBYTE)&syms_rva)[2],
338  ((PBYTE)&syms_rva)[3], // mov r8, symbols_rva;
339  0x48, 0x89, 0xc8, // mov rax, rcx;
340  0x48, 0x05,
341  ((PBYTE)&shellcode_entry)[0],
342  ((PBYTE)&shellcode_entry)[1],
343  ((PBYTE)&shellcode_entry)[2],
344  ((PBYTE)&shellcode_entry)[3], // add rax, shellcode_entry;
345  0xff, 0xe0 // jmp rax;
346 #endif // _M_IX86
347  };
348 
349  // Set the section info.
350  DWORD sh_sec_offset = (DWORD)((PBYTE)sh_sec - this->pe_rawf.data());
351  DWORD padding_size = 0x10 - sh_sec->SizeOfRawData % 0x10;
352 
353  // Resize the whole pe.
354  this->pe_rawf.resize(this->pe_rawf.size() + sizeof(shellcode_stub) + padding_size);
355  sh_sec = (PIMAGE_SECTION_HEADER)(this->pe_rawf.data() + sh_sec_offset);
356 
357  // Copy the stub.
358  memset(this->pe_rawf.data() + sh_sec->PointerToRawData + sh_sec->SizeOfRawData, 0xcc,
359  padding_size);
360  memcpy_s(this->pe_rawf.data() + sh_sec->PointerToRawData + sh_sec->SizeOfRawData +
361  padding_size, sizeof(shellcode_stub), shellcode_stub, sizeof(shellcode_stub));
362 
363  // Update the section.
364  entry = sh_sec->VirtualAddress + sh_sec->SizeOfRawData + padding_size;
365  sh_sec->SizeOfRawData += sizeof(shellcode_stub) + padding_size;
366 };
367 
368 // Disable the relocations at the PE.
369 BOOL cobf::disable_the_relocation()
370 {
371  // Get the headers.
372  PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER)this->pe_rawf.data();
373  PIMAGE_NT_HEADERS nt_hdrs = (PIMAGE_NT_HEADERS)&this->pe_rawf.data()[dos_hdr->e_lfanew];
374 
375  // Get the table.
376  PIMAGE_RESOURCE_DIRECTORY p_relocs; size_t relocs_size;
377  if (!this->get_data_table(IMAGE_DIRECTORY_ENTRY_BASERELOC, (PVOID*)&p_relocs, relocs_size))
378  {
379  // Cannot verify the relocations.
380  return FALSE;
381  };
382 
383  // Zero it.
384  if (p_relocs) ZeroMemory(p_relocs, relocs_size);
385  nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] = { 0, 0 };
386 
387  // Stop the relocations.
388  nt_hdrs->FileHeader.Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
389 
390  // Configure the sections.
391  PIMAGE_SECTION_HEADER c_sec = (PIMAGE_SECTION_HEADER)&this->pe_rawf[dos_hdr->e_lfanew +
392  sizeof(nt_hdrs->Signature) + sizeof(nt_hdrs->FileHeader) +
393  nt_hdrs->FileHeader.SizeOfOptionalHeader];
394  for (size_t idx = 0; idx < nt_hdrs->FileHeader.NumberOfSections; idx++)
395  {
396  // Strip all of the information.
397  c_sec[idx].PointerToRelocations = 0;
398  c_sec[idx].NumberOfRelocations = 0;
399  };
400 
401  return TRUE;
402 };
403 
404 // Strip any debug symbols from the PE.
405 BOOL cobf::remove_debug_symbols()
406 {
407  // Get the headers.
408  PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER)this->pe_rawf.data();
409  PIMAGE_NT_HEADERS nt_hdrs = (PIMAGE_NT_HEADERS)&this->pe_rawf.data()[dos_hdr->e_lfanew];
410 
411  // Get the table.
412  PIMAGE_DEBUG_DIRECTORY p_debug; size_t debug_size;
413  if (!this->get_data_table(IMAGE_DIRECTORY_ENTRY_DEBUG, (PVOID*)&p_debug, debug_size))
414  {
415  // Cannot verify the debug table.
416  return FALSE;
417  };
418 
419  // Zero it.
420  if (p_debug) ZeroMemory(p_debug, debug_size);
421  nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] = { 0, 0 };
422 
423  // Strip it.
424  nt_hdrs->FileHeader.NumberOfSymbols = 0;
425  nt_hdrs->FileHeader.PointerToSymbolTable = 0;
426 
427  // Configure the sections.
428  PIMAGE_SECTION_HEADER c_sec = (PIMAGE_SECTION_HEADER)&this->pe_rawf[dos_hdr->e_lfanew +
429  sizeof(nt_hdrs->Signature) + sizeof(nt_hdrs->FileHeader) +
430  nt_hdrs->FileHeader.SizeOfOptionalHeader];
431  for (size_t idx = 0; idx < nt_hdrs->FileHeader.NumberOfSections; idx++)
432  {
433  // Strip all of the information.
434  c_sec[idx].PointerToLinenumbers = 0;
435  c_sec[idx].NumberOfLinenumbers = 0;
436  };
437 
438  return TRUE;
439 };
440 
441 // Make the import table section writable for the shellcode.
442 BOOL cobf::make_the_iat_writable()
443 {
444  // Get the headers.
445  PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER)this->pe_rawf.data();
446  PIMAGE_NT_HEADERS nt_hdrs = (PIMAGE_NT_HEADERS)&this->pe_rawf.data()[dos_hdr->e_lfanew];
447 
448  // Get the table.
449  PIMAGE_SECTION_HEADER imports_sec;
450  if (!this->section_of_rva(nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT
451  ].VirtualAddress, imports_sec))
452  {
453  // Cannot verify the imports.
454  return FALSE;
455  };
456 
457  // Change the protection.
458  imports_sec->Characteristics |= IMAGE_SCN_MEM_WRITE;
459  return TRUE;
460 };
461 
462 // Add the shellcode entry as a callback.
463 BOOL cobf::add_shellcode_entry(PIMAGE_SECTION_HEADER& sh_sec, DWORD entry)
464 {
465  // Get the headers.
466  PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER)this->pe_rawf.data();
467  PIMAGE_NT_HEADERS nt_hdrs = (PIMAGE_NT_HEADERS)&this->pe_rawf.data()[dos_hdr->e_lfanew];
468 
469  // Build the array of addresses.
470  vector<PVOID> tls_cbs = { (PVOID)(nt_hdrs->OptionalHeader.ImageBase + entry) };
471  vector<BYTE> tls_data;
472 
473  // Get the table.
474  PIMAGE_TLS_DIRECTORY p_tls; size_t tls_size;
475  if (!this->get_data_table(IMAGE_DIRECTORY_ENTRY_TLS, (PVOID*)&p_tls, tls_size))
476  {
477  // Cannot verify the tls table.
478  return FALSE;
479  };
480 
481  // The tls directory can be existing or not.
482  if (p_tls)
483  {
484  // Get the offset to the array.
485  DWORD tls_cbs_off = (DWORD)(p_tls->AddressOfCallBacks - nt_hdrs->OptionalHeader.ImageBase);
486  if (!this->rva_to_offset(tls_cbs_off, tls_cbs_off)) return FALSE;
487 
488  // Adding the availible callbacks.
489  PVOID* p_tls_cbs = (PVOID*)&this->pe_rawf[tls_cbs_off];
490 
491  // Insert and remove the old pointer.
492  do { tls_cbs.push_back(*p_tls_cbs);
493  } while (*p_tls_cbs && (*p_tls_cbs++ = NULL, TRUE));
494 
495  // Removing the old array and pointer.
496  p_tls->AddressOfCallBacks = nt_hdrs->OptionalHeader.ImageBase + sh_sec->VirtualAddress +
497  sh_sec->SizeOfRawData;
498  }
499  else
500  {
501  // Building a new tls directory.
502  IMAGE_TLS_DIRECTORY tls_dir = { 0 }; DWORD index = 0;
503  tls_dir.AddressOfIndex = nt_hdrs->OptionalHeader.ImageBase + sh_sec->VirtualAddress +
504  sh_sec->SizeOfRawData + sizeof(tls_dir);
505  tls_dir.AddressOfCallBacks = tls_dir.AddressOfIndex + sizeof(index);
506 
507  // Build up the bytes array.
508  tls_data.insert(tls_data.end(), (PBYTE)&tls_dir, (PBYTE)&tls_dir + sizeof(tls_dir));
509  tls_data.insert(tls_data.end(), (PBYTE)&index, (PBYTE)&index + sizeof(index));
510  tls_cbs.push_back(NULL);
511 
512  // Point to the new table.
513  nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS] = {
514  sh_sec->VirtualAddress + sh_sec->SizeOfRawData,
515  (DWORD)(sizeof(tls_dir) + sizeof(index) + tls_cbs.size() * sizeof(PVOID))
516  };
517  };
518 
519  // Writing to the shellcode section.
520  DWORD sh_sec_offset = (DWORD)((PBYTE)sh_sec - this->pe_rawf.data());
521 
522  // Resize the whole pe.
523  this->pe_rawf.resize(this->pe_rawf.size() + tls_data.size() + tls_cbs.size() * sizeof(PVOID));
524  sh_sec = (PIMAGE_SECTION_HEADER)(this->pe_rawf.data() + sh_sec_offset);
525 
526  // Copy the stub.
527  memcpy_s(this->pe_rawf.data() + sh_sec->PointerToRawData + sh_sec->SizeOfRawData,
528  tls_data.size() + tls_cbs.size() * sizeof(PVOID), tls_data.data(), tls_data.size());
529  memcpy_s(this->pe_rawf.data() + sh_sec->PointerToRawData + sh_sec->SizeOfRawData + tls_data.size(),
530  tls_cbs.size() * sizeof(PVOID), tls_cbs.data(), tls_cbs.size() * sizeof(PVOID));
531 
532  // Update the section.
533  sh_sec->SizeOfRawData += (DWORD)(tls_data.size() + tls_cbs.size() * sizeof(PVOID));
534  return TRUE;
535 };
536 
537 // Finalize the obfuscated PE.
538 VOID cobf::finalize_pe(PIMAGE_SECTION_HEADER& sh_sec)
539 {
540  // Get the sections.
541  PIMAGE_DOS_HEADER dos_hdr = (PIMAGE_DOS_HEADER)this->pe_rawf.data();
542  PIMAGE_NT_HEADERS nt_hdrs = (PIMAGE_NT_HEADERS)&this->pe_rawf.data()[dos_hdr->e_lfanew];
543 
544  // Calculate the needed size.
545  size_t gap_size = nt_hdrs->OptionalHeader.FileAlignment - (sh_sec->SizeOfRawData %
546  nt_hdrs->OptionalHeader.FileAlignment);
547 
548  // Set the section info.
549  DWORD sh_sec_offset = (DWORD)((PBYTE)sh_sec - this->pe_rawf.data());
550 
551  // Resize the whole pe.
552  this->pe_rawf.resize((size_t)sh_sec->PointerToRawData + (size_t)sh_sec->SizeOfRawData + gap_size);
553  sh_sec = (PIMAGE_SECTION_HEADER)(this->pe_rawf.data() + sh_sec_offset);
554 
555  // Update the section information.
556  sh_sec->Misc.VirtualSize = sh_sec->SizeOfRawData;
557  sh_sec->SizeOfRawData += (DWORD)gap_size;
558  nt_hdrs->OptionalHeader.SizeOfImage += sh_sec->Misc.VirtualSize + nt_hdrs->OptionalHeader.SectionAlignment -
559  (sh_sec->Misc.VirtualSize % nt_hdrs->OptionalHeader.SectionAlignment);
560  nt_hdrs->OptionalHeader.CheckSum = 0;
561 };
562 
563 // Matching with the module name or any symbol.
564 BOOL cobf::csym::match_wildcard(PCCH wild_card, PCCH string)
565 {
566  // Init.
567  PCCH s_wild;
568  PCCH s_str;
569  BOOL wild = FALSE;
570 
571 loop_start:
572  for (s_wild = wild_card, s_str = string; *s_str; ++s_str, ++s_wild) {
573  if (*s_wild == '*')
574  {
575  // Found a wildcard.
576  wild = TRUE;
577  string = s_str, wild_card = s_wild;
578 
579  // Overlooking any consecutive wildcards.
580  do { ++wild_card; } while (*wild_card == '*');
581 
582  // Reached the end of the wildcard string.
583  if (!*wild_card) return TRUE;
584  goto loop_start;
585  }
586  // Default match.
587  else if (*s_wild != *s_str) goto wild_check;
588  };
589  while (*s_wild == '*') ++s_wild;
590  return (!*s_wild);
591 
592 wild_check:
593  // Move to next char.
594  if (!wild) return FALSE;
595  string++;
596  goto loop_start;
597 };
598 
599 // Check the symbol name.
600 BOOL cobf::csym::check_sym(string n_sym)
601 {
602  // Extra check if imported by name.
603  return this->by_name && match_wildcard(n_sym.c_str(),
604  this->sym_name.c_str());
605 };
606 
607 // Check the symbol ordinal.
608 BOOL cobf::csym::check_sym(WORD n_ord)
609 {
610  // Extra check if imported by ordinal.
611  return !this->by_name && this->sym_ord == n_ord;
612 };
613 
614 // Obfuscate by name.
615 VOID cobf::csym::obfuscate(string o_sym)
616 {
617  // Obfuscate.
618  this->obf_name = o_sym;
619  this->to_name = TRUE;
620  this->obfuscated = TRUE;
621 };
622 
623 // Obfuscate by ordinal.
624 VOID cobf::csym::obfuscate(WORD o_ord)
625 {
626  // Obfuscate.
627  this->obf_ord = o_ord;
628  this->to_name = FALSE;
629  this->obfuscated = TRUE;
630 };
631 
632 // Unobfuscate.
633 VOID cobf::csym::unobfuscate()
634 {
635  // Unbfuscate.
636  this->obfuscated = FALSE;
637 };
638 
639 // Apply the obfuscation.
640 VOID cobf::csym::apply_obfuscation(PBYTE pe_rawf, DWORD strings_off, vector<BYTE>& strings,
641  vector<shellcode::obfuscated_sym>& symbols)
642 {
643  // Check if not obfuscated.
644  if (!this->obfuscated) return;
645 
646  // Build the symbol.
647  shellcode::obfuscated_sym symbol;
648  symbol.dll_name = this->dll_rva;
649  symbol.sym_thnk = this->fth_rva;
650 
651  // Test if imported by name.
652  if (symbol.by_name = this->by_name)
653  {
654  // Imported by name.
655  symbol.sym_info.sym_hash = shellcode::hash_string((PCHAR)this->sym_name.c_str());
656 
657  // Removing the old name.
658  for (size_t idx = 0; idx < this->sym_name.size() + sizeof(CHAR); idx++)
659  {
660  // Randomize it.
661  pe_rawf[this->name_off + idx] = rand();
662  };
663  }
664  // Imported by ordinal.
665  else symbol.sym_info.sym_ord = this->obf_ord;
666 
667  // Calculating the thunk data.
668  PVOID thunk_data;
669  if (this->to_name)
670  {
671  // Obfuscated to name.
672  thunk_data = (PVOID)(strings_off + strings.size());
673 
674  // Append a new import by name struct.
675  strings.push_back(rand());
676  strings.push_back(rand());
677  strings.insert(strings.end(), this->obf_name.data(),
678  this->obf_name.data() + this->obf_name.size() +
679  sizeof(CHAR));
680  }
681  // Obfuscated to ordinal.
682  else thunk_data = (PVOID)(this->obf_ord | IMAGE_ORDINAL_FLAG);
683 
684  // Save the symbol.
685  symbols.push_back(symbol);
686  *(PVOID*)&pe_rawf[this->oth_off] = thunk_data;
687 };
688 
689 // Constructor.
690 cobf::csym::csym(string sym_name, DWORD dll_rva, DWORD fth_rva, DWORD oth_off, DWORD name_off)
691  : sym_name(sym_name), dll_rva(dll_rva), fth_rva(fth_rva), oth_off(oth_off), name_off(name_off)
692 {
693  // Init.
694  this->by_name = TRUE;
695  this->sym_ord = 0;
696  this->obfuscated = FALSE;
697  this->obf_ord = 0;
698  this->to_name = FALSE;
699 };
700 
701 // Constructor.
702 cobf::csym::csym(WORD sym_ord, DWORD dll_rva, DWORD fth_rva, DWORD oth_off) :
703  sym_ord(sym_ord), dll_rva(dll_rva), fth_rva(fth_rva), oth_off(oth_off)
704 {
705  // Init.
706  this->by_name = FALSE;
707  this->obfuscated = FALSE;
708  this->obf_ord = 0;
709  this->to_name = FALSE;
710  this->name_off = 0;
711 };
712 
713 #endif // !OBFUSCATE_CPP.
cobf::unobf_sym
cobf_error unobf_sym(string dll_name, string sym_name)
Unobfuscate one symbol (name).
Definition: obfuscate.cpp:68
shellcode::shellcode_size
static DWORD shellcode_size
Definition: shellcode.hpp:250
cobf_error::COBF_NO_ERROR
@ COBF_NO_ERROR
shellcode::shellcode_start
static PVOID shellcode_start
Definition: shellcode.hpp:248
shellcode::shellcode_entry
static DWORD shellcode_entry
Definition: shellcode.hpp:249
cobf::generate
cobf_error generate(string out_file)
Generate the obfuscated PE.
Definition: obfuscate.cpp:78
shellcode::shellcodes_funs
static DWORD shellcodes_funs[shellcode_number_of_functions]
Definition: shellcode.hpp:253
cobf.hpp
cobf_error
cobf_error
Definition: utils.hpp:15
cobf::obf_sym
cobf_error obf_sym(string dll_name, string sym_name, string obf_name)
Obfuscate one symbol (name) with another (name).
Definition: obfuscate.cpp:32