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)
19 transform(dll_name.begin(), dll_name.end(), dll_name.begin(), ::toupper);
22 vector<csym*> symbols;
23 this->find_symbols(dll_name, sym_info, symbols);
27 for (
auto& symbol : symbols) symbol->obfuscate(obf_info);
28 return cobf_error::COBF_NO_ERROR;
33 return this->obf_sym_internal(dll_name, sym_name, obf_name);
38 return this->obf_sym_internal(dll_name, sym_name, obf_ord);
43 return this->obf_sym_internal(dll_name, sym_ord, obf_ord);
48 return this->obf_sym_internal(dll_name, sym_ord, obf_name);
51 template <
typename t_sym_info>
52 cobf_error cobf::unobf_sym_internal(
string dll_name, t_sym_info sym_info)
55 transform(dll_name.begin(), dll_name.end(), dll_name.begin(), ::toupper);
58 vector<csym*> symbols;
59 this->find_symbols(dll_name, sym_info, symbols);
63 for (
auto& symbol : symbols) symbol->unobfuscate();
64 return cobf_error::COBF_NO_ERROR;
69 return this->unobf_sym_internal(dll_name, sym_name);
74 return this->unobf_sym_internal(dll_name, sym_ord);
81 if (this->pe_rawf.empty())
return cobf_error::COBF_PE_UNLOADED;
84 cobf_error ret_err = cobf_error::COBF_NO_ERROR;
85 PIMAGE_SECTION_HEADER sh_sec;
92 HANDLE h_file = CreateFileA(
98 FILE_ATTRIBUTE_NORMAL,
103 if (h_file == INVALID_HANDLE_VALUE)
106 return cobf_error::COBF_CANNOT_CREATE_FILE;
110 auto orig_pe = this->pe_rawf;
113 if (!this->create_shellcode_section(sh_sec, funs_table))
116 ret_err = cobf_error::COBF_CANNOT_CREATE_SECTION;
117 goto OBFUSCATE_FINISH;
121 this->apply_obfuscations(sh_sec, symbols);
124 this->add_shellcode_stub(sh_sec, funs_table, symbols, stub_entry);
127 if (!this->add_shellcode_entry(sh_sec, stub_entry))
130 ret_err = cobf_error::COBF_CANNOT_ADD_ENTRY;
131 goto OBFUSCATE_FINISH;
135 if (!this->disable_the_relocation())
138 ret_err = cobf_error::COBF_CANNOT_DISABLE_RELOCS;
139 goto OBFUSCATE_FINISH;
143 if (!this->make_the_iat_writable())
146 ret_err = cobf_error::COBF_INVALID_IAT_SECTION;
147 goto OBFUSCATE_FINISH;
151 if (!this->remove_debug_symbols())
154 ret_err = cobf_error::COBF_CANNOT_REMOVE_DBG_SYMS;
155 goto OBFUSCATE_FINISH;
159 this->finalize_pe(sh_sec);
164 this->pe_rawf.data(),
165 (DWORD)this->pe_rawf.size(),
171 ret_err = cobf_error::COBF_CANNOT_WRITE_FILE;
172 goto OBFUSCATE_FINISH;
178 this->pe_rawf = orig_pe;
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;
187 template <
typename t_sym_info>
188 VOID cobf::find_symbols(
string dll_name, t_sym_info sym_info, vector<csym*>& p_syms)
191 for (
auto& mod : this->pe_mods)
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);
201 BOOL cobf::create_shellcode_section(PIMAGE_SECTION_HEADER& sh_sec, DWORD& funs_rva)
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];
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))
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)];
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;
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++;
239 DWORD sh_sec_offset = (DWORD)((PBYTE)sh_sec - this->pe_rawf.data());
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);
248 memcpy_s(this->pe_rawf.data() + sh_sec->PointerToRawData, sh_sec->SizeOfRawData,
259 p_sh_funs[idx] += sh_sec->VirtualAddress;
267 VOID cobf::apply_obfuscations(PIMAGE_SECTION_HEADER& sh_sec, DWORD& syms_rva)
270 vector<BYTE> strings_of_imports;
271 vector<shellcode::obfuscated_sym> symbols;
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);
279 symbols.push_back({ 0 });
280 DWORD sh_sec_offset = (DWORD)((PBYTE)sh_sec - this->pe_rawf.data());
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);
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);
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;
300 VOID cobf::add_shellcode_stub(PIMAGE_SECTION_HEADER& sh_sec, DWORD funs_offset, DWORD syms_rva, DWORD& entry)
304 BYTE shellcode_stub[] =
307 0x83, 0x7c, 0x24, 0x08, 0x01,
308 0x74, 0x03, 0xc2, 0x0c, 0x00,
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],
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],
319 0x8b, 0x44, 0x24, 0x04,
321 ((PBYTE)&shellcode_entry)[0],
322 ((PBYTE)&shellcode_entry)[1],
323 ((PBYTE)&shellcode_entry)[2],
324 ((PBYTE)&shellcode_entry)[3],
330 ((PBYTE)&funs_offset)[0],
331 ((PBYTE)&funs_offset)[1],
332 ((PBYTE)&funs_offset)[2],
333 ((PBYTE)&funs_offset)[3],
335 ((PBYTE)&syms_rva)[0],
336 ((PBYTE)&syms_rva)[1],
337 ((PBYTE)&syms_rva)[2],
338 ((PBYTE)&syms_rva)[3],
341 ((PBYTE)&shellcode_entry)[0],
342 ((PBYTE)&shellcode_entry)[1],
343 ((PBYTE)&shellcode_entry)[2],
344 ((PBYTE)&shellcode_entry)[3],
350 DWORD sh_sec_offset = (DWORD)((PBYTE)sh_sec - this->pe_rawf.data());
351 DWORD padding_size = 0x10 - sh_sec->SizeOfRawData % 0x10;
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);
358 memset(this->pe_rawf.data() + sh_sec->PointerToRawData + sh_sec->SizeOfRawData, 0xcc,
360 memcpy_s(this->pe_rawf.data() + sh_sec->PointerToRawData + sh_sec->SizeOfRawData +
361 padding_size,
sizeof(shellcode_stub), shellcode_stub,
sizeof(shellcode_stub));
364 entry = sh_sec->VirtualAddress + sh_sec->SizeOfRawData + padding_size;
365 sh_sec->SizeOfRawData +=
sizeof(shellcode_stub) + padding_size;
369 BOOL cobf::disable_the_relocation()
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];
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))
384 if (p_relocs) ZeroMemory(p_relocs, relocs_size);
385 nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] = { 0, 0 };
388 nt_hdrs->FileHeader.Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
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++)
397 c_sec[idx].PointerToRelocations = 0;
398 c_sec[idx].NumberOfRelocations = 0;
405 BOOL cobf::remove_debug_symbols()
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];
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))
420 if (p_debug) ZeroMemory(p_debug, debug_size);
421 nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] = { 0, 0 };
424 nt_hdrs->FileHeader.NumberOfSymbols = 0;
425 nt_hdrs->FileHeader.PointerToSymbolTable = 0;
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++)
434 c_sec[idx].PointerToLinenumbers = 0;
435 c_sec[idx].NumberOfLinenumbers = 0;
442 BOOL cobf::make_the_iat_writable()
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];
449 PIMAGE_SECTION_HEADER imports_sec;
450 if (!this->section_of_rva(nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT
451 ].VirtualAddress, imports_sec))
458 imports_sec->Characteristics |= IMAGE_SCN_MEM_WRITE;
463 BOOL cobf::add_shellcode_entry(PIMAGE_SECTION_HEADER& sh_sec, DWORD entry)
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];
470 vector<PVOID> tls_cbs = { (PVOID)(nt_hdrs->OptionalHeader.ImageBase + entry) };
471 vector<BYTE> tls_data;
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))
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;
489 PVOID* p_tls_cbs = (PVOID*)&this->pe_rawf[tls_cbs_off];
492 do { tls_cbs.push_back(*p_tls_cbs);
493 }
while (*p_tls_cbs && (*p_tls_cbs++ = NULL, TRUE));
496 p_tls->AddressOfCallBacks = nt_hdrs->OptionalHeader.ImageBase + sh_sec->VirtualAddress +
497 sh_sec->SizeOfRawData;
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);
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);
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))
520 DWORD sh_sec_offset = (DWORD)((PBYTE)sh_sec - this->pe_rawf.data());
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);
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));
533 sh_sec->SizeOfRawData += (DWORD)(tls_data.size() + tls_cbs.size() *
sizeof(PVOID));
538 VOID cobf::finalize_pe(PIMAGE_SECTION_HEADER& sh_sec)
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];
545 size_t gap_size = nt_hdrs->OptionalHeader.FileAlignment - (sh_sec->SizeOfRawData %
546 nt_hdrs->OptionalHeader.FileAlignment);
549 DWORD sh_sec_offset = (DWORD)((PBYTE)sh_sec - this->pe_rawf.data());
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);
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;
564 BOOL cobf::csym::match_wildcard(PCCH wild_card, PCCH
string)
572 for (s_wild = wild_card, s_str =
string; *s_str; ++s_str, ++s_wild) {
577 string = s_str, wild_card = s_wild;
580 do { ++wild_card; }
while (*wild_card ==
'*');
583 if (!*wild_card)
return TRUE;
587 else if (*s_wild != *s_str)
goto wild_check;
589 while (*s_wild ==
'*') ++s_wild;
594 if (!wild)
return FALSE;
600 BOOL cobf::csym::check_sym(
string n_sym)
603 return this->by_name && match_wildcard(n_sym.c_str(),
604 this->sym_name.c_str());
608 BOOL cobf::csym::check_sym(WORD n_ord)
611 return !this->by_name && this->sym_ord == n_ord;
615 VOID cobf::csym::obfuscate(
string o_sym)
618 this->obf_name = o_sym;
619 this->to_name = TRUE;
620 this->obfuscated = TRUE;
624 VOID cobf::csym::obfuscate(WORD o_ord)
627 this->obf_ord = o_ord;
628 this->to_name = FALSE;
629 this->obfuscated = TRUE;
633 VOID cobf::csym::unobfuscate()
636 this->obfuscated = FALSE;
640 VOID cobf::csym::apply_obfuscation(PBYTE pe_rawf, DWORD strings_off, vector<BYTE>& strings,
641 vector<shellcode::obfuscated_sym>& symbols)
644 if (!this->obfuscated)
return;
647 shellcode::obfuscated_sym symbol;
648 symbol.dll_name = this->dll_rva;
649 symbol.sym_thnk = this->fth_rva;
652 if (symbol.by_name = this->by_name)
655 symbol.sym_info.sym_hash = shellcode::hash_string((PCHAR)this->sym_name.c_str());
658 for (
size_t idx = 0; idx < this->sym_name.size() +
sizeof(CHAR); idx++)
661 pe_rawf[this->name_off + idx] = rand();
665 else symbol.sym_info.sym_ord = this->obf_ord;
672 thunk_data = (PVOID)(strings_off + strings.size());
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() +
682 else thunk_data = (PVOID)(this->obf_ord | IMAGE_ORDINAL_FLAG);
685 symbols.push_back(symbol);
686 *(PVOID*)&pe_rawf[this->oth_off] = thunk_data;
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)
694 this->by_name = TRUE;
696 this->obfuscated = FALSE;
698 this->to_name = FALSE;
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)
706 this->by_name = FALSE;
707 this->obfuscated = FALSE;
709 this->to_name = FALSE;
713 #endif // !OBFUSCATE_CPP.