@@ -425,14 +425,99 @@ BOOL IsModulePatched (HMODULE importmodule, moduleentry_t patchtable [], UINT ta
425425 return FALSE ;
426426}
427427
428+ #define MAX_PAGES_PROTECT 2
429+
430+ typedef struct PROTECT_INSTANCE_TAG
431+ {
432+ DWORD old_protect[MAX_PAGES_PROTECT];
433+ LPVOID address;
434+ SIZE_T size;
435+ } PROTECT_INSTANCE;
436+
437+ typedef struct PROTECT_INSTANCE_TAG * PROTECT_HANDLE;
438+
439+ #ifdef _WIN64
440+ #define PAGE_MASK 0xFFFFFFFFFFFFF000
441+ #else
442+ #define PAGE_MASK 0xFFFFF000
443+ #endif
444+
445+ #define PAGE_SIZE 0x1000
446+
447+ static BOOL VLDVirtualProtect (PROTECT_HANDLE protect_handle, LPVOID address, SIZE_T size, DWORD protect)
448+ {
449+ BOOL result = TRUE ;
450+ size_t page_count = 0 ;
451+
452+ // save the address and size so that we can restore in the same way
453+ protect_handle->address = address;
454+ protect_handle->size = size;
455+
456+ uintptr_t current_address = (uintptr_t )address;
457+
458+ // walk all pages while we still have size > 0
459+ while ((size > 0 ) && (page_count < MAX_PAGES_PROTECT))
460+ {
461+ uintptr_t page_address = current_address & PAGE_MASK;
462+ SIZE_T size_in_page = page_address + PAGE_SIZE - current_address;
463+ SIZE_T size_to_protect = (size_in_page < size) ? size_in_page : size;
464+
465+ result = VirtualProtect ((LPVOID)current_address, size_to_protect, protect, &protect_handle->old_protect [page_count]);
466+ if (!result)
467+ {
468+ Report (L" %zu: !!! VirtualProtect FAILED when protecting for address=%p, size=%zu, with GetLastError()=%lu, protect_handle->address=%p, protect_handle->size=%zu" ,
469+ __LINE__, current_address, size_to_protect,
470+ GetLastError (),
471+ protect_handle->address , protect_handle->size );
472+ }
473+ page_count++;
474+ current_address += size_to_protect;
475+ size -= size_to_protect;
476+ }
477+
478+ return result;
479+ }
480+
481+ static void VLDVirtualRestore (PROTECT_HANDLE protect_handle)
482+ {
483+ size_t page_count = 0 ;
484+ SIZE_T size = protect_handle->size ;
485+ uintptr_t current_address = (uintptr_t )protect_handle->address ;
486+
487+ // walk all pages while we still have size > 0
488+ while ((size > 0 ) && (page_count < MAX_PAGES_PROTECT))
489+ {
490+ uintptr_t page_address = current_address & PAGE_MASK;
491+ SIZE_T size_in_page = page_address + PAGE_SIZE - current_address;
492+ SIZE_T size_to_protect = (size_in_page < size) ? size_in_page : size;
493+
494+ DWORD dont_care;
495+ if (!VirtualProtect ((LPVOID)current_address, size_to_protect, protect_handle->old_protect [page_count], &dont_care))
496+ {
497+ static volatile DWORD lastError = GetLastError ();
498+ Report (L" %zu: !!! VirtualProtect FAILED when restoring for address=%p, size=%zu, with GetLastError()=%lu, protect_handle->old_protect[page_count]=%lu, protect_handle->address=%p, protect_handle->size=%zu" ,
499+ __LINE__, current_address, size_to_protect,
500+ GetLastError (), protect_handle->old_protect [page_count],
501+ protect_handle->address , protect_handle->size );
502+ abort ();
503+ }
504+
505+ page_count++;
506+ current_address += size_to_protect;
507+ size -= size_to_protect;
508+ }
509+
510+ }
511+
428512LPVOID FindRealCode (LPVOID pCode)
429513{
430514 LPVOID result;
431515 if (pCode != NULL )
432516 {
433- // we need to make sure we can read the first 3 ULONG_PTRs
434- DWORD old_protect;
435- if (VirtualProtect (pCode, sizeof (ULONG_PTR) * 3 , PAGE_EXECUTE_READ, &old_protect))
517+ // we need to make sure we can read the first 7 ULONG_PTRs
518+ PROTECT_INSTANCE protect_1;
519+
520+ if (VLDVirtualProtect (&protect_1, pCode, sizeof (ULONG_PTR) * 7 , PAGE_EXECUTE_READ))
436521 {
437522 if (*(WORD*)pCode == 0x25ff ) // JMP r/m32
438523 {
@@ -442,12 +527,14 @@ LPVOID FindRealCode(LPVOID pCode)
442527 PBYTE pNextInst = (PBYTE)((ULONG_PTR)pCode + 6 );
443528
444529 // now that we got the offset, make sure we can read the code at the offset
445- DWORD old_protect_2 ;
530+ PROTECT_INSTANCE protect_2 ;
446531 PBYTE addr = pNextInst + offset;
447- if (VirtualProtect (addr, sizeof (LPVOID), PAGE_EXECUTE_READ, &old_protect_2))
448- {
449- result = *(LPVOID*)(addr);
450- (void )VirtualProtect (addr, sizeof (LPVOID), old_protect_2, &old_protect_2);
532+
533+ if (VLDVirtualProtect (&protect_2, (LPVOID*)addr, sizeof (LPVOID), PAGE_EXECUTE_READ))
534+ {
535+ pCode = *(LPVOID*)(addr);
536+ result = FindRealCode (pCode);
537+ VLDVirtualRestore (&protect_2);
451538 }
452539 else
453540 {
@@ -456,12 +543,12 @@ LPVOID FindRealCode(LPVOID pCode)
456543#else
457544 DWORD addr = *((DWORD*)((ULONG_PTR)pCode + 2 ));
458545 // now that we got the address to read, make sure we can read the code at the offset
459- DWORD old_protect_2 ;
460- if (VirtualProtect ( (LPVOID* )addr, sizeof (LPVOID), PAGE_EXECUTE_READ, &old_protect_2 ))
546+ PROTECT_INSTANCE protect_2 ;
547+ if (VLDVirtualProtect (&protect_2, (LPVOID)addr, sizeof (LPVOID), PAGE_EXECUTE_READ))
461548 {
462549 pCode = *(LPVOID*)(addr);
463550 result = FindRealCode (pCode);
464- ( void ) VirtualProtect ((LPVOID*)addr, sizeof (LPVOID), old_protect_2, &old_protect_2 );
551+ VLDVirtualRestore (&protect_2 );
465552 }
466553 else
467554 {
@@ -471,19 +558,28 @@ LPVOID FindRealCode(LPVOID pCode)
471558 }
472559 else if (*(BYTE*)pCode == 0xE9 ) // JMP rel32
473560 {
474- // Relative next instruction
561+ // Relative next instruction
562+ PROTECT_INSTANCE protect_2;
475563 PBYTE pNextInst = (PBYTE)((ULONG_PTR)pCode + 5 );
476564 LONG offset = *((LONG*)((ULONG_PTR)pCode + 1 ));
477- pCode = (LPVOID*)(pNextInst + offset);
478- result = FindRealCode (pCode);
565+ if (VLDVirtualProtect (&protect_2, pNextInst + offset, sizeof (LPVOID), PAGE_EXECUTE_READ))
566+ {
567+ pCode = (LPVOID*)(pNextInst + offset);
568+ result = FindRealCode (pCode);
569+ VLDVirtualRestore (&protect_2);
570+ }
571+ else
572+ {
573+ result = NULL ;
574+ }
479575 }
480576 else
481577 {
482578 result = pCode;
483579 }
484580
485581 // restore the page protection state
486- ( void ) VirtualProtect (pCode, sizeof (ULONG_PTR) * 3 , old_protect, &old_protect );
582+ VLDVirtualRestore (&protect_1 );
487583 }
488584 else
489585 {
@@ -595,7 +691,9 @@ BOOL PatchImport (HMODULE importmodule, moduleentry_t *patchModule)
595691 int result = 0 ;
596692 while (idte->FirstThunk != 0x0 ) {
597693 PCHAR importdllname = (PCHAR)R2VA (importmodule, idte->Name );
598- UNREFERENCED_PARAMETER (importdllname);
694+ UNREFERENCED_PARAMETER (importdllname);
695+ HMODULE importdllbaseaddress = GetModuleHandleA (importdllname);
696+ UNREFERENCED_PARAMETER (importdllbaseaddress);
599697
600698 // Locate the import's IAT entry.
601699 IMAGE_THUNK_DATA *thunk = (IMAGE_THUNK_DATA*)R2VA (importmodule, idte->FirstThunk );
0 commit comments