/** * Converts a PIN instruction object into a disassembled string. **/ std::string dumpInstruction(INS ins) { std::stringstream ss; ADDRINT address = INS_Address(ins); // Generate address and module information ss << "0x" << setfill('0') << setw(8) << uppercase << hex << address << "::" << getModule(address) << " "; // Generate instruction byte encoding for (int i=0;i<INS_Size(ins);i++) { ss << setfill('0') << setw(2) << (((unsigned int) *(unsigned char*)(address + i)) & 0xFF) << " "; } for (int i=INS_Size(ins);i<8;i++) { ss << " "; } // Generate diassembled string ss << INS_Disassemble(ins); // Look up call information for direct calls if (INS_IsCall(ins) && INS_IsDirectBranchOrCall(ins)) { ss << " -> " << RTN_FindNameByAddress(INS_DirectBranchOrCallTargetAddress(ins)); } return ss.str(); }
VOID PolymorphicCodeHandlerModule::inspectTrace(TRACE trace){ // set the range of address in which the current trace resides this->trace_head = TRACE_Address(trace); this->trace_tail = trace_head + TRACE_Size(trace); for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) { for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) { // for ech instruction we have to check if it has been overwritten by a previous instruction of the current trace (polimiorfic code detection) INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(checkIfWrittenAddress), IARG_INST_PTR, IARG_CONTEXT, IARG_UINT32, INS_Size(ins), IARG_PTR, this, IARG_END); for (UINT32 op = 0; op<INS_MemoryOperandCount(ins); op++) { if(INS_MemoryOperandIsWritten(ins,op)){ // for each write operation we have to check if the traget address is inside the current trace (attempt to write polimorfic code) INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(polimorficCodeHandler), IARG_INST_PTR, IARG_MEMORYOP_EA, op, IARG_PTR, this, IARG_END); } } } } }
// record the page(s) occupied by the instruction VOID SANDBOX::RecordIns(INS ins) { const ADDRINT beginAddr = INS_Address(ins); const ADDRINT endAddr = beginAddr + INS_Size(ins) - 1; RecordAddressRange(reinterpret_cast<const char *>(beginAddr), reinterpret_cast<const char *>(endAddr)); }
VOID Trace(TRACE trace, VOID *v) { const INS beginIns = BBL_InsHead(TRACE_BblHead(trace)); const INS endIns = BBL_InsTail(TRACE_BblTail(trace)); const ADDRINT beginAddr = INS_Address(beginIns); const ADDRINT endAddr = INS_Address(endIns) + INS_Size(endIns) - 1; sandbox.CheckAddressRange(reinterpret_cast<const char *>(beginAddr), reinterpret_cast<const char *>(endAddr)); }
// Insert a direct branch over the first mov immediate static VOID insertJump (RTN rtn) { for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins)) { if (INS_IsMov(ins) && INS_HasImmediateOperand(ins)) { INS_InsertDirectJump(ins, IPOINT_BEFORE, INS_Address(ins) + INS_Size(ins)); instrumentationCount++; return; } } }
const char * dumpInstruction(INS ins) { ADDRINT address = INS_Address(ins); std::stringstream ss; // Generate instruction byte encoding for (size_t i=0;i<INS_Size(ins);i++) { ss << setfill('0') << setw(2) << hex << (((unsigned int) *(unsigned char*)(address + i)) & 0xFF) << " "; } for (size_t i=INS_Size(ins);i<8;i++) { ss << " "; } // Generate diassembled string ss << INS_Disassemble(ins); return strdup(ss.str().c_str()); }
VOID Instruction(INS ins, VOID *v) { ADDRINT nextAddr = INS_NextAddress(ins); UINT32 maxRRegs = INS_MaxNumRRegs(ins); UINT32 maxWRegs = INS_MaxNumWRegs(ins); USIZE sz = INS_Size(ins); INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordFirstInstructionInfo, IARG_THREAD_ID, IARG_INST_PTR, IARG_ADDRINT, nextAddr, IARG_UINT32, maxRRegs, IARG_UINT32, maxWRegs, IARG_ADDRINT, sz, IARG_UINT32, 'r', IARG_END); }
// Insert an indirect branch over the first mov immediate static VOID insertIndirectJump (RTN rtn) { for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins)) { if (INS_IsMov(ins) && INS_HasImmediateOperand(ins)) { INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(returnValue), IARG_ADDRINT, INS_Address(ins) + INS_Size(ins), IARG_RETURN_REGS, scratchReg, IARG_END); INS_InsertIndirectJump(ins, IPOINT_BEFORE, scratchReg); instrumentationCount++; return; } } }
VOID Trace(TRACE trace, VOID *v) { // Instrument only at the head of the trace BBL bbl = TRACE_BblHead(trace); if (BBL_Valid(bbl)) { INS_InsertCall(BBL_InsHead(bbl), IPOINT_BEFORE, (AFUNPTR)docount, IARG_UINT32, 1, IARG_END); } for (bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) { for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) { ASSERTX(INS_Size(ins) != 0); } } }
int main(INT32 argc, CHAR **argv) { PIN_InitSymbols(); if( PIN_Init(argc,argv) ) { return Usage(); } IMG img = IMG_Open(KnobInputFile); if (!IMG_Valid(img)) { std::cout << "Could not open " << KnobInputFile.Value() << endl; exit(1); } std::cout << hex; rtnInternalRangeList.clear(); for (SEC sec = IMG_SecHead(img); SEC_Valid(sec); sec = SEC_Next(sec)) { std::cout << "Section: " << setw(8) << SEC_Address(sec) << " " << SEC_Name(sec) << endl; for (RTN rtn = SEC_RtnHead(sec); RTN_Valid(rtn); rtn = RTN_Next(rtn)) { std::cout << " Rtn: " << setw(8) << hex << RTN_Address(rtn) << " " << RTN_Name(rtn) << endl; string path; INT32 line; PIN_GetSourceLocation(RTN_Address(rtn), NULL, &line, &path); if (path != "") { std::cout << "File " << path << " Line " << line << endl; } RTN_Open(rtn); if (!INS_Valid(RTN_InsHead(rtn))) { RTN_Close(rtn); continue; } RTN_INTERNAL_RANGE rtnInternalRange; rtnInternalRange.start = INS_Address(RTN_InsHead(rtn)); rtnInternalRange.end = INS_Address(RTN_InsHead(rtn)) + INS_Size(RTN_InsHead(rtn)); INS lastIns = INS_Invalid(); for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins)) { std::cout << " " << setw(8) << hex << INS_Address(ins) << " " << INS_Disassemble(ins) << endl; if (INS_Valid(lastIns)) { if ((INS_Address(lastIns) + INS_Size(lastIns)) == INS_Address(ins)) { rtnInternalRange.end = INS_Address(ins)+INS_Size(ins); } else { rtnInternalRangeList.push_back(rtnInternalRange); std::cout << " rtnInternalRangeList.push_back " << setw(8) << hex << rtnInternalRange.start << " " << setw(8) << hex << rtnInternalRange.end << endl; // make sure this ins has not already appeared in this RTN for (vector<RTN_INTERNAL_RANGE>::iterator ri = rtnInternalRangeList.begin(); ri != rtnInternalRangeList.end(); ri++) { if ((INS_Address(ins) >= ri->start) && (INS_Address(ins)<ri->end)) { std::cout << "***Error - above instruction already appeared in this RTN\n"; std::cout << " in rtnInternalRangeList " << setw(8) << hex << ri->start << " " << setw(8) << hex << ri->end << endl; exit (1); } } rtnInternalRange.start = INS_Address(ins); rtnInternalRange.end = INS_Address(ins) + INS_Size(ins); } } lastIns = ins; } RTN_Close(rtn); rtnInternalRangeList.clear(); } } IMG_Close(img); }
VOID Instruction(INS ins, VOID *v) { if (INS_IsMemoryRead(ins) && !instrumentedReadFromIpWithNoOffset) { BOOL readsFromIpWithNoOffset = FALSE; for (UINT32 i = 0; i < INS_OperandCount(ins); i++) { if (!INS_OperandIsMemory(ins, i)) continue; if (INS_OperandMemoryBaseReg(ins, i) == REG_INST_PTR && INS_OperandMemoryDisplacement(ins, i)==0) { readsFromIpWithNoOffset = TRUE; break; } } if (!readsFromIpWithNoOffset) { return; } instrumentedReadFromIpWithNoOffset = TRUE; // only instrument one of these printf ("Instrumenting [ip] read %p %s\n", INS_Address(ins), INS_Disassemble(ins).c_str()); globalIpOfReadRecordedAtInstrumentationTime = INS_Address(ins); globalReadInsSize = INS_Size(ins); fflush (stdout); INS_InsertCall(ins,IPOINT_BEFORE, (AFUNPTR)IpReadBefore, IARG_INST_PTR, IARG_MEMORYREAD_EA, IARG_REG_VALUE, REG_INST_PTR, IARG_END); INS_InsertCall(ins,IPOINT_AFTER, (AFUNPTR)IpReadAfter, IARG_REG_VALUE, REG_INST_PTR, IARG_END); } else if (INS_IsMemoryWrite(ins) && !instrumentedWriteFromIpWithNoOffset) { /* const xed_decoded_inst_t* xedd = INS_XedDec(ins); xed_reg_enum_t breg1 = xed_decoded_inst_get_base_reg(xedd,0); if (breg1== XED_REG_RIP) { readsFromIpWithNoOffset = TRUE; } */ BOOL writesFromIpWithNoOffset = FALSE; for (UINT32 i = 0; i < INS_OperandCount(ins); i++) { if (!INS_OperandIsMemory(ins, i)) continue; if (INS_OperandMemoryBaseReg(ins, i) == REG_INST_PTR && INS_OperandMemoryDisplacement(ins, i)==0) { writesFromIpWithNoOffset = TRUE; break; } } if (!writesFromIpWithNoOffset) { return; } instrumentedReadFromIpWithNoOffset = TRUE; // only instrument one of these printf ("Instrumenting [ip] write %p %s\n", INS_Address(ins), INS_Disassemble(ins).c_str()); globalIpOfWriteRecordedAtInstrumentationTime = INS_Address(ins); globalWriteInsSize = INS_Size(ins); fflush (stdout); INS_InsertCall(ins,IPOINT_BEFORE, (AFUNPTR)IpWriteBefore, IARG_INST_PTR, IARG_MEMORYWRITE_EA, IARG_REG_VALUE, REG_INST_PTR, IARG_END); INS_InsertCall(ins,IPOINT_AFTER, (AFUNPTR)IpWriteAfter, IARG_REG_VALUE, REG_INST_PTR, IARG_END); } }
/* Trace instrumentation */ static void TRACE_Instrumentation(TRACE trace, VOID *v) { for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) { for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) { /* Check if the analysis me be unlocked */ tracer::pintool::checkUnlockAnalysis(INS_Address(ins)); if (!tracer::pintool::analysisTrigger.getState()) /* Analysis locked */ continue; if (tracer::pintool::instructionBlacklisted(INS_Address(ins)) == true || tracer::pintool::instructionWhitelisted(INS_Address(ins)) == false) /* Insruction blacklisted */ continue; /* Prepare the Triton's instruction */ triton::arch::Instruction* tritonInst = new triton::arch::Instruction(); /* Save memory read1 informations */ if (INS_IsMemoryRead(ins)) { INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)saveMemoryAccess, IARG_PTR, tritonInst, IARG_MEMORYREAD_EA, IARG_MEMORYREAD_SIZE, IARG_END); } /* Save memory read2 informations */ if (INS_HasMemoryRead2(ins)) { INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)saveMemoryAccess, IARG_PTR, tritonInst, IARG_MEMORYREAD2_EA, IARG_MEMORYREAD_SIZE, IARG_END); } /* Callback before */ INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)callbackBefore, IARG_PTR, tritonInst, IARG_INST_PTR, IARG_UINT32, INS_Size(ins), IARG_CONTEXT, IARG_THREAD_ID, IARG_END); /* Callback after */ /* Syscall after context must be catcher with INSERT_POINT.SYSCALL_EXIT */ if (INS_IsSyscall(ins) == false) { IPOINT where = IPOINT_AFTER; if (INS_HasFallThrough(ins) == false) where = IPOINT_TAKEN_BRANCH; INS_InsertCall(ins, where, (AFUNPTR)callbackAfter, IARG_PTR, tritonInst, IARG_CONTEXT, IARG_THREAD_ID, IARG_END); } /* I/O memory monitoring for snapshot */ if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsWritten(ins, 0)) { INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)callbackSnapshot, IARG_MEMORYOP_EA, 0, IARG_UINT32, INS_MemoryWriteSize(ins), IARG_END); } } } }
instruction::instruction(const INS& ins) { this->address = INS_Address(ins); this->next_address = INS_NextAddress(ins); // this->opcode = INS_Mnemonic(ins); this->opcode_size = static_cast<uint8_t>(INS_Size(ins)); this->opcode_buffer = std::shared_ptr<uint8_t>(new uint8_t[this->opcode_size], std::default_delete<uint8_t[]>()); PIN_SafeCopy(opcode_buffer.get(), reinterpret_cast<const VOID*>(this->address), this->opcode_size); this->disassemble = INS_Disassemble(ins); // including image, routine auto img = IMG_FindByAddress(this->address); this->including_image = IMG_Valid(img) ? IMG_Name(img) : ""; // this->including_routine = RTN_FindNameByAddress(this->address); PIN_LockClient(); auto routine = RTN_FindByAddress(this->address); PIN_UnlockClient(); if (RTN_Valid(routine)) { auto routine_mangled_name = RTN_Name(routine); this->including_routine_name = PIN_UndecorateSymbolName(routine_mangled_name, UNDECORATION_NAME_ONLY); } else this->including_routine_name = ""; // has fall through this->has_fall_through = INS_HasFallThrough(ins); // is call, ret or syscall this->is_call = INS_IsCall(ins); this->is_branch = INS_IsBranch(ins); this->is_ret = INS_IsRet(ins); this->is_syscall = INS_IsSyscall(ins); this->category = static_cast<xed_category_enum_t>(INS_Category(ins)); this->iclass = static_cast<xed_iclass_enum_t>(INS_Opcode(ins)); // read registers auto read_reg_number = INS_MaxNumRRegs(ins); for (decltype(read_reg_number) reg_id = 0; reg_id < read_reg_number; ++reg_id) { this->src_registers.push_back(INS_RegR(ins, reg_id)); } // written registers auto written_reg_number = INS_MaxNumWRegs(ins); for (decltype(written_reg_number) reg_id = 0; reg_id < written_reg_number; ++reg_id) { this->dst_registers.push_back(INS_RegW(ins, reg_id)); } auto is_special_reg = [](const REG& reg) -> bool { return (reg >= REG_MM_BASE); }; this->is_special = std::any_of(std::begin(this->src_registers), std::end(this->src_registers), is_special_reg) || std::any_of(std::begin(this->dst_registers), std::end(this->dst_registers), is_special_reg) || (this->category == XED_CATEGORY_X87_ALU) || (this->iclass == XED_ICLASS_XEND) || (this->category == XED_CATEGORY_LOGICAL_FP) || (this->iclass == XED_ICLASS_PUSHA) || (this->iclass == XED_ICLASS_PUSHAD) || (this->iclass == XED_ICLASS_PUSHF) || (this->iclass == XED_ICLASS_PUSHFD) || (this->iclass == XED_ICLASS_PUSHFQ); // is memory read, write this->is_memory_read = INS_IsMemoryRead(ins); this->is_memory_write = INS_IsMemoryWrite(ins); this->is_memory_read2 = INS_HasMemoryRead2(ins); }
VOID Instruction(INS ins, VOID *v) { ADDRINT nextAddr = INS_NextAddress(ins); UINT32 maxRRegs = INS_MaxNumRRegs(ins); UINT32 maxWRegs = INS_MaxNumWRegs(ins); ADDRINT sz = INS_Size(ins); if (numContextsInstrumented < 100) { numContextsInstrumented++; INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordContext, // 4 dummy params to get the real params to be pushed on the stack in Intel64 IARG_UINT32, 1, IARG_UINT32, 2, IARG_UINT32, 3, IARG_UINT32, 4, IARG_CONTEXT, IARG_END); INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordContextFastCall, IARG_FAST_ANALYSIS_CALL, IARG_CONTEXT, IARG_END); INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)VerifyContext, IARG_INST_PTR, IARG_CONTEXT, IARG_END); } else if (numRegularInstrumented < 100) { numRegularInstrumented++; INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordInstructionInfoFastCall, IARG_FAST_ANALYSIS_CALL, IARG_THREAD_ID, IARG_INST_PTR, IARG_REG_VALUE, REG_GFLAGS, IARG_ADDRINT, nextAddr, IARG_UINT32, maxRRegs, IARG_UINT32, maxWRegs, IARG_ADDRINT, sz, #ifdef TARGET_IA32E IARG_ADDRINT, 0xdeadbeefdeadbeefLL, #else IARG_ADDRINT, 0xdeadbeef, #endif IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_END); INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordInstructionInfo, // 4 dummy params to get the real params to be pushed on the stack in Intel64 IARG_UINT32, 1, IARG_UINT32, 2, IARG_UINT32, 3, IARG_UINT32, 4, IARG_THREAD_ID, IARG_INST_PTR, IARG_REG_VALUE, REG_GFLAGS, IARG_ADDRINT, nextAddr, IARG_UINT32, maxRRegs, IARG_UINT32, maxWRegs, IARG_ADDRINT, sz, #ifdef TARGET_IA32E IARG_ADDRINT, 0xdeadbeefdeadbeefLL, #else IARG_ADDRINT, 0xdeadbeef, #endif IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_END); INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)VerifyInstructionInfo, IARG_THREAD_ID, IARG_INST_PTR, IARG_REG_VALUE, REG_GFLAGS, IARG_ADDRINT, nextAddr, IARG_UINT32, maxRRegs, IARG_UINT32, maxWRegs, IARG_ADDRINT, sz, #ifdef TARGET_IA32E IARG_ADDRINT, 0xdeadbeefdeadbeefLL, #else IARG_ADDRINT, 0xdeadbeef, #endif IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_REG_VALUE, REG_GDX, IARG_END); } }