18 std::ofstream patch_report;
19 patch_report.open(reportPath);
20 if (patch_report.is_open() ==
false) {
24 if (patch_report.is_open()) {
34 std::set<DWORD> impThunkRVAs;
35 moduleData.loadImportThunks(impThunkRVAs);
36 if (impThunkRVAs.size() == 0) {
40 const size_t thunk_size = moduleData.is64bit() ?
sizeof(ULONGLONG) : sizeof(
DWORD);
41 std::set<DWORD>::iterator itr;
42 for (itr = impThunkRVAs.begin(); itr != impThunkRVAs.end(); ++itr) {
43 const DWORD iat_field = *itr;
45 if (originalSec.isContained(iat_field, thunk_size)) {
46 const DWORD offset = iat_field - originalSec.rva;
47 memset(originalSec.loadedSection + offset, 0, thunk_size);
48 memset(remoteSec.loadedSection + offset, 0, thunk_size);
54bool pesieve::CodeScanner::clearLoadConfig(
PeSection &originalSec,
PeSection &remoteSec)
57 WORD charact = peconv::get_dll_characteristics(moduleData.original_module);
58 if ((charact & 0x4000) == 0) {
61 BYTE *ldconf_ptr = peconv::get_load_config_ptr(moduleData.original_module, moduleData.original_size);
62 if (!ldconf_ptr)
return false;
64 peconv::t_load_config_ver ver = peconv::get_load_config_version(moduleData.original_module, moduleData.original_size, ldconf_ptr);
65 if (ver != peconv::LOAD_CONFIG_W8_VER && ver != peconv::LOAD_CONFIG_W10_VER) {
68 ULONGLONG cflag_va = 0;
69 size_t field_size = 0;
70 if (this->moduleData.is64bit()) {
71 peconv::IMAGE_LOAD_CONFIG_DIR64_W8* ldc = (peconv::IMAGE_LOAD_CONFIG_DIR64_W8*) ldconf_ptr;
72 cflag_va = ldc->GuardCFCheckFunctionPointer;
73 field_size =
sizeof(ULONGLONG);
76 peconv::IMAGE_LOAD_CONFIG_DIR32_W8* ldc = (peconv::IMAGE_LOAD_CONFIG_DIR32_W8*) ldconf_ptr;
77 cflag_va = ldc->GuardCFCheckFunctionPointer;
78 field_size =
sizeof(
DWORD);
80 if (cflag_va == 0)
return false;
82 const ULONGLONG module_base = (ULONG_PTR)moduleData.moduleHandle;
83 const ULONGLONG cflag_rva = cflag_va - module_base;
84 if (!originalSec.
isContained(cflag_rva, field_size)) {
88 size_t sec_offset = size_t(cflag_rva - originalSec.
rva);
89 memset(originalSec.
loadedSection + sec_offset, 0, field_size);
96 IMAGE_DATA_DIRECTORY* dir = peconv::get_directory_entry(moduleData.original_module, IMAGE_DIRECTORY_ENTRY_EXPORT);
100 DWORD iat_rva = dir->VirtualAddress;
101 DWORD iat_size = dir->Size;
106 std::cout <<
"Exports are in the Code section!" << std::endl;
108 DWORD offset = iat_rva - originalSec.
rva;
109 IMAGE_EXPORT_DIRECTORY *exports = (IMAGE_EXPORT_DIRECTORY*) ((ULONGLONG)originalSec.
loadedSection + offset);
110 if (!peconv::validate_ptr(originalSec.
loadedSection, originalSec.
loadedSize, exports,
sizeof(IMAGE_EXPORT_DIRECTORY))) {
113 DWORD functions_offset = exports->AddressOfFunctions - originalSec.
rva;
114 DWORD functions_count = exports->NumberOfFunctions;
116 const size_t func_area_size = functions_count *
sizeof(
DWORD);
123 memset(originalSec.
loadedSection + functions_offset, 0, func_area_size);
124 memset(remoteSec.
loadedSection + functions_offset, 0, func_area_size);
129size_t pesieve::CodeScanner::collectPatches(
DWORD section_rva, PBYTE orig_code, PBYTE patched_code,
size_t code_size, OUT
PatchList &patchesList)
131 PatchAnalyzer analyzer(moduleData, section_rva, patched_code, code_size);
134 for (
DWORD i = 0; i < (
DWORD) code_size; i++) {
135 if (orig_code[i] == patched_code[i]) {
136 if (currPatch !=
nullptr) {
138 currPatch->
setEnd(section_rva + i);
139 analyzer.analyzeOther(*currPatch);
144 if (currPatch ==
nullptr) {
146 currPatch =
new(std::nothrow)
PatchList::Patch(moduleData.moduleHandle, patchesList.size(), (
DWORD) section_rva + i);
147 if (!currPatch)
continue;
148 patchesList.insert(currPatch);
149 DWORD parsed_size = (
DWORD) analyzer.analyzeHook(*currPatch);
150 if (parsed_size > 0) {
151 currPatch->
setEnd(section_rva + i + parsed_size);
153 i += (parsed_size - 1);
159 if (currPatch !=
nullptr) {
161 currPatch->
setEnd(section_rva + (
DWORD) code_size);
164 return patchesList.size();
168 inline BYTE*
first_different(
const BYTE *buf_ptr,
size_t bif_size,
const BYTE padding)
170 for (
size_t i = 0; i < bif_size; i++) {
171 if (buf_ptr[i] != padding) {
172 return (BYTE*)(buf_ptr + i);
184 clearIAT(originalSec, remoteSec);
185 clearExports(originalSec, remoteSec);
186 clearLoadConfig(originalSec, remoteSec);
191 std::cout <<
"Code RVA: "
192 << std::hex << originalSec.
rva
200 if ((originalSec.
rawSize == 0 || peconv::is_padding(originalSec.
loadedSection, smaller_size, 0))
201 && !peconv::is_padding(remoteSec.
loadedSection, smaller_size, 0))
218 const DWORD found_rva = remoteSec.
rva + found_offset;
222 patchesList.insert(currPatch);
226 if (patchesList.size()) {
235size_t pesieve::CodeScanner::collectExecutableSections(
RemoteModuleData &_remoteModData, std::map<size_t, PeSection*> §ions,
CodeScanReport &my_report)
237 size_t initial_size = sections.size();
239 for (
DWORD i = 0; i < sec_count; i++) {
240 PIMAGE_SECTION_HEADER section_hdr = peconv::get_section_hdr(_remoteModData.
headerBuffer, _remoteModData.
getHeaderSize(), i);
241 if (section_hdr ==
nullptr) {
248 && !(section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE)
261 sections[i] = remoteSec;
273 if (sec_count == 0) {
276 sections[0] = remoteSec;
285 return sections.size() - initial_size;
288void pesieve::CodeScanner::freeExecutableSections(std::map<size_t, PeSection*> §ions)
290 std::map<size_t, PeSection*>::iterator itr;
291 for (itr = sections.begin(); itr != sections.end(); ++itr) {
299 IN ULONGLONG load_base,
300 IN std::map<size_t, PeSection*> &remote_code,
301 OUT std::map<DWORD, CodeScanReport::t_section_status> §ionToResult,
307 if (!moduleData.relocateToBase(load_base)) {
313 std::map<size_t, PeSection*>::iterator itr;
315 for (itr = remote_code.begin(); itr != remote_code.end(); ++itr) {
316 size_t sec_indx = itr->first;
319 PeSection originalSec(moduleData, sec_indx);
322 sectionToResult[originalSec.
rva] = sec_status;
333 else if (errors > 0) {
341 if (!moduleData.isInitialized()) {
342 std::cerr <<
"[-] Module not initialized" << std::endl;
345 if (!remoteModData.isInitialized()) {
346 std::cerr <<
"[-] Failed to read the module header" << std::endl;
350 if (!my_report)
return nullptr;
355 std::map<size_t, PeSection*> remote_code;
357 if (!collectExecutableSections(remoteModData, remote_code, *my_report)) {
358 my_report->
status = last_res;
364 const ULONGLONG load_base = (ULONGLONG)moduleData.moduleHandle;
365 const ULONGLONG hdr_base = remoteModData.getHdrImageBase();
366 my_report->
origBase = moduleData.getHdrImageBase();
371 std::cout <<
"[WARNING] Load Base: " << std::hex << load_base <<
" is different than the Hdr Base: " << hdr_base <<
"\n";
374 std::map<DWORD, CodeScanReport::t_section_status> section_to_result;
375 t_scan_status scan_res2 = scanUsingBase(hdr_base, remote_code, section_to_result, list2);
380 last_res = scan_res2;
383 std::cout <<
"Using patches list for the base: " << my_report->
relocBase <<
" list size: " << my_report->
patchesList.
size() <<
"\n";
387 this->freeExecutableSections(remote_code);
389 postProcessScan(*my_report);
391 my_report->
status = last_res;
398 if (
report.patchesList.size() == 0) {
401 peconv::ExportsMapper local_mapper;
402 local_mapper.add_to_lookup(moduleData.szModName, (HMODULE) moduleData.original_module, (ULONGLONG) moduleData.moduleHandle);
403 report.patchesList.checkForHookedExports(local_mapper);
A report from the code scan, generated by CodeScanner.
size_t generateTags(const std::string &reportPath)
enum pesieve::CodeScanReport::section_status t_section_status
size_t countInaccessibleSections()
std::map< DWORD, t_section_status > sectionToResult
virtual CodeScanReport * scanRemote()
A postprocessor of the detected code patches. Detects if the patch is a hook, and if so,...
void setEnd(DWORD end_rva)
const size_t toTAGs(std::ofstream &patch_report, const char delimiter)
Buffers the defined PE section belonging to the module loaded in the scanned process into the local m...
bool isContained(ULONGLONG field_start, size_t field_size)
Buffers the data from the module loaded in the scanned process into the local memory.
BYTE headerBuffer[peconv::MAX_HEADER_SIZE]
bool isSectionExecutable(const size_t section_number, bool allow_data, bool allow_inaccessible)
bool isSectionEntry(const size_t section_number)
#define MASK_TO_DWORD(val)
bool is_code(BYTE *loadedData, size_t loadedSize)
DWORD(__stdcall *_PssCaptureSnapshot)(HANDLE ProcessHandle
BYTE * first_different(const BYTE *buf_ptr, size_t bif_size, const BYTE padding)
enum pesieve::module_scan_status t_scan_status
Final summary about the scanned process.