Skip to content

Commit

Permalink
added external hooking API
Browse files Browse the repository at this point in the history
  • Loading branch information
rdbo committed Dec 23, 2022
1 parent 40b2b17 commit bb91547
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 13 deletions.
16 changes: 12 additions & 4 deletions libmem/include/libmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -731,14 +731,17 @@ LM_UnhookCode(lm_address_t from,
lm_address_t trampoline,
lm_size_t size);

LM_API lm_bool_t
LM_HookCodeEx(lm_address_t from,
LM_API lm_size_t
LM_HookCodeEx(lm_process_t proc,
lm_address_t from,
lm_address_t to,
lm_address_t *ptrampoline);

LM_API lm_bool_t
LM_UnhookCodeEx(lm_address_t from,
lm_address_t *ptrampoline);
LM_UnhookCodeEx(lm_process_t proc,
lm_address_t from,
lm_address_t trampoline,
lm_size_t size);

/****************************************/

Expand Down Expand Up @@ -776,6 +779,11 @@ LM_API lm_size_t
LM_CodeLength(lm_address_t code,
lm_size_t minlength);

LM_API lm_size_t
LM_CodeLengthEx(lm_process_t proc,
lm_address_t code,
lm_size_t minlength);

#if LM_LANG == LM_LANG_CPP
}
#endif
Expand Down
25 changes: 25 additions & 0 deletions libmem/src/asm.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,28 @@ LM_CodeLength(lm_address_t code, lm_size_t minlength)
return length;
}

/********************************/

LM_API lm_size_t
LM_CodeLengthEx(lm_process_t proc,
lm_address_t code,
lm_size_t minlength)
{
lm_size_t length;
lm_inst_t inst;
lm_byte_t codebuf[LM_INST_SIZE];

LM_ASSERT(LM_VALID_PROCESS(proc) &&
code != LM_ADDRESS_BAD &&
minlength > 0);

for (length = 0; length < minlength; code = (lm_address_t)LM_OFFSET(code, length)) {
LM_ReadMemoryEx(proc, code, codebuf, sizeof(codebuf));
if (LM_Disassemble(codebuf, &inst) == LM_FALSE)
return 0;
length += inst.size;
}

return length;
}

108 changes: 99 additions & 9 deletions libmem/src/hook.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ _LM_GenerateHook(lm_address_t from,
/* dereference of RIP will be the jump address */
LM_CSNPRINTF(code, sizeof(code),
"jmp [rip];"
/* these NOPs will become the jump address */
/* these nops will become the jump address */
"nop; nop; nop; nop; nop; nop; nop; nop");
} else {
LM_CSNPRINTF(code, sizeof(code), "jmp %p", (void *)to);
}

size = LM_AssembleEx(code, LM_ARCH, bits, from, pcodebuf);

/* replace nops with jump address */
if (size > 0 && bits == 64) {
*(lm_uint64_t *)(
LM_OFFSET(*pcodebuf, size - sizeof(lm_uint64_t))
Expand Down Expand Up @@ -52,7 +53,7 @@ LM_HookCode(lm_address_t from,
lm_size_t codesize;
lm_size_t alignedsize;

LM_ASSERT(from != LM_NULLPTR && to != LM_NULLPTR);
LM_ASSERT(from != LM_ADDRESS_BAD && to != LM_ADDRESS_BAD);

if (!(codesize = _LM_GenerateHook(from, to, LM_BITS, &codebuf)))
return ret;
Expand All @@ -65,7 +66,6 @@ LM_HookCode(lm_address_t from,
if (!LM_ProtMemory(from, codesize, LM_PROT_XRW, &old_prot))
goto FREE_EXIT;

/* TODO: Add jump back for trampoline */
if (ptrampoline) {
/* the jump back code is the same as the hook code, but
with a different jump address */
Expand Down Expand Up @@ -93,13 +93,19 @@ LM_HookCode(lm_address_t from,
return ret;
}

/********************************/

LM_API lm_bool_t
LM_UnhookCode(lm_address_t from,
lm_address_t trampoline,
lm_size_t size)
{
lm_prot_t old_prot;

LM_ASSERT(from != LM_ADDRESS_BAD &&
trampoline != LM_ADDRESS_BAD &&
size > 0);

if (!LM_ProtMemory(from, size, LM_PROT_XRW, &old_prot))
return LM_FALSE;

Expand All @@ -111,18 +117,102 @@ LM_UnhookCode(lm_address_t from,
return LM_TRUE;
}

LM_API lm_bool_t
LM_HookCodeEx(lm_address_t from,
/********************************/

LM_API lm_size_t
LM_HookCodeEx(lm_process_t proc,
lm_address_t from,
lm_address_t to,
lm_address_t *ptrampoline)
{
/* TODO: Implement */
lm_size_t ret = 0;
lm_size_t bits;
lm_byte_t *codebuf;
lm_prot_t old_prot;
lm_size_t codesize;
lm_size_t alignedsize;

LM_ASSERT(LM_VALID_PROCESS(proc) &&
from != LM_ADDRESS_BAD &&
to != LM_ADDRESS_BAD);

bits = LM_GetProcessBitsEx(proc);

if (!(codesize = _LM_GenerateHook(from, to, bits, &codebuf)))
return ret;

/* Get minimum hook size that doesn't overwrite the existing instructions */
alignedsize = LM_CodeLengthEx(proc, from, codesize);
if (!alignedsize)
goto FREE_EXIT;

if (!LM_ProtMemoryEx(proc, from, codesize, LM_PROT_XRW, &old_prot))
goto FREE_EXIT;

if (ptrampoline) {
/* the jump back code is the same as the hook code, but
with a different jump address */
lm_byte_t *tramp_code;

tramp_code = (lm_byte_t *)LM_MALLOC(alignedsize + codesize);
if (!tramp_code)
goto FREE_EXIT;

/* read the original bytes that will be written to the trampoline */
LM_ReadMemoryEx(proc, from, tramp_code, alignedsize);

*ptrampoline = LM_AllocMemoryEx(proc,
alignedsize + codesize,
LM_PROT_XRW);
if (*ptrampoline != LM_ADDRESS_BAD) {
LM_WriteMemoryEx(proc, *ptrampoline,
tramp_code, alignedsize);

/* place jump back code on trampoline after the
original instructions */
LM_HookCodeEx(
proc,
(lm_address_t)LM_OFFSET(*ptrampoline, alignedsize),
(lm_address_t)LM_OFFSET(from, alignedsize),
LM_NULLPTR
);
}

LM_FREE(tramp_code);

if (*ptrampoline == LM_ADDRESS_BAD)
goto FREE_EXIT;
}

LM_WriteMemoryEx(proc, from, codebuf, codesize);

LM_ProtMemoryEx(proc, from, codesize, old_prot, LM_NULLPTR);

ret = alignedsize;
FREE_EXIT:
LM_FreeCodeBuffer(codebuf);

return ret;
}

/********************************/

LM_API lm_bool_t
LM_UnhookCodeEx(lm_address_t from,
lm_address_t *ptrampoline)
LM_UnhookCodeEx(lm_process_t proc,
lm_address_t from,
lm_address_t trampoline,
lm_size_t size)
{
/* TODO: Implement */
lm_prot_t old_prot;

if (!LM_ProtMemoryEx(proc, from, size, LM_PROT_XRW, &old_prot))
return LM_FALSE;

LM_WriteMemoryEx(proc, from, trampoline, size);

LM_ProtMemory(from, size, old_prot, LM_NULLPTR);
LM_FreeMemory(trampoline, size);

return LM_TRUE;
}

0 comments on commit bb91547

Please sign in to comment.