Skip to content

Commit

Permalink
Fix for Windows arm64
Browse files Browse the repository at this point in the history
  • Loading branch information
kubo committed Mar 12, 2023
1 parent 5090f4b commit 432bfee
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 9 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ if(NOT FUNCHOOK_CPU)
if (FUNCHOOK_CPU MATCHES "aarch64")
set(FUNCHOOK_CPU arm64)
endif ()
if (FUNCHOOK_CPU MATCHES "ARM64")
set(FUNCHOOK_CPU arm64)
endif ()
endif ()

if (FUNCHOOK_CPU MATCHES "arm64")
Expand Down
2 changes: 1 addition & 1 deletion src/funchook.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ static int funchook_prepare_internal(funchook_t *funchook, void **target_func, v
for (i = 0; i < LITERAL_POOL_NUM; i++) {
size_t *addr = (size_t*)(entry->trampoline + LITERAL_POOL_OFFSET + i * 2);
if (*addr != 0) {
funchook_log(funchook, " %016lx : 0x%lx\n", (size_t)addr, *addr);
funchook_log(funchook, " "ADDR_FMT" : 0x%"PRIxPTR"\n", (size_t)addr, *addr);
}
}
#endif
Expand Down
13 changes: 10 additions & 3 deletions src/funchook_arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ static int to_regno(funchook_t *funchook, uint32_t avail_regs, uint32_t *regno)
static int funchook_write_jump32(funchook_t *funchook, const uint32_t *src, const uint32_t *dst, uint32_t *out)
{
intptr_t imm = ROUND_DOWN((size_t)dst, PAGE_SIZE) - ROUND_DOWN((size_t)src, PAGE_SIZE);
size_t immlo = (imm >> 12) & 0x03;
size_t immhi = (imm >> 14) & 0x7FFFFul;
uint32_t immlo = (uint32_t)(imm >> 12) & 0x03;
uint32_t immhi = (uint32_t)(imm >> 14) & 0x7FFFFul;

/* adrp x9, dst */
out[0] = 0x90000009 | (immlo << 29) | (immhi << 5);
Expand Down Expand Up @@ -170,7 +170,7 @@ int funchook_make_trampoline(funchook_t *funchook, ip_displacement_t *disp, cons
size_t *literal_pool = (size_t*)(trampoline + LITERAL_POOL_OFFSET);

#define LDR_ADDR(regno, addr) do { \
int imm19__ = ((size_t)literal_pool - (size_t)ctx.dst) >> 2; \
int imm19__ = (int)((size_t)literal_pool - (size_t)ctx.dst) >> 2; \
*(literal_pool++) = (addr); \
*(ctx.dst++) = 0x58000000 | TO_IMM19(imm19__) | (regno); \
} while (0)
Expand Down Expand Up @@ -319,6 +319,13 @@ int funchook_make_trampoline(funchook_t *funchook, ip_displacement_t *disp, cons
break;
}
ctx.src++;

// special case
if ((func[0] & 0xFC000000) == 0x14000000 && (func[1] & 0xFFFF0000) == 0) {
// The first instruction is B (unconditional jump).
// The second is UDF (permanently undefined).
ctx.src = func + 2;
}
if (ctx.src - func >= JUMP32_SIZE) {
rv = to_regno(funchook, avail_regs, &regno);
if (rv != 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/funchook_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
#define ADDR_FMT "%08" PRIxPTR
#endif

#if defined __aarch64__
#if defined _M_ARM64 || defined __aarch64__
#define CPU_ARM64
#define CPU_64BIT
#endif
Expand Down
31 changes: 29 additions & 2 deletions src/funchook_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
*/
#define PSAPI_VERSION 1
#include <stdint.h>
#include <stdio.h>
#include <windows.h>
#include <psapi.h>
#include "funchook_internal.h"
Expand Down Expand Up @@ -87,7 +88,7 @@ static int alloc_page_info(funchook_t *funchook, page_list_t **pl_out, void *hin
{
void *addr;
page_list_t *pl;
#ifdef CPU_X86_64
#ifdef CPU_64BIT
void *old_hint = hint;
while (1) {
MEMORY_BASIC_INFORMATION mbi;
Expand Down Expand Up @@ -339,7 +340,7 @@ void *funchook_resolve_func(funchook_t *funchook, void *func)
HMODULE hMod;
BOOL ok;
IMAGE_IMPORT_DESCRIPTOR *desc_head, *desc;
uint8_t *fn = (uint8_t*)func;
insn_t *fn = (insn_t*)func;
size_t pos = 0;
DWORD cnt;

Expand All @@ -349,6 +350,7 @@ void *funchook_resolve_func(funchook_t *funchook, void *func)
funchook_log(funchook, " func %p is in %.*s\n", func, (int)len, path);
}
}
#if defined CPU_X86 || defined CPU_X86_64
if (fn[0] == 0xe9) {
fn = (fn + 5) + *(int*)(fn + 1);
funchook_log(funchook, " relative jump to %p\n", fn);
Expand All @@ -361,6 +363,31 @@ void *funchook_resolve_func(funchook_t *funchook, void *func)
#endif
funchook_log(funchook, " indirect jump to addresss at %p\n", (void*)pos);
}
#endif
#if defined CPU_ARM64
#define ADRP_XIP0 0x90000010
#define ADRP_XIP0_MASK 0x9F00001F
#define ADRP_XIP0_IMMLO 0x60000000
#define ADRP_XIP0_IMMHI 0x00FFFFE0
#define LDR_XIP0 0xF9400210
#define LDR_XIP0_MASK 0xFFC003FF
#define LDR_XIP0_IMM12 0x003FFC00
#define BR_XIP0 0xD61F0200
if ((fn[0] & ADRP_XIP0_MASK) == ADRP_XIP0 &&
(fn[1] & LDR_XIP0_MASK) == LDR_XIP0 &&
fn[2] == BR_XIP0) {
// fn[0]: addrp xip0, immhi&immlo
// fn[1]: ldr xip0, [xip0,imm12]
// fn[2]: br xip0
size_t addr = (size_t)fn & ~((1 << 12) - 1);
size_t immhi = ((size_t)(fn[0] & ADRP_XIP0_IMMHI) >> 5) << (12 + 2);
size_t immlo = ((size_t)(fn[0] & ADRP_XIP0_IMMLO) >> 29) << 12;
size_t imm12 = ((size_t)(fn[1] & LDR_XIP0_IMM12) >> 10) << 3;
pos = addr + immhi + immlo + imm12;
// fprintf(stderr, "%016I64x: %08x %08x %08x : %I64x %I64x %I64x %I64x\n", (size_t)fn, fn[0], fn[1], fn[2], addr, immhi, immlo, imm12);
funchook_log(funchook, " indirect jump to addresss at %p\n", (void*)pos);
}
#endif
if (pos == 0) {
return func;
}
Expand Down
7 changes: 5 additions & 2 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ if (FUNCHOOK_CPU STREQUAL x86)
endif ()


if (MSVC)
if (NOT MSVC)
set(FUNCHOOK_ASM_SUFFIX _gas.S)
elseif (FUNCHOOK_CPU MATCHES "^x86")
enable_language(ASM_MASM)
set(FUNCHOOK_ASM_SUFFIX _masm.asm)
else ()
set(FUNCHOOK_ASM_SUFFIX _gas.S)
set(FUNCHOOK_CPU noasm)
set(FUNCHOOK_ASM_SUFFIX .c)
endif ()

add_library(funchook_test SHARED libfunchook_test.c libfunchook_test_${FUNCHOOK_CPU}${FUNCHOOK_ASM_SUFFIX})
Expand Down
19 changes: 19 additions & 0 deletions test/libfunchook_test_noasm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifdef WIN32
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif

extern int get_val_in_dll(void);

DLLEXPORT
int call_get_val_in_dll(void)
{
return get_val_in_dll();
}

DLLEXPORT
int jump_get_val_in_dll(void)
{
return get_val_in_dll();
}

0 comments on commit 432bfee

Please sign in to comment.