mirror of
https://gitlab.com/Mr_Goldberg/goldberg_emulator.git
synced 2025-12-06 12:14:54 +01:00
Update detours library.
This commit is contained in:
parent
3b3dc98b3a
commit
7039d10159
7 changed files with 308 additions and 176 deletions
|
|
@ -7,33 +7,15 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
|
||||
#pragma warning(disable:4068) // unknown pragma (suppress)
|
||||
|
||||
#if _MSC_VER >= 1900
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4091) // empty typedef
|
||||
#endif
|
||||
|
||||
#define _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 1
|
||||
#include <windows.h>
|
||||
|
||||
#if (_MSC_VER < 1299)
|
||||
#pragma warning(disable: 4710)
|
||||
#endif
|
||||
|
||||
//#define DETOUR_DEBUG 1
|
||||
#define DETOURS_INTERNAL
|
||||
|
||||
#include "detours.h"
|
||||
|
||||
#if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH
|
||||
#error detours.h version mismatch
|
||||
#endif
|
||||
|
||||
#if _MSC_VER >= 1900
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#define NOTHROW
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -880,7 +862,8 @@ struct _DETOUR_TRAMPOLINE
|
|||
{
|
||||
// An ARM64 instruction is 4 bytes long.
|
||||
//
|
||||
// The overwrite is always 2 instructions plus a literal, so 16 bytes, 4 instructions.
|
||||
// The overwrite is always composed of 3 instructions (12 bytes) which perform an indirect jump
|
||||
// using _DETOUR_TRAMPOLINE::pbDetour as the address holding the target location.
|
||||
//
|
||||
// Copied instructions can expand.
|
||||
//
|
||||
|
|
@ -915,7 +898,7 @@ struct _DETOUR_TRAMPOLINE
|
|||
C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 184);
|
||||
|
||||
enum {
|
||||
SIZE_OF_JMP = 16
|
||||
SIZE_OF_JMP = 12
|
||||
};
|
||||
|
||||
inline ULONG fetch_opcode(PBYTE pbCode)
|
||||
|
|
@ -929,6 +912,79 @@ inline void write_opcode(PBYTE &pbCode, ULONG Opcode)
|
|||
pbCode += 4;
|
||||
}
|
||||
|
||||
struct ARM64_INDIRECT_JMP {
|
||||
struct {
|
||||
ULONG Rd : 5;
|
||||
ULONG immhi : 19;
|
||||
ULONG iop : 5;
|
||||
ULONG immlo : 2;
|
||||
ULONG op : 1;
|
||||
} ardp;
|
||||
|
||||
struct {
|
||||
ULONG Rt : 5;
|
||||
ULONG Rn : 5;
|
||||
ULONG imm : 12;
|
||||
ULONG opc : 2;
|
||||
ULONG iop1 : 2;
|
||||
ULONG V : 1;
|
||||
ULONG iop2 : 3;
|
||||
ULONG size : 2;
|
||||
} ldr;
|
||||
|
||||
ULONG br;
|
||||
};
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4201)
|
||||
|
||||
union ARM64_INDIRECT_IMM {
|
||||
struct {
|
||||
ULONG64 pad : 12;
|
||||
ULONG64 adrp_immlo : 2;
|
||||
ULONG64 adrp_immhi : 19;
|
||||
};
|
||||
|
||||
LONG64 value;
|
||||
};
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
PBYTE detour_gen_jmp_indirect(BYTE *pbCode, ULONG64 *pbJmpVal)
|
||||
{
|
||||
// adrp x17, [jmpval]
|
||||
// ldr x17, [x17, jmpval]
|
||||
// br x17
|
||||
|
||||
struct ARM64_INDIRECT_JMP *pIndJmp;
|
||||
union ARM64_INDIRECT_IMM jmpIndAddr;
|
||||
|
||||
jmpIndAddr.value = (((LONG64)pbJmpVal) & 0xFFFFFFFFFFFFF000) -
|
||||
(((LONG64)pbCode) & 0xFFFFFFFFFFFFF000);
|
||||
|
||||
pIndJmp = (struct ARM64_INDIRECT_JMP *)pbCode;
|
||||
pbCode = (BYTE *)(pIndJmp + 1);
|
||||
|
||||
pIndJmp->ardp.Rd = 17;
|
||||
pIndJmp->ardp.immhi = jmpIndAddr.adrp_immhi;
|
||||
pIndJmp->ardp.iop = 0x10;
|
||||
pIndJmp->ardp.immlo = jmpIndAddr.adrp_immlo;
|
||||
pIndJmp->ardp.op = 1;
|
||||
|
||||
pIndJmp->ldr.Rt = 17;
|
||||
pIndJmp->ldr.Rn = 17;
|
||||
pIndJmp->ldr.imm = (((ULONG64)pbJmpVal) & 0xFFF) / 8;
|
||||
pIndJmp->ldr.opc = 1;
|
||||
pIndJmp->ldr.iop1 = 1;
|
||||
pIndJmp->ldr.V = 0;
|
||||
pIndJmp->ldr.iop2 = 7;
|
||||
pIndJmp->ldr.size = 3;
|
||||
|
||||
pIndJmp->br = 0xD61F0220;
|
||||
|
||||
return pbCode;
|
||||
}
|
||||
|
||||
PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal)
|
||||
{
|
||||
PBYTE pbLiteral;
|
||||
|
|
@ -995,7 +1051,7 @@ inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals)
|
|||
the bottom 12 bits cleared to zero, and then writes the result to a general-purpose register. This permits the
|
||||
calculation of the address at a 4KB aligned memory region. In conjunction with an ADD (immediate) instruction, or
|
||||
a Load/Store instruction with a 12-bit immediate offset, this allows for the calculation of, or access to, any address
|
||||
within ±4GB of the current PC.
|
||||
within +/- 4GB of the current PC.
|
||||
|
||||
PC-rel. addressing
|
||||
This section describes the encoding of the PC-rel. addressing instruction class. The encodings in this section are
|
||||
|
|
@ -1062,7 +1118,10 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
|
|||
PDETOUR_TRAMPOLINE *ppLower,
|
||||
PDETOUR_TRAMPOLINE *ppUpper)
|
||||
{
|
||||
// We have to place trampolines within +/- 2GB of code.
|
||||
// The encoding used by detour_gen_jmp_indirect actually enables a
|
||||
// displacement of +/- 4GiB. In the future, this could be changed to
|
||||
// reflect that. For now, just reuse the x86 logic which is plenty.
|
||||
|
||||
ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
|
||||
ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
|
||||
DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi));
|
||||
|
|
@ -1250,6 +1309,65 @@ static PVOID detour_alloc_region_from_hi(PBYTE pbLo, PBYTE pbHi)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static PVOID detour_alloc_trampoline_allocate_new(PBYTE pbTarget,
|
||||
PDETOUR_TRAMPOLINE pLo,
|
||||
PDETOUR_TRAMPOLINE pHi)
|
||||
{
|
||||
PVOID pbTry = NULL;
|
||||
|
||||
// NB: We must always also start the search at an offset from pbTarget
|
||||
// in order to maintain ASLR entropy.
|
||||
|
||||
#if defined(DETOURS_64BIT)
|
||||
// Try looking 1GB below or lower.
|
||||
if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) {
|
||||
pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget - 0x40000000);
|
||||
}
|
||||
// Try looking 1GB above or higher.
|
||||
if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) {
|
||||
pbTry = detour_alloc_region_from_lo(pbTarget + 0x40000000, (PBYTE)pHi);
|
||||
}
|
||||
// Try looking 1GB below or higher.
|
||||
if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) {
|
||||
pbTry = detour_alloc_region_from_lo(pbTarget - 0x40000000, pbTarget);
|
||||
}
|
||||
// Try looking 1GB above or lower.
|
||||
if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) {
|
||||
pbTry = detour_alloc_region_from_hi(pbTarget, pbTarget + 0x40000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Try anything below.
|
||||
if (pbTry == NULL) {
|
||||
pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget);
|
||||
}
|
||||
// try anything above.
|
||||
if (pbTry == NULL) {
|
||||
pbTry = detour_alloc_region_from_lo(pbTarget, (PBYTE)pHi);
|
||||
}
|
||||
|
||||
return pbTry;
|
||||
}
|
||||
|
||||
PVOID WINAPI DetourAllocateRegionWithinJumpBounds(_In_ LPCVOID pbTarget,
|
||||
_Out_ PDWORD pcbAllocatedSize)
|
||||
{
|
||||
PDETOUR_TRAMPOLINE pLo;
|
||||
PDETOUR_TRAMPOLINE pHi;
|
||||
detour_find_jmp_bounds((PBYTE)pbTarget, &pLo, &pHi);
|
||||
|
||||
PVOID pbNewlyAllocated =
|
||||
detour_alloc_trampoline_allocate_new((PBYTE)pbTarget, pLo, pHi);
|
||||
if (pbNewlyAllocated == NULL) {
|
||||
DETOUR_TRACE(("Couldn't find available memory region!\n"));
|
||||
*pcbAllocatedSize = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*pcbAllocatedSize = DETOUR_REGION_SIZE;
|
||||
return pbNewlyAllocated;
|
||||
}
|
||||
|
||||
static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget)
|
||||
{
|
||||
// We have to place trampolines within +/- 2GB of target.
|
||||
|
|
@ -1294,41 +1412,10 @@ static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget)
|
|||
// Round pbTarget down to 64KB block.
|
||||
pbTarget = pbTarget - (PtrToUlong(pbTarget) & 0xffff);
|
||||
|
||||
PVOID pbTry = NULL;
|
||||
|
||||
// NB: We must always also start the search at an offset from pbTarget
|
||||
// in order to maintain ASLR entropy.
|
||||
|
||||
#if defined(DETOURS_64BIT)
|
||||
// Try looking 1GB below or lower.
|
||||
if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) {
|
||||
pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget - 0x40000000);
|
||||
}
|
||||
// Try looking 1GB above or higher.
|
||||
if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) {
|
||||
pbTry = detour_alloc_region_from_lo(pbTarget + 0x40000000, (PBYTE)pHi);
|
||||
}
|
||||
// Try looking 1GB below or higher.
|
||||
if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) {
|
||||
pbTry = detour_alloc_region_from_lo(pbTarget - 0x40000000, pbTarget);
|
||||
}
|
||||
// Try looking 1GB above or lower.
|
||||
if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) {
|
||||
pbTry = detour_alloc_region_from_hi(pbTarget, pbTarget + 0x40000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Try anything below.
|
||||
if (pbTry == NULL) {
|
||||
pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget);
|
||||
}
|
||||
// try anything above.
|
||||
if (pbTry == NULL) {
|
||||
pbTry = detour_alloc_region_from_lo(pbTarget, (PBYTE)pHi);
|
||||
}
|
||||
|
||||
if (pbTry != NULL) {
|
||||
s_pRegion = (DETOUR_REGION*)pbTry;
|
||||
PVOID pbNewlyAllocated =
|
||||
detour_alloc_trampoline_allocate_new(pbTarget, pLo, pHi);
|
||||
if (pbNewlyAllocated != NULL) {
|
||||
s_pRegion = (DETOUR_REGION*)pbNewlyAllocated;
|
||||
s_pRegion->dwSignature = DETOUR_REGION_SIGNATURE;
|
||||
s_pRegion->pFree = NULL;
|
||||
s_pRegion->pNext = s_pRegions;
|
||||
|
|
@ -1655,7 +1742,7 @@ LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer)
|
|||
#endif // DETOURS_ARM
|
||||
|
||||
#ifdef DETOURS_ARM64
|
||||
PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, NULL, o->pTrampoline->pbDetour);
|
||||
PBYTE pbCode = detour_gen_jmp_indirect(o->pbTarget, (ULONG64*)&(o->pTrampoline->pbDetour));
|
||||
pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain);
|
||||
*o->ppbPointer = o->pTrampoline->rbCode;
|
||||
UNREFERENCED_PARAMETER(pbCode);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue