// start of the function to inject always happens to be 2 bytes long.
? this is not reliable, this my modification:
fill 32 nop in the begin of injectSharedLibrary to ensure the code copy to target is clean.
the second question is that why the last INT 3 inst. not supply in injectSharedLibrary but find and replace the RET inst. ?
the .patch:
Index:
inject-x86_64.c
===================================================================
--- inject-x86_64.c (revision 654940)
+++ inject-x86_64.c (working copy)
@@ -25,6 +25,13 @@
void injectSharedLibrary(long mallocaddr, long freeaddr, long dlopenaddr)
{
+ // add nop in the function head, so that we can jump into it for diff c-compiler optimize
+ asm(
+ "nop \nnop \nnop \nnop \nnop \nnop \nnop \nnop \n"
+ "nop \nnop \nnop \nnop \nnop \nnop \nnop \nnop \n"
+ "nop \nnop \nnop \nnop \nnop \nnop \nnop \nnop \n"
+ "nop \nnop \nnop \nnop \nnop \nnop \nnop \nnop \n"
+ );
// here are the assumptions I'm making about what data will be located
// where at the time the target executes this code:
//
@@ -103,7 +110,9 @@
// call free()
"callq *%rbx \n"
// restore previous rbx value
- "pop %rbx"
+ "pop %rbx \n"
+ // break to restore everything
+ "int $3"
);
// we already overwrote the RET instruction at the end of this function
@@ -223,8 +232,12 @@
regs.rcx = libPathLength;
ptrace_setregs(target, ®s);
+ // +30 to skip function header(we have 32 nop after the header)
+ // ensure clean code is copied
+ void *safeInjectSharedLibrary = (void *)((intptr_t)injectSharedLibrary + 30);
+
// figure out the size of injectSharedLibrary() so we know how big of a buffer to allocate.
- size_t injectSharedLibrary_size = (intptr_t)injectSharedLibrary_end - (intptr_t)injectSharedLibrary;
+ size_t injectSharedLibrary_size = (intptr_t)injectSharedLibrary_end - (intptr_t)safeInjectSharedLibrary;
// also figure out where the RET instruction at the end of
// injectSharedLibrary() lies so that we can overwrite it with an INT 3
@@ -233,7 +246,6 @@
// which means that functions are padded with NOPs. as a result, even
// though we've found the length of the function, it is very likely
// padded with NOPs, so we need to actually search to find the RET.
- intptr_t injectSharedLibrary_ret = (intptr_t)findRet(injectSharedLibrary_end) - (intptr_t)injectSharedLibrary;
// back up whatever data used to be at the address we want to modify.
char* backup = malloc(injectSharedLibrary_size * sizeof(char));
@@ -245,9 +257,8 @@
memset(newcode, 0, injectSharedLibrary_size * sizeof(char));
// copy the code of injectSharedLibrary() to a buffer.
- memcpy(newcode, injectSharedLibrary, injectSharedLibrary_size - 1);
+ memcpy(newcode, safeInjectSharedLibrary, injectSharedLibrary_size);
// overwrite the RET instruction with an INT 3.
- newcode[injectSharedLibrary_ret] = INTEL_INT3_INSTRUCTION;
// copy injectSharedLibrary()'s code to the target address inside the
// target process' address space.
// start of the function to inject always happens to be 2 bytes long. ? this is not reliable, this my modification:
the second question is that why the last INT 3 inst. not supply in injectSharedLibrary but find and replace the RET inst. ?
the .patch: