EASYHOOK_NT_INTERNAL DbgRelocateRIPRelative( ULONGLONG InOffset, ULONGLONG InTargetOffset, BOOL* OutWasRelocated) { /* Description: Check whether the given instruction is RIP relative and relocates it. If it is not RIP relative, nothing is done. Parameters: - InOffset The instruction pointer to check for RIP addressing and relocate. - InTargetOffset The instruction pointer where the RIP relocation should go to. Please note that RIP relocation are relocated relative to the offset you specify here and therefore are still not absolute! - OutWasRelocated TRUE if the instruction was RIP relative and has been relocated, FALSE otherwise. */ #ifndef _M_X64 return FALSE; #else NTSTATUS NtStatus; CHAR Buf[MAX_PATH]; ULONG AsmSize; ULONG64 NextInstr; CHAR Line[MAX_PATH]; LONG Pos; LONGLONG RelAddr; LONGLONG MemDelta = InTargetOffset - InOffset; ASSERT(MemDelta == (LONG)MemDelta); *OutWasRelocated = FALSE; // test field... /*BYTE t[10] = {0x8b, 0x05, 0x12, 0x34, 0x56, 0x78}; InOffset = (LONGLONG)t; MemDelta = InTargetOffset - InOffset; */ if(!RTL_SUCCESS(DebugControl->Disassemble(InOffset, 0, Buf, sizeof(Buf), &AsmSize, &NextInstr))) THROW(STATUS_INVALID_PARAMETER_1, L"Unable to disassemble entry point. "); Pos = RtlAnsiIndexOf(Buf, '['); if(Pos < 0) RETURN; // parse content if(RtlAnsiSubString(Buf, Pos + 1, RtlAnsiIndexOf(Buf, ']') - Pos - 1, Line, MAX_PATH) != 16) RETURN; if(!RtlAnsiHexToLongLong(Line, 16, &RelAddr)) RETURN; // verify that we are really RIP relative... RelAddr -= NextInstr; if(RelAddr != (LONG)RelAddr) RETURN; if(*((LONG*)(NextInstr - 4)) != RelAddr) RETURN; /* Just relocate this instruction... */ RelAddr = RelAddr - MemDelta; if(RelAddr != (LONG)RelAddr) THROW(STATUS_NOT_SUPPORTED, L"The given entry point contains at least one RIP-Relative instruction that could not be relocated!"); // copy instruction RtlCopyMemory((void*)InTargetOffset, (void*)InOffset, (ULONG)(NextInstr - InOffset)); *((LONG*)(InTargetOffset + (NextInstr - InOffset) - 4)) = (LONG)RelAddr; *OutWasRelocated = TRUE; RETURN; THROW_OUTRO: FINALLY_OUTRO: return NtStatus; #endif }
EASYHOOK_NT_INTERNAL LhRelocateRIPRelativeInstruction( ULONGLONG InOffset, ULONGLONG InTargetOffset, BOOL* OutWasRelocated) { /* Description: Check whether the given instruction is RIP relative and relocates it. If it is not RIP relative, nothing is done. Only applicable to 64-bit processes, 32-bit will always return FALSE. Parameters: - InOffset The instruction pointer to check for RIP addressing and relocate. - InTargetOffset The instruction pointer where the RIP relocation should go to. Please note that RIP relocation are relocated relative to the offset you specify here and therefore are still not absolute! - OutWasRelocated TRUE if the instruction was RIP relative and has been relocated, FALSE otherwise. */ #ifndef _M_X64 return FALSE; #else #ifndef MAX_INSTR #define MAX_INSTR 100 #endif NTSTATUS NtStatus; CHAR Buf[MAX_INSTR]; ULONG AsmSize; ULONG64 NextInstr; CHAR Line[MAX_INSTR]; LONG Pos; LONGLONG RelAddr; LONGLONG MemDelta = InTargetOffset - InOffset; ULONGLONG RelAddrOffset = 0; LONGLONG RelAddrSign = 1; ASSERT(MemDelta == (LONG)MemDelta,L"reloc.c - MemDelta == (LONG)MemDelta"); *OutWasRelocated = FALSE; // test field... /* BYTE t[10] = {0x8b, 0x05, 0x12, 0x34, 0x56, 0x78}; // udis86 outputs: 0000000000000000 8b0512345678 mov eax, [rip+0x78563412] InOffset = (LONGLONG)t; MemDelta = InTargetOffset - InOffset; */ // Disassemble the current instruction if(!RTL_SUCCESS(LhDisassembleInstruction((void*)InOffset, &AsmSize, Buf, sizeof(Buf), &NextInstr))) THROW(STATUS_INVALID_PARAMETER_1, L"Unable to disassemble entry point. "); // Check that the address is RIP relative (i.e. look for "[rip+") Pos = RtlAnsiIndexOf(Buf, '['); if(Pos < 0) RETURN; if (Buf[Pos + 1] == 'r' && Buf[Pos + 2] == 'i' && Buf[Pos + 3] == 'p' && (Buf[Pos + 4] == '+' || Buf[Pos + 4] == '-')) { /* Support negative relative addresses https://easyhook.codeplex.com/workitem/25592 e.g. Win8.1 64-bit OLEAUT32.dll!VarBoolFromR8 Entry Point: 66 0F 2E 05 DC 25 FC FF ucomisd xmm0, [rip-0x3da24] IP:ffc46d4 Relocated: 66 0F 2E 05 10 69 F6 FF ucomisd xmm0, [rip-0x996f0] IP:100203a0 */ if (Buf[Pos + 4] == '-') RelAddrSign = -1; Pos += 4; // parse content if (RtlAnsiSubString(Buf, Pos + 1, RtlAnsiIndexOf(Buf, ']') - Pos - 1, Line, MAX_INSTR) <= 0) RETURN; // Convert HEX string to LONGLONG RelAddr = RtlAnsiHexToLongLong(Line, MAX_INSTR); if (!RelAddr) RETURN; // Apply correct sign RelAddr *= RelAddrSign; // Verify that we are really RIP relative (i.e. must be 32-bit) if(RelAddr != (LONG)RelAddr) RETURN; /* Ensure the RelAddr is equal to the RIP address in code https://easyhook.codeplex.com/workitem/25487 Thanks to Michal for pointing out that the operand will not always be at *(NextInstr - 4) e.g. Win8.1 64-bit OLEAUT32.dll!GetVarConversionLocaleSetting Entry Point: 83 3D 71 08 06 00 00 cmp dword [rip+0x60871], 0x0 IP:ffa1937 Relocated: 83 3D 09 1E 0B 00 00 cmp dword [rip+0xb1e09], 0x0 IP:ff5039f */ for (Pos = 1; Pos <= NextInstr - InOffset - 4; Pos++) { if (*((LONG*)(InOffset + Pos)) == RelAddr) { if (RelAddrOffset != 0) { // More than one offset matches the address, therefore we can't determine correct offset for operand RelAddrOffset = 0; break; } RelAddrOffset = Pos; } } if (RelAddrOffset == 0) { THROW(STATUS_INTERNAL_ERROR, L"The given entry point contains a RIP-relative instruction for which we can't determine the correct address offset!"); } /* Relocate this instruction... */ // Adjust the relative address RelAddr = RelAddr - MemDelta; // Ensure the RIP address can still be relocated if(RelAddr != (LONG)RelAddr) THROW(STATUS_NOT_SUPPORTED, L"The given entry point contains at least one RIP-Relative instruction that could not be relocated!"); // Copy instruction to target RtlCopyMemory((void*)InTargetOffset, (void*)InOffset, (ULONG)(NextInstr - InOffset)); // Correct the rip address *((LONG*)(InTargetOffset + RelAddrOffset)) = (LONG)RelAddr; *OutWasRelocated = TRUE; } RETURN; THROW_OUTRO: FINALLY_OUTRO: return NtStatus; #endif }