Skip to content

Commit

Permalink
Fix ntdll loader patch for Windows 10 (1607) Anniversary Update causi…
Browse files Browse the repository at this point in the history
…ng crashes because EntryPoint is called through __guard_dispatch_icall_fptr()
  • Loading branch information
ioannis-e committed Sep 1, 2016
1 parent 03c1412 commit 48d9fef
Showing 1 changed file with 21 additions and 4 deletions.
25 changes: 21 additions & 4 deletions src/vld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ PBYTE NtDllFindParamAddress(const PBYTE pAddress)
PBYTE ptr = pAddress;
// Test previous 32 bytes to find the begining address we need to patch
// for 32bit find => push [ebp][14h] => parameters are pushed to stack
// for 64bit find => mov r8,... => parameters are moved to registers r8, rdx, rcx
// for 64bit find => mov r8,... => parameters are moved to registers r8, edx, rcx
while (pAddress - --ptr < 0x20) {
#ifdef _WIN64
if (((ptr[0] & 0x4D) == ptr[0]) && (ptr[1] == 0x8B) && ((ptr[2] & 0xC7) == ptr[2])) {
if (((ptr[0] & 0x4D) >= 0x4C) && (ptr[1] == 0x8B) && ((ptr[2] & 0xC7) == ptr[2])) {
#else
if ((ptr[0] == 0xFF) && (ptr[1] == 0x75) && (ptr[2] == 0x14)) {
#endif
Expand Down Expand Up @@ -198,9 +198,26 @@ BOOL NtDllPatch(const PBYTE pReturnAddress, NTDLL_LDR_PATCH &NtDllPatch)
memset(NtDllPatch.pDetourAddress, 0x90, NtDllPatch.nDetourSize);
#ifdef _WIN64
// Copy original param instructions
memcpy(&NtDllPatch.pDetourAddress[0], NtDllPatch.pPatchAddress, nParamSize);
memcpy(NtDllPatch.pDetourAddress, NtDllPatch.pPatchAddress, nParamSize);

BYTE reg = 0x00;

LPBYTE icall = NtDllPatch.pPatchAddress + nParamSize - (3 /*instruction size*/ + sizeof(DWORD));
if ((*(LPDWORD)icall & 0x00'0D'8B'4C) == 0x00'0D'8B'4C) {
// From Windows 10 (1607) calls to the EntryPoint are dispatched through
// __guard_dispatch_icall_fptr. In such case correct the relative address.
DWORD fptr = *(LPDWORD)(icall + 3) + (3 /*instruction size*/ + sizeof(DWORD)) - (DWORD)(NtDllPatch.pDetourAddress - NtDllPatch.pPatchAddress);
memcpy(NtDllPatch.pDetourAddress + nParamSize - sizeof(DWORD), &fptr, sizeof(DWORD));

// Additionally in such case the EntryPoint is held in another register
// that was moved to rax. In such case identify the correct register
// holding the EntryPoint
reg = ((*(icall - 3) & 0xF1) == 0x41 ? 0x08 : 0x00) + (*(icall - 1) & 0x07);
} else {
reg = ((pCallAddress[0] & 0xF1) == 0x41 ? 0x08 : 0x00) + (pCallAddress[pReturnAddress - pCallAddress - 1] & 0x07);
}

// Copy the register that holds the EntryPoint to r9
BYTE reg = ((pCallAddress[0] & 0xF1) == 0x41 ? 0x08 : 0x00) + (pCallAddress[pReturnAddress - pCallAddress - 1] & 0x07);
ptr[0] = 0x4C + ((reg & 0x08) ? 0x01 : 0x00);
ptr[2] = 0xC8 + (reg & 0x07);
memcpy(&NtDllPatch.pDetourAddress[nParamSize], &ptr, _countof(ptr));
Expand Down

3 comments on commit 48d9fef

@DraconPern
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this and it works on Windows 7 64 and Windows 10 Enterprise 1607

@umvarma
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not able to compile the WIN64 configuration on Windows 10, Visual Studio 2012 and Visual Studio 2013 with this patch. I get compiler errors in line number 206. Is "0x00'0D'8B'4C" valid in C/C++?

@ioannis-e
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is valid in C++17 which is supported by VS2015, remove ' from the number to compile the line in VS2013

Please sign in to comment.