@@ -1,21 +1,22 @@ | |||
/* | |||
\todo: | |||
What if there's a loop in the function which loops back to an overwritten instruction? | |||
start: | |||
jmp hook_function | |||
bla | |||
jXX start+3 | |||
*/ | |||
// todo: on weird jump: stop the disassembling there or treat as normal instruction? | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <assert.h> | |||
#include <stdbool.h> | |||
#include <Windows.h> | |||
#include <stddef.h> | |||
#ifdef WINDOWS | |||
#include <windows.h> | |||
#else | |||
#include <sys/mman.h> | |||
#include <string.h> | |||
#endif | |||
#include "udis86.h" | |||
#include "list.h" | |||
#include "hook.h" | |||
#include "misc.h" | |||
#define MINIMUM_REQUIRED_FUNCTION_LENGTH_SHORT_HOOK 5 | |||
#define MINIMUM_REQUIRED_FUNCTION_LENGTH_LONG_HOOK 16 | |||
@@ -93,6 +94,9 @@ int hook(void* function, size_t functionLength, void* replacement, void** trampo | |||
return (int)*trampoline; | |||
printf("Needed for trampoline %p: %d (Found %d)\n", *trampoline, trampolineSizeNeeded, functionLength); | |||
#ifdef WINDOWS | |||
FlushInstructionCache(GetCurrentProcess(), function, needed); | |||
#endif | |||
return SUCCESS; | |||
} | |||
@@ -111,7 +115,7 @@ static void* build_trampoline(void* function, size_t functionSize, size_t* tramp | |||
*trampolineSize = 0; | |||
if(!(trampoline = VirtualAlloc(NULL, PAGE_BOUNDARY, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE))) | |||
if(!(trampoline = alloc_rwx(PAGE_BOUNDARY))) | |||
return (void*)CANT_ALLOC; | |||
printf("trampoline @ %p\n", trampoline); | |||
@@ -136,7 +140,7 @@ static void* build_trampoline(void* function, size_t functionSize, size_t* tramp | |||
// Check for XXX [rip + ?] | |||
const struct ud_operand* op = NULL; | |||
for(int i = 0; op = ud_insn_opr(&ud, i); i++) | |||
for(int i = 0; ; i++, op = ud_insn_opr(&ud, i)) | |||
{ | |||
if((op->type & UD_OP_REG) == UD_OP_REG) | |||
{ | |||
@@ -226,7 +230,7 @@ static int32_t get_rip_delta(ud_t* ud) | |||
const struct ud_operand* op = NULL; | |||
int32_t ret = 0; | |||
for(int i = 0; op = ud_insn_opr(ud, i); i++) | |||
for(int i = 0; ; i++, op = ud_insn_opr(ud, i)) | |||
{ | |||
// Only the RIP offset is interesting | |||
if((op->type & UD_OP_REG) != UD_OP_REG || op->base != UD_R_RIP) | |||
@@ -271,7 +275,7 @@ static size_t write_jcc_jump(const uint8_t* instruction, void* whereToWrite, voi | |||
static size_t get_jump_offset(ud_t* ud, size_t offsetOfInstr) | |||
{ | |||
const struct ud_operand* op = NULL; | |||
for(int i = 0; op = ud_insn_opr(ud, i); i++) | |||
for(int i = 0; ; i++, op = ud_insn_opr(ud, i)) | |||
{ | |||
if(op->type == UD_OP_JIMM) | |||
{ | |||
@@ -360,8 +364,3 @@ static size_t write_x64_jump(unsigned char* where, void* toWhere) | |||
return sizeof(jmpMemTemplate)+sizeof(toWhere); | |||
} | |||
//! fixme: | |||
static bool loops_into_overwritten_code(void* function) | |||
{ | |||
return false; | |||
} |
@@ -15,7 +15,8 @@ typedef enum HOOK_STATUS | |||
/** | |||
\brief | |||
\param functionLength Length of the function you want to hook. If the length isn't known, pass 0 and the library will try to figure it out | |||
\param functionLength Length of the function you want to hook. | |||
If the length isn't known, pass 0 and the library will try to figure it out | |||
*/ | |||
int hook(void* function, size_t functionLength, void* replacement, void* trampoline); | |||
@@ -1,5 +1,4 @@ | |||
#include <stdio.h> | |||
#include <Windows.h> | |||
#include "misc.h" | |||
#include "hook.h" | |||
@@ -47,8 +46,9 @@ int main(int argc, char** argv) | |||
original(3, 1, 1, 1, 1); | |||
//original(5, 1, 1, 1, 1); | |||
#if WINDOWS | |||
VirtualFree(original, 0, MEM_RELEASE); | |||
#endif | |||
(void)getc(stdin); | |||
} | |||
@@ -1,15 +1,43 @@ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <stdbool.h> | |||
#include <string.h> | |||
#ifdef WINDOWS | |||
#include <windows.h> | |||
#else | |||
#include <sys/mman.h> | |||
#endif | |||
#include "udis86.h" | |||
#include "misc.h" | |||
void* alloc_rwx(size_t size) { | |||
#ifdef WINDOWS | |||
return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWIRTE); | |||
#else | |||
return mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |||
#endif | |||
} | |||
bool set_rwx(void* addr, size_t size) { | |||
#ifdef WINDOWS | |||
DWORD tmp; | |||
return VirtualProtect(addr, size, PAGE_EXECUTE_READWIRTE, &tmp) == TRUE; | |||
#else | |||
return mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC) == 0; | |||
#endif | |||
} | |||
void disassemble_func(void* function, size_t numberOfInstr) | |||
{ | |||
unsigned char* p = function; | |||
ud_t ud; | |||
ud_init(&ud); | |||
ud_set_input_buffer(&ud, function, (size_t)function | (0x1000 - 1)); // Can't read further than page boundary - there be dragons | |||
ud_set_input_buffer(&ud, function, | |||
(size_t)function | (0x1000 - 1) // Can't read further than page boundary - there be dragons | |||
); | |||
ud_set_pc(&ud, (uint64_t)function); | |||
ud_set_mode(&ud, 64); | |||
ud_set_syntax(&ud, UD_SYN_INTEL); | |||
@@ -24,8 +52,15 @@ void disassemble_func(void* function, size_t numberOfInstr) | |||
printf("%p %s\n", ud_insn_off(&ud), ud_insn_asm(&ud)); | |||
// ugly, ugly hack todo: make it work | |||
/* jmp qword [rip] is used by the hooking engine | |||
* x64 relative jumps don't exists so this way is used: | |||
* jmp qword [rip] | |||
* address where to tjump to | |||
* other code | |||
* Disassembling the address fucks up the dissassembling | |||
* todo: Follow all jump targets? | |||
*/ | |||
if(strcmp(ud_insn_asm(&ud), "jmp qword [rip]") == 0) | |||
p += 8; | |||
} | |||
} | |||
} |
@@ -2,5 +2,7 @@ | |||
#define MISC_H | |||
void disassemble_func(void* func, size_t numberOfInstr); | |||
bool set_rwx(void* addr, size_t size); | |||
#endif MISC_H | |||
void* alloc_rwx(size_t size); | |||
#endif MISC_H |