From f92e89cd172bf29780eba437feb395053d80c805 Mon Sep 17 00:00:00 2001 From: Matthew Francis-Landau Date: Fri, 6 May 2016 03:13:45 -0700 Subject: [PATCH] difficult to get internal method address that we want to ignore.... --- .gitignore | 2 + make | 39 ++++----- src/asm.s | 8 ++ src/child_manager.cc | 20 +++-- src/jit_internal.h | 33 ++++++-- src/jit_main.cc | 178 ------------------------------------------ src/main.cc | 12 ++- src/parent_manager.cc | 4 + src/redmagic.h | 6 +- src/tracer.cc | 65 ++++++++++++++- 10 files changed, 152 insertions(+), 215 deletions(-) delete mode 100644 src/jit_main.cc diff --git a/.gitignore b/.gitignore index 1e41277..fba0816 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.o jit-test .deps +build/ +release/ diff --git a/make b/make index 001b215..8185cbe 100755 --- a/make +++ b/make @@ -13,15 +13,12 @@ TARGET = 'jit-test' UNIT_TARGET = 'build/unit_tests' CXX_FLAGS = ( + '-fPIC ' '-std=c++14 ' '-I ./deps/ ' '-ggdb ' '-O0 ' - '-I ./deps/udis86' - # '-I /home/matthew/Downloads/bochs-code/bochs/cpu/ ' - # '-I /home/matthew/Downloads/bochs-code/bochs/ ' - # '-I /home/matthew/Downloads/bochs-code/bochs/instrument/stubs ' - + '-I ./deps/udis86 ' ) CXX_FLAGS_UNIT = ( '-I ./deps/catch/ ' @@ -29,13 +26,6 @@ CXX_FLAGS_UNIT = ( ) LIBS = ( '-pthread ' - 'deps/udis86/libudis86/.libs/libudis86.a ' - # '/home/matthew/Downloads/bochs-code/bochs/cpu/libcpu.a ' - # '/home/matthew/Downloads/bochs-code/bochs/logio.o ' - # '/home/matthew/Downloads/bochs-code/bochs/cpu/fpu/libfpu.a ' - # '/home/matthew/Downloads/bochs-code/bochs/cpu/cpudb/libcpudb.a ' - # '/home/matthew/Downloads/bochs-code/bochs/gui/libgui.a ' - # '-ljemalloc' ) LD_FLAGS = '' @@ -56,13 +46,19 @@ def mic(): def release(): global CXX_FLAGS - CXX_FLAGS = CXX_FLAGS.replace('-O0', '-O3') + CXX_FLAGS = CXX_FLAGS.replace('-O0', '-O2') CXX_FLAGS = CXX_FLAGS.replace('-ggdb', '') + CXX_FLAGS += ' -DNDEBUG' build() + Run('mkdir -p release') + Run('cp build/libredmagic.so.1.0.0 release/') + Run('cp src/redmagic.h release/') + Run('strip --strip-unneeded -w -K redmagic_* release/libredmagic.so.1.0.0') + def clean(): - Shell('cd deps/udis86 && make clean', shell=True) autoclean() + Shell('cd deps/udis86 && make clean', shell=True) def run(): build() @@ -75,8 +71,15 @@ def debug(): )) def link(): - objs = ' '.join(filter(lambda x: 'unit_' not in x, glob.glob('build/*.o'))) - Run('{CXX} {LD_FLAGS} -o {TARGET} {objs} {LIBS}'.format( + objs = ' '.join(filter(lambda x: 'unit_' not in x and 'main.o' not in x, glob.glob('build/*.o'))) + # Run('ar rcs build/redmagic.a {objs} {LIBRARY_LIBS}'.format( + # **dict(globals(), **locals()) + # )) + udis_libs = ' '.join(glob.glob('deps/udis86/libudis86/.libs/*.o')) + Run('{LD} -shared -fPIC -Wl,-soname,libredmagic.so.1.0.0 -o build/libredmagic.so.1.0.0 {objs} {udis_libs} {LIBS}'.format( + **dict(globals(), **locals()) + )) + Run('{LD} {LD_FLAGS} -o {TARGET} build/main.o build/libredmagic.so.1.0.0 -Wl,-rpath=$ORIGIN/build/'.format( **dict(globals(), **locals()) )) after() @@ -119,8 +122,8 @@ def unit(): def deps(): # udis86 version 1.7.2 - if not os.path.isfile('deps/udis86/libudis86/.libs/libudis86.a'): - Shell('cd deps/udis86 && ./autogen.sh && PYTHON=`which python2` ./configure --enable-static && make', shell=True) + if not os.path.isfile('deps/udis86/libudis86/.libs/libudis86.so') or not os.path.isfile('deps/udis86/libudis86/itab.h'): + Shell('cd deps/udis86 && ./autogen.sh && PYTHON=`which python2` ./configure && make', shell=True) after() diff --git a/src/asm.s b/src/asm.s index 30a0ac0..5c13d72 100644 --- a/src/asm.s +++ b/src/asm.s @@ -19,3 +19,11 @@ red_asm_end_trace: red_asm_begin_trace: int3 ret + + + .global red_asm_return_after_method_call +red_asm_return_after_method_call: + # at this point we will replace the instruction pointer with where we should have returned to + int3 + # this next line will never run + jmp red_asm_return_after_method_call diff --git a/src/child_manager.cc b/src/child_manager.cc index 012ef94..3825bf9 100644 --- a/src/child_manager.cc +++ b/src/child_manager.cc @@ -19,19 +19,24 @@ extern "C" void redmagic_backwards_branch(void *id) { child_manager->backwards_branch(id); } -extern "C" void redmagic_force_begin_trace() { +extern "C" void redmagic_force_begin_trace(void *id) { child_manager->begin_trace(); } -extern "C" void redmagic_force_end_trace() { +extern "C" void redmagic_force_end_trace(void *id) { child_manager->end_trace(); } +extern "C" void redmagic_force_jump_to_trace(void *id) { + +} + extern "C" { - void red_asm_temp_disable_trace (); - void red_asm_temp_enable_trace (); - void red_asm_end_trace (); - void red_asm_begin_trace (); + void red_asm_temp_disable_trace(); + void red_asm_temp_enable_trace(); + void red_asm_end_trace(); + void red_asm_begin_trace(); + void red_asm_return_after_method_call(); } namespace redmagic { @@ -40,6 +45,7 @@ namespace redmagic { { red_asm_temp_enable_trace, TEMP_ENABLE_ACT }, { red_asm_end_trace, END_TRACE_ACT }, { red_asm_begin_trace, BEGIN_TRACE_ACT }, + { red_asm_return_after_method_call, RETURN_FROM_METHOD_ACT }, { NULL, MAX_ACT } }; } @@ -100,7 +106,7 @@ void ChildManager::end_trace() { if(!is_traced) { perror("ending trace when was not started\n"); } - asm("act_end_trace: int3"); + red_asm_end_trace(); is_traced = false; } diff --git a/src/jit_internal.h b/src/jit_internal.h index 468fdc2..b67f64f 100644 --- a/src/jit_internal.h +++ b/src/jit_internal.h @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include @@ -84,11 +86,13 @@ namespace redmagic { void set_program_pval(mem_loc_t where, uint8_t what); int get_program_pval(mem_loc_t where); + bool is_ignored_method(mem_loc_t where); private: int send_pipe, recv_pipe; pid_t child_pid; std::map tracers; std::map program_map; + std::set ignored_methods; }; class Tracer { @@ -120,16 +124,13 @@ namespace redmagic { mem_loc_t read_cache_loc = -1; unsigned int num_ins = 0; + + std::vector traces; }; extern ChildManager *child_manager; extern ParentManager *parent_manager; - enum CommOp { - START_TRACE, - END_TRACE, - }; - struct Check_struct { // which register to check // -1 if there is no need for a check @@ -147,7 +148,18 @@ namespace redmagic { }; }; + enum TraceOp { + // represents that this is a typical instruction + INST_TRACE_OP, // a standard jump instruction + INST_LOOP_TRACE_OP, // a jump that is backwards and will execute multiple times in a row, eg only wait to exit is for this branch to fall through + BEGIN_TRACE_OP, // pushed at the start of the tracing processes + END_TRACE_OP, + TEMP_BREAK_TRACE_OP, // temp_disable/enable method + IGNORED_CALL_TRACE_OP, // when there is a call like malloc or some other registered call, work around it instead of tracing through it + }; + struct JumpTrace { + TraceOp op; register_t ins_pc; // pc of where the instruction is located register_t target_pc; // pc after the instruction executed ud_mnemonic_code instruction; @@ -157,6 +169,16 @@ namespace redmagic { // int instruction_len; }; + enum CommOp { + // client ops + START_TRACE, + END_TRACE, + + // parent ops + SEND_TRACE, + + }; + struct Communication_struct { CommOp op; pid_t thread_pid; @@ -170,6 +192,7 @@ namespace redmagic { BEGIN_TRACE_ACT, TEMP_DISABLE_ACT, TEMP_ENABLE_ACT, + RETURN_FROM_METHOD_ACT, NO_ACT, diff --git a/src/jit_main.cc b/src/jit_main.cc deleted file mode 100644 index 76d70a8..0000000 --- a/src/jit_main.cc +++ /dev/null @@ -1,178 +0,0 @@ -#if 0 - -#include "redmagic.h" -#include "jit_internal.h" - -#include "udis86.h" - -#include -using namespace std; - - -struct redmagic_handle_t *redmagic_global_default = nullptr; - -// #define CHECK_GLOBAL(handle) \ -// if(handle == nullptr) { \ -// handle = redmagic_global_default; \ -// } - -static int udis_input_hook(ud_t *obj) { - // this method is suppose to only go forward one byte each time - // if the skip method is called then this just get call n times, so not too useful - struct redmagic_handle_t *user = (struct redmagic_handle_t*)ud_get_user_opaque_data(obj); - - unsigned long at = user->read_offset; - long res = ptrace(PTRACE_PEEKDATA, user->child_pid, at, NULL); - // TODO: make this cache the internal result - user->read_offset++; - return res & 0xff; -} - - - -extern "C" void redmagic_start() { - // auto r = new redmagic_handle_t; - // if(redmagic_global_default == nullptr) { - // redmagic_global_default = r; - // } - // return r; - - pid_t child = fork(); - if(child == 0) { - // we are the child process - ptrace(PTRACE_TRACEME, 0, NULL, NULL); - - // allow for the parent processes to connect - asm("int3"); - - return;// NULL; - } else { - auto r = new redmagic_handle_t; - redmagic_global_default = r; - r->child_pid = child; - - ud_t disassm; - ud_init(&disassm); - ud_set_user_opaque_data(&disassm, r); - ud_set_input_hook(&disassm, udis_input_hook); - ud_set_mode(&disassm, 64); // 64 bit - ud_set_vendor(&disassm, UD_VENDOR_INTEL); - ud_set_syntax(&disassm, UD_SYN_INTEL); - - int res, stat; - // wait for a traceme call to arrive - res = waitpid(child, &stat, WUNTRACED); - cout << "attached to childed: " << res << " " << stat << endl << flush; - if((res != child) || !(WIFSTOPPED(stat))) { - cerr << "unexpected state\n"; - exit(-1); - } - //struct user_regs_struct regs, oregs; - // ptrace(PTRACE_GETREGS, r->child_pid, ®s, NULL); - // cout << "got back regs\n" << flush; - - // while(waitpid(child, NULL, WNOHANG) == 0) { - // ptrace(PTRACE_CONT, child, NULL, NULL); - // wait(NULL); - // long i = ptrace(PTRACE_GETREGS, child, ®s, NULL); - // //if(memcmp(®s,&oregs, sizeof(regs)) != 0) { - // cout << "a:" << regs.rip << endl << flush; - // oregs = regs; - // //} - // //asm("int3"); - // ptrace(PTRACE_CONT, child, NULL, NULL); - // } - - // http://www.secretmango.com/jimb/Whitepapers/ptrace/ptrace.html - - while(true) { - if((res = ptrace(PTRACE_SINGLESTEP, child, NULL, NULL)) < 0) { - cerr << "failed single step\n"; - exit(-1); - } - res = wait(&stat); - - int signo; - if((signo = WSTOPSIG(stat)) == SIGTRAP) { - signo = 0; - } - if(signo == SIGINT) { - cerr << "processes was killed\n"; - exit(-1); - } - - struct user_regs_struct regs; - if(ptrace(PTRACE_GETREGS, child, ®s, ®s) < 0) { - cerr << "failed to get regs\n"; - exit(-1); - } - - r->pc = regs.rip; - r->read_offset = regs.rip; - ud_set_pc(&disassm, regs.rip); - - if (!ud_disassemble(&disassm)) { - cerr << "fail disassm\n"; - exit(-1); - } - - - cout << "instrunction pointer: "<head; -// r->tail = prev_head; -// //handle->head = r; -// } while(!__sync_bool_compare_and_swap(&handle->head, prev_head, r)); - -// // get the pid of the current thread vs the processes -// r->pid = syscall(__NR_gettid); - -// r->manager = std::thread([r](){ -// struct user_regs_struct regs; -// cout << "requesting start with ptrace\n" << flush; -// ptrace(PTRACE_ATTACH, r->pid, nullptr, nullptr); -// r->flags |= 0x1; -// waitpid(r->pid, NULL, 0); -// cout << "subthread stopped\n" << flush; -// long i = ptrace(PTRACE_GETREGS, r->pid, ®s, NULL); -// cout << "sp:"<< regs.rsp << " " << regs.rip <pid << endl << flush ; - -// // kill(r->pid, SIGSTOP); - -// while((r->flags & 0x1) == 0) ; -// cout << "resumed\n" << flush; - -// asm("int3"); - -// // going to have to wait for the new thread to start tracing this thread -// return r; -// } - -#endif diff --git a/src/main.cc b/src/main.cc index dabee1f..8210205 100644 --- a/src/main.cc +++ b/src/main.cc @@ -14,16 +14,26 @@ int main(int argc, char* argv[]) { // to be called as early as possible redmagic_start(); - redmagic_force_begin_trace(); + redmagic_force_begin_trace((void*)123); cout << "asdf\n"; sleep(2); + char *a = (char*)malloc(1000); + //asm("int3"); + redmagic_temp_disable(); + cout << "test123"; + redmagic_temp_enable(); + sleep(1); + redmagic_force_end_trace((void*)123); + + + } diff --git a/src/parent_manager.cc b/src/parent_manager.cc index eaf5f88..f5cb437 100644 --- a/src/parent_manager.cc +++ b/src/parent_manager.cc @@ -76,3 +76,7 @@ int ParentManager::get_program_pval(mem_loc_t where) { } return f->second; } + +bool ParentManager::is_ignored_method(mem_loc_t where) { + return ignored_methods.find(where) != ignored_methods.end(); +} diff --git a/src/redmagic.h b/src/redmagic.h index ff7ac51..47ae38e 100644 --- a/src/redmagic.h +++ b/src/redmagic.h @@ -15,8 +15,10 @@ void REDMAGIC_NOINLINE redmagic_start(); void REDMAGIC_NOINLINE redmagic_backwards_branch(void *); // control forcing an the JIT to start a trace of this thread -void REDMAGIC_NOINLINE redmagic_force_begin_trace(); -void REDMAGIC_NOINLINE redmagic_force_end_trace(); +void REDMAGIC_NOINLINE redmagic_force_begin_trace(void *); +void REDMAGIC_NOINLINE redmagic_force_end_trace(void *); + +void REDMAGIC_NOINLINE redmagic_force_jump_to_trace(void *); // temporarly disable JIT in a given method diff --git a/src/tracer.cc b/src/tracer.cc index b7aa387..b3d2043 100644 --- a/src/tracer.cc +++ b/src/tracer.cc @@ -6,6 +6,7 @@ //#include + #include #include @@ -13,6 +14,11 @@ using namespace std; using namespace redmagic; +extern "C" { + void red_asm_return_after_method_call(); +} + + // convert a register from udis to sys/reg.h static int ud_register_to_sys(ud_type t) { switch(t) { @@ -169,6 +175,9 @@ void Tracer::run() { mem_loc_t ins_loc; unsigned char replaced_dat; + mem_loc_t current_replaced_loc = -1; + mem_loc_t after_method_call_pc = -1; + cerr << "tracer running " << thread_pid << endl << flush; if(ptrace(PTRACE_ATTACH, thread_pid, NULL, NULL) < 0) { @@ -282,6 +291,7 @@ void Tracer::run() { } else { // invalidate the cache since we have to write back the correct byte // read_cache_loc = -1; + current_replaced_loc = -1; writeByte(read_offset, (uint8_t)(prev_asm_ins & 0xff)); // reset the location of the instruction pointer so that when we continue we will execute this instruction if(ptrace(PTRACE_POKEUSER, thread_pid, sizeof(register_t) * RIP, read_offset) < 0) { @@ -303,13 +313,23 @@ void Tracer::run() { } case END_TRACE_ACT: { // TODO: - exit(2); - break; + if(current_replaced_loc != -1) { + int prev_asm_ins = manager->get_program_pval(current_replaced_loc); + assert(prev_asm_ins != -1); + writeByte(current_replaced_loc, (uint8_t)(prev_asm_ins & 0xff)); + current_replaced_loc = -1; + } + goto end_tracing; } case TEMP_DISABLE_ACT: { temp_disable = true; + if(current_replaced_loc != -1) { + int prev_asm_ins = manager->get_program_pval(current_replaced_loc); + assert(prev_asm_ins != -1); + writeByte(current_replaced_loc, (uint8_t)(prev_asm_ins & 0xff)); + current_replaced_loc = -1; + } goto continue_program; - break; } case TEMP_ENABLE_ACT: { temp_disable = false; @@ -320,7 +340,15 @@ void Tracer::run() { goto locate_next_replace_instruction; } - + case RETURN_FROM_METHOD_ACT: { + // returned from a method that we were not tracing + setOffset(after_method_call_pc); + if(ptrace(PTRACE_POKEUSER, thread_pid, sizeof(register_t) * RIP, after_method_call_pc) < 0) { + perror("failed to set rip after intercepted method return"); + } + after_method_call_pc = -1; + goto locate_next_replace_instruction; + } } } @@ -362,6 +390,7 @@ void Tracer::run() { } /* JumpTrace jtrace; */ + jtrace.op = INST_TRACE_OP; jtrace.check = reg_check; jtrace.ins_pc = ud_insn_off(&disassm); jtrace.instruction = ud_insn_mnemonic(&disassm); @@ -375,6 +404,23 @@ void Tracer::run() { /*register_t*/ new_pc = ptrace(PTRACE_PEEKUSER, thread_pid, RIP * sizeof(register_t), NULL); jtrace.target_pc = new_pc; + if(jtrace.instruction == UD_Icall) { + // check if we are in a method call that we want to ignore + if(manager->is_ignored_method(new_pc) || new_pc == (register_t)&strcmp) { + // this is an ignored method + register_t sp = ptrace(PTRACE_PEEKUSER, thread_pid, RSP * sizeof(register_t), NULL); + after_method_call_pc = ptrace(PTRACE_PEEKDATA, thread_pid, sp, NULL); + if(ptrace(PTRACE_POKEDATA, thread_pid, sp, &red_asm_return_after_method_call) < 0) { + perror("failed to set return address after ignored method"); + } + goto continue_program; + } + } + + // save this tracing operation + traces.push_back(jtrace); + + setOffset(new_pc); // read_offset = new_pc; // ud_set_pc(&disassm, new_pc); @@ -406,6 +452,8 @@ void Tracer::run() { manager->set_program_pval(ins_loc, replaced_dat); + assert(current_replaced_loc == -1); + current_replaced_loc = ins_loc; writeByte(ins_loc, (uint8_t)0xCC); @@ -425,6 +473,15 @@ void Tracer::run() { } + + end_tracing: + if(ptrace(PTRACE_CONT, thread_pid, NULL, NULL) < 0) { + perror("failed to continue trace after finished"); + } + + cout << "finished the trace\n"; + + // need to send the results of the traced back to the main running program } Check_struct Tracer::decode_instruction() {