├── inc ├── vmclient.h ├── draw.h ├── backward.h ├── context.h ├── utils.h ├── vm.h ├── state.h └── expr.h ├── test ├── libdyntrac.so ├── sample.c ├── dyntrac.c ├── z3test.c ├── openreiltest.c ├── sample3.c └── Makefile ├── .gitmodules ├── README.md ├── src ├── main.cpp ├── symx.cpp ├── utils.cpp ├── backward.cpp ├── draw.cpp ├── vmclient.cpp ├── expr.cpp ├── vm.cpp └── state.cpp ├── LICENSE ├── CMakeLists.txt ├── arch ├── arm │ ├── arm.h │ └── arm.cpp └── openreil │ ├── openreil.h │ └── openreil.cpp └── solver ├── z3.h └── z3.cpp /inc/vmclient.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/libdyntrac.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pzread/symx/HEAD/test/libdyntrac.so -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "z3"] 2 | path = z3 3 | url = https://git.codeplex.com/z3 4 | [submodule "capstone"] 5 | path = capstone 6 | url = https://github.com/aquynh/capstone.git 7 | [submodule "dynamorio"] 8 | path = dynamorio 9 | url = https://github.com/DynamoRIO/dynamorio.git 10 | [submodule "openreil"] 11 | path = openreil 12 | url = https://github.com/Cr4sh/openreil.git 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # symx 2 | Lightweight Symbolic Execution Engine 3 | 4 | # compile 5 | ### Z3 6 | ``` 7 | cd z3 8 | python scripts/mk_make.py 9 | cd build 10 | make 11 | sudo make install 12 | ``` 13 | ### Capstone Engine 14 | ``` 15 | cd capstone 16 | ./make.sh 17 | sudo make install 18 | ``` 19 | ### symx 20 | ``` 21 | cd bin 22 | cmake .. 23 | make 24 | ``` 25 | 26 | #todo 27 | 1. ELF loader (For now, need to hardcode symx.cpp and arch/arm.cpp) 28 | -------------------------------------------------------------------------------- /inc/draw.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifndef _DRAW_H_ 6 | #define _DRAW_H_ 7 | 8 | namespace symx { 9 | 10 | class Draw { 11 | public: 12 | Draw(); 13 | ~Draw(); 14 | int update_link(uint64_t from,uint64_t to); 15 | int update_block(uint64_t pos,char *data); 16 | int output(const char *filename); 17 | private: 18 | Agraph_t *g; 19 | std::unordered_map record; 20 | int add_block(uint64_t pos); 21 | }; 22 | 23 | }; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_PREFIX "main" 2 | 3 | #include 4 | #include 5 | 6 | #include"utils.h" 7 | #include"state.h" 8 | #include"solver/z3.h" 9 | #include"arch/openreil/openreil.h" 10 | 11 | using namespace symx; 12 | 13 | int main() { 14 | 15 | //Just for test 16 | /*vm::VirtualMachine *vm = new vm::VirtualMachine(); 17 | const char *argv[] = {"sample",NULL}; 18 | 19 | vm->create(".","./sample",argv); 20 | 21 | vm->destroy(); 22 | 23 | delete vm;*/ 24 | 25 | Solver *solver = new z3_solver::Z3Solver(); 26 | Context *context = new openreil::Context(solver,"./sample3"); 27 | Executor *engine = new Executor(context); 28 | 29 | engine->execute(0x0804825E); 30 | 31 | delete context; 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/symx.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include"utils.h" 13 | #include"context.h" 14 | #include"state.h" 15 | #include"arch/arm/arm.h" 16 | #include"solver/z3.h" 17 | 18 | /* 19 | For quick testing 20 | */ 21 | int main() { 22 | //Parameter 23 | int binfd; 24 | 25 | auto *solver = new z3_solver::Z3Solver(); 26 | auto *ctx = new arm::ARMContext(solver); 27 | 28 | binfd = open("./exp",O_RDONLY); 29 | 30 | //
block emit test 31 | arm::initialize(); 32 | auto probe = ref(-1,binfd,-0x10000); 33 | state_executor(ctx,probe,0x10a0c); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /inc/backward.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include"utils.h" 4 | #include"expr.h" 5 | #include"context.h" 6 | 7 | #ifndef _BACKWARD_H_ 8 | #define _BACKWARD_H_ 9 | 10 | namespace symx { 11 | using namespace symx; 12 | 13 | class TargetVisitor : public ExprVisitor { 14 | public: 15 | std::unordered_set dyn_expr; 16 | int pre_visit(const refBytVec &vec); 17 | int pre_visit(const refBytMem &mem); 18 | int pre_visit(const refOperator &oper); 19 | int pre_visit(const refCond &cond); 20 | int post_visit(const refBytVec &vec); 21 | int post_visit(const refBytMem &mem); 22 | int post_visit(const refOperator &oper); 23 | int post_visit(const refCond &cond); 24 | private: 25 | std::unordered_set vis_expr; 26 | }; 27 | 28 | class Backward { 29 | public: 30 | Backward() {} 31 | int check_point(const refExpr &pc); 32 | }; 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /test/sample.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *input = (unsigned char*)0x1000; 6 | char *output = (unsigned char*)0x2000; 7 | 8 | int get(char *buf,unsigned int off,unsigned int len) { 9 | unsigned int i = 0; 10 | while(input[off + i] != '\0' && i < len) { 11 | buf[i] = input[off + i]; 12 | i++; 13 | } 14 | buf[i] = '\0'; 15 | return i; 16 | } 17 | int ru(char *s,char *p) { 18 | while(*s != '\0') { 19 | if(*p == '*') { 20 | if(ru(s + 1,p)) { 21 | return 1; 22 | } 23 | } else { 24 | if(*s != *p) { 25 | return 0; 26 | } 27 | s++; 28 | } 29 | p++; 30 | } 31 | return (*s) == (*p); 32 | } 33 | 34 | int main() { 35 | char s[100]; 36 | char p[100]; 37 | 38 | get(s,0,10); 39 | get(p,100,10); 40 | 41 | ru(s,p); 42 | 43 | //out: 44 | 45 | asm("int3"); 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /inc/context.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONTEXT_H_ 2 | #define _CONTEXT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include"utils.h" 12 | #include"vm.h" 13 | 14 | namespace symx { 15 | using namespace symx; 16 | 17 | class Solver { 18 | public: 19 | virtual bool solve( 20 | const std::unordered_set &cons, 21 | std::unordered_map *var) = 0; 22 | }; 23 | class Context { 24 | private: 25 | int last_varid = 0; 26 | 27 | public: 28 | Solver *solver; 29 | 30 | virtual ~Context() {}; 31 | virtual VirtualMachine* create_vm() = 0; 32 | virtual int destroy_vm(VirtualMachine *vm) = 0; 33 | 34 | Context(Solver *_solver) : solver(_solver) {} 35 | int get_next_varid() { 36 | last_varid += 1; 37 | return last_varid; 38 | } 39 | }; 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include"utils.h" 7 | 8 | void internal_err(const char *prefix,const char *fmt,...) { 9 | va_list args; 10 | std::string cfmt; 11 | 12 | cfmt = "\e[1;31m[" + std::to_string(getpid()) + "][" + prefix + "]\e[m\t\t" + fmt; 13 | va_start(args,fmt); 14 | vfprintf(stderr,cfmt.c_str(),args); 15 | fflush(stderr); 16 | va_end(args); 17 | while(1); 18 | } 19 | void internal_info(const char *prefix,const char *fmt,...) { 20 | va_list args; 21 | std::string cfmt; 22 | 23 | cfmt = "[" + std::to_string(getpid()) + "][" + prefix + "]\t\t" + fmt; 24 | va_start(args,fmt); 25 | vfprintf(stderr,cfmt.c_str(),args); 26 | fflush(stderr); 27 | va_end(args); 28 | } 29 | void internal_dbg(const char *prefix,const char *fmt,...) { 30 | va_list args; 31 | std::string cfmt; 32 | 33 | cfmt = "\e[1;33m[" + std::to_string(getpid()) + "][" + prefix + "]\e[m\t\t" + fmt; 34 | va_start(args,fmt); 35 | vfprintf(stderr,cfmt.c_str(),args); 36 | fflush(stderr); 37 | va_end(args); 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 PZ Read 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0) 2 | 3 | project(symx CXX) 4 | project(vmclient CXX) 5 | 6 | include(CheckCXXCompilerFlag) 7 | CHECK_CXX_COMPILER_FLAG(-std=c++14 COMPILER_SUPPORTS_CXX14) 8 | CHECK_CXX_COMPILER_FLAG(-std=c++1y COMPILER_SUPPORTS_CXX1Y) 9 | if(COMPILER_SUPPORTS_CXX14) 10 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") 11 | elseif(COMPILER_SUPPORTS_CXX1Y) 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y") 13 | else() 14 | message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support. Please use a different C++ compiler.") 15 | endif() 16 | 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall -Wextra -Wno-unused-parameter") 18 | 19 | include_directories(AFTER "." "inc" "dynamorio/include") 20 | link_directories(AFTER "dynamorio/lib64") 21 | 22 | add_executable(symx src/main.cpp src/utils.cpp src/expr.cpp src/state.cpp src/vm.cpp solver/z3.cpp arch/openreil/openreil.cpp) 23 | target_link_libraries(symx rt z3 drinjectlib drconfiglib openreil) 24 | set_target_properties(symx PROPERTIES COMPILE_FLAGS "-g") 25 | 26 | add_library(vmclient SHARED src/vmclient.cpp) 27 | set_target_properties(vmclient PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32") 28 | -------------------------------------------------------------------------------- /arch/arm/arm.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include"context.h" 6 | #include"state.h" 7 | 8 | #ifndef _ARM_H_ 9 | #define _ARM_H_ 10 | 11 | #define ARM_REG_SIZE 4 12 | #define ARM_FLAG_NUM 4 13 | #define ARM_SR_N 0 14 | #define ARM_SR_Z 1 15 | #define ARM_SR_C 2 16 | #define ARM_SR_V 3 17 | 18 | namespace arm { 19 | 20 | using namespace arm; 21 | 22 | class ARMProbe; 23 | typedef std::shared_ptr refARMProbe; 24 | 25 | class ARMProbe : public symx::Probe { 26 | public: 27 | pid_t pid; 28 | uint8_t *bin; 29 | uint64_t off; 30 | 31 | ARMProbe(pid_t _pid,int fd,uint64_t _off); 32 | uint64_t read_reg(const unsigned int regid,bool *symbol) const; 33 | bool read_flag(const unsigned int flagid) const; 34 | ssize_t read_mem( 35 | const uint64_t addr, 36 | const uint8_t *buf, 37 | const size_t len) const; 38 | int get_insmd() const; 39 | std::vector get_mem_map() const; 40 | }; 41 | class ARMContext : public symx::Context { 42 | public: 43 | ARMContext(symx::Solver *solver); 44 | symx::refBlock interpret( 45 | const symx::refProbe &_probe, 46 | const symx::ProgCtr &pc); 47 | }; 48 | 49 | int initialize(); 50 | 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /inc/utils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifndef _UTILS_H_ 6 | #define _UTILS_H_ 7 | 8 | #define err(fmt,...) internal_err(LOG_PREFIX,fmt,##__VA_ARGS__) 9 | #define info(fmt,...) internal_info(LOG_PREFIX,fmt,##__VA_ARGS__) 10 | #define dbg(fmt,...) internal_dbg(LOG_PREFIX,fmt,##__VA_ARGS__) 11 | 12 | void internal_err(const char *prefix,const char *fmt,...); 13 | void internal_info(const char *prefix,const char *fmt,...); 14 | void internal_dbg(const char *prefix,const char *fmt,...); 15 | 16 | template 17 | std::shared_ptr ref(Args&&... args) { 18 | return std::make_shared(std::forward(args)...); 19 | } 20 | 21 | //Predefine 22 | namespace symx { 23 | class Context; 24 | class VirtualMachine; 25 | class Snapshot; 26 | class AddrSpace; 27 | class Block; 28 | class State; 29 | class ProgCtr; 30 | class MemRecord; 31 | class Solver; 32 | typedef std::shared_ptr refSnapshot; 33 | typedef std::shared_ptr refAddrSpace; 34 | typedef std::shared_ptr refBlock; 35 | typedef std::shared_ptr refState; 36 | typedef std::shared_ptr refMemRecord; 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/backward.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_PREFIX "backward" 2 | 3 | #include"utils.h" 4 | #include"expr.h" 5 | #include"backward.h" 6 | 7 | using namespace symx; 8 | 9 | int TargetVisitor::pre_visit(const refBytVec &vec) { 10 | if(vis_expr.find(vec) != vis_expr.end()) { 11 | return 0; 12 | } 13 | return 1; 14 | } 15 | int TargetVisitor::pre_visit(const refBytMem &mem) { 16 | if(vis_expr.find(mem) != vis_expr.end()) { 17 | return 0; 18 | } 19 | return 1; 20 | } 21 | int TargetVisitor::pre_visit(const refOperator &oper) { 22 | if(oper->type == ExprOpSelect) { 23 | dyn_expr.insert(oper); 24 | return 0; 25 | } 26 | if(vis_expr.find(oper) != vis_expr.end()) { 27 | return 0; 28 | } 29 | return 1; 30 | } 31 | int TargetVisitor::pre_visit(const refCond &cond) { 32 | return 0; 33 | } 34 | int TargetVisitor::post_visit(const refBytVec &vec) { 35 | vis_expr.insert(vec); 36 | return 1; 37 | } 38 | int TargetVisitor::post_visit(const refBytMem &mem) { 39 | vis_expr.insert(mem); 40 | return 1; 41 | } 42 | int TargetVisitor::post_visit(const refOperator &oper) { 43 | vis_expr.insert(oper); 44 | return 1; 45 | } 46 | int TargetVisitor::post_visit(const refCond &cond) { 47 | return 1; 48 | } 49 | 50 | int Backward::check_point(const refExpr &pc) { 51 | TargetVisitor targetvis; 52 | 53 | expr_walk(&targetvis,pc); 54 | if(targetvis.dyn_expr.size() > 0) { 55 | dbg("symbolic pc %d\n",targetvis.dyn_expr.size()); 56 | } 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /test/dyntrac.c: -------------------------------------------------------------------------------- 1 | #ifndef LINUX 2 | #define LINUX 3 | #endif 4 | #ifndef X86_32 5 | #define X86_32 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | static void basic_block_call() { 12 | 13 | } 14 | static dr_emit_flags_t event_basic_block( 15 | void *drctx, 16 | void *tag, 17 | instrlist_t *bb, 18 | bool for_trace, 19 | bool translating 20 | ) { 21 | /* 22 | dr_mutex_lock(ins_count_lock); 23 | ins_count += num_ins; 24 | dr_mutex_unlock(ins_count_lock); 25 | 26 | dr_save_arith_flags(drcontext,bb,where,SPILL_SLOT_1); 27 | instrlist_meta_preinsert(bb,where,LOCK( 28 | INSTR_CREATE_add(drcontext, 29 | OPND_CREATE_ABSMEM((uint8_t*)&ins_count,OPSZ_8), 30 | OPND_CREATE_INT_32OR8(num_ins)))); 31 | dr_restore_arith_flags(drcontext,bb,where,SPILL_SLOT_1); 32 | */ 33 | 34 | instr_t *where = instrlist_first(bb); 35 | dr_mem_info_t meminfo; 36 | 37 | dr_printf("0x%08x\n",instr_get_app_pc(where)); 38 | if(dr_query_memory_ex(instr_get_app_pc(where),&meminfo) && 39 | !dr_memory_is_dr_internal(meminfo.base_pc)) { 40 | dr_printf("0x%08x 0x%08x\n",meminfo.base_pc,meminfo.size); 41 | } 42 | 43 | dr_insert_clean_call(drctx,bb,where,basic_block_call,false,0); 44 | 45 | return DR_EMIT_DEFAULT; 46 | } 47 | static void event_exit() {} 48 | 49 | DR_EXPORT void dr_init(client_id_t id) { 50 | dr_register_exit_event(event_exit); 51 | dr_register_bb_event(event_basic_block); 52 | } 53 | -------------------------------------------------------------------------------- /src/draw.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_PREFIX "draw" 2 | 3 | #include 4 | #include 5 | #include"utils.h" 6 | #include"draw.h" 7 | 8 | using namespace symx; 9 | 10 | Draw::Draw() { 11 | g = agopen((char*)"flow",Agdirected,NULL); 12 | agattr(g,AGNODE,(char*)"shape",(char*)"box"); 13 | agattr(g,AGNODE,(char*)"label",(char*)""); 14 | agattr(g,AGNODE,(char*)"fontname",(char*)"Courier"); 15 | agattr(g,AGEDGE,(char*)"headport",(char*)"n"); 16 | agattr(g,AGEDGE,(char*)"tailport",(char*)"s"); 17 | agattr(g,AGEDGE,(char*)"arrowsize",(char*)"0.5"); 18 | agattr(g,AGRAPH,(char*)"splines",(char*)"spline"); 19 | agattr(g,AGRAPH,(char*)"ranksep",(char*)"0.8"); 20 | agattr(g,AGRAPH,(char*)"center",(char*)"true"); 21 | } 22 | Draw::~Draw() { 23 | agclose(g); 24 | } 25 | 26 | int Draw::output(const char *filename) { 27 | FILE *f = fopen(filename,"w"); 28 | agwrite(g,f); 29 | fclose(f); 30 | return 0; 31 | } 32 | int Draw::update_link(uint64_t from,uint64_t to) { 33 | auto fromit = record.find(from); 34 | if(fromit == record.end()) { 35 | add_block(from); 36 | fromit = record.find(from); 37 | } 38 | auto toit = record.find(to); 39 | if(toit == record.end()) { 40 | add_block(to); 41 | toit = record.find(to); 42 | } 43 | agedge(g,fromit->second,toit->second,(char*)"",TRUE); 44 | return 0; 45 | } 46 | int Draw::update_block(uint64_t pos,char *data) { 47 | auto blkit = record.find(pos); 48 | if(blkit == record.end()) { 49 | add_block(pos); 50 | blkit = record.find(pos); 51 | } 52 | agset(blkit->second,(char*)"label",agstrdup(g,data)); 53 | return 0; 54 | } 55 | int Draw::add_block(uint64_t pos) { 56 | Agnode_t *node; 57 | char name[512]; 58 | snprintf(name,sizeof(name) - 1,"0x%08lx",pos); 59 | node = agnode(g,name,TRUE); 60 | record[pos] = node; 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /arch/openreil/openreil.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include"utils.h" 7 | #include"context.h" 8 | #include"vm.h" 9 | 10 | #ifndef _OPENREIL_H_ 11 | #define _OPENREIL_H_ 12 | 13 | namespace openreil { 14 | using namespace openreil; 15 | 16 | class VirtualMachine; 17 | 18 | class Snapshot : public symx::Snapshot { 19 | private: 20 | VirtualMachine *const vm; 21 | 22 | static int inst_handler(reil_inst_t *inst,void *ctx); 23 | symx::refExpr translate_fixsize( 24 | symx::refExpr exr, 25 | unsigned int size) const; 26 | symx::refExpr translate_get_arg( 27 | const std::unordered_map ®map, 28 | const reil_arg_t &arg) const; 29 | int translate_set_arg( 30 | std::unordered_map *regmap, 31 | const reil_arg_t &arg, 32 | const symx::refExpr &value) const; 33 | std::vector translate( 34 | uint8_t *code, 35 | const symx::ProgCtr &pc, 36 | size_t len) const; 37 | 38 | public: 39 | Snapshot(VirtualMachine *vm,const uint64_t *_reg); 40 | int mem_read(uint8_t *buf,uint64_t pos,size_t len) const; 41 | }; 42 | class VirtualMachine : public symx::VirtualMachine { 43 | public: 44 | uint64_t event_get_pc() const; 45 | symx::refSnapshot event_suspend(); 46 | int mem_read(uint8_t *buf,uint64_t pos,size_t len); 47 | }; 48 | class Context : public symx::Context { 49 | private: 50 | const char *container_path; 51 | const char *exe_path; 52 | 53 | public: 54 | Context(symx::Solver *_solver,const char *_exe_path) 55 | : symx::Context(_solver), 56 | container_path("."), 57 | exe_path(_exe_path) {} 58 | VirtualMachine* create_vm(); 59 | int destroy_vm(symx::VirtualMachine *vm); 60 | }; 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /test/z3test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static void error_handler(Z3_context ctx,Z3_error_code error) { 6 | fprintf(stderr,"Z3 Solver: %s\n",Z3_get_error_msg_ex(ctx,error)); 7 | } 8 | int main(){ 9 | Z3_context context; 10 | Z3_solver solver; 11 | Z3_sort bvsort1; 12 | Z3_sort bvsort4; 13 | Z3_sort memsort; 14 | Z3_ast x_ast,y_ast,z_ast,u_ast,v_ast,w_ast,test_ast; 15 | Z3_model model; 16 | 17 | Z3_config config = Z3_mk_config(); 18 | Z3_set_param_value(config,"model","true"); 19 | context = Z3_mk_context_rc(config); 20 | Z3_set_error_handler(context,error_handler); 21 | 22 | solver = Z3_mk_solver(context); 23 | Z3_solver_inc_ref(context,solver); 24 | 25 | bvsort1 = Z3_mk_bv_sort(context,8); 26 | bvsort4 = Z3_mk_bv_sort(context,32); 27 | 28 | memsort = Z3_mk_array_sort(context,bvsort4,bvsort1); 29 | y_ast = Z3_mk_const(context,Z3_mk_string_symbol(context,"mem"),memsort); 30 | Z3_inc_ref(context,y_ast); 31 | 32 | u_ast = Z3_mk_unsigned_int64(context,13,bvsort4); 33 | Z3_inc_ref(context,u_ast); 34 | v_ast = Z3_mk_select(context,y_ast,u_ast); 35 | Z3_inc_ref(context,v_ast); 36 | 37 | z_ast = Z3_mk_unsigned_int64(context,7,bvsort1); 38 | Z3_inc_ref(context,z_ast); 39 | test_ast = Z3_mk_eq(context,v_ast,z_ast); 40 | Z3_inc_ref(context,test_ast); 41 | Z3_solver_assert(context,solver,test_ast); 42 | 43 | w_ast = Z3_mk_const(context,Z3_mk_string_symbol(context,"w"),bvsort1); 44 | y_ast = Z3_mk_store(context,y_ast,u_ast,w_ast); 45 | Z3_inc_ref(context,y_ast); 46 | 47 | v_ast = Z3_mk_select(context,y_ast,u_ast); 48 | Z3_inc_ref(context,v_ast); 49 | 50 | z_ast = Z3_mk_unsigned_int64(context,2,bvsort1); 51 | Z3_inc_ref(context,z_ast); 52 | test_ast = Z3_mk_eq(context,v_ast,z_ast); 53 | Z3_inc_ref(context,test_ast); 54 | Z3_solver_assert(context,solver,test_ast); 55 | 56 | Z3_solver_check(context,solver); 57 | model = Z3_solver_get_model(context,solver); 58 | fprintf(stderr,"%s\n",Z3_model_to_string(context,model)); 59 | 60 | fprintf(stderr,"%s\n",Z3_simplify_get_help(context)); 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /solver/z3.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_PREFIX 2 | #define LOG_PREFIX "z3_solver" 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include"utils.h" 10 | #include"context.h" 11 | #include"expr.h" 12 | #include"state.h" 13 | 14 | #ifndef _SOLVER_H_ 15 | #define _SOLVER_H_ 16 | 17 | namespace z3_solver { 18 | class Z3Solver; 19 | class Z3SolvExpr; 20 | class Z3SolvCond; 21 | typedef std::shared_ptr refZ3SolvExpr; 22 | typedef std::shared_ptr refZ3SolvCond; 23 | 24 | class Z3SolvExpr { 25 | public: 26 | Z3_context context; 27 | Z3_ast ast; 28 | Z3SolvExpr(Z3_context _context,Z3_ast _ast); 29 | ~Z3SolvExpr(); 30 | }; 31 | class Z3SolvCond { 32 | public: 33 | Z3_context context; 34 | Z3_ast ast; 35 | Z3SolvCond(Z3_context _context,Z3_ast _ast); 36 | ~Z3SolvCond(); 37 | }; 38 | 39 | class Z3TransVisitor : public symx::ExprVisitor { 40 | private: 41 | const Z3Solver *solver; 42 | std::unordered_map cache_expr; 43 | std::unordered_map cache_cond; 44 | 45 | Z3_sort bvsort1; 46 | Z3_sort bvsort4; 47 | Z3_ast bvimm41; 48 | Z3_params simplify_param; 49 | 50 | public: 51 | Z3TransVisitor(const Z3Solver *_solver); 52 | Z3_ast expr_to_ast(const symx::refExpr &expr); 53 | Z3_ast cond_to_ast(const symx::refCond &cond); 54 | int pre_visit(const symx::refBytVec &vec); 55 | int pre_visit(const symx::refBytMem &mem); 56 | int pre_visit(const symx::refOperator &oper); 57 | int pre_visit(const symx::refCond &cond); 58 | int post_visit(const symx::refBytVec &vec); 59 | int post_visit(const symx::refBytMem &mem); 60 | int post_visit(const symx::refOperator &oper); 61 | int post_visit(const symx::refCond &cond); 62 | }; 63 | class Z3Solver : public symx::Solver { 64 | private: 65 | Z3TransVisitor *trans_vis; 66 | 67 | static void error_handler(Z3_context ctx,Z3_error_code error) { 68 | err("Z3 Solver: %s\n", 69 | Z3_get_error_msg_ex(ctx,error)); 70 | } 71 | 72 | public: 73 | Z3_context context; 74 | Z3_solver solver; 75 | 76 | Z3Solver(); 77 | ~Z3Solver(); 78 | bool solve( 79 | const std::unordered_set &cons, 80 | std::unordered_map *var); 81 | }; 82 | 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /test/openreiltest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define MAX_ARG_STR 50 8 | 9 | const char *inst_op[] = 10 | { 11 | "NONE", "UNK", "JCC", 12 | "STR", "STM", "LDM", 13 | "ADD", "SUB", "NEG", "MUL", "DIV", "MOD", "SMUL", "SDIV", "SMOD", 14 | "SHL", "SHR", "AND", "OR", "XOR", "NOT", 15 | "EQ", "LT" 16 | }; 17 | 18 | int arg_size[] = { 1, 8, 16, 32, 64 }; 19 | 20 | char *arg_print(reil_arg_t *arg, char *arg_str) 21 | { 22 | memset(arg_str, 0, MAX_ARG_STR); 23 | 24 | switch (arg->type) 25 | { 26 | case A_NONE: 27 | 28 | snprintf(arg_str, MAX_ARG_STR - 1, ""); 29 | break; 30 | 31 | case A_REG: 32 | case A_TEMP: 33 | 34 | snprintf(arg_str, MAX_ARG_STR - 1, "%s:%d", arg->name, arg_size[arg->size]); 35 | break; 36 | 37 | case A_CONST: 38 | 39 | snprintf(arg_str, MAX_ARG_STR - 1, "%llx:%d", arg->val, arg_size[arg->size]); 40 | break; 41 | } 42 | 43 | return arg_str; 44 | } 45 | 46 | void inst_print(reil_inst_t *inst) 47 | { 48 | char arg_str[MAX_ARG_STR]; 49 | 50 | // print address and mnemonic 51 | printf( 52 | "%.8llx.%.2x %7s ", 53 | inst->raw_info.addr, inst->inum, inst_op[inst->op] 54 | ); 55 | 56 | // print instruction arguments 57 | printf("%16s, ", arg_print(&inst->a, arg_str)); 58 | printf("%16s, ", arg_print(&inst->b, arg_str)); 59 | printf("%16s ", arg_print(&inst->c, arg_str)); 60 | 61 | printf("\n"); 62 | } 63 | 64 | int inst_handler(reil_inst_t *inst, void *context) 65 | { 66 | // increment IR instruction counter 67 | *(int *)context += 1; 68 | 69 | // print IR instruction to the stdout 70 | inst_print(inst); 71 | 72 | return 0; 73 | } 74 | 75 | int translate_inst(reil_arch_t arch, unsigned char *data, int len) 76 | { 77 | int translated = 0; 78 | 79 | // initialize REIL translator 80 | reil_t reil = reil_init(arch, inst_handler, (void *)&translated); 81 | if (reil) 82 | { 83 | // translate single instruction to REIL 84 | reil_translate(reil, 0, data, len); 85 | reil_close(reil); 86 | return translated; 87 | } 88 | 89 | return -1; 90 | } 91 | 92 | int main(int argc, char *argv[]) 93 | { 94 | unsigned char test_data[16] = {0x38,0xC2}; // xor eax, eax 95 | int len = 2; 96 | 97 | if (translate_inst(ARCH_X86, test_data, len) >= 0) 98 | { 99 | return 0; 100 | } 101 | 102 | return -1; 103 | } 104 | -------------------------------------------------------------------------------- /test/sample3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *input = (unsigned char*)0x1000; 6 | char *output = (unsigned char*)0x2000; 7 | char buf[100] = {0}; 8 | char store[100] = {0}; 9 | 10 | int get(char *buf,unsigned int off,unsigned int len) { 11 | unsigned int i = 0; 12 | while(input[off + i] != '\0' && i < len) { 13 | buf[i] = input[off + i]; 14 | i++; 15 | } 16 | buf[i] = '\0'; 17 | return i; 18 | } 19 | 20 | int ru(char *s,char *p) { 21 | while(*s != '\0') { 22 | if(*p == '*') { 23 | if(ru(s + 1,p)) { 24 | return 1; 25 | } 26 | } else { 27 | if(*s != *p) { 28 | return 0; 29 | } 30 | s++; 31 | } 32 | p++; 33 | } 34 | return (*s) == (*p); 35 | } 36 | 37 | int main() { 38 | char *ptr,*end; 39 | int type; 40 | unsigned int len; 41 | int auth = 0; 42 | 43 | //fgets(buf,30,stdin); 44 | get(buf,0,30); 45 | ptr = buf; 46 | while(*ptr) { 47 | /*if(strncmp(ptr,"AUTH",4) == 0) { 48 | type = 1; 49 | } else if(strncmp(ptr,"SERH",4) == 0) { 50 | type = 2; 51 | } else if(strncmp(ptr,"STOR",4) == 0) { 52 | type = 3; 53 | } else { 54 | type = 0; 55 | }*/ 56 | if(*ptr == 'A') { 57 | type = 1; 58 | } else if(*ptr == 'S') { 59 | type = 2; 60 | } else if(*ptr == 'T') { 61 | type = 3; 62 | } else { 63 | type = 0; 64 | } 65 | ptr += 1; 66 | end = strstr(ptr,"|"); 67 | if(end == NULL) { 68 | goto out; 69 | } 70 | /*end = ptr; 71 | while(*end != '\0' && *end != '|') { 72 | end++; 73 | } 74 | if(*end != '|') { 75 | goto out; 76 | }*/ 77 | len = end - ptr; 78 | *end = '\0'; 79 | 80 | if(*ptr == '\0') { 81 | goto out; 82 | } 83 | 84 | switch(type) { 85 | case 1: 86 | if(len > 5) { 87 | goto out; 88 | } 89 | if(strcmp(ptr,"admin") == 0) { 90 | auth = 1; 91 | } 92 | break; 93 | case 2: 94 | if(len > 4) { 95 | goto out; 96 | } 97 | ru(store,ptr); 98 | break; 99 | case 3: 100 | if(auth != 1) { 101 | goto out; 102 | } 103 | if(len > 10) { 104 | goto out; 105 | } 106 | strncpy(store,ptr,10); 107 | store[10] = '\0'; 108 | break; 109 | default: 110 | goto out; 111 | break; 112 | } 113 | 114 | ptr += (len + 1); 115 | } 116 | 117 | out: 118 | 119 | asm("int3"); 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /inc/vm.h: -------------------------------------------------------------------------------- 1 | #ifndef _VM_H_ 2 | #define _VM_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include"utils.h" 17 | #include"expr.h" 18 | #include"state.h" 19 | #include"context.h" 20 | 21 | #ifndef PAGE_SIZE 22 | #define PAGE_SIZE 0x1000 23 | #endif 24 | #define PAGE_MASK (~0xFFF) 25 | 26 | #define UNIX_PATH_MAX 108 27 | #define VMCOM_EVT_ENTER 1 28 | #define VMCOM_EVT_EXECUTE 2 29 | #define VMCOM_EVT_RET 10 30 | #define VMCOM_EVT_READMEM 11 31 | 32 | //For X86_32 33 | enum REGIDX { 34 | REGIDX_EAX = 0, 35 | REGIDX_EBX, 36 | REGIDX_ECX, 37 | REGIDX_EDX, 38 | REGIDX_EDI, 39 | REGIDX_ESI, 40 | REGIDX_EBP, 41 | REGIDX_ESP, 42 | 43 | REGIDX_GS, 44 | REGIDX_GS_BASE, 45 | 46 | REGIDX_EFLAGS, 47 | REGIDX_DFLAG, 48 | 49 | REGIDX_CF, 50 | REGIDX_PF, 51 | REGIDX_AF, 52 | REGIDX_ZF, 53 | REGIDX_SF, 54 | REGIDX_OF, 55 | 56 | REGIDX_END 57 | }; 58 | #pragma pack(push) 59 | #pragma pack(4) 60 | struct vmcom_enter { 61 | uint32_t entrypc; 62 | uint32_t endpc; 63 | }; 64 | struct vmcom_context { 65 | uint32_t pc; 66 | uint32_t reg[REGIDX_END]; 67 | uint32_t flag; 68 | }; 69 | struct vmcom_membuf { 70 | uint8_t buf[16384]; 71 | uint32_t pos; 72 | uint32_t len; 73 | }; 74 | struct vmcom_frame { 75 | uint32_t evt; 76 | union { 77 | struct vmcom_enter enter; 78 | struct vmcom_context context; 79 | struct vmcom_membuf membuf; 80 | }; 81 | }; 82 | #pragma pack(pop) 83 | 84 | namespace symx { 85 | using namespace symx; 86 | 87 | class Snapshot { 88 | private: 89 | csh cs; 90 | 91 | public: 92 | virtual int mem_read( 93 | uint8_t *buf, 94 | uint64_t pos, 95 | size_t len) const = 0; 96 | virtual std::vector translate( 97 | uint8_t *code, 98 | const ProgCtr &pc, 99 | size_t len) const = 0; 100 | 101 | Snapshot(cs_arch arch,cs_mode mode); 102 | std::vector translate_bb(const symx::ProgCtr &pc) const; 103 | 104 | std::vector reg; 105 | std::vector flag; 106 | }; 107 | class VirtualMachine { 108 | private: 109 | void *data; 110 | 111 | int vmcom_create(); 112 | int vmcom_accept(int listen_fd); 113 | 114 | protected: 115 | enum VMSTATE { 116 | RUNNING, 117 | EVENT, 118 | SUSPEND 119 | } state; 120 | char name[NAME_MAX + 1]; 121 | pid_t pid; 122 | int com_evt; 123 | struct vmcom_frame *com_mem; 124 | 125 | int set_state(VMSTATE next_state); 126 | 127 | public: 128 | virtual ~VirtualMachine() {}; 129 | virtual uint64_t event_get_pc() const = 0; 130 | virtual refSnapshot event_suspend() = 0; 131 | 132 | int create( 133 | const char *container_path, 134 | const char *exe_path, 135 | const char **argv); 136 | int destroy(); 137 | int event_wait(); 138 | int event_send(int evt); 139 | int event_ret(); 140 | }; 141 | 142 | class MemPage : public std::enable_shared_from_this { 143 | public: 144 | const uint64_t start; 145 | const unsigned int prot; 146 | std::bitset dirty; 147 | std::bitset symbol; 148 | MemPage(const uint64_t _start,const unsigned int _prot) 149 | : start(_start),prot(_prot) {} 150 | }; 151 | class AddrSpace : public std::enable_shared_from_this{ 152 | private: 153 | Context *ctx; 154 | const refSnapshot snap; 155 | std::map page_map; 156 | std::mutex access_lock; 157 | 158 | public: 159 | refExpr mem; 160 | std::unordered_map mem_symbol; 161 | std::vector mem_constr; 162 | 163 | AddrSpace(Context *_ctx,const refSnapshot &_snap); 164 | int read(refState state,uint8_t *buf,uint64_t pos,size_t len); 165 | int handle_select(const uint64_t idx,const unsigned int size); 166 | std::vector source_select( 167 | const refOperator &sel, 168 | const std::unordered_map &var) const; 169 | }; 170 | class MemRecord : public std::enable_shared_from_this { 171 | public: 172 | const refOperator oper; 173 | const refExpr mem; 174 | const refExpr idx; 175 | const unsigned int size; 176 | MemRecord( 177 | const refOperator &_oper, 178 | const refExpr &_mem, 179 | const refExpr &_idx, 180 | const unsigned int _size) 181 | : oper(_oper),mem(_mem),idx(_idx),size(_size) {} 182 | }; 183 | } 184 | 185 | #endif 186 | -------------------------------------------------------------------------------- /inc/state.h: -------------------------------------------------------------------------------- 1 | #ifndef _STATE_H_ 2 | #define _STATE_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include"utils.h" 11 | #include"expr.h" 12 | #include"vm.h" 13 | 14 | namespace symx { 15 | using namespace symx; 16 | 17 | class ProgCtr { 18 | public: 19 | const uint64_t rawpc; 20 | const int mode; 21 | ProgCtr(const uint64_t _rawpc,const int _mode) 22 | : rawpc(_rawpc),mode(_mode) {} 23 | bool operator==(const ProgCtr &other) const { 24 | return rawpc == other.rawpc && mode == other.mode; 25 | } 26 | }; 27 | } 28 | namespace std { 29 | template<> struct hash { 30 | std::size_t operator()(const symx::ProgCtr &key) const { 31 | return (key.rawpc << 8) | key.mode; 32 | } 33 | }; 34 | } 35 | namespace symx { 36 | class BaseState : public std::enable_shared_from_this { 37 | public: 38 | const refExpr mem; 39 | const std::vector reg; 40 | const std::vector flag; 41 | 42 | BaseState( 43 | const refExpr &_mem, 44 | const std::vector _reg, 45 | const std::vector _flag) 46 | : mem(_mem),reg(_reg),flag(_flag) {} 47 | }; 48 | 49 | class State : public BaseState { 50 | public: 51 | const ProgCtr pc; 52 | const refAddrSpace as; 53 | std::unordered_set constr; 54 | std::unordered_set select_set; 55 | std::unordered_map mem_symbol_concrete; 56 | 57 | unsigned long length; 58 | std::vector path; 59 | std::unordered_map blkmap; 60 | 61 | State( 62 | const ProgCtr &_pc, 63 | const refAddrSpace &_as, 64 | const refExpr &_mem, 65 | const std::vector &_reg, 66 | const std::vector &_flag) 67 | : BaseState(_mem,_reg,_flag),pc(_pc),as(_as) {} 68 | 69 | bool operator<(const State& other) const; 70 | }; 71 | class Block : public BaseState { 72 | public: 73 | const refCond cond; 74 | const refExpr nextpc; 75 | 76 | Block( 77 | const refExpr &_mem, 78 | const std::vector &_reg, 79 | const std::vector &_flag, 80 | const refCond &_cond, 81 | const refExpr &_nextpc) 82 | : BaseState(_mem,_reg,_flag),cond(_cond),nextpc(_nextpc) {}; 83 | }; 84 | class BuildVisitor : public ExprVisitor { 85 | private: 86 | Solver *solver; 87 | const refState state; 88 | std::unordered_map expr_map; 89 | std::unordered_map cond_map; 90 | std::unordered_set select_set; 91 | 92 | refExpr solid_operator(const refOperator &oper); 93 | refExpr solid_mem_read(const refOperator &oper); 94 | 95 | public: 96 | BuildVisitor(Solver *_solver,const refState &_state) 97 | : solver(_solver),state(_state) {} 98 | refExpr get_expr(const refExpr &expr); 99 | refCond get_cond(const refCond &cond); 100 | const std::unordered_set& get_mem_record(); 101 | int pre_visit(const refBytVec &vec); 102 | int pre_visit(const refBytMem &mem); 103 | int pre_visit(const refOperator &oper); 104 | int pre_visit(const refCond &cond); 105 | int post_visit(const refBytVec &vec); 106 | int post_visit(const refBytMem &mem); 107 | int post_visit(const refOperator &oper); 108 | int post_visit(const refCond &cond); 109 | }; 110 | 111 | class ActiveVisitor : public ExprVisitor { 112 | private: 113 | std::unordered_map> cache_expr; 114 | std::unordered_map> cache_cond; 115 | 116 | public: 117 | const std::vector& get_expr_addr(const refExpr &expr); 118 | const std::vector& get_cond_addr(const refCond &cond); 119 | int pre_visit(const refBytVec &vec); 120 | int pre_visit(const refBytMem &mem); 121 | int pre_visit(const refOperator &oper); 122 | int pre_visit(const refCond &cond); 123 | int post_visit(const refBytVec &vec); 124 | int post_visit(const refBytMem &mem); 125 | int post_visit(const refOperator &oper); 126 | int post_visit(const refCond &cond); 127 | }; 128 | class ActiveSolver { 129 | private: 130 | Solver *solver; 131 | ActiveVisitor act_vis; 132 | 133 | public: 134 | ActiveSolver(Solver *_solver) : solver(_solver) {} 135 | bool solve( 136 | const std::unordered_set &target_constr, 137 | const std::unordered_set &constr, 138 | std::unordered_map *concrete); 139 | }; 140 | 141 | class Executor { 142 | private: 143 | Context *ctx; 144 | ActiveSolver *act_solver; 145 | 146 | refCond condition_pc(const refExpr &exrpc,const uint64_t rawpc); 147 | std::vector solve_state( 148 | const refState cstate, 149 | BuildVisitor *build_vis, 150 | const refBlock cblk); 151 | 152 | public: 153 | Executor(Context *_ctx) : ctx(_ctx) {} 154 | ~Executor(); 155 | int execute(uint64_t target_rawpc); 156 | }; 157 | } 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /src/vmclient.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define LINUX 12 | #define X86_32 13 | extern "C" { 14 | #include 15 | } 16 | 17 | #include"vm.h" 18 | 19 | using namespace symx; 20 | 21 | static char name[NAME_MAX + 1]; 22 | static int com_evt; 23 | static struct vmcom_frame *com_mem; 24 | 25 | static void event_exit(); 26 | static void event_thread_init(void *drctx); 27 | static dr_emit_flags_t event_basic_block( 28 | void *drctx, 29 | void *tag, 30 | instrlist_t *bb, 31 | bool for_trace, 32 | bool translating); 33 | static void call_basic_block(app_pc pc,unsigned long gs_base); 34 | static int com_push(int evt); 35 | static int com_loop(); 36 | 37 | DR_EXPORT void dr_init(client_id_t id) { 38 | char mem_path[PATH_MAX + 1]; 39 | int mem_fd; 40 | char event_path[PATH_MAX + 1]; 41 | struct sockaddr_un addr; 42 | socklen_t addrlen; 43 | 44 | strncpy(name,dr_get_options(id),sizeof(name) - 1); 45 | 46 | snprintf(mem_path,sizeof(mem_path),"%s_mem",name); 47 | mem_fd = open(mem_path,O_RDWR); 48 | com_mem = (struct vmcom_frame*)mmap( 49 | NULL, 50 | sizeof(struct vmcom_frame), 51 | PROT_READ | PROT_WRITE, 52 | MAP_SHARED, 53 | mem_fd, 54 | 0); 55 | close(mem_fd); 56 | 57 | snprintf(event_path,sizeof(event_path),"%s_event",name); 58 | addr.sun_family = AF_UNIX; 59 | strncpy(addr.sun_path,event_path,UNIX_PATH_MAX - 1); 60 | com_evt = socket(AF_UNIX,SOCK_STREAM,0); 61 | addrlen = offsetof(struct sockaddr_un,sun_path) + strlen(addr.sun_path); 62 | connect(com_evt,(struct sockaddr*)&addr,addrlen); 63 | 64 | dr_register_exit_event(event_exit); 65 | dr_register_thread_init_event(event_thread_init); 66 | dr_register_bb_event(event_basic_block); 67 | } 68 | 69 | static void event_exit() { 70 | munmap(com_mem,sizeof(vmcom_frame)); 71 | close(com_evt); 72 | } 73 | static void event_thread_init(void *drctx) { 74 | /*module_data_t *main_mod; 75 | module_handle_t main_modh; 76 | dr_symbol_export_iterator_t *export_it; 77 | dr_symbol_export_t *export_sym; 78 | 79 | main_mod = dr_lookup_module_by_name("sample"); 80 | main_modh = main_mod->handle; 81 | 82 | export_it = dr_symbol_export_iterator_start(main_modh); 83 | while(dr_symbol_export_iterator_hasnext(export_it)) { 84 | export_sym = dr_symbol_export_iterator_next(export_it); 85 | } 86 | dr_symbol_export_iterator_start(main_modh); 87 | 88 | dr_free_module_data(main_mod);*/ 89 | 90 | //com_mem->enter.entrypc = (uint32_t)main_mod->entry_point; 91 | 92 | com_push(VMCOM_EVT_ENTER); 93 | com_loop(); 94 | } 95 | static dr_emit_flags_t event_basic_block( 96 | void *drctx, 97 | void *tag, 98 | instrlist_t *bb, 99 | bool for_trace, 100 | bool translating 101 | ) { 102 | instr_t *where = instrlist_first(bb); 103 | dr_save_arith_flags(drctx,bb,where,SPILL_SLOT_1); 104 | dr_insert_get_seg_base( 105 | drctx, 106 | bb, 107 | where, 108 | DR_SEG_GS, 109 | DR_REG_EAX); 110 | dr_insert_clean_call( 111 | drctx, 112 | bb, 113 | where, 114 | (void*)call_basic_block, 115 | false, 116 | 2, 117 | OPND_CREATE_INT32(dr_fragment_app_pc(tag)), 118 | opnd_create_reg(DR_REG_EAX)); 119 | dr_restore_arith_flags(drctx,bb,where,SPILL_SLOT_1); 120 | return DR_EMIT_DEFAULT; 121 | } 122 | static void call_basic_block(app_pc pc,unsigned long gs_base) { 123 | void *drctx = dr_get_current_drcontext(); 124 | dr_mcontext_t ctx; 125 | 126 | com_mem->context.pc = (uint32_t)pc; 127 | ctx.size = sizeof(ctx); 128 | ctx.flags = DR_MC_CONTROL; 129 | if(dr_get_mcontext(drctx,&ctx)) { 130 | com_mem->context.reg[REGIDX_EAX] = ctx.eax; 131 | com_mem->context.reg[REGIDX_EBX] = ctx.ebx; 132 | com_mem->context.reg[REGIDX_ECX] = ctx.ecx; 133 | com_mem->context.reg[REGIDX_EDX] = ctx.edx; 134 | com_mem->context.reg[REGIDX_EDI] = ctx.edi; 135 | com_mem->context.reg[REGIDX_ESI] = ctx.esi; 136 | com_mem->context.reg[REGIDX_EBP] = ctx.ebp; 137 | com_mem->context.reg[REGIDX_ESP] = ctx.esp; 138 | com_mem->context.reg[REGIDX_GS] = 0x0; 139 | com_mem->context.reg[REGIDX_GS_BASE] = gs_base; 140 | com_mem->context.flag = ctx.eflags; 141 | } 142 | 143 | com_push(VMCOM_EVT_EXECUTE); 144 | com_loop(); 145 | } 146 | 147 | static int com_push(int evt) { 148 | com_mem->evt = evt; 149 | write(com_evt,&evt,sizeof(evt)); 150 | return 0; 151 | } 152 | static int com_loop() { 153 | int evt; 154 | dr_mem_info_t meminfo; 155 | 156 | while(read(com_evt,&evt,sizeof(evt)) > 0) { 157 | switch(evt) { 158 | case VMCOM_EVT_READMEM: 159 | if(!dr_query_memory_ex((byte*)com_mem->membuf.pos,&meminfo) || 160 | !(meminfo.prot & DR_MEMPROT_READ)) { 161 | com_mem->membuf.len = 0; 162 | } else { 163 | if(com_mem->membuf.len > sizeof(com_mem->membuf.buf)) { 164 | dr_printf("membuf overflow\n"); 165 | } else { 166 | memcpy( 167 | com_mem->membuf.buf, 168 | (void*)com_mem->membuf.pos, 169 | com_mem->membuf.len); 170 | } 171 | } 172 | com_push(VMCOM_EVT_READMEM); 173 | break; 174 | 175 | case VMCOM_EVT_RET: 176 | return 0; 177 | } 178 | } 179 | return 0; 180 | } 181 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 3.0 3 | 4 | # Default target executed when no arguments are given to make. 5 | default_target: all 6 | .PHONY : default_target 7 | 8 | # Allow only one "make -f Makefile2" at a time, but pass parallelism. 9 | .NOTPARALLEL: 10 | .PHONY : .NOTPARALLEL 11 | 12 | #============================================================================= 13 | # Special targets provided by cmake. 14 | 15 | # Disable implicit rules so canonical targets will work. 16 | .SUFFIXES: 17 | 18 | # Remove some rules from gmake that .SUFFIXES does not remove. 19 | SUFFIXES = 20 | 21 | .SUFFIXES: .hpux_make_needs_suffix_list 22 | 23 | # Suppress display of executed commands. 24 | $(VERBOSE).SILENT: 25 | 26 | # A target that is always out of date. 27 | cmake_force: 28 | .PHONY : cmake_force 29 | 30 | #============================================================================= 31 | # Set environment variables for the build. 32 | 33 | # The shell in which to execute make rules. 34 | SHELL = /bin/sh 35 | 36 | # The CMake executable. 37 | CMAKE_COMMAND = /usr/bin/cmake 38 | 39 | # The command to remove a file. 40 | RM = /usr/bin/cmake -E remove -f 41 | 42 | # Escaping for special characters. 43 | EQUALS = = 44 | 45 | # The top-level source directory on which CMake was run. 46 | CMAKE_SOURCE_DIR = /home/user/Work/symx/test 47 | 48 | # The top-level build directory on which CMake was run. 49 | CMAKE_BINARY_DIR = /home/user/Work/symx/test 50 | 51 | #============================================================================= 52 | # Targets provided globally by CMake. 53 | 54 | # Special rule for the target edit_cache 55 | edit_cache: 56 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." 57 | /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. 58 | .PHONY : edit_cache 59 | 60 | # Special rule for the target edit_cache 61 | edit_cache/fast: edit_cache 62 | .PHONY : edit_cache/fast 63 | 64 | # Special rule for the target rebuild_cache 65 | rebuild_cache: 66 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." 67 | /usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) 68 | .PHONY : rebuild_cache 69 | 70 | # Special rule for the target rebuild_cache 71 | rebuild_cache/fast: rebuild_cache 72 | .PHONY : rebuild_cache/fast 73 | 74 | # The main all target 75 | all: cmake_check_build_system 76 | $(CMAKE_COMMAND) -E cmake_progress_start /home/user/Work/symx/test/CMakeFiles /home/user/Work/symx/test/CMakeFiles/progress.marks 77 | $(MAKE) -f CMakeFiles/Makefile2 all 78 | $(CMAKE_COMMAND) -E cmake_progress_start /home/user/Work/symx/test/CMakeFiles 0 79 | .PHONY : all 80 | 81 | # The main clean target 82 | clean: 83 | $(MAKE) -f CMakeFiles/Makefile2 clean 84 | .PHONY : clean 85 | 86 | # The main clean target 87 | clean/fast: clean 88 | .PHONY : clean/fast 89 | 90 | # Prepare targets for installation. 91 | preinstall: all 92 | $(MAKE) -f CMakeFiles/Makefile2 preinstall 93 | .PHONY : preinstall 94 | 95 | # Prepare targets for installation. 96 | preinstall/fast: 97 | $(MAKE) -f CMakeFiles/Makefile2 preinstall 98 | .PHONY : preinstall/fast 99 | 100 | # clear depends 101 | depend: 102 | $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 103 | .PHONY : depend 104 | 105 | #============================================================================= 106 | # Target rules for targets named dyntrac 107 | 108 | # Build rule for target. 109 | dyntrac: cmake_check_build_system 110 | $(MAKE) -f CMakeFiles/Makefile2 dyntrac 111 | .PHONY : dyntrac 112 | 113 | # fast build rule for target. 114 | dyntrac/fast: 115 | $(MAKE) -f CMakeFiles/dyntrac.dir/build.make CMakeFiles/dyntrac.dir/build 116 | .PHONY : dyntrac/fast 117 | 118 | dyntrac.o: dyntrac.c.o 119 | .PHONY : dyntrac.o 120 | 121 | # target to build an object file 122 | dyntrac.c.o: 123 | $(MAKE) -f CMakeFiles/dyntrac.dir/build.make CMakeFiles/dyntrac.dir/dyntrac.c.o 124 | .PHONY : dyntrac.c.o 125 | 126 | dyntrac.i: dyntrac.c.i 127 | .PHONY : dyntrac.i 128 | 129 | # target to preprocess a source file 130 | dyntrac.c.i: 131 | $(MAKE) -f CMakeFiles/dyntrac.dir/build.make CMakeFiles/dyntrac.dir/dyntrac.c.i 132 | .PHONY : dyntrac.c.i 133 | 134 | dyntrac.s: dyntrac.c.s 135 | .PHONY : dyntrac.s 136 | 137 | # target to generate assembly for a file 138 | dyntrac.c.s: 139 | $(MAKE) -f CMakeFiles/dyntrac.dir/build.make CMakeFiles/dyntrac.dir/dyntrac.c.s 140 | .PHONY : dyntrac.c.s 141 | 142 | # Help Target 143 | help: 144 | @echo "The following are some of the valid targets for this Makefile:" 145 | @echo "... all (the default if no target is provided)" 146 | @echo "... clean" 147 | @echo "... depend" 148 | @echo "... dyntrac" 149 | @echo "... edit_cache" 150 | @echo "... rebuild_cache" 151 | @echo "... dyntrac.o" 152 | @echo "... dyntrac.i" 153 | @echo "... dyntrac.s" 154 | .PHONY : help 155 | 156 | 157 | 158 | #============================================================================= 159 | # Special targets to cleanup operation of make. 160 | 161 | # Special rule to run CMake to check the build system integrity. 162 | # No rule that depends on this can have commands that come from listfiles 163 | # because they might be regenerated. 164 | cmake_check_build_system: 165 | $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 166 | .PHONY : cmake_check_build_system 167 | 168 | -------------------------------------------------------------------------------- /src/expr.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_PREFIX "expr" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include"context.h" 8 | #include"utils.h" 9 | #include"expr.h" 10 | 11 | using namespace symx; 12 | 13 | namespace symx { 14 | int ExprVisitor::walk(const refExpr &expr) { 15 | unsigned int i; 16 | 17 | if(expr->pre_accept(this) == 0) { 18 | return 0; 19 | } 20 | switch(expr->type) { 21 | case ExprDangle: 22 | case ExprImm: 23 | case ExprVar: 24 | case ExprMem: 25 | break; 26 | case ExprOpIte: 27 | { 28 | auto oper = std::static_pointer_cast(expr); 29 | walk(oper->cond); 30 | walk(oper->operand[0]); 31 | walk(oper->operand[1]); 32 | break; 33 | } 34 | default: 35 | auto oper = std::static_pointer_cast(expr); 36 | for(i = 0; i < oper->op_count; i++) { 37 | walk(oper->operand[i]); 38 | } 39 | break; 40 | } 41 | 42 | return expr->post_accept(this); 43 | } 44 | int ExprVisitor::walk(const refCond &cond) { 45 | unsigned int i; 46 | 47 | if(cond->pre_accept(this) == 0){ 48 | return 0; 49 | } 50 | switch(cond->type) { 51 | case CondDangle: 52 | break; 53 | default: 54 | for(i = 0; i < cond->cond_count; i++) { 55 | walk(cond->cond[i]); 56 | } 57 | for(i = 0; i < cond->expr_count; i++) { 58 | walk(cond->expr[i]); 59 | } 60 | break; 61 | } 62 | return cond->post_accept(this); 63 | } 64 | 65 | BytVec::BytVec(const unsigned int _size,Context *ctx) 66 | : Expr(ExprVar,_size), 67 | id(ctx->get_next_varid()) {} 68 | BytMem::BytMem(Context *ctx) 69 | : Expr(ExprMem,0),id(ctx->get_next_varid()) {} 70 | 71 | refExpr expr_store( 72 | const refExpr &mem, 73 | const refExpr &idx, 74 | const refExpr &val 75 | ) { 76 | return ref(mem,idx,val); 77 | } 78 | refExpr expr_select( 79 | const refExpr &mem, 80 | const refExpr &idx, 81 | const unsigned int size 82 | ) { 83 | return ref(size,mem,idx); 84 | } 85 | refExpr expr_extract( 86 | const refExpr &op1, 87 | const unsigned int start, 88 | const unsigned int end 89 | ) { 90 | return ref(end - start,op1,start); 91 | } 92 | refExpr expr_ite( 93 | const refCond &cond, 94 | const refExpr &op1, 95 | const refExpr &op2 96 | ) { 97 | assert(op1->size == op2->size); 98 | return ref(op1->size,cond,op1,op2); 99 | } 100 | 101 | refExpr expr_add(const refExpr &op1,const refExpr &op2) { 102 | assert(op1->size == op2->size); 103 | return ref(ExprOpAdd,op1->size,op1,op2); 104 | } 105 | refExpr expr_sub(const refExpr &op1,const refExpr &op2) { 106 | assert(op1->size == op2->size); 107 | return ref(ExprOpSub,op1->size,op1,op2); 108 | } 109 | refExpr expr_mul(const refExpr &op1,const refExpr &op2) { 110 | assert(op1->size == op2->size); 111 | return ref(ExprOpMul,op1->size,op1,op2); 112 | } 113 | refExpr expr_and(const refExpr &op1,const refExpr &op2) { 114 | assert(op1->size == op2->size); 115 | return ref(ExprOpAnd,op1->size,op1,op2); 116 | } 117 | refExpr expr_or(const refExpr &op1,const refExpr &op2) { 118 | assert(op1->size == op2->size); 119 | return ref(ExprOpOr,op1->size,op1,op2); 120 | } 121 | refExpr expr_xor(const refExpr &op1,const refExpr &op2) { 122 | assert(op1->size == op2->size); 123 | return ref(ExprOpXor,op1->size,op1,op2); 124 | } 125 | refExpr expr_shl(const refExpr &op1,const refExpr &op2) { 126 | assert(op1->size == op2->size); 127 | return ref(ExprOpShl,op1->size,op1,op2); 128 | } 129 | refExpr expr_lshr(const refExpr &op1,const refExpr &op2) { 130 | assert(op1->size == op2->size); 131 | return ref(ExprOpLshr,op1->size,op1,op2); 132 | } 133 | refExpr expr_ashr(const refExpr &op1,const refExpr &op2) { 134 | assert(op1->size == op2->size); 135 | return ref(ExprOpAshr,op1->size,op1,op2); 136 | } 137 | refExpr expr_ror(const refExpr &op1,const refExpr &op2) { 138 | assert(op1->size == op2->size); 139 | return ref(ExprOpRor,op1->size,op1,op2); 140 | } 141 | refExpr expr_neg(const refExpr &op1) { 142 | return ref(ExprOpNeg,op1->size,op1); 143 | } 144 | refExpr expr_not(const refExpr &op1) { 145 | return ref(ExprOpNot,op1->size,op1); 146 | } 147 | refExpr expr_concat(const refExpr &op1,const refExpr &op2) { 148 | return ref(ExprOpConcat,op1->size + op2->size,op1,op2); 149 | } 150 | refExpr expr_sext(const refExpr &op1,const unsigned int size) { 151 | assert(op1->size <= size); 152 | return ref(ExprOpSext,size,op1); 153 | } 154 | refExpr expr_zext(const refExpr &op1,const unsigned int size) { 155 | assert(op1->size <= size); 156 | return ref(ExprOpZext,size,op1); 157 | } 158 | 159 | refCond cond_eq(const refExpr &op1,const refExpr &op2) { 160 | assert(op1->size == op2->size); 161 | return ref(CondEq,op1,op2); 162 | } 163 | refCond cond_sl(const refExpr &op1,const refExpr &op2) { 164 | assert(op1->size == op2->size); 165 | return ref(CondSl,op1,op2); 166 | } 167 | refCond cond_sle(const refExpr &op1,const refExpr &op2) { 168 | assert(op1->size == op2->size); 169 | return ref(CondSle,op1,op2); 170 | } 171 | refCond cond_ul(const refExpr &op1,const refExpr &op2) { 172 | assert(op1->size == op2->size); 173 | return ref(CondUl,op1,op2); 174 | } 175 | refCond cond_ule(const refExpr &op1,const refExpr &op2) { 176 | assert(op1->size == op2->size); 177 | return ref(CondUle,op1,op2); 178 | } 179 | refCond cond_sg(const refExpr &op1,const refExpr &op2) { 180 | assert(op1->size == op2->size); 181 | return ref(CondSg,op1,op2); 182 | } 183 | refCond cond_sge(const refExpr &op1,const refExpr &op2) { 184 | assert(op1->size == op2->size); 185 | return ref(CondSge,op1,op2); 186 | } 187 | refCond cond_ug(const refExpr &op1,const refExpr &op2) { 188 | assert(op1->size == op2->size); 189 | return ref(CondUg,op1,op2); 190 | } 191 | refCond cond_uge(const refExpr &op1,const refExpr &op2) { 192 | assert(op1->size == op2->size); 193 | return ref(CondUge,op1,op2); 194 | } 195 | refCond cond_ite(const refCond &cond,const refCond &op1,const refCond &op2) { 196 | return ref(cond,op1,op2); 197 | } 198 | refCond cond_and(const refCond &op1,const refCond &op2) { 199 | return ref(CondAnd,op1,op2); 200 | } 201 | refCond cond_or(const refCond &op1,const refCond &op2) { 202 | return ref(CondOr,op1,op2); 203 | } 204 | refCond cond_xor(const refCond &op1,const refCond &op2) { 205 | return ref(CondXor,op1,op2); 206 | } 207 | refCond cond_not(const refCond &op1) { 208 | return ref(CondNot,op1); 209 | } 210 | 211 | }; 212 | -------------------------------------------------------------------------------- /src/vm.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_PREFIX "vm" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define LINUX 20 | #define X86_32 21 | extern "C" { 22 | #include 23 | #include 24 | #include 25 | } 26 | 27 | #include"utils.h" 28 | #include"vm.h" 29 | 30 | using namespace symx; 31 | 32 | int VirtualMachine::create( 33 | const char *container_path, 34 | const char *exe_path, 35 | const char **argv 36 | ) { 37 | void *data; 38 | process_id_t pid; 39 | int listen_fd; 40 | 41 | dr_inject_process_create(exe_path,argv,&data); 42 | pid = dr_inject_get_process_id(data); 43 | snprintf(name,sizeof(name),"symx_vm"); 44 | 45 | if(dr_register_process( 46 | exe_path, 47 | pid, 48 | false, 49 | "../dynamorio", 50 | DR_MODE_CODE_MANIPULATION, 51 | false, 52 | DR_PLATFORM_32BIT, 53 | "")) { 54 | goto error; 55 | } 56 | if(dr_register_client( 57 | exe_path, 58 | pid, 59 | false, 60 | DR_PLATFORM_32BIT, 61 | 0, 62 | 0, 63 | "./libvmclient.so", 64 | name)) { 65 | goto error; 66 | } 67 | if(!dr_inject_process_inject(data,false,NULL)) { 68 | goto error; 69 | } 70 | 71 | listen_fd = vmcom_create(); 72 | if(!dr_inject_process_run(data)) { 73 | goto error; 74 | } 75 | vmcom_accept(listen_fd); 76 | 77 | //dr_inject_wait_for_child(data,0); 78 | 79 | this->pid = pid; 80 | this->data = data; 81 | state = RUNNING; 82 | info("VM create: %d %s %s\n",this->pid,container_path,exe_path); 83 | return 0; 84 | 85 | error: 86 | 87 | dr_inject_process_exit(data,true); 88 | return -1; 89 | } 90 | int VirtualMachine::vmcom_create() { 91 | char event_path[PATH_MAX + 1]; 92 | char mem_path[PATH_MAX + 1]; 93 | int mem_fd; 94 | int listen_fd; 95 | struct sockaddr_un addr; 96 | socklen_t addrlen; 97 | 98 | snprintf(mem_path,sizeof(mem_path),"%s_mem",name); 99 | unlink(mem_path); 100 | mem_fd = open(mem_path,O_RDWR | O_CREAT | O_TRUNC,0600); 101 | ftruncate(mem_fd,65536); 102 | com_mem = (struct vmcom_frame*)mmap( 103 | NULL, 104 | sizeof(vmcom_frame), 105 | PROT_READ | PROT_WRITE, 106 | MAP_SHARED, 107 | mem_fd, 108 | 0); 109 | close(mem_fd); 110 | 111 | snprintf(event_path,sizeof(event_path),"%s_event",name); 112 | listen_fd = socket(AF_UNIX,SOCK_STREAM,0); 113 | addr.sun_family = AF_UNIX; 114 | strncpy(addr.sun_path,event_path,UNIX_PATH_MAX - 1); 115 | unlink(addr.sun_path); 116 | addrlen = offsetof(struct sockaddr_un,sun_path) + strlen(addr.sun_path); 117 | bind(listen_fd,(struct sockaddr*)&addr,addrlen); 118 | listen(listen_fd,1024); 119 | 120 | return listen_fd; 121 | } 122 | int VirtualMachine::vmcom_accept(int listen_fd) { 123 | struct sockaddr_un addr; 124 | socklen_t addrlen; 125 | 126 | addrlen = sizeof(addr); 127 | com_evt = accept(listen_fd,(struct sockaddr*)&addr,&addrlen); 128 | close(listen_fd); 129 | return 0; 130 | } 131 | int VirtualMachine::destroy() { 132 | munmap(com_mem,sizeof(vmcom_frame)); 133 | close(com_evt); 134 | dr_inject_process_exit(data,true); 135 | return 0; 136 | } 137 | int VirtualMachine::set_state(VMSTATE next_state) { 138 | if(next_state == EVENT) { 139 | assert(state = RUNNING); 140 | } 141 | if(next_state == RUNNING) { 142 | assert(state == EVENT); 143 | } 144 | if(next_state == SUSPEND) { 145 | assert(state == EVENT); 146 | } 147 | state = next_state; 148 | return 0; 149 | } 150 | int VirtualMachine::event_wait() { 151 | int evt; 152 | 153 | if(read(com_evt,&evt,sizeof(evt)) == sizeof(evt)) { 154 | state = EVENT; 155 | return evt; 156 | } 157 | return -1; 158 | } 159 | int VirtualMachine::event_send(int evt) { 160 | return write(com_evt,&evt,sizeof(evt)); 161 | } 162 | int VirtualMachine::event_ret() { 163 | int evt = VMCOM_EVT_RET; 164 | 165 | if(set_state(RUNNING)) { 166 | return -1; 167 | } 168 | return write(com_evt,&evt,sizeof(evt)); 169 | } 170 | 171 | Snapshot::Snapshot(cs_arch arch,cs_mode mode) { 172 | cs_open(arch,mode,&cs); 173 | cs_option(cs,CS_OPT_DETAIL,CS_OPT_ON); 174 | } 175 | std::vector Snapshot::translate_bb(const symx::ProgCtr &pc) const { 176 | uint64_t curpc = pc.rawpc; 177 | uint64_t endpc = curpc; 178 | uint8_t code[8192]; 179 | const uint8_t *codeptr; 180 | cs_insn *ins; 181 | size_t remain; 182 | uint8_t *block; 183 | 184 | cs_option(cs,CS_OPT_MODE,pc.mode); 185 | ins = cs_malloc(cs); 186 | remain = PAGE_SIZE - (curpc & (~PAGE_MASK)); 187 | while(true) { 188 | if(mem_read(code,curpc,remain)) { 189 | return {}; 190 | } 191 | codeptr = code; 192 | while(remain > 0) { 193 | if(!cs_disasm_iter(cs,&codeptr,&remain,&curpc,ins)) { 194 | break; 195 | } 196 | dbg("%s %s\n",ins->mnemonic,ins->op_str); 197 | if(cs_insn_group(cs,ins,CS_GRP_CALL) || 198 | cs_insn_group(cs,ins,CS_GRP_RET) || 199 | cs_insn_group(cs,ins,CS_GRP_IRET) || 200 | cs_insn_group(cs,ins,CS_GRP_JUMP)) { 201 | endpc = ins->address + ins->size; 202 | goto out; 203 | } 204 | if(ins->id == X86_INS_INT3) { 205 | return {}; 206 | } 207 | } 208 | curpc += (uint64_t)codeptr - (uint64_t)code; 209 | remain += PAGE_SIZE; 210 | } 211 | 212 | out: 213 | 214 | block = new uint8_t[endpc - pc.rawpc]; 215 | mem_read(block,pc.rawpc,endpc - pc.rawpc); 216 | 217 | auto ret = translate(block,pc,endpc - pc.rawpc); 218 | 219 | delete[] block; 220 | cs_free(ins,1); 221 | return ret; 222 | } 223 | 224 | AddrSpace::AddrSpace(Context *_ctx,const refSnapshot &_snap) 225 | : ctx(_ctx),snap(_snap) 226 | { 227 | mem = BytMem::create_var(ctx); 228 | //TODO initialize memory layout 229 | } 230 | int AddrSpace::read(refState state,uint8_t *buf,uint64_t pos,size_t len) { 231 | //assume executable page is read only 232 | //TODO check page 233 | return snap->mem_read(buf,pos,len); 234 | } 235 | int AddrSpace::handle_select(const uint64_t idx,const unsigned int size) { 236 | int ret = 0; 237 | uint64_t pos,base; 238 | unsigned int off; 239 | uint8_t buf[1]; 240 | refBytVec val; 241 | std::map::iterator page_it; 242 | 243 | assert(size % 8 == 0); 244 | 245 | pos = idx; 246 | while(pos < (idx + size / 8)) { 247 | base = pos & ~(PAGE_SIZE - 1); 248 | off = pos & (PAGE_SIZE - 1); 249 | 250 | page_it = page_map.find(base); 251 | if(page_it == page_map.end()) { 252 | //err("page out bound\n"); 253 | //for test 254 | auto page = MemPage(base,PROT_READ | PROT_WRITE); 255 | page_it = page_map.insert(std::make_pair(base,page)).first; 256 | } 257 | 258 | auto &page = page_it->second; 259 | for(; off < PAGE_SIZE && pos < (idx + size / 8); off++,pos++) { 260 | if(page.dirty.test(off)) { 261 | continue; 262 | } 263 | 264 | if(pos >= 0x1000 && pos < 0x2000) { 265 | //for test 266 | //val = BytVec::create_imm(8,0xb); 267 | //page.symbol.reset(off); 268 | val = BytVec::create_var(8,ctx); 269 | mem_symbol[pos] = val; 270 | page.symbol.set(off); 271 | } else { 272 | if(snap->mem_read(buf,pos,sizeof(*buf))) { 273 | err("read page failed %016lx\n",pos); 274 | //TODO return read error 275 | continue; 276 | } 277 | val = BytVec::create_imm(8,buf[0]); 278 | page.symbol.reset(off); 279 | } 280 | 281 | mem_constr.push_back(cond_eq( 282 | expr_select(mem,BytVec::create_imm(32,pos),8), 283 | val)); 284 | 285 | page.dirty.set(off); 286 | ret += 1; 287 | } 288 | } 289 | 290 | return ret; 291 | } 292 | std::vector AddrSpace::source_select( 293 | const refOperator &sel, 294 | const std::unordered_map &var 295 | ) const { 296 | std::vector retseq; 297 | refExpr mem; 298 | uint64_t base; 299 | uint64_t idx; 300 | 301 | assert(sel->type == ExprOpSelect); 302 | 303 | auto base_it = var.find(sel->operand[1]); 304 | 305 | assert(base_it != var.end()); 306 | 307 | mem = sel->operand[0]; 308 | base = base_it->second; 309 | 310 | while(mem->type != ExprMem) { 311 | 312 | assert(mem->type == ExprOpStore); 313 | 314 | auto str = std::static_pointer_cast(mem); 315 | auto idx_it = var.find(str->operand[1]); 316 | 317 | assert(idx_it != var.end()); 318 | 319 | idx = idx_it->second; 320 | 321 | if(idx == base) { 322 | retseq.push_back(str); 323 | break; 324 | } 325 | 326 | mem = str->operand[0]; 327 | } 328 | 329 | return retseq; 330 | } 331 | -------------------------------------------------------------------------------- /inc/expr.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include"utils.h" 5 | 6 | #ifndef _EXPR_H_ 7 | #define _EXPR_H_ 8 | 9 | namespace symx { 10 | using namespace symx; 11 | 12 | class Context; 13 | class Expr; 14 | class BytMem; 15 | class BytVec; 16 | class Operator; 17 | class Cond; 18 | class ExprVisitor; 19 | typedef std::shared_ptr refExpr; 20 | typedef std::shared_ptr refBytVec; 21 | typedef std::shared_ptr refBytMem; 22 | typedef std::shared_ptr refOperator; 23 | typedef std::shared_ptr refCond; 24 | 25 | class ExprVisitor { 26 | private: 27 | std::unordered_set vis_expr; 28 | std::unordered_set vis_cond; 29 | 30 | public: 31 | virtual ~ExprVisitor() {}; 32 | virtual int pre_visit(const refBytVec &vec) = 0; 33 | virtual int pre_visit(const refBytMem &mem) = 0; 34 | virtual int pre_visit(const refOperator &oper) = 0; 35 | virtual int pre_visit(const refCond &cond) = 0; 36 | virtual int post_visit(const refBytVec &vec) = 0; 37 | virtual int post_visit(const refBytMem &mem) = 0; 38 | virtual int post_visit(const refOperator &oper) = 0; 39 | virtual int post_visit(const refCond &cond) = 0; 40 | 41 | int walk(const refExpr &expr); 42 | int walk(const refCond &cond); 43 | 44 | template 45 | int iter_walk(refIt begin,refIt end) { 46 | for(auto it = begin; it != end; it++) { 47 | walk(*it); 48 | } 49 | return 0; 50 | } 51 | }; 52 | 53 | enum ExprType { 54 | ExprDangle, 55 | ExprImm, 56 | ExprVar, 57 | ExprMem, 58 | 59 | ExprOpStore, 60 | ExprOpSelect, 61 | ExprOpExtract, 62 | ExprOpIte, 63 | 64 | ExprOpAdd, 65 | ExprOpSub, 66 | ExprOpMul, 67 | ExprOpUdiv, 68 | ExprOpSdiv, 69 | ExprOpAnd, 70 | ExprOpOr, 71 | ExprOpXor, 72 | ExprOpShl, 73 | ExprOpLshr, 74 | ExprOpAshr, 75 | ExprOpRor, 76 | ExprOpNeg, 77 | ExprOpNot, 78 | ExprOpConcat, 79 | ExprOpSext, 80 | ExprOpZext, 81 | }; 82 | class Expr : public std::enable_shared_from_this { 83 | public: 84 | const enum ExprType type; 85 | const unsigned int size; 86 | 87 | Expr(const enum ExprType _type,const unsigned int _size) 88 | : type(_type),size(_size) {} 89 | virtual int pre_accept(ExprVisitor *visitor) const = 0; 90 | virtual int post_accept(ExprVisitor *visitor) const = 0; 91 | }; 92 | class BytVec : public Expr { 93 | public: 94 | union { 95 | const unsigned int id; 96 | const unsigned int index; 97 | const uint64_t data; 98 | }; 99 | BytVec(const refBytVec old) 100 | : Expr(old->type,old->size),data(old->data) {} 101 | int pre_accept(ExprVisitor *visitor) const { 102 | return visitor->pre_visit( 103 | std::static_pointer_cast( 104 | shared_from_this())); 105 | } 106 | int post_accept(ExprVisitor *visitor) const { 107 | return visitor->post_visit( 108 | std::static_pointer_cast( 109 | shared_from_this())); 110 | } 111 | BytVec(const unsigned int _size,const unsigned int _index) : 112 | Expr(ExprDangle,_size),index(_index) {} 113 | BytVec(const unsigned int _size,const uint64_t imm) : 114 | Expr(ExprImm,_size),data(imm) {} 115 | BytVec(const unsigned int _size,Context *ctx); 116 | static refBytVec create_dangle( 117 | const unsigned int size, 118 | const unsigned int index 119 | ) { 120 | return ref(size,index); 121 | } 122 | static refBytVec create_imm( 123 | const unsigned int size, 124 | const uint64_t imm 125 | ) { 126 | return ref(size,imm); 127 | } 128 | static refBytVec create_var(const unsigned int size,Context *ctx) { 129 | return ref(size,ctx); 130 | } 131 | }; 132 | class BytMem : public Expr { 133 | public: 134 | union { 135 | const unsigned int id; 136 | const unsigned int index; 137 | }; 138 | BytMem(const refBytMem old) 139 | : Expr(old->type,old->size),index(old->index) {} 140 | int pre_accept(ExprVisitor *visitor) const { 141 | return visitor->pre_visit( 142 | std::static_pointer_cast( 143 | shared_from_this())); 144 | } 145 | int post_accept(ExprVisitor *visitor) const { 146 | return visitor->post_visit( 147 | std::static_pointer_cast( 148 | shared_from_this())); 149 | } 150 | BytMem(const unsigned int _index) 151 | : Expr(ExprDangle,0),index(_index) {} 152 | BytMem(Context *ctx); 153 | static refBytMem create_dangle(const unsigned int index) { 154 | return ref(index); 155 | } 156 | static refBytMem create_var(Context *ctx) { 157 | return ref(ctx); 158 | } 159 | }; 160 | class Operator : public Expr { 161 | public: 162 | refExpr operand[3]; 163 | refCond cond; 164 | unsigned int start; 165 | const unsigned int op_count; 166 | 167 | Operator( 168 | const enum ExprType op_type, 169 | const unsigned int _size, 170 | const refExpr &op1 171 | ) : Expr(op_type,_size),op_count(1) { 172 | operand[0] = op1; 173 | } 174 | Operator( 175 | const enum ExprType op_type, 176 | const unsigned int _size, 177 | const refExpr &op1, 178 | const refExpr &op2) 179 | : Expr(op_type,_size),op_count(2) { 180 | operand[0] = op1; 181 | operand[1] = op2; 182 | } 183 | Operator( 184 | const refExpr &mem, 185 | const refExpr &idx, 186 | const refExpr &val) 187 | : Expr(ExprOpStore,0),op_count(3) { 188 | operand[0] = mem; 189 | operand[1] = idx; 190 | operand[2] = val; 191 | } 192 | Operator( 193 | const unsigned int _size, 194 | const refExpr &mem, 195 | const refExpr &idx) 196 | : Expr(ExprOpSelect,_size),op_count(2) { 197 | operand[0] = mem; 198 | operand[1] = idx; 199 | } 200 | Operator( 201 | const unsigned int _size, 202 | const refExpr &op1, 203 | const unsigned int _start) 204 | : Expr(ExprOpExtract,_size),start(_start),op_count(1) { 205 | operand[0] = op1; 206 | } 207 | Operator( 208 | const unsigned int _size, 209 | const refCond &_cond, 210 | const refExpr &op1, 211 | const refExpr &op2) 212 | : Expr(ExprOpIte,_size),cond(_cond),op_count(2) { 213 | operand[0] = op1; 214 | operand[1] = op2; 215 | } 216 | int pre_accept(ExprVisitor *visitor) const { 217 | return visitor->pre_visit( 218 | std::static_pointer_cast( 219 | shared_from_this())); 220 | } 221 | int post_accept(ExprVisitor *visitor) const { 222 | return visitor->post_visit( 223 | std::static_pointer_cast( 224 | shared_from_this())); 225 | } 226 | }; 227 | 228 | enum CondType { 229 | CondDangle, 230 | CondIte, 231 | CondFalse, 232 | CondTrue, 233 | CondEq, 234 | CondSl, 235 | CondSle, 236 | CondUl, 237 | CondUle, 238 | CondSg, 239 | CondSge, 240 | CondUg, 241 | CondUge, 242 | CondAnd, 243 | CondOr, 244 | CondXor, 245 | CondNot, 246 | }; 247 | class Cond : public std::enable_shared_from_this { 248 | public: 249 | const enum CondType type; 250 | const unsigned int expr_count; 251 | const unsigned int cond_count; 252 | unsigned int index; 253 | refCond cond[3]; 254 | refExpr expr[2]; 255 | 256 | Cond( 257 | const enum CondType _type, 258 | const refCond &op1) 259 | : type(_type),expr_count(0),cond_count(1) { 260 | cond[0] = op1; 261 | } 262 | Cond( 263 | const enum CondType _type, 264 | const refCond &op1, 265 | const refCond &op2) 266 | : type(_type),expr_count(0),cond_count(2) { 267 | cond[0] = op1; 268 | cond[1] = op2; 269 | } 270 | Cond( 271 | const refCond &op1, 272 | const refCond &op2, 273 | const refCond &op3) 274 | : type(CondIte),expr_count(0),cond_count(3) { 275 | cond[0] = op1; 276 | cond[1] = op2; 277 | cond[2] = op3; 278 | } 279 | Cond( 280 | const enum CondType _type, 281 | const refExpr &op1, 282 | const refExpr &op2) 283 | : type(_type),expr_count(2),cond_count(0) { 284 | expr[0] = op1; 285 | expr[1] = op2; 286 | } 287 | int pre_accept(ExprVisitor *visitor) const { 288 | return visitor->pre_visit( 289 | std::static_pointer_cast( 290 | shared_from_this())); 291 | } 292 | int post_accept(ExprVisitor *visitor) const { 293 | return visitor->post_visit( 294 | std::static_pointer_cast( 295 | shared_from_this())); 296 | } 297 | Cond(const unsigned int _index) : 298 | type(CondDangle), 299 | expr_count(0), 300 | cond_count(0), 301 | index(_index) {} 302 | Cond(const enum CondType _type) 303 | : type(_type),expr_count(0),cond_count(0) {} 304 | static refCond create_dangle(const unsigned int index) { 305 | return ref(index); 306 | } 307 | static refCond create_false() { 308 | return ref(CondFalse); 309 | } 310 | static refCond create_true() { 311 | return ref(CondTrue); 312 | } 313 | }; 314 | 315 | refExpr expr_store( 316 | const refExpr &mem, 317 | const refExpr &idx, 318 | const refExpr &val); 319 | refExpr expr_select( 320 | const refExpr &mem, 321 | const refExpr &idx, 322 | const unsigned int size); 323 | refExpr expr_ite(const refCond &cond,const refExpr &op1,const refExpr &op2); 324 | refExpr expr_add(const refExpr &op1,const refExpr &op2); 325 | refExpr expr_sub(const refExpr &op1,const refExpr &op2); 326 | refExpr expr_mul(const refExpr &op1,const refExpr &op2); 327 | refExpr expr_and(const refExpr &op1,const refExpr &op2); 328 | refExpr expr_or(const refExpr &op1,const refExpr &op2); 329 | refExpr expr_xor(const refExpr &op1,const refExpr &op2); 330 | refExpr expr_shl(const refExpr &op1,const refExpr &op2); 331 | refExpr expr_lshr(const refExpr &op1,const refExpr &op2); 332 | refExpr expr_ashr(const refExpr &op1,const refExpr &op2); 333 | refExpr expr_ror(const refExpr &op1,const refExpr &op2); 334 | refExpr expr_neg(const refExpr &op1); 335 | refExpr expr_not(const refExpr &op1); 336 | refExpr expr_extract( 337 | const refExpr &op1, 338 | const unsigned int start, 339 | const unsigned int end); 340 | //op1 low, op2 high 341 | refExpr expr_concat(const refExpr &op1,const refExpr &op2); 342 | refExpr expr_sext(const refExpr &op1,const unsigned int size); 343 | refExpr expr_zext(const refExpr &op1,const unsigned int size); 344 | 345 | refCond cond_eq(const refExpr &op1,const refExpr &op2); 346 | refCond cond_sl(const refExpr &op1,const refExpr &op2); 347 | refCond cond_sle(const refExpr &op1,const refExpr &op2); 348 | refCond cond_ul(const refExpr &op1,const refExpr &op2); 349 | refCond cond_ule(const refExpr &op1,const refExpr &op2); 350 | refCond cond_sg(const refExpr &op1,const refExpr &op2); 351 | refCond cond_sge(const refExpr &op1,const refExpr &op2); 352 | refCond cond_ug(const refExpr &op1,const refExpr &op2); 353 | refCond cond_uge(const refExpr &op1,const refExpr &op2); 354 | refCond cond_ite(const refCond &cond,const refCond &op1,const refCond &op2); 355 | refCond cond_and(const refCond &op1,const refCond &op2); 356 | refCond cond_or(const refCond &op1,const refCond &op2); 357 | refCond cond_xor(const refCond &op1,const refCond &op2); 358 | refCond cond_not(const refCond &op1); 359 | 360 | }; 361 | 362 | #endif 363 | -------------------------------------------------------------------------------- /arch/openreil/openreil.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_PREFIX "openreil" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include"utils.h" 13 | #include"expr.h" 14 | #include"vm.h" 15 | #include"state.h" 16 | #include"arch/openreil/openreil.h" 17 | 18 | using namespace openreil; 19 | 20 | static std::vector instlist; 21 | static const char *REGNAME[] = { 22 | "R_EAX", 23 | "R_EBX", 24 | "R_ECX", 25 | "R_EDX", 26 | "R_EDI", 27 | "R_ESI", 28 | "R_EBP", 29 | "R_ESP", 30 | 31 | "R_GS", 32 | "R_GS_BASE", 33 | 34 | "R_EFLAGS", 35 | "R_DFLAG", 36 | 37 | "R_CF", 38 | "R_PF", 39 | "R_AF", 40 | "R_ZF", 41 | "R_SF", 42 | "R_OF", 43 | }; 44 | static const unsigned int REGSIZE[] = { 45 | 32, 46 | 32, 47 | 32, 48 | 32, 49 | 32, 50 | 32, 51 | 32, 52 | 32, 53 | 16, 54 | 32, 55 | 32, 56 | 32, 57 | 1, 58 | 1, 59 | 1, 60 | 1, 61 | 1, 62 | 1, 63 | }; 64 | static const unsigned int REILSIZE[] = { 65 | 1, 66 | 8, 67 | 16, 68 | 32, 69 | 64, 70 | }; 71 | static const symx::refExpr IMMFALSE = symx::BytVec::create_imm(1,0x0); 72 | static const symx::refExpr IMMTRUE = symx::BytVec::create_imm(1,0x1); 73 | 74 | VirtualMachine* Context::create_vm() { 75 | VirtualMachine *vm = new VirtualMachine(); 76 | const char *argv[] = {exe_path,NULL}; 77 | if(vm->create(container_path,exe_path,argv)) { 78 | err("virtual machine create failed\n"); 79 | } 80 | return vm; 81 | } 82 | int Context::destroy_vm(symx::VirtualMachine *vm) { 83 | vm->destroy(); 84 | delete vm; 85 | return 0; 86 | } 87 | uint64_t VirtualMachine::event_get_pc() const { 88 | assert(com_mem->evt == VMCOM_EVT_EXECUTE); 89 | return com_mem->context.pc; 90 | } 91 | symx::refSnapshot VirtualMachine::event_suspend() { 92 | int i; 93 | uint64_t reg[REGIDX_END]; 94 | 95 | if(set_state(SUSPEND)) { 96 | return nullptr; 97 | } 98 | 99 | for(i = 0; i < REGIDX_EFLAGS; i++) { 100 | reg[i] = com_mem->context.reg[i]; 101 | } 102 | 103 | reg[REGIDX_EFLAGS] = com_mem->context.flag; 104 | reg[REGIDX_DFLAG] = (com_mem->context.flag >> 10) & 0x1; 105 | 106 | reg[REGIDX_CF] = (com_mem->context.flag >> 0) & 0x1; 107 | reg[REGIDX_PF] = (com_mem->context.flag >> 2) & 0x1; 108 | reg[REGIDX_AF] = (com_mem->context.flag >> 4) & 0x1; 109 | reg[REGIDX_ZF] = (com_mem->context.flag >> 6) & 0x1; 110 | reg[REGIDX_SF] = (com_mem->context.flag >> 7) & 0x1; 111 | reg[REGIDX_OF] = (com_mem->context.flag >> 11) & 0x1; 112 | 113 | return ref(this,reg); 114 | } 115 | int VirtualMachine::mem_read(uint8_t *buf,uint64_t pos,size_t len) { 116 | assert(len < sizeof(com_mem->membuf.buf)); 117 | 118 | com_mem->membuf.pos = (uint32_t)pos; 119 | com_mem->membuf.len = len; 120 | event_send(VMCOM_EVT_READMEM); 121 | event_wait(); 122 | 123 | if(com_mem->membuf.len == 0) { 124 | return -1; 125 | } 126 | 127 | memcpy(buf,com_mem->membuf.buf,len); 128 | return 0; 129 | } 130 | 131 | Snapshot::Snapshot(VirtualMachine *_vm,const uint64_t *_reg) 132 | : symx::Snapshot(CS_ARCH_X86,CS_MODE_32),vm(_vm) 133 | { 134 | int i; 135 | for(i = 0; i < REGIDX_END; i++) { 136 | reg.push_back(symx::BytVec::create_imm(REGSIZE[i],_reg[i])); 137 | } 138 | } 139 | int Snapshot::mem_read(uint8_t *buf,uint64_t pos,size_t len) const { 140 | return vm->mem_read(buf,pos,len); 141 | } 142 | 143 | #define MAX_ARG_STR 50 144 | const char *inst_op[] = { 145 | "NONE", "UNK", "JCC", 146 | "STR", "STM", "LDM", 147 | "ADD", "SUB", "NEG", "MUL", "DIV", "MOD", "SMUL", "SDIV", "SMOD", 148 | "SHL", "SHR", "AND", "OR", "XOR", "NOT", 149 | "EQ", "LT" 150 | }; 151 | int arg_size[] = { 1, 8, 16, 32, 64 }; 152 | char *arg_print(reil_arg_t *arg,char *arg_str) { 153 | memset(arg_str, 0, MAX_ARG_STR); 154 | switch (arg->type) { 155 | case A_NONE: 156 | break; 157 | case A_REG: 158 | case A_TEMP: 159 | snprintf( 160 | arg_str, 161 | MAX_ARG_STR - 1, 162 | "%s:%d", 163 | arg->name, 164 | arg_size[arg->size]); 165 | break; 166 | case A_CONST: 167 | snprintf( 168 | arg_str, 169 | MAX_ARG_STR - 1, 170 | "%llx:%d", 171 | arg->val, 172 | arg_size[arg->size]); 173 | break; 174 | } 175 | return arg_str; 176 | } 177 | void inst_print(const std::vector::iterator &inst) { 178 | char arg_str[3][MAX_ARG_STR]; 179 | arg_print(&inst->a, arg_str[0]); 180 | arg_print(&inst->b, arg_str[1]); 181 | arg_print(&inst->c, arg_str[2]); 182 | dbg("%.8llx.%.2x %7s %16s, %16s, %16s\n", 183 | inst->raw_info.addr, 184 | inst->inum, 185 | inst_op[inst->op], 186 | arg_str[0], 187 | arg_str[1], 188 | arg_str[2]); 189 | } 190 | int Snapshot::inst_handler(reil_inst_t *inst,void *ctx) { 191 | instlist.push_back(*inst); 192 | return 0; 193 | } 194 | std::vector Snapshot::translate( 195 | uint8_t *code, 196 | const symx::ProgCtr &pc, 197 | size_t len 198 | ) const { 199 | unsigned int i; 200 | uint64_t rawpc = pc.rawpc; 201 | reil_t reil; 202 | int translated; 203 | 204 | std::vector blklist; 205 | symx::refCond prevcond = nullptr; 206 | symx::refExpr mem; 207 | std::vector reglist; 208 | std::vector flaglist; 209 | std::unordered_map regmap; 210 | symx::refExpr xra,xrb,xrc; 211 | 212 | //initialize openreil, translate to reil IR 213 | reil = reil_init(ARCH_X86,inst_handler,(void*)&translated); 214 | instlist.clear(); 215 | reil_translate(reil,rawpc,code,len); 216 | reil_close(reil); 217 | 218 | //initialize dangle memory, register 219 | mem = symx::BytMem::create_dangle(-1); 220 | for(i = 0; i < REGIDX_END; i++) { 221 | auto reg = symx::BytVec::create_dangle(REGSIZE[i],i); 222 | regmap[REGNAME[i]] = reg; 223 | } 224 | 225 | blklist.clear(); 226 | 227 | for(auto ins = instlist.begin(); ins != instlist.end(); ins++) { 228 | inst_print(ins); 229 | 230 | switch(ins->op) { 231 | case I_STR: 232 | translate_set_arg( 233 | ®map, 234 | ins->c, 235 | translate_get_arg(regmap,ins->a)); 236 | break; 237 | 238 | case I_ADD: 239 | case I_SUB: 240 | case I_MUL: 241 | case I_SHR: 242 | case I_SHL: 243 | xra = translate_fixsize( 244 | translate_get_arg(regmap,ins->a), 245 | ins->a.size); 246 | xrb = translate_fixsize( 247 | translate_get_arg(regmap,ins->b), 248 | ins->b.size); 249 | 250 | switch(ins->op) { 251 | case I_ADD: 252 | xrc = symx::expr_add(xra,xrb); 253 | break; 254 | case I_SUB: 255 | xrc = symx::expr_sub(xra,xrb); 256 | break; 257 | case I_MUL: 258 | xrc = symx::expr_mul(xra,xrb); 259 | break; 260 | case I_SHR: 261 | xrc = symx::expr_lshr(xra,xrb); 262 | break; 263 | case I_SHL: 264 | xrc = symx::expr_shl(xra,xrb); 265 | break; 266 | default: 267 | err("unexpected\n"); 268 | break; 269 | } 270 | translate_set_arg(®map,ins->c,xrc); 271 | break; 272 | 273 | case I_AND: 274 | case I_OR: 275 | case I_XOR: 276 | xra = translate_get_arg(regmap,ins->a); 277 | xrb = translate_get_arg(regmap,ins->b); 278 | 279 | if(xra->size != xrb->size) { 280 | xra = translate_fixsize(xra,ins->c.size); 281 | xrb = translate_fixsize(xrb,ins->c.size); 282 | } 283 | 284 | switch(ins->op) { 285 | case I_AND: 286 | xrc = symx::expr_and(xra,xrb); 287 | break; 288 | case I_OR: 289 | xrc = symx::expr_or(xra,xrb); 290 | break; 291 | case I_XOR: 292 | xrc = symx::expr_xor(xra,xrb); 293 | break; 294 | 295 | default: 296 | err("unexpected\n"); 297 | break; 298 | } 299 | translate_set_arg(®map,ins->c,xrc); 300 | break; 301 | 302 | case I_NEG: 303 | case I_NOT: 304 | xra = translate_get_arg(regmap,ins->a); 305 | switch(ins->op) { 306 | case I_NEG: 307 | xrc = symx::expr_neg(xra); 308 | break; 309 | case I_NOT: 310 | xrc = symx::expr_not(xra); 311 | break; 312 | default: 313 | err("unexpected\n"); 314 | break; 315 | } 316 | translate_set_arg(®map,ins->c,xrc); 317 | break; 318 | 319 | case I_EQ: 320 | case I_LT: 321 | xra = translate_fixsize( 322 | translate_get_arg(regmap,ins->a), 323 | ins->a.size); 324 | xrb = translate_fixsize( 325 | translate_get_arg(regmap,ins->b), 326 | ins->b.size); 327 | 328 | switch(ins->op) { 329 | case I_EQ: 330 | xrc = symx::expr_ite( 331 | symx::cond_eq(xra,xrb), 332 | IMMTRUE, 333 | IMMFALSE); 334 | break; 335 | case I_LT: 336 | xrc = symx::expr_ite( 337 | symx::cond_ul(xra,xrb), 338 | IMMTRUE, 339 | IMMFALSE); 340 | break; 341 | default: 342 | err("unexpected\n"); 343 | break; 344 | } 345 | translate_set_arg(®map,ins->c,xrc); 346 | break; 347 | 348 | case I_LDM: 349 | xra = translate_fixsize( 350 | translate_get_arg(regmap,ins->a), 351 | ins->a.size); 352 | translate_set_arg( 353 | ®map, 354 | ins->c, 355 | symx::expr_select(mem,xra,REILSIZE[ins->c.size])); 356 | break; 357 | 358 | case I_STM: 359 | xra = translate_fixsize( 360 | translate_get_arg(regmap,ins->a), 361 | ins->a.size); 362 | mem = symx::expr_store( 363 | mem, 364 | translate_get_arg(regmap,ins->c), 365 | xra); 366 | break; 367 | 368 | case I_JCC: 369 | { 370 | xra = translate_get_arg(regmap,ins->a); 371 | xrc = translate_get_arg(regmap,ins->c); 372 | 373 | reglist.clear(); 374 | for(i = 0; i < REGIDX_END; i++) { 375 | reglist.push_back(regmap[REGNAME[i]]); 376 | } 377 | 378 | auto cond = symx::cond_eq( 379 | xra, 380 | symx::BytVec::create_imm(xra->size,0)); 381 | 382 | if(prevcond == nullptr) { 383 | blklist.push_back(ref( 384 | mem, 385 | reglist, 386 | flaglist, 387 | symx::cond_not(cond), 388 | xrc)); 389 | prevcond = cond; 390 | } else { 391 | blklist.push_back(ref( 392 | mem, 393 | reglist, 394 | flaglist, 395 | symx::cond_and(prevcond,symx::cond_not(cond)), 396 | xrc)); 397 | prevcond = symx::cond_and(prevcond,cond); 398 | } 399 | 400 | break; 401 | } 402 | case I_NONE: 403 | break; 404 | 405 | default: 406 | err("unsupport unstruction %d\n",ins->op); 407 | break; 408 | } 409 | } 410 | 411 | instlist.clear(); 412 | 413 | //assume openreil always has JCC jumping to next block 414 | //something like this at the end of the block 415 | //JCC 1:1 , 0xDEADBEEF 416 | 417 | return blklist; 418 | } 419 | symx::refExpr Snapshot::translate_fixsize( 420 | symx::refExpr exr, 421 | unsigned int size 422 | ) const { 423 | if(exr->size < REILSIZE[size]) { 424 | return symx::expr_zext(exr,REILSIZE[size]); 425 | } else if(exr->size > REILSIZE[size]) { 426 | return symx::expr_extract(exr,0,REILSIZE[size]); 427 | } 428 | return exr; 429 | } 430 | symx::refExpr Snapshot::translate_get_arg( 431 | const std::unordered_map ®map, 432 | const reil_arg_t &arg) const { 433 | //unsigned int size = REILSIZE[arg.size]; 434 | symx::refExpr xrt; 435 | 436 | assert(arg.type == A_REG || arg.type == A_TEMP || arg.type == A_CONST); 437 | 438 | if(arg.type == A_REG || arg.type == A_TEMP) { 439 | auto it = regmap.find(arg.name); 440 | 441 | assert(it != regmap.end()); 442 | 443 | xrt = it->second; 444 | return xrt; 445 | } else { 446 | return symx::BytVec::create_imm(REILSIZE[arg.size],arg.val); 447 | } 448 | } 449 | int Snapshot::translate_set_arg( 450 | std::unordered_map *regmap, 451 | const reil_arg_t &arg, 452 | const symx::refExpr &value) const { 453 | unsigned int size = REILSIZE[arg.size]; 454 | symx::refExpr xrt; 455 | 456 | assert(arg.type == A_REG || arg.type == A_TEMP); 457 | 458 | if(size == value->size) { 459 | xrt = value; 460 | } else if(size < value->size) { 461 | xrt = symx::expr_extract(value,0,size); 462 | } else if(size > value->size) { 463 | xrt = symx::expr_zext(value,size); 464 | } 465 | 466 | auto ret = regmap->insert(std::make_pair(std::string(arg.name),xrt)); 467 | if(!ret.second) { 468 | regmap->find(arg.name)->second = xrt; 469 | } 470 | return 0; 471 | } 472 | 473 | -------------------------------------------------------------------------------- /solver/z3.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_PREFIX "z3_solver" 2 | 3 | #include 4 | #include 5 | #include 6 | #include"utils.h" 7 | #include"expr.h" 8 | #include"z3.h" 9 | 10 | using namespace symx; 11 | 12 | #define INCREF(x) Z3_inc_ref(solver->context,(x)) 13 | #define DECREF(x) Z3_dec_ref(solver->context,(x)) 14 | 15 | namespace z3_solver { 16 | 17 | Z3SolvExpr::Z3SolvExpr(Z3_context _context,Z3_ast _ast) 18 | : context(_context),ast(_ast) { 19 | Z3_inc_ref(context,ast); 20 | } 21 | Z3SolvExpr::~Z3SolvExpr() { 22 | Z3_dec_ref(context,ast); 23 | } 24 | Z3SolvCond::Z3SolvCond(Z3_context _context,Z3_ast _ast) 25 | : context(_context),ast(_ast) { 26 | Z3_inc_ref(context,ast); 27 | } 28 | Z3SolvCond::~Z3SolvCond() { 29 | Z3_dec_ref(context,ast); 30 | } 31 | Z3TransVisitor::Z3TransVisitor(const Z3Solver *_solver) : solver(_solver) { 32 | bvsort1 = Z3_mk_bv_sort(solver->context,8); 33 | bvsort4 = Z3_mk_bv_sort(solver->context,32); 34 | bvimm41 = Z3_mk_unsigned_int64(solver->context,1,bvsort4); 35 | INCREF(bvimm41); 36 | 37 | simplify_param = Z3_mk_params(solver->context); 38 | Z3_params_inc_ref(solver->context,simplify_param); 39 | Z3_params_set_bool( 40 | solver->context, 41 | simplify_param, 42 | Z3_mk_string_symbol(solver->context,"sort_store"), 43 | Z3_TRUE); 44 | Z3_params_set_bool( 45 | solver->context, 46 | simplify_param, 47 | Z3_mk_string_symbol(solver->context,"mul2concat"), 48 | Z3_TRUE); 49 | } 50 | Z3_ast Z3TransVisitor::expr_to_ast(const refExpr &expr) { 51 | auto it = cache_expr.find(expr); 52 | if(it == cache_expr.end()) { 53 | err("expr hasn't been translated\n"); 54 | } 55 | return it->second->ast; 56 | } 57 | Z3_ast Z3TransVisitor::cond_to_ast(const refCond &cond) { 58 | auto it = cache_cond.find(cond); 59 | if(it == cache_cond.end()) { 60 | err("cond hasn't been translated\n"); 61 | } 62 | return it->second->ast; 63 | } 64 | int Z3TransVisitor::pre_visit(const refBytVec &vec) { 65 | if(cache_expr.find(vec) != cache_expr.end()) { 66 | return 0; 67 | } 68 | return 1; 69 | } 70 | int Z3TransVisitor::pre_visit(const refBytMem &mem) { 71 | if(cache_expr.find(mem) != cache_expr.end()) { 72 | return 0; 73 | } 74 | return 1; 75 | } 76 | int Z3TransVisitor::pre_visit(const refOperator &oper) { 77 | if(cache_expr.find(oper) != cache_expr.end()) { 78 | return 0; 79 | } 80 | return 1; 81 | } 82 | int Z3TransVisitor::pre_visit(const refCond &cond) { 83 | if(cache_cond.find(cond) != cache_cond.end()) { 84 | return 0; 85 | } 86 | return 1; 87 | } 88 | int Z3TransVisitor::post_visit(const refBytVec &vec) { 89 | Z3_ast res_ast; 90 | switch(vec->type) { 91 | case ExprImm: 92 | res_ast = Z3_mk_unsigned_int64( 93 | solver->context, 94 | vec->data, 95 | Z3_mk_bv_sort(solver->context,vec->size)); 96 | INCREF(res_ast); 97 | break; 98 | case ExprVar: 99 | res_ast = Z3_mk_const( 100 | solver->context, 101 | Z3_mk_int_symbol( 102 | solver->context, 103 | vec->id), 104 | Z3_mk_bv_sort(solver->context,vec->size)); 105 | INCREF(res_ast); 106 | break; 107 | default: 108 | err("illegal case\n"); 109 | return -1; 110 | } 111 | cache_expr[vec] = ref(solver->context,res_ast); 112 | DECREF(res_ast); 113 | return 0; 114 | } 115 | int Z3TransVisitor::post_visit(const refBytMem &mem) { 116 | Z3_ast res_ast; 117 | switch(mem->type) { 118 | case ExprMem: 119 | res_ast = Z3_mk_const( 120 | solver->context, 121 | Z3_mk_int_symbol( 122 | solver->context, 123 | mem->id), 124 | Z3_mk_array_sort( 125 | solver->context, 126 | bvsort4, 127 | bvsort1)); 128 | INCREF(res_ast); 129 | break; 130 | default: 131 | err("illegal case\n"); 132 | return -1; 133 | } 134 | cache_expr[mem] = ref(solver->context,res_ast); 135 | DECREF(res_ast); 136 | return 0; 137 | } 138 | int Z3TransVisitor::post_visit(const refOperator &oper) { 139 | Z3_ast res_ast; 140 | switch(oper->type) { 141 | case ExprOpStore: 142 | { 143 | unsigned int i; 144 | unsigned int size; 145 | Z3_ast mem_ast = expr_to_ast(oper->operand[0]); 146 | Z3_ast idx_ast = expr_to_ast(oper->operand[1]); 147 | Z3_ast val_ast = expr_to_ast(oper->operand[2]); 148 | Z3_ast old_mem_ast,old_idx_ast; 149 | 150 | size = oper->operand[2]->size; 151 | 152 | assert(size % 8 == 0); 153 | 154 | INCREF(mem_ast); 155 | INCREF(idx_ast); 156 | for(i = 0; i < size; i += 8) { 157 | Z3_ast tmp_ast = Z3_mk_extract( 158 | solver->context, 159 | i + 7, 160 | i, 161 | val_ast); 162 | INCREF(tmp_ast); 163 | old_mem_ast = mem_ast; 164 | mem_ast = Z3_mk_store( 165 | solver->context, 166 | mem_ast, 167 | idx_ast, 168 | tmp_ast); 169 | INCREF(mem_ast); 170 | DECREF(tmp_ast); 171 | DECREF(old_mem_ast); 172 | old_idx_ast = idx_ast; 173 | idx_ast = Z3_mk_bvadd( 174 | solver->context, 175 | idx_ast, 176 | bvimm41); 177 | INCREF(idx_ast); 178 | DECREF(old_idx_ast); 179 | } 180 | DECREF(idx_ast); 181 | res_ast = mem_ast; 182 | break; 183 | } 184 | case ExprOpSelect: 185 | { 186 | unsigned int i; 187 | unsigned int size; 188 | Z3_ast mem_ast = expr_to_ast(oper->operand[0]); 189 | Z3_ast idx_ast = expr_to_ast(oper->operand[1]); 190 | Z3_ast old_idx_ast,old_res_ast; 191 | 192 | if((size = oper->size) == 0){ 193 | err("illegal size\n"); 194 | } 195 | 196 | assert(size % 8 == 0); 197 | 198 | res_ast = Z3_mk_select(solver->context,mem_ast,idx_ast); 199 | INCREF(res_ast); 200 | INCREF(idx_ast); 201 | for(i = 8; i < size; i += 8) { 202 | old_idx_ast = idx_ast; 203 | idx_ast = Z3_mk_bvadd( 204 | solver->context, 205 | idx_ast, 206 | bvimm41); 207 | INCREF(idx_ast); 208 | DECREF(old_idx_ast); 209 | Z3_ast tmp_ast = Z3_mk_select( 210 | solver->context, 211 | mem_ast, 212 | idx_ast); 213 | INCREF(tmp_ast); 214 | old_res_ast = res_ast; 215 | res_ast = Z3_mk_concat( 216 | solver->context, 217 | tmp_ast, 218 | res_ast); 219 | INCREF(res_ast); 220 | DECREF(tmp_ast); 221 | DECREF(old_res_ast); 222 | } 223 | DECREF(idx_ast); 224 | break; 225 | } 226 | case ExprOpExtract: 227 | res_ast = Z3_mk_extract( 228 | solver->context, 229 | (oper->start + oper->size) - 1, 230 | oper->start, 231 | expr_to_ast(oper->operand[0])); 232 | INCREF(res_ast); 233 | break; 234 | case ExprOpIte: 235 | res_ast = Z3_mk_ite( 236 | solver->context, 237 | cond_to_ast(oper->cond), 238 | expr_to_ast(oper->operand[0]), 239 | expr_to_ast(oper->operand[1])); 240 | INCREF(res_ast); 241 | break; 242 | case ExprOpAdd: 243 | res_ast = Z3_mk_bvadd( 244 | solver->context, 245 | expr_to_ast(oper->operand[0]), 246 | expr_to_ast(oper->operand[1])); 247 | INCREF(res_ast); 248 | break; 249 | case ExprOpSub: 250 | res_ast = Z3_mk_bvsub( 251 | solver->context, 252 | expr_to_ast(oper->operand[0]), 253 | expr_to_ast(oper->operand[1])); 254 | INCREF(res_ast); 255 | break; 256 | case ExprOpMul: 257 | res_ast = Z3_mk_bvmul( 258 | solver->context, 259 | expr_to_ast(oper->operand[0]), 260 | expr_to_ast(oper->operand[1])); 261 | INCREF(res_ast); 262 | break; 263 | case ExprOpUdiv: 264 | res_ast = Z3_mk_bvudiv( 265 | solver->context, 266 | expr_to_ast(oper->operand[0]), 267 | expr_to_ast(oper->operand[1])); 268 | INCREF(res_ast); 269 | break; 270 | case ExprOpSdiv: 271 | res_ast = Z3_mk_bvsdiv( 272 | solver->context, 273 | expr_to_ast(oper->operand[0]), 274 | expr_to_ast(oper->operand[1])); 275 | INCREF(res_ast); 276 | break; 277 | case ExprOpAnd: 278 | res_ast = Z3_mk_bvand( 279 | solver->context, 280 | expr_to_ast(oper->operand[0]), 281 | expr_to_ast(oper->operand[1])); 282 | INCREF(res_ast); 283 | break; 284 | case ExprOpOr: 285 | res_ast = Z3_mk_bvor( 286 | solver->context, 287 | expr_to_ast(oper->operand[0]), 288 | expr_to_ast(oper->operand[1])); 289 | INCREF(res_ast); 290 | break; 291 | case ExprOpXor: 292 | res_ast = Z3_mk_bvxor( 293 | solver->context, 294 | expr_to_ast(oper->operand[0]), 295 | expr_to_ast(oper->operand[1])); 296 | INCREF(res_ast); 297 | break; 298 | case ExprOpShl: 299 | res_ast = Z3_mk_bvshl( 300 | solver->context, 301 | expr_to_ast(oper->operand[0]), 302 | expr_to_ast(oper->operand[1])); 303 | INCREF(res_ast); 304 | break; 305 | case ExprOpLshr: 306 | res_ast = Z3_mk_bvlshr( 307 | solver->context, 308 | expr_to_ast(oper->operand[0]), 309 | expr_to_ast(oper->operand[1])); 310 | INCREF(res_ast); 311 | break; 312 | case ExprOpAshr: 313 | res_ast = Z3_mk_bvashr( 314 | solver->context, 315 | expr_to_ast(oper->operand[0]), 316 | expr_to_ast(oper->operand[1])); 317 | INCREF(res_ast); 318 | break; 319 | case ExprOpRor: 320 | res_ast = Z3_mk_ext_rotate_right( 321 | solver->context, 322 | expr_to_ast(oper->operand[0]), 323 | expr_to_ast(oper->operand[1])); 324 | INCREF(res_ast); 325 | break; 326 | case ExprOpNeg: 327 | res_ast = Z3_mk_bvneg( 328 | solver->context, 329 | expr_to_ast(oper->operand[0])); 330 | INCREF(res_ast); 331 | break; 332 | case ExprOpNot: 333 | res_ast = Z3_mk_bvnot( 334 | solver->context, 335 | expr_to_ast(oper->operand[0])); 336 | INCREF(res_ast); 337 | break; 338 | case ExprOpConcat: 339 | res_ast = Z3_mk_concat( 340 | solver->context, 341 | expr_to_ast(oper->operand[1]), 342 | expr_to_ast(oper->operand[0])); 343 | INCREF(res_ast); 344 | break; 345 | case ExprOpSext: 346 | res_ast = Z3_mk_sign_ext( 347 | solver->context, 348 | (oper->size - oper->operand[0]->size), 349 | expr_to_ast(oper->operand[0])); 350 | INCREF(res_ast); 351 | break; 352 | case ExprOpZext: 353 | res_ast = Z3_mk_zero_ext( 354 | solver->context, 355 | (oper->size - oper->operand[0]->size), 356 | expr_to_ast(oper->operand[0])); 357 | INCREF(res_ast); 358 | break; 359 | default: 360 | err("illegal case\n"); 361 | return -1; 362 | } 363 | auto old_ast = res_ast; 364 | res_ast = Z3_simplify_ex( 365 | solver->context, 366 | res_ast, 367 | simplify_param); 368 | INCREF(res_ast); 369 | DECREF(old_ast); 370 | 371 | cache_expr[oper] = ref(solver->context,res_ast); 372 | DECREF(res_ast); 373 | return 0; 374 | } 375 | int Z3TransVisitor::post_visit(const refCond &cond) { 376 | Z3_ast res_ast; 377 | switch(cond->type) { 378 | case CondFalse: 379 | res_ast = Z3_mk_false(solver->context); 380 | INCREF(res_ast); 381 | break; 382 | case CondTrue: 383 | res_ast = Z3_mk_true(solver->context); 384 | INCREF(res_ast); 385 | break; 386 | case CondEq: 387 | res_ast = Z3_mk_eq( 388 | solver->context, 389 | expr_to_ast(cond->expr[0]), 390 | expr_to_ast(cond->expr[1])); 391 | INCREF(res_ast); 392 | break; 393 | case CondSl: 394 | res_ast = Z3_mk_bvslt( 395 | solver->context, 396 | expr_to_ast(cond->expr[0]), 397 | expr_to_ast(cond->expr[1])); 398 | INCREF(res_ast); 399 | break; 400 | case CondSle: 401 | res_ast = Z3_mk_bvsle( 402 | solver->context, 403 | expr_to_ast(cond->expr[0]), 404 | expr_to_ast(cond->expr[1])); 405 | INCREF(res_ast); 406 | break; 407 | case CondUl: 408 | res_ast = Z3_mk_bvult( 409 | solver->context, 410 | expr_to_ast(cond->expr[0]), 411 | expr_to_ast(cond->expr[1])); 412 | INCREF(res_ast); 413 | break; 414 | case CondUle: 415 | res_ast = Z3_mk_bvule( 416 | solver->context, 417 | expr_to_ast(cond->expr[0]), 418 | expr_to_ast(cond->expr[1])); 419 | INCREF(res_ast); 420 | break; 421 | case CondSg: 422 | res_ast = Z3_mk_bvsgt( 423 | solver->context, 424 | expr_to_ast(cond->expr[0]), 425 | expr_to_ast(cond->expr[1])); 426 | INCREF(res_ast); 427 | break; 428 | case CondSge: 429 | res_ast = Z3_mk_bvsge( 430 | solver->context, 431 | expr_to_ast(cond->expr[0]), 432 | expr_to_ast(cond->expr[1])); 433 | INCREF(res_ast); 434 | break; 435 | case CondUg: 436 | res_ast = Z3_mk_bvugt( 437 | solver->context, 438 | expr_to_ast(cond->expr[0]), 439 | expr_to_ast(cond->expr[1])); 440 | INCREF(res_ast); 441 | break; 442 | case CondUge: 443 | res_ast = Z3_mk_bvuge( 444 | solver->context, 445 | expr_to_ast(cond->expr[0]), 446 | expr_to_ast(cond->expr[1])); 447 | INCREF(res_ast); 448 | break; 449 | case CondIte: 450 | { 451 | res_ast = Z3_mk_ite( 452 | solver->context, 453 | cond_to_ast(cond->cond[0]), 454 | cond_to_ast(cond->cond[1]), 455 | cond_to_ast(cond->cond[2])); 456 | INCREF(res_ast); 457 | break; 458 | } 459 | case CondAnd: 460 | { 461 | Z3_ast conds[] = { 462 | cond_to_ast(cond->cond[0]), 463 | cond_to_ast(cond->cond[1])}; 464 | res_ast = Z3_mk_and(solver->context,2,conds); 465 | INCREF(res_ast); 466 | break; 467 | } 468 | case CondOr: 469 | { 470 | Z3_ast conds[] = { 471 | cond_to_ast(cond->cond[0]), 472 | cond_to_ast(cond->cond[1])}; 473 | res_ast = Z3_mk_or(solver->context,2,conds); 474 | INCREF(res_ast); 475 | break; 476 | } 477 | case CondXor: 478 | res_ast = Z3_mk_xor( 479 | solver->context, 480 | cond_to_ast(cond->cond[0]), 481 | cond_to_ast(cond->cond[1])); 482 | INCREF(res_ast); 483 | break; 484 | case CondNot: 485 | res_ast = Z3_mk_not( 486 | solver->context, 487 | cond_to_ast(cond->cond[0])); 488 | INCREF(res_ast); 489 | break; 490 | default: 491 | err("illegal case\n"); 492 | return -1; 493 | } 494 | auto old_ast = res_ast; 495 | res_ast = Z3_simplify_ex( 496 | solver->context, 497 | res_ast, 498 | simplify_param); 499 | INCREF(res_ast); 500 | DECREF(old_ast); 501 | 502 | cache_cond[cond] = ref(solver->context,res_ast); 503 | DECREF(res_ast); 504 | return 0; 505 | } 506 | Z3Solver::Z3Solver() { 507 | Z3_config config = Z3_mk_config(); 508 | Z3_set_param_value(config,"model","true"); 509 | context = Z3_mk_context_rc(config); 510 | Z3_set_error_handler(context,error_handler); 511 | 512 | solver = Z3_mk_solver(context); 513 | Z3_solver_inc_ref(context,solver); 514 | 515 | trans_vis = new Z3TransVisitor(this); 516 | } 517 | Z3Solver::~Z3Solver() { 518 | delete trans_vis; 519 | } 520 | bool Z3Solver::solve( 521 | const std::unordered_set &cons, 522 | std::unordered_map *var 523 | ) { 524 | Z3_model model; 525 | Z3_ast res_ast; 526 | 527 | for(auto it = var->begin(); it != var->end(); it++) { 528 | trans_vis->walk(it->first); 529 | } 530 | trans_vis->iter_walk(cons.begin(),cons.end()); 531 | 532 | Z3_solver_reset(context,solver); 533 | 534 | for(auto it = cons.begin(); it != cons.end(); it++) { 535 | Z3_solver_assert(context,solver,trans_vis->cond_to_ast(*it)); 536 | } 537 | if(Z3_solver_check(context,solver) != Z3_TRUE) { 538 | return false; 539 | } 540 | 541 | model = Z3_solver_get_model(context,solver); 542 | Z3_model_inc_ref(context,model); 543 | for(auto it = var->begin(); it != var->end(); it++) { 544 | if(Z3_model_eval( 545 | context, 546 | model, 547 | trans_vis->expr_to_ast(it->first), 548 | Z3_TRUE, 549 | &res_ast 550 | ) == Z3_FALSE) { 551 | err("evaluate error\n"); 552 | return false; 553 | } 554 | Z3_inc_ref(context,res_ast); 555 | auto ret = Z3_get_numeral_uint64( 556 | context, 557 | res_ast, 558 | (unsigned __int64*)&it->second); 559 | Z3_dec_ref(context,res_ast); 560 | if(ret == Z3_FALSE) { 561 | err("get numeral error\n"); 562 | return false; 563 | } 564 | } 565 | Z3_model_dec_ref(context,model); 566 | 567 | return true; 568 | } 569 | } 570 | -------------------------------------------------------------------------------- /arch/arm/arm.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_PREFIX "ARM" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include"utils.h" 14 | #include"context.h" 15 | #include"state.h" 16 | #include"expr.h" 17 | #include"arm.h" 18 | 19 | using namespace symx; 20 | using namespace arm; 21 | 22 | namespace arm { 23 | 24 | static refBytVec imm40,imm41,imm44,imm48,imm4FFFF,imm4FFFFFFFE; 25 | static refBytVec insmod_arm,insmod_thumb ; 26 | int initialize() { 27 | imm40 = BytVec::create_imm(4,0x0); 28 | imm41 = BytVec::create_imm(4,0x1); 29 | imm44 = BytVec::create_imm(4,0x4); 30 | imm48 = BytVec::create_imm(4,0x8); 31 | imm4FFFF = BytVec::create_imm(4,0xFFFF); 32 | imm4FFFFFFFE = BytVec::create_imm(4,0xFFFFFFFE); 33 | 34 | insmod_arm = BytVec::create_imm(4,CS_MODE_ARM); 35 | insmod_thumb = BytVec::create_imm(4,CS_MODE_THUMB); 36 | 37 | return 0; 38 | } 39 | 40 | ARMProbe::ARMProbe(pid_t _pid,int fd,uint64_t _off) : pid(_pid),off(_off) { 41 | struct stat st; 42 | fstat(fd,&st); 43 | bin = (uint8_t*)mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,fd,0); 44 | } 45 | uint64_t ARMProbe::read_reg(const unsigned int regid,bool *symbol) const { 46 | //for test 47 | *symbol = false; 48 | switch(regid) { 49 | case ARM_REG_R0: 50 | *symbol = true; 51 | return 0x0; 52 | case ARM_REG_R1: 53 | return 0XBEAFF100; 54 | case ARM_REG_R2: 55 | return 0xBEAFF200; 56 | case ARM_REG_R3: 57 | return 0x102E1; 58 | case ARM_REG_R4: 59 | return 0x0; 60 | case ARM_REG_R5: 61 | return 0x0; 62 | case ARM_REG_R6: 63 | return 0x0; 64 | case ARM_REG_R7: 65 | return 0x0; 66 | case ARM_REG_R8: 67 | return 0x0; 68 | case ARM_REG_R9: 69 | return 0x0; 70 | case ARM_REG_R10: 71 | return 0x0; 72 | case ARM_REG_R11: 73 | return 0x0; 74 | case ARM_REG_R12: 75 | return 0x0; 76 | case ARM_REG_PC: 77 | return 0x10A0C; 78 | case ARM_REG_SP: 79 | return 0xBEAFF000; 80 | case ARM_REG_LR: 81 | return 0xDEADBEEE; 82 | } 83 | return 0; 84 | } 85 | bool ARMProbe::read_flag(const unsigned int flagid) const { 86 | //for test 87 | switch(flagid) { 88 | case ARM_SR_N: 89 | return false; 90 | case ARM_SR_Z: 91 | return true; 92 | case ARM_SR_C: 93 | return true; 94 | case ARM_SR_V: 95 | return false; 96 | } 97 | return false; 98 | } 99 | ssize_t ARMProbe::read_mem( 100 | const uint64_t addr, 101 | const uint8_t *buf, 102 | const size_t len 103 | ) const { 104 | //for test 105 | if(addr >= 0xBEAFF000) { 106 | if(len != 1) { 107 | err("unhandled argv\n"); 108 | } 109 | uint32_t val = 0xBEAFF000 + \ 110 | ((addr & (~3)) - 0xBEAFF000 + 1) * 0x10000; 111 | memcpy((void*)buf,(char*)(&val) + (addr & 3),1); 112 | } else { 113 | memcpy((void*)buf,(void*)(bin + off + addr),len); 114 | } 115 | return len; 116 | } 117 | int ARMProbe::get_insmd() const { 118 | //for test 119 | return CS_MODE_THUMB; 120 | } 121 | std::vector ARMProbe::get_mem_map() const { 122 | std::vector mem_map; 123 | //for test 124 | mem_map.push_back(MemPage(0x10000,PAGE_READ | PAGE_EXEC | PAGE_PROBE)); 125 | mem_map.push_back(MemPage( 126 | 0xBEAFF000, 127 | PAGE_READ | PAGE_EXEC | PAGE_PROBE)); 128 | 129 | return mem_map; 130 | } 131 | 132 | ARMContext::ARMContext(Solver *_solver) : Context( 133 | _solver, 134 | ARM_REG_SIZE, 135 | ARM_REG_ENDING, 136 | ARM_FLAG_NUM, 137 | ARM_REG_PC 138 | ) { 139 | cs_open(CS_ARCH_ARM,CS_MODE_THUMB,&cs); 140 | cs_option(cs,CS_OPT_DETAIL,CS_OPT_ON); 141 | } 142 | static refExpr get_relative_pc(const ProgCtr &pc) { 143 | if(pc.insmd == CS_MODE_THUMB) { 144 | return BytVec::create_imm(4,pc.rawpc + 4); 145 | } else { 146 | return BytVec::create_imm(4,pc.rawpc + 8); 147 | } 148 | } 149 | static refExpr get_op_expr( 150 | const std::pair &meta, 151 | const cs_arm_op &op 152 | ) { 153 | refExpr ret; 154 | refExpr append; 155 | 156 | auto blk = meta.first; 157 | auto &pc = meta.second; 158 | 159 | if(op.type == ARM_OP_IMM) { 160 | ret = BytVec::create_imm(4,op.imm); 161 | } else if(op.type == ARM_OP_REG) { 162 | if(op.reg == ARM_REG_PC) { 163 | ret = get_relative_pc(pc); 164 | } else { 165 | ret = blk->reg[op.reg]; 166 | } 167 | } else if(op.type == ARM_OP_MEM) { 168 | assert(op.mem.base != ARM_REG_INVALID); 169 | if(op.mem.base == ARM_REG_PC) { 170 | ret = get_relative_pc(pc); 171 | } else { 172 | ret = blk->reg[op.mem.base]; 173 | } 174 | append = imm40; 175 | if(op.mem.index != ARM_REG_INVALID) { 176 | append = blk->reg[op.mem.index]; 177 | if(op.mem.scale == -1) { 178 | append = expr_neg(blk->reg[op.mem.index]); 179 | } 180 | if(op.mem.lshift > 0) { 181 | append = expr_shl( 182 | append, 183 | BytVec::create_imm(4,op.mem.lshift)); 184 | } 185 | } 186 | if(op.mem.disp != 0) { 187 | if(append == imm40) { 188 | append = BytVec::create_imm(4,op.mem.disp); 189 | } else { 190 | append = expr_add( 191 | append, 192 | BytVec::create_imm(4,op.mem.disp)); 193 | } 194 | } 195 | if(append != imm40) { 196 | if(op.subtracted) { 197 | ret = expr_sub(ret,append); 198 | } else { 199 | ret = expr_add(ret,append); 200 | } 201 | } 202 | 203 | switch(op.shift.type) { 204 | case ARM_SFT_INVALID: 205 | break; 206 | /*case ARM_SFT_ASR: 207 | index = expr_ashr( 208 | index, 209 | BytVec::create_imm(4,op.shift.value)); 210 | break; 211 | case ARM_SFT_LSL: 212 | index = expr_shl( 213 | index, 214 | BytVec::create_imm(4,op.shift.value)); 215 | break; 216 | case ARM_SFT_LSR: 217 | index = expr_lshr( 218 | index, 219 | BytVec::create_imm(4,op.shift.value)); 220 | break; 221 | case ARM_SFT_ROR: 222 | index = expr_ror( 223 | index, 224 | BytVec::create_imm(4,op.shift.value)); 225 | break; 226 | case ARM_SFT_ASR_REG: 227 | index = expr_ashr( 228 | index, 229 | blk->reg[op.shift.value]); 230 | break; 231 | case ARM_SFT_LSL_REG: 232 | index = expr_shl( 233 | index, 234 | blk->reg[op.shift.value]); 235 | break; 236 | case ARM_SFT_LSR_REG: 237 | index = expr_lshr( 238 | index, 239 | blk->reg[op.shift.value]); 240 | break; 241 | case ARM_SFT_ROR_REG: 242 | index = expr_ror( 243 | index, 244 | blk->reg[op.shift.value]); 245 | break;*/ 246 | default: 247 | err("TODO: shift\n"); 248 | break; 249 | } 250 | } 251 | 252 | return ret; 253 | } 254 | static int set_pre_wb( 255 | const std::pair &meta, 256 | const cs_arm_op &op, 257 | refExpr *nreg 258 | ) { 259 | assert(op.type == ARM_OP_MEM); 260 | assert(op.mem.base != ARM_REG_INVALID); 261 | nreg[op.mem.base] = get_op_expr(meta,op); 262 | return 0; 263 | } 264 | static int set_post_wb( 265 | const std::pair &meta, 266 | const cs_arm_op op_base, 267 | const cs_arm_op op_append, 268 | refExpr *nreg 269 | ) { 270 | refExpr append; 271 | assert(op_base.type == ARM_OP_MEM); 272 | assert(op_base.mem.base != ARM_REG_INVALID); 273 | assert(op_append.type != ARM_OP_MEM); 274 | if(op_append.subtracted) { 275 | append = expr_sub( 276 | get_op_expr(meta,op_base), 277 | get_op_expr(meta,op_append)); 278 | } else { 279 | append = expr_add( 280 | get_op_expr(meta,op_base), 281 | get_op_expr(meta,op_append)); 282 | } 283 | nreg[op_base.mem.base] = append; 284 | return 0; 285 | } 286 | static refExpr get_cc_expr( 287 | const refExpr old_expr, 288 | const refExpr new_expr, 289 | const refCond flag[], 290 | cs_arm *det 291 | ) { 292 | refExpr ret_expr; 293 | 294 | switch(det->cc) { 295 | case ARM_CC_INVALID: 296 | case ARM_CC_AL: 297 | ret_expr = new_expr; 298 | break; 299 | case ARM_CC_EQ: 300 | ret_expr = expr_ite(flag[ARM_SR_Z],new_expr,old_expr); 301 | break; 302 | case ARM_CC_NE: 303 | ret_expr = expr_ite(flag[ARM_SR_Z],old_expr,new_expr); 304 | break; 305 | case ARM_CC_HS: 306 | ret_expr = expr_ite(flag[ARM_SR_C],new_expr,old_expr); 307 | break; 308 | case ARM_CC_LO: 309 | ret_expr = expr_ite(flag[ARM_SR_C],old_expr,new_expr); 310 | break; 311 | case ARM_CC_MI: 312 | ret_expr = expr_ite(flag[ARM_SR_N],new_expr,old_expr); 313 | break; 314 | case ARM_CC_PL: 315 | ret_expr = expr_ite(flag[ARM_SR_N],old_expr,new_expr); 316 | break; 317 | case ARM_CC_VS: 318 | ret_expr = expr_ite(flag[ARM_SR_V],new_expr,old_expr); 319 | break; 320 | case ARM_CC_VC: 321 | ret_expr = expr_ite(flag[ARM_SR_V],old_expr,new_expr); 322 | break; 323 | case ARM_CC_HI: 324 | ret_expr = expr_ite( 325 | cond_and(flag[ARM_SR_C],cond_not(flag[ARM_SR_Z])), 326 | new_expr, 327 | old_expr); 328 | break; 329 | case ARM_CC_LS: 330 | ret_expr = expr_ite( 331 | cond_and(flag[ARM_SR_C],cond_not(flag[ARM_SR_Z])), 332 | old_expr, 333 | new_expr); 334 | break; 335 | case ARM_CC_GE: 336 | ret_expr = expr_ite( 337 | cond_xor(flag[ARM_SR_N],flag[ARM_SR_V]), 338 | old_expr, 339 | new_expr); 340 | break; 341 | case ARM_CC_LT: 342 | ret_expr = expr_ite( 343 | cond_xor(flag[ARM_SR_N],flag[ARM_SR_V]), 344 | new_expr, 345 | old_expr); 346 | break; 347 | case ARM_CC_GT: 348 | ret_expr = expr_ite( 349 | cond_or(flag[ARM_SR_Z], 350 | cond_xor(flag[ARM_SR_N],flag[ARM_SR_V])), 351 | old_expr, 352 | new_expr); 353 | break; 354 | case ARM_CC_LE: 355 | ret_expr = expr_ite( 356 | cond_or(flag[ARM_SR_Z], 357 | cond_xor(flag[ARM_SR_N],flag[ARM_SR_V])), 358 | new_expr, 359 | old_expr); 360 | break; 361 | } 362 | return ret_expr; 363 | } 364 | static refCond get_cc_cond( 365 | const refCond old_cond, 366 | const refCond new_cond, 367 | const refCond flag[], 368 | cs_arm *det 369 | ) { 370 | refCond ret_cond; 371 | 372 | switch(det->cc) { 373 | case ARM_CC_INVALID: 374 | case ARM_CC_AL: 375 | ret_cond = new_cond; 376 | break; 377 | case ARM_CC_EQ: 378 | ret_cond = cond_ite(flag[ARM_SR_Z],new_cond,old_cond); 379 | break; 380 | case ARM_CC_NE: 381 | ret_cond = cond_ite(flag[ARM_SR_Z],old_cond,new_cond); 382 | break; 383 | case ARM_CC_HS: 384 | ret_cond = cond_ite(flag[ARM_SR_C],new_cond,old_cond); 385 | break; 386 | case ARM_CC_LO: 387 | ret_cond = cond_ite(flag[ARM_SR_C],old_cond,new_cond); 388 | break; 389 | case ARM_CC_MI: 390 | ret_cond = cond_ite(flag[ARM_SR_N],new_cond,old_cond); 391 | break; 392 | case ARM_CC_PL: 393 | ret_cond = cond_ite(flag[ARM_SR_N],old_cond,new_cond); 394 | break; 395 | case ARM_CC_VS: 396 | ret_cond = cond_ite(flag[ARM_SR_V],new_cond,old_cond); 397 | break; 398 | case ARM_CC_VC: 399 | ret_cond = cond_ite(flag[ARM_SR_V],old_cond,new_cond); 400 | break; 401 | case ARM_CC_HI: 402 | ret_cond = cond_ite( 403 | cond_and(flag[ARM_SR_C],cond_not(flag[ARM_SR_Z])), 404 | new_cond, 405 | old_cond); 406 | break; 407 | case ARM_CC_LS: 408 | ret_cond = cond_ite( 409 | cond_and(flag[ARM_SR_C],cond_not(flag[ARM_SR_Z])), 410 | old_cond, 411 | new_cond); 412 | break; 413 | case ARM_CC_GE: 414 | ret_cond = cond_ite( 415 | cond_xor(flag[ARM_SR_N],flag[ARM_SR_V]), 416 | old_cond, 417 | new_cond); 418 | break; 419 | case ARM_CC_LT: 420 | ret_cond = cond_ite( 421 | cond_xor(flag[ARM_SR_N],flag[ARM_SR_V]), 422 | new_cond, 423 | old_cond); 424 | break; 425 | case ARM_CC_GT: 426 | ret_cond = cond_ite( 427 | cond_or(flag[ARM_SR_Z], 428 | cond_xor(flag[ARM_SR_N],flag[ARM_SR_V])), 429 | old_cond, 430 | new_cond); 431 | break; 432 | case ARM_CC_LE: 433 | ret_cond = cond_ite( 434 | cond_or(flag[ARM_SR_Z], 435 | cond_xor(flag[ARM_SR_N],flag[ARM_SR_V])), 436 | new_cond, 437 | old_cond); 438 | break; 439 | } 440 | return ret_cond; 441 | } 442 | refBlock ARMContext::interpret(const refProbe &_probe,const ProgCtr &entry_pc) { 443 | int i; 444 | const refARMProbe probe = std::dynamic_pointer_cast(_probe); 445 | refBlock blk = state_create_block(this,entry_pc); 446 | cs_insn *insn,*ins; 447 | size_t count; 448 | size_t idx; 449 | cs_arm *det; 450 | cs_arm_op *ops; 451 | bool end_flag; 452 | 453 | ProgCtr pc; 454 | std::pair meta; 455 | bool branch_flag; 456 | refExpr nr[ARM_REG_ENDING]; 457 | refExpr nm,xrd,xrs,xrt; 458 | refCond nf[4]; 459 | refCond cdt; 460 | 461 | char codeline[1024]; 462 | 463 | nm = blk->mem; 464 | for(i = 0;i < ARM_REG_ENDING;i++){ 465 | nr[i] = blk->reg[i]; 466 | } 467 | for(i = 0;i < ARM_FLAG_NUM;i++) { 468 | nf[i] = blk->flag[i]; 469 | } 470 | blk->next_insmd = BytVec::create_imm(4,entry_pc.insmd); 471 | 472 | cs_option(cs,CS_OPT_MODE,entry_pc.insmd); 473 | cs_option(cs,CS_OPT_DETAIL,CS_OPT_ON); 474 | count = cs_disasm( 475 | cs, 476 | probe->bin + probe->off + entry_pc.rawpc, 477 | 64, 478 | entry_pc.rawpc, 479 | 0, 480 | &insn); 481 | 482 | pc = entry_pc; 483 | meta.first = blk; 484 | meta.second = pc; 485 | ins = insn; 486 | end_flag = false; 487 | for(idx = 0; idx < count && !end_flag; idx++) { 488 | snprintf( 489 | codeline, 490 | sizeof(codeline) - 1, 491 | "0x%08lx\t%s %s", 492 | ins->address, 493 | ins->mnemonic, 494 | ins->op_str); 495 | info("%s\n",codeline); 496 | blk->discode.push_back(codeline); 497 | 498 | pc.rawpc = ins->address; 499 | det = &ins->detail->arm; 500 | ops = det->operands; 501 | blk->reg[ARM_REG_PC] = BytVec::create_imm(4,pc.rawpc); 502 | nr[ARM_REG_PC] = blk->reg[ARM_REG_PC]; 503 | branch_flag = false; 504 | 505 | switch(ins->id) { 506 | case ARM_INS_PUSH: 507 | xrt = blk->reg[ARM_REG_SP]; 508 | nm = blk->mem; 509 | for(i = det->op_count - 1; i >= 0; i--) { 510 | xrt = expr_sub(xrt,imm44); 511 | xrs = get_op_expr(meta,ops[i]); 512 | nm = expr_store(nm,xrt,xrs); 513 | } 514 | nr[ARM_REG_SP] = xrt; 515 | break; 516 | case ARM_INS_POP: 517 | xrt = blk->reg[ARM_REG_SP]; 518 | for(i = 0; i < det->op_count; i++) { 519 | nr[ops[i].reg] = expr_select(blk->mem,xrt,4); 520 | xrt = expr_add(xrt,imm44); 521 | } 522 | nr[ARM_REG_SP] = xrt; 523 | break; 524 | case ARM_INS_ADD: 525 | case ARM_INS_SUB: 526 | case ARM_INS_MUL: 527 | if(det->op_count == 2) { 528 | xrd = get_op_expr(meta,ops[0]); 529 | xrs = get_op_expr(meta,ops[1]); 530 | } else { 531 | xrd = get_op_expr(meta,ops[1]); 532 | xrs = get_op_expr(meta,ops[2]); 533 | } 534 | switch(ins->id) { 535 | case ARM_INS_ADD: 536 | xrt = expr_add(xrd,xrs); 537 | break; 538 | case ARM_INS_SUB: 539 | xrt = expr_sub(xrd,xrs); 540 | break; 541 | case ARM_INS_MUL: 542 | xrt = expr_mul(xrd,xrs); 543 | break; 544 | } 545 | nr[ops[0].reg] = xrt; 546 | break; 547 | /* 548 | cond_sl(xrt,imm40); 549 | cond_eq(xrt,imm40); 550 | cond_uge(xrd,expr_neg(xrs)); 551 | 552 | cdt = cond_sl(xrt,imm40); 553 | cond_and( 554 | cond_xor(cond_sl(xrd,imm40),cdt), 555 | cond_xor(cond_sl(xrs,imm40),cdt)); 556 | */ 557 | case ARM_INS_MOV: 558 | nr[ops[0].reg] = get_op_expr(meta,ops[1]); 559 | break; 560 | case ARM_INS_MOVW: 561 | assert(ops[1].type == ARM_OP_IMM); 562 | nr[ops[0].reg] = BytVec::create_imm( 563 | 4, 564 | (ops[1].imm & 0xFFFF)); 565 | break; 566 | case ARM_INS_MOVT: 567 | assert(ops[1].type == ARM_OP_IMM); 568 | xrd = get_op_expr(meta,ops[0]); 569 | xrs = BytVec::create_imm(2,ops[1].imm); 570 | nr[ops[0].reg] = expr_concat(expr_extract(xrd,0,2),xrs); 571 | break; 572 | case ARM_INS_STR: 573 | case ARM_INS_STRB: 574 | xrs = get_op_expr(meta,ops[0]); 575 | xrd = get_op_expr(meta,ops[1]); 576 | if(ins->id == ARM_INS_STR) { 577 | nm = expr_store(blk->mem,xrd,xrs); 578 | } else { 579 | nm = expr_store( 580 | blk->mem, 581 | xrd, 582 | expr_extract(xrs,0,1)); 583 | } 584 | if(det->writeback) { 585 | if(det->op_count == 2) { 586 | set_pre_wb(meta,ops[1],nr); 587 | } else if(det->op_count == 3){ 588 | set_post_wb(meta,ops[1],ops[2],nr); 589 | } else { 590 | err("WB unexcepted\n"); 591 | } 592 | } 593 | break; 594 | case ARM_INS_LDR: 595 | case ARM_INS_LDRB: 596 | xrs = get_op_expr(meta,ops[1]); 597 | if(ins->id == ARM_INS_LDR) { 598 | nr[ops[0].reg] = expr_select(blk->mem,xrs,4); 599 | } else { 600 | nr[ops[0].reg] = expr_zext( 601 | expr_select(blk->mem,xrs,1), 602 | 4); 603 | } 604 | if(det->writeback) { 605 | if(det->op_count == 2) { 606 | set_pre_wb(meta,ops[1],nr); 607 | } else if(det->op_count == 3){ 608 | set_post_wb(meta,ops[1],ops[2],nr); 609 | } else { 610 | err("WB unexcepted\n"); 611 | } 612 | } 613 | break; 614 | case ARM_INS_CMP: 615 | xrd = get_op_expr(meta,ops[0]); 616 | xrs = get_op_expr(meta,ops[1]); 617 | xrt = expr_sub(xrd,xrs); 618 | cdt = cond_sl(xrt,imm40); 619 | nf[ARM_SR_N] = cdt; 620 | nf[ARM_SR_Z] = cond_eq(xrt,imm40); 621 | nf[ARM_SR_C] = cond_uge(xrd,xrs); 622 | nf[ARM_SR_V] = cond_and( 623 | cond_xor(cond_sl(xrd,imm40),cdt), 624 | cond_xor(cond_sl(expr_neg(xrs),imm40),cdt)); 625 | break; 626 | case ARM_INS_TBB: 627 | xrs = get_op_expr(meta,ops[0]); 628 | xrt = expr_zext(expr_select(blk->mem,xrs,1),4); 629 | nr[ARM_REG_PC] = expr_add( 630 | get_relative_pc(pc), 631 | expr_shl(xrt,imm41)); 632 | branch_flag = true; 633 | break; 634 | case ARM_INS_CBZ: 635 | case ARM_INS_CBNZ: 636 | xrs = get_op_expr(meta,ops[0]); 637 | xrd = get_op_expr(meta,ops[1]); 638 | cdt = cond_eq(xrs,imm40); 639 | if(ins->id == ARM_INS_CBZ) { 640 | nr[ARM_REG_PC] = expr_ite( 641 | cdt, 642 | xrd, 643 | BytVec::create_imm( 644 | 4, 645 | pc.rawpc + ins->size)); 646 | } else { 647 | nr[ARM_REG_PC] = expr_ite( 648 | cdt, 649 | BytVec::create_imm( 650 | 4, 651 | pc.rawpc + ins->size), 652 | xrd); 653 | } 654 | branch_flag = true; 655 | break; 656 | case ARM_INS_IT: 657 | //just ignore 658 | break; 659 | case ARM_INS_BL: 660 | case ARM_INS_BLX: 661 | if(pc.insmd == CS_MODE_THUMB) { 662 | xrt = BytVec::create_imm( 663 | 4, 664 | ((pc.rawpc + ins->size) | 1)); 665 | } else { 666 | xrt = BytVec::create_imm( 667 | 4, 668 | (pc.rawpc + ins->size)); 669 | } 670 | nr[ARM_REG_LR] = xrt; 671 | case ARM_INS_B: 672 | case ARM_INS_BX: 673 | xrd = get_op_expr(meta,ops[0]); 674 | if(ins->id == ARM_INS_B || ins->id == ARM_INS_BL) { 675 | branch_flag = true; 676 | } 677 | nr[ARM_REG_PC] = xrd; 678 | break; 679 | default: 680 | err("TODO: inst\n"); 681 | break; 682 | } 683 | 684 | if(nm != blk->mem) { 685 | blk->mem = get_cc_expr(blk->mem,nm,blk->flag,det); 686 | nm = blk->mem; 687 | } 688 | for(i = 0;i < ARM_REG_ENDING;i++){ 689 | if(nr[i] != blk->reg[i] && i != ARM_REG_PC) { 690 | blk->reg[i] = get_cc_expr( 691 | blk->reg[i], 692 | nr[i], 693 | blk->flag, 694 | det); 695 | nr[i] = blk->reg[i]; 696 | } 697 | } 698 | if(nr[ARM_REG_PC] != blk->reg[ARM_REG_PC]) { 699 | xrd = nr[ARM_REG_PC]; 700 | if(branch_flag == false) { 701 | //handle mode change 702 | xrt = expr_ite( 703 | cond_eq(expr_and(xrd,imm41),imm41), 704 | insmod_thumb, 705 | insmod_arm); 706 | blk->next_insmd = get_cc_expr( 707 | blk->next_insmd, 708 | xrt, 709 | blk->flag, 710 | det); 711 | xrd = expr_and(xrd,imm4FFFFFFFE); 712 | } 713 | blk->reg[ARM_REG_PC] = get_cc_expr( 714 | BytVec::create_imm(4,pc.rawpc + ins->size), 715 | xrd, 716 | blk->flag, 717 | det); 718 | nr[ARM_REG_PC] = blk->reg[ARM_REG_PC]; 719 | end_flag = true; 720 | } 721 | for(i = 0;i < ARM_FLAG_NUM;i++){ 722 | if(nf[i] != blk->flag[i]) { 723 | nf[i] = get_cc_cond( 724 | blk->flag[i], 725 | nf[i], 726 | blk->flag, 727 | det); 728 | } 729 | } 730 | //flag are always update at last 731 | for(i = 0;i < ARM_FLAG_NUM;i++){ 732 | blk->flag[i] = nf[i]; 733 | } 734 | 735 | ins += 1; 736 | } 737 | cs_free(insn,count); 738 | 739 | return blk; 740 | } 741 | 742 | }; 743 | -------------------------------------------------------------------------------- /src/state.cpp: -------------------------------------------------------------------------------- 1 | #define LOG_PREFIX "state" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include"utils.h" 13 | #include"context.h" 14 | #include"expr.h" 15 | #include"state.h" 16 | #include"solver/z3.h" 17 | 18 | using namespace symx; 19 | 20 | int count = 0; 21 | unsigned long maxlen = 0; 22 | 23 | namespace symx { 24 | static std::unordered_map block_length; 25 | class Compare { 26 | public: 27 | bool operator() (const refState &a,const refState &b) { 28 | if(a->length != 0 && b->length != 0) { 29 | return a->length < b->length; 30 | } 31 | if(a->length == 0) { 32 | return false; 33 | } 34 | return true; 35 | } 36 | }; 37 | static std::priority_queue,Compare> worklist; 38 | //static std::queue worklist; 39 | 40 | refExpr BuildVisitor::get_expr(const refExpr &expr) { 41 | auto it = expr_map.find(expr); 42 | if(it == expr_map.end()) { 43 | err("expr not exist\n"); 44 | return nullptr; 45 | } 46 | return it->second; 47 | } 48 | refCond BuildVisitor::get_cond(const refCond &cond) { 49 | auto it = cond_map.find(cond); 50 | if(it == cond_map.end()) { 51 | err("cond not exist\n"); 52 | return nullptr; 53 | } 54 | return it->second; 55 | } 56 | const std::unordered_set& BuildVisitor::get_mem_record() { 57 | return select_set; 58 | } 59 | int BuildVisitor::pre_visit(const refBytVec &vec) { 60 | if(expr_map.find(vec) != expr_map.end()) { 61 | return 0; 62 | } 63 | return 1; 64 | } 65 | int BuildVisitor::pre_visit(const refBytMem &mem) { 66 | if(expr_map.find(mem) != expr_map.end()) { 67 | return 0; 68 | } 69 | return 1; 70 | } 71 | int BuildVisitor::pre_visit(const refOperator &oper) { 72 | if(expr_map.find(oper) != expr_map.end()) { 73 | return 0; 74 | } 75 | return 1; 76 | } 77 | int BuildVisitor::pre_visit(const refCond &cond) { 78 | if(cond_map.find(cond) != cond_map.end()) { 79 | return 0; 80 | } 81 | return 1; 82 | } 83 | int BuildVisitor::post_visit(const refBytVec &vec) { 84 | if(vec->type == ExprDangle) { 85 | expr_map[vec] = state->reg[vec->index]; 86 | } else { 87 | expr_map[vec] = ref(vec); 88 | } 89 | return 1; 90 | } 91 | int BuildVisitor::post_visit(const refBytMem &mem) { 92 | if(mem->type == ExprDangle) { 93 | expr_map[mem] = state->mem; 94 | } else { 95 | expr_map[mem] = ref(mem); 96 | } 97 | return 1; 98 | } 99 | int BuildVisitor::post_visit(const refOperator &oper) { 100 | refExpr bldexr; 101 | 102 | switch(oper->type) { 103 | case ExprOpSelect: 104 | { 105 | auto mem = expr_map[oper->operand[0]]; 106 | auto idx = expr_map[oper->operand[1]]; 107 | bldexr = expr_select(mem,idx,oper->size); 108 | break; 109 | } 110 | case ExprOpStore: 111 | { 112 | auto mem = expr_map[oper->operand[0]]; 113 | auto idx = expr_map[oper->operand[1]]; 114 | auto val = expr_map[oper->operand[2]]; 115 | bldexr = expr_store(mem,idx,val); 116 | break; 117 | } 118 | case ExprOpExtract: 119 | bldexr = expr_extract( 120 | expr_map[oper->operand[0]], 121 | oper->start, 122 | oper->start + oper->size); 123 | break; 124 | 125 | case ExprOpIte: 126 | bldexr = expr_ite( 127 | cond_map[oper->cond], 128 | expr_map[oper->operand[0]], 129 | expr_map[oper->operand[1]]); 130 | break; 131 | 132 | default: 133 | if(oper->op_count == 1) { 134 | bldexr = ref( 135 | oper->type, 136 | oper->size, 137 | expr_map[oper->operand[0]]); 138 | } else if(oper->op_count == 2) { 139 | bldexr = ref( 140 | oper->type, 141 | oper->size, 142 | expr_map[oper->operand[0]], 143 | expr_map[oper->operand[1]]); 144 | } else if(oper->op_count == 3) { 145 | bldexr = ref( 146 | expr_map[oper->operand[0]], 147 | expr_map[oper->operand[1]], 148 | expr_map[oper->operand[2]]); 149 | } 150 | break; 151 | } 152 | 153 | bldexr = solid_operator( 154 | std::static_pointer_cast(bldexr)); 155 | 156 | if(bldexr->type == ExprOpSelect) { 157 | auto bldoper = std::static_pointer_cast(bldexr); 158 | select_set.insert(ref( 159 | bldoper, 160 | bldoper->operand[0], 161 | bldoper->operand[1], 162 | oper->size)); 163 | } 164 | 165 | expr_map[oper] = bldexr; 166 | return 1; 167 | } 168 | int BuildVisitor::post_visit(const refCond &cond) { 169 | switch(cond->type) { 170 | case CondDangle: 171 | cond_map[cond] = state->flag[cond->index]; 172 | break; 173 | default: 174 | if(cond->cond_count == 0 && cond->expr_count == 2) { 175 | cond_map[cond] = ref( 176 | cond->type, 177 | expr_map[cond->expr[0]], 178 | expr_map[cond->expr[1]]); 179 | } else if(cond->cond_count == 1 && cond->expr_count == 0) { 180 | cond_map[cond] = ref( 181 | cond->type, 182 | cond_map[cond->cond[0]]); 183 | } else if(cond->cond_count == 2 && cond->expr_count == 0) { 184 | cond_map[cond] = ref( 185 | cond->type, 186 | cond_map[cond->cond[0]], 187 | cond_map[cond->cond[1]]); 188 | } else if(cond->cond_count == 3 && cond->expr_count == 0) { 189 | cond_map[cond] = cond_ite( 190 | cond_map[cond->cond[0]], 191 | cond_map[cond->cond[1]], 192 | cond_map[cond->cond[2]]); 193 | } 194 | break; 195 | } 196 | return 1; 197 | } 198 | refExpr BuildVisitor::solid_operator(const refOperator &oper) { 199 | refExpr retexr = oper; 200 | std::unordered_set constr; 201 | std::unordered_map concrete; 202 | 203 | switch(oper->type) { 204 | case ExprOpSelect: 205 | retexr = solid_mem_read(oper); 206 | 207 | assert(retexr->size == oper->size); 208 | 209 | break; 210 | case ExprOpStore: 211 | break; 212 | case ExprOpExtract: 213 | if(oper->operand[0]->type == ExprImm) { 214 | concrete[oper] = 0; 215 | if(solver->solve(constr,&concrete)) { 216 | retexr = BytVec::create_imm(oper->size,concrete[oper]); 217 | } 218 | } 219 | break; 220 | case ExprOpIte: 221 | break; 222 | default: 223 | { 224 | unsigned int i; 225 | bool solid = true; 226 | 227 | for(i = 0; i < oper->op_count; i++) { 228 | if(oper->operand[i]->type != ExprImm) { 229 | solid = false; 230 | } 231 | } 232 | if(solid) { 233 | concrete[oper] = 0; 234 | if(solver->solve(constr,&concrete)) { 235 | retexr = BytVec::create_imm(oper->size,concrete[oper]); 236 | } 237 | } 238 | break; 239 | } 240 | } 241 | 242 | return retexr; 243 | } 244 | refExpr BuildVisitor::solid_mem_read(const refOperator &oper) { 245 | uint64_t addr; 246 | unsigned int size; 247 | refExpr tmpexr; 248 | 249 | assert(oper->type == ExprOpSelect); 250 | 251 | if(oper->operand[1]->type != ExprImm) { 252 | return oper; 253 | } 254 | addr = std::static_pointer_cast(oper->operand[1])->data; 255 | size = oper->size; 256 | 257 | tmpexr = oper->operand[0]; 258 | while(tmpexr->type != ExprMem) { 259 | auto strexr = std::static_pointer_cast(tmpexr); 260 | if(strexr->operand[1]->type != ExprImm) { 261 | return oper; 262 | } 263 | if( 264 | addr == std::static_pointer_cast( 265 | strexr->operand[1])->data && 266 | size == strexr->operand[2]->size 267 | ) { 268 | return strexr->operand[2]; 269 | } 270 | tmpexr = strexr->operand[0]; 271 | } 272 | return oper; 273 | 274 | /*addr = std::static_pointer_cast(oper->operand[1])->data; 275 | size = oper->size; 276 | memexr = oper->operand[0]; 277 | 278 | bitmap = new int[size]; 279 | for(i = 0; i < size; i++) { 280 | bitmap[i] = 0; 281 | } 282 | 283 | //TODO O(N^2) -> O(N) 284 | while(memexr->type != ExprMem) { 285 | auto strexr = std::static_pointer_cast(memexr); 286 | 287 | if(strexr->operand[1]->type != ExprImm) { 288 | break; 289 | } 290 | 291 | auto straddr = std::static_pointer_cast( 292 | strexr->operand[1])->data; 293 | auto start = std::max(straddr,addr); 294 | auto end = std::min(straddr + strexr->operand[2]->size,addr + size); 295 | 296 | if(start < end) { 297 | int val = 0; 298 | if(strexr->operand[2]->type != ExprImm) { 299 | val = 1; 300 | } else { 301 | val = 2; 302 | } 303 | for(i = start; i < end; i++) { 304 | bitmap[i - addr] = std::max(bitmap[i - addr],val); 305 | } 306 | } 307 | 308 | memexr = strexr->operand[0]; 309 | } 310 | if(memexr->type == ExprMem) { 311 | for(i = 0; i < size; i++) { 312 | if(bitmap[i] != 2) { 313 | break; 314 | } 315 | } 316 | if(i == size) { 317 | concrete[oper] = 0; 318 | if(solver->solve(constr,&concrete)) { 319 | retexr = BytVec::create_imm(oper->size,concrete[oper]); 320 | } 321 | } 322 | } 323 | 324 | delete bitmap;*/ 325 | } 326 | 327 | const std::vector& ActiveVisitor::get_expr_addr( 328 | const refExpr &expr 329 | ) { 330 | auto it = cache_expr.find(expr); 331 | 332 | assert(it != cache_expr.end()); 333 | 334 | return it->second; 335 | } 336 | const std::vector& ActiveVisitor::get_cond_addr( 337 | const refCond &cond 338 | ) { 339 | auto it = cache_cond.find(cond); 340 | 341 | assert(it != cache_cond.end()); 342 | 343 | return it->second; 344 | } 345 | int ActiveVisitor::pre_visit(const refBytVec &vec) { 346 | if(cache_expr.find(vec) != cache_expr.end()) { 347 | return 0; 348 | } 349 | return 1; 350 | } 351 | int ActiveVisitor::pre_visit(const refBytMem &mem) { 352 | if(cache_expr.find(mem) != cache_expr.end()) { 353 | return 0; 354 | } 355 | return 1; 356 | } 357 | int ActiveVisitor::pre_visit(const refOperator &oper) { 358 | if(cache_expr.find(oper) != cache_expr.end()) { 359 | return 0; 360 | } 361 | return 1; 362 | } 363 | int ActiveVisitor::pre_visit(const refCond &cond) { 364 | if(cache_cond.find(cond) != cache_cond.end()) { 365 | return 0; 366 | } 367 | return 1; 368 | } 369 | int ActiveVisitor::post_visit(const refBytVec &vec) { 370 | cache_expr[vec] = {}; 371 | return 1; 372 | } 373 | int ActiveVisitor::post_visit(const refBytMem &mem) { 374 | cache_expr[mem] = {}; 375 | return 1; 376 | } 377 | int ActiveVisitor::post_visit(const refOperator &oper) { 378 | unsigned int i; 379 | 380 | auto cache_set = &cache_expr.insert( 381 | std::make_pair(oper,std::vector())).first->second; 382 | for(i = 0; i < oper->op_count; i++) { 383 | auto it = cache_expr.find(oper->operand[i]); 384 | 385 | assert(it != cache_expr.end()); 386 | 387 | cache_set->insert( 388 | cache_set->end(), 389 | it->second.begin(), 390 | it->second.end()); 391 | } 392 | 393 | if(oper->type == ExprOpIte) { 394 | auto it = cache_cond.find(oper->cond); 395 | 396 | assert(it != cache_cond.end()); 397 | 398 | cache_set->insert( 399 | cache_set->end(), 400 | it->second.begin(), 401 | it->second.end()); 402 | } 403 | 404 | if(oper->type == ExprOpSelect && oper->operand[1]->type == ExprImm) { 405 | auto immexr = std::static_pointer_cast( 406 | oper->operand[1]); 407 | 408 | if(immexr->data < 0x2000) { 409 | err("test\n"); 410 | } 411 | 412 | for(i = 0; i < oper->size / 8; i++) { 413 | cache_set->insert(cache_set->end(),immexr->data + (uint64_t)i); 414 | } 415 | } 416 | 417 | std::sort(cache_set->begin(),cache_set->end()); 418 | auto last_it = std::unique(cache_set->begin(),cache_set->end()); 419 | cache_set->erase(last_it,cache_set->end()); 420 | 421 | return 1; 422 | } 423 | int ActiveVisitor::post_visit(const refCond &cond) { 424 | unsigned int i; 425 | 426 | auto cache_set = &cache_cond.insert( 427 | std::make_pair(cond,std::vector())).first->second; 428 | for(i = 0; i < cond->expr_count; i++) { 429 | auto it = cache_expr.find(cond->expr[i]); 430 | 431 | assert(it != cache_expr.end()); 432 | 433 | cache_set->insert( 434 | cache_set->end(), 435 | it->second.begin(), 436 | it->second.end()); 437 | } 438 | for(i = 0; i < cond->cond_count; i++) { 439 | auto it = cache_cond.find(cond->cond[i]); 440 | 441 | assert(it != cache_cond.end()); 442 | 443 | cache_set->insert( 444 | cache_set->end(), 445 | it->second.begin(), 446 | it->second.end()); 447 | } 448 | 449 | std::sort(cache_set->begin(),cache_set->end()); 450 | auto last_it = std::unique(cache_set->begin(),cache_set->end()); 451 | cache_set->erase(last_it,cache_set->end()); 452 | 453 | return 1; 454 | } 455 | 456 | bool ActiveSolver::solve( 457 | const std::unordered_set &target_constr, 458 | const std::unordered_set &constr, 459 | std::unordered_map *concrete 460 | ) { 461 | std::unordered_set act_constr; 462 | /*std::vector in_addr; 463 | std::unordered_set in_addrset; 464 | 465 | act_vis.iter_walk(target_constr.begin(),target_constr.end()); 466 | for(auto it = target_constr.begin(); it != target_constr.end(); it++) { 467 | act_vis.walk(*it); 468 | 469 | const auto &tmpvec = act_vis.get_cond_addr(*it); 470 | in_addr.insert(in_addr.end(),tmpvec.begin(),tmpvec.end()); 471 | } 472 | std::sort(in_addr.begin(),in_addr.end()); 473 | auto last_it = std::unique(in_addr.begin(),in_addr.end()); 474 | in_addr.erase(last_it,in_addr.end()); 475 | 476 | in_addrset.insert(in_addr.begin(),in_addr.end()); 477 | 478 | act_constr = target_constr; 479 | act_constr.insert(constr.begin(),constr.end()); 480 | 481 | //Try to use previous symbol value 482 | for(auto it = in_addrset.begin(); it != in_addrset.end(); it++) { 483 | if(*it < 0x2000) { 484 | err(" *%08lx\n",*it); 485 | } 486 | }*/ 487 | /*for( 488 | auto sym_it = mem_symbol_concrete.begin(); 489 | sym_it != mem_symbol_concrete.end(); 490 | sym_it++ 491 | ) { 492 | info(" %08lx\n",sym_it->first); 493 | if(in_addrset.find(sym_it->first) == in_addrset.end()) { 494 | act_constr.insert(sym_it->second); 495 | } else { 496 | err("conflict\n"); 497 | } 498 | }*/ 499 | 500 | /*for(auto cond_it = constr.begin(); cond_it != constr.end(); cond_it++) { 501 | act_vis.walk(*cond_it); 502 | 503 | const auto &out_addr = act_vis.get_cond_addr(*cond_it); 504 | 505 | auto in_it = in_addr.begin(); 506 | auto out_it = out_addr.begin(); 507 | while(in_it != in_addr.end() && out_it != out_addr.end()) { 508 | if(*in_it == *out_it) { 509 | act_constr.insert(*cond_it); 510 | break; 511 | } 512 | if(*in_it < *out_it) { 513 | in_it++; 514 | } else { 515 | out_it++; 516 | } 517 | } 518 | }*/ 519 | 520 | act_constr = constr; 521 | act_constr.insert(target_constr.begin(),target_constr.end()); 522 | dbg("%u %u\n",concrete->size(),act_constr.size()); 523 | 524 | return solver->solve(act_constr,concrete); 525 | } 526 | 527 | refCond Executor::condition_pc(const refExpr &exrpc,const uint64_t rawpc) { 528 | return cond_eq(exrpc,BytVec::create_imm(exrpc->size,rawpc)); 529 | } 530 | std::vector Executor::solve_state( 531 | const refState cstate, 532 | BuildVisitor *build_vis, 533 | const refBlock cblk 534 | ) { 535 | std::vector statelist; 536 | 537 | refAddrSpace cas; 538 | refCond jmp_cond; 539 | refExpr next_exrpc; 540 | uint64_t next_rawpc; 541 | refExpr next_mem; 542 | std::vector next_reg; 543 | std::vector next_flag; 544 | 545 | std::unordered_set next_selset; 546 | std::vector solid_seladdr; 547 | 548 | std::unordered_set constr; 549 | std::unordered_set target_constr; 550 | std::unordered_map concrete; 551 | refState nstate; 552 | 553 | //initialize environment 554 | statelist.clear(); 555 | cas = cstate->as; 556 | next_reg.clear(); 557 | next_flag.clear(); 558 | 559 | next_selset.clear(); 560 | solid_seladdr.clear(); 561 | 562 | constr.clear(); 563 | concrete.clear(); 564 | 565 | build_vis->walk(cblk->cond); 566 | jmp_cond = build_vis->get_cond(cblk->cond); 567 | build_vis->walk(cblk->nextpc); 568 | next_exrpc = build_vis->get_expr(cblk->nextpc); 569 | build_vis->walk(cblk->mem); 570 | next_mem = build_vis->get_expr(cblk->mem); 571 | for(auto it = cblk->reg.begin(); it != cblk->reg.end(); it++) { 572 | build_vis->walk(*it); 573 | next_reg.push_back(build_vis->get_expr(*it)); 574 | } 575 | for(auto it = cblk->flag.begin(); it != cblk->flag.end(); it++) { 576 | build_vis->walk(*it); 577 | next_flag.push_back(build_vis->get_cond(*it)); 578 | } 579 | 580 | //get memory record 581 | const auto &tmp_selset = build_vis->get_mem_record(); 582 | //copy old select record 583 | next_selset = cstate->select_set; 584 | //handle solid select address 585 | for(auto it = tmp_selset.begin(); it != tmp_selset.end(); it++) { 586 | if((*it)->idx->type == ExprImm) { 587 | auto addr = std::static_pointer_cast( 588 | (*it)->idx)->data; 589 | cas->handle_select(addr,(*it)->size); 590 | } else { 591 | next_selset.insert(*it); 592 | } 593 | } 594 | 595 | //initialize constraint 596 | constr.insert(jmp_cond); 597 | constr.insert(cstate->constr.begin(),cstate->constr.end()); 598 | constr.insert(cas->mem_constr.begin(),cas->mem_constr.end()); 599 | target_constr.insert(jmp_cond); 600 | 601 | //initialize solver variable 602 | //TODO support instruction mode 603 | 604 | concrete[next_exrpc] = 0; 605 | for( 606 | auto it = cas->mem_symbol.begin(); 607 | it != cas->mem_symbol.end(); 608 | it++ 609 | ) { 610 | concrete[it->second] = 0; 611 | } 612 | for(auto it = next_selset.begin(); it != next_selset.end(); it++) { 613 | concrete[(*it)->idx] = 0; 614 | } 615 | 616 | while(true) { 617 | //solve 618 | if(!act_solver->solve( 619 | target_constr, 620 | constr, 621 | &concrete)) { 622 | break; 623 | } 624 | next_rawpc = concrete[next_exrpc]; 625 | 626 | //handle dynamic select, update address space 627 | bool as_update = false; 628 | for(auto it = next_selset.begin(); it != next_selset.end(); it++) { 629 | auto addr = concrete[(*it)->idx]; 630 | if(cas->handle_select(addr,(*it)->size) > 0) { 631 | as_update = true; 632 | } 633 | } 634 | if(as_update) { 635 | constr.insert(cas->mem_constr.begin(),cas->mem_constr.end()); 636 | for( 637 | auto it = cas->mem_symbol.begin(); 638 | it != cas->mem_symbol.end(); 639 | it++ 640 | ) { 641 | concrete[it->second] = 0; 642 | } 643 | continue; 644 | } 645 | 646 | /*dbg("eip %016lx\n",next_rawpc); 647 | dbg("eax %016lx\n",concrete[next_reg[REGIDX_EAX]]); 648 | dbg("edx %016lx\n",concrete[next_reg[REGIDX_EDX]]); 649 | dbg("zf %016lx\n",concrete[next_reg[REGIDX_ZF]]); 650 | 651 | std::vector> tmpvec; 652 | for(auto it = next_selset.begin(); it != next_selset.end(); it++) { 653 | tmpvec.push_back(std::make_pair(concrete[(*it)->idx],concrete[(*it)->oper])); 654 | } 655 | std::sort(tmpvec.begin(),tmpvec.end()); 656 | for(auto it = tmpvec.begin(); it != tmpvec.end(); it++) { 657 | dbg("ldr idx %016lx val %016lx\n",it->first,it->second); 658 | } 659 | tmpvec.clear(); 660 | for(auto it = next_strseq.begin(); it != next_strseq.end(); it++) { 661 | tmpvec.push_back(std::make_pair(concrete[(*it)->idx],concrete[(*it)->oper->operand[2]])); 662 | } 663 | std::sort(tmpvec.begin(),tmpvec.end()); 664 | for(auto it = tmpvec.begin(); it != tmpvec.end(); it++) { 665 | dbg("str idx %016lx val %016lx\n",it->first,it->second); 666 | }*/ 667 | 668 | auto cond_pc = condition_pc(next_exrpc,next_rawpc); 669 | nstate = ref( 670 | ProgCtr(next_rawpc,CS_MODE_32), 671 | cas, 672 | next_mem, 673 | next_reg, 674 | next_flag); 675 | nstate->constr = constr; 676 | nstate->constr.insert(cond_pc); 677 | nstate->select_set = next_selset; 678 | 679 | /*for( 680 | auto it = cas->mem_symbol.begin(); 681 | it != cas->mem_symbol.end(); 682 | it++ 683 | ) { 684 | assert(it->second->size == 8); 685 | nstate->mem_symbol_concrete[it->first] = cond_eq( 686 | it->second, 687 | BytVec::create_imm( 688 | it->second->size, 689 | concrete[it->second])); 690 | }*/ 691 | 692 | statelist.push_back(nstate); 693 | target_constr.insert(cond_not(cond_pc)); 694 | 695 | auto rawpc = nstate->pc.rawpc; 696 | 697 | nstate->path = cstate->path; 698 | nstate->path.push_back(rawpc); 699 | nstate->blkmap = cstate->blkmap; 700 | 701 | if(nstate->blkmap.find(rawpc) != nstate->blkmap.end()) { 702 | auto it = block_length.find(rawpc); 703 | if(it == block_length.end()) { 704 | block_length[rawpc] = nstate->path.size() - nstate->blkmap[rawpc]; 705 | } else { 706 | it->second = std::max(it->second,nstate->path.size() - nstate->blkmap[rawpc]); 707 | } 708 | nstate->length = block_length[rawpc]; 709 | } else { 710 | nstate->blkmap[rawpc] = nstate->path.size(); 711 | 712 | auto it = block_length.find(rawpc); 713 | if(it == block_length.end()) { 714 | nstate->length = 0; 715 | } else { 716 | nstate->length = it->second; 717 | } 718 | } 719 | 720 | maxlen = std::max(maxlen,nstate->path.size()); 721 | if(nstate->path.size() >= 1000) { 722 | for( 723 | auto it = cas->mem_symbol.begin(); 724 | it != cas->mem_symbol.end(); 725 | it++ 726 | ) { 727 | concrete[it->second] = 0; 728 | } 729 | ctx->solver->solve(constr,&concrete); 730 | 731 | std::map tmpmap; 732 | for( 733 | auto it = cas->mem_symbol.begin(); 734 | it != cas->mem_symbol.end(); 735 | it++ 736 | ) { 737 | bool ret = tmpmap.insert(std::make_pair(it->first,concrete[it->second])).second; 738 | if(ret == false) { 739 | err("duplicate symbol %08lx\n",it->first); 740 | } 741 | } 742 | for(auto it = tmpmap.begin(); it != tmpmap.end(); it++) { 743 | dbg("sym %08lx %x\n",it->first,it->second); 744 | } 745 | 746 | dbg("long path %d\n",count); 747 | exit(0); 748 | } 749 | } 750 | 751 | return statelist; 752 | } 753 | 754 | int Executor::execute(uint64_t target_rawpc) { 755 | refSnapshot snap; 756 | std::unordered_map > block_cache; 757 | refState nstate,cstate; 758 | std::vector blklist; 759 | refBlock cblk; 760 | 761 | FILE *f = fopen("pathlog","w"); 762 | 763 | //Create base component 764 | VirtualMachine *vm = ctx->create_vm(); 765 | 766 | //Get main entry snapshot 767 | if(vm->event_wait() != VMCOM_EVT_ENTER) { 768 | err("unexpected event\n"); 769 | } 770 | vm->event_ret(); 771 | while(vm->event_wait() == VMCOM_EVT_EXECUTE) { 772 | dbg("%08lx\n",vm->event_get_pc()); 773 | if(vm->event_get_pc() == target_rawpc) { 774 | info("find main entry\n"); 775 | break; 776 | } 777 | vm->event_ret(); 778 | } 779 | snap = vm->event_suspend(); 780 | 781 | //Init ActiveSolver 782 | act_solver = new ActiveSolver(ctx->solver); 783 | 784 | auto base_as = ref(ctx,snap); 785 | nstate = ref( 786 | ProgCtr(target_rawpc,CS_MODE_32), 787 | base_as, 788 | base_as->mem, 789 | snap->reg, 790 | snap->flag); 791 | worklist.push(nstate); 792 | 793 | while(!worklist.empty()) { 794 | cstate = worklist.top(); 795 | //cstate = worklist.front(); 796 | worklist.pop(); 797 | info("\e[1;32mrun state 0x%016lx\e[m\n",cstate->pc.rawpc); 798 | 799 | count++; 800 | dbg("length %u state %u maxlen %u queue %u\n",cstate->length,count,maxlen,worklist.size()); 801 | 802 | //work_dispatch(); 803 | 804 | auto blklist_it = block_cache.find(cstate->pc); 805 | if(blklist_it == block_cache.end()) { 806 | blklist = snap->translate_bb(cstate->pc); 807 | block_cache[cstate->pc] = blklist; 808 | } else { 809 | blklist = blklist_it->second; 810 | } 811 | 812 | if(blklist.size() == 0) { 813 | unsigned int j; 814 | fprintf(f,"\n"); 815 | for(j = 0; j < cstate->path.size(); j++) { 816 | fprintf(f,"%08lx\n",cstate->path[j]); 817 | } 818 | fflush(f); 819 | } 820 | 821 | auto build_vis = new BuildVisitor(ctx->solver,cstate); 822 | 823 | for(auto blkit = blklist.begin(); blkit != blklist.end(); blkit++) { 824 | auto statelist = solve_state(cstate,build_vis,*blkit); 825 | 826 | for(auto it = statelist.begin(); 827 | it != statelist.end(); 828 | it++ 829 | ) { 830 | worklist.push(*it); 831 | } 832 | } 833 | 834 | delete build_vis; 835 | } 836 | 837 | delete act_solver; 838 | 839 | ctx->destroy_vm(vm); 840 | return 0; 841 | } 842 | }; 843 | --------------------------------------------------------------------------------