├── .gitignore ├── PIN_hit_tracer ├── PIN_hit_tracer.cpp └── PIN_hit_tracer.vcproj ├── PIN_trace.cpp ├── PIN_trace.cpp └── PIN_trace.cpp.vcproj └── PinTools.sln /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | Thumbs.db 3 | *.obj 4 | *.exe 5 | *.pdb 6 | *.user 7 | *.aps 8 | *.pch 9 | *.vspscc 10 | *_i.c 11 | *_p.c 12 | *.ncb 13 | *.suo 14 | *.tlb 15 | *.tlh 16 | *.bak 17 | *.cache 18 | *.ilk 19 | *.log 20 | [Bb]in 21 | [Dd]ebug*/ 22 | *.lib 23 | *.sbr 24 | obj/ 25 | [Rr]elease*/ 26 | _ReSharper*/ 27 | [Tt]est[Rr]esult* -------------------------------------------------------------------------------- /PIN_hit_tracer/PIN_hit_tracer.cpp: -------------------------------------------------------------------------------- 1 | /* This program will log every function ever hit. */ 2 | /* Takes advantage of INTEL Pin's intelligence. */ 3 | /* It doesn't need to know in advance the functions but */ 4 | /* it detects when a CALL is executed instead :) */ 5 | /* TODO: I'm not interested in calls to system DLLs... */ 6 | 7 | #include 8 | #include 9 | #include // used for find() 10 | #include "pin.H" 11 | 12 | 13 | using std::vector; 14 | using std::find; 15 | 16 | 17 | /* Global Variables */ 18 | FILE* LogFile; 19 | vector loggedAddresses; 20 | ADDRINT MAX_USER_MEM = 0x50000000; // Somehow arbitrary, improve! 21 | 22 | 23 | 24 | /* Command Line stuff */ 25 | KNOB KnobLogArgs(KNOB_MODE_WRITEONCE, "pintool", "a", "0", "log call arguments "); 26 | 27 | 28 | 29 | void Fini(INT32 code, void *v) 30 | { 31 | fprintf(LogFile, "# EOF\n"); 32 | fclose(LogFile); 33 | } 34 | 35 | 36 | 37 | /* Auxiliary function. This is a HIT tracer, I just want to log every function ONCE */ 38 | BOOL alreadyLoggedAddresses(ADDRINT ip) 39 | { 40 | if(find(loggedAddresses.begin(), loggedAddresses.end(), ip) != loggedAddresses.end()) 41 | { 42 | // item IS IN vector 43 | return true; 44 | } 45 | else 46 | { 47 | // item is NOT in vector. Push it for the next time. 48 | loggedAddresses.push_back(ip); 49 | return false; 50 | } 51 | } 52 | 53 | 54 | /* Callbacks implementing the actual logging */ 55 | void LogCall(ADDRINT ip) 56 | { 57 | /* This can be extended to fancier logging capabilities */ 58 | if (ip >= MAX_USER_MEM || alreadyLoggedAddresses(ip)) 59 | return; 60 | 61 | UINT32 *CallArg = (UINT32 *)ip; 62 | fprintf(LogFile, "$ %p\n", CallArg); // $ has no meaning, just a random token 63 | } 64 | 65 | 66 | void LogCallAndArgs(ADDRINT ip, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2) 67 | { 68 | /* This can be extended to fancier logging capabilities */ 69 | if (ip >= MAX_USER_MEM || alreadyLoggedAddresses(ip)) 70 | return; 71 | 72 | UINT32 *CallArg = (UINT32 *)ip; 73 | /* NOTE: $ has no meaning, just a random token */ 74 | fprintf(LogFile, "$ %p: %u %u %u\n", CallArg, arg0, arg1, arg2); 75 | } 76 | 77 | 78 | void LogIndirectCall(ADDRINT target, BOOL taken) 79 | { 80 | if(!taken) 81 | return; 82 | else if(target >= MAX_USER_MEM || alreadyLoggedAddresses(target)) 83 | return; 84 | 85 | LogCall(target); 86 | } 87 | 88 | 89 | void LogIndirectCallAndArgs(ADDRINT target, BOOL taken, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2) 90 | { 91 | if(!taken) 92 | return; 93 | else if(target >= MAX_USER_MEM || alreadyLoggedAddresses(target)) 94 | return; 95 | 96 | LogCallAndArgs(target, arg0, arg1, arg2); 97 | } 98 | 99 | 100 | /* This is called every time a new instruction is encountered */ 101 | void Trace(TRACE trace, void *v) 102 | { 103 | /* Do I want to log function arguments as well? */ 104 | const BOOL log_args = KnobLogArgs.Value(); 105 | 106 | 107 | /* Iterate through basic blocks */ 108 | for(BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) 109 | { 110 | /* Since a BB is single entry, single exit a possible call can only be at the end */ 111 | INS tail = BBL_InsTail(bbl); 112 | 113 | if(INS_IsCall(tail)) 114 | { 115 | if(INS_IsDirectBranchOrCall(tail)) 116 | { 117 | /* For direct branches or calls, returns the target address */ 118 | const ADDRINT target = INS_DirectBranchOrCallTargetAddress(tail); 119 | 120 | if(log_args) 121 | { 122 | INS_InsertPredicatedCall( 123 | tail, 124 | IPOINT_BEFORE, 125 | AFUNPTR(LogCallAndArgs), // Fn to jmp to 126 | IARG_ADDRINT, // "target"'s type 127 | target, // The XXX in "CALL XXX" :) 128 | IARG_FUNCARG_ENTRYPOINT_VALUE, // Arg_0 value 129 | 0, 130 | IARG_FUNCARG_ENTRYPOINT_VALUE, // Arg_1 value 131 | 1, 132 | IARG_FUNCARG_ENTRYPOINT_VALUE, // Arg_2 value 133 | 2, 134 | IARG_END // No more args 135 | ); 136 | } 137 | else 138 | { 139 | INS_InsertPredicatedCall( 140 | tail, 141 | IPOINT_BEFORE, 142 | AFUNPTR(LogCall), // Fn to jmp to 143 | IARG_ADDRINT, // "target"'s type 144 | target, // The XXX in "CALL XXX" :) 145 | IARG_END // No more args 146 | ); 147 | } 148 | 149 | } 150 | else 151 | { 152 | /* This is an indirect call (INS_IsBranchOrCall == True) */ 153 | if(log_args) 154 | { 155 | INS_InsertCall( 156 | tail, 157 | IPOINT_BEFORE, 158 | AFUNPTR(LogIndirectCallAndArgs), // Fn to jmp to 159 | IARG_BRANCH_TARGET_ADDR, // "target"'s type 160 | IARG_BRANCH_TAKEN, 161 | IARG_FUNCARG_ENTRYPOINT_VALUE, // Arg_0 value 162 | 0, 163 | IARG_FUNCARG_ENTRYPOINT_VALUE, // Arg_1 value 164 | 1, 165 | IARG_FUNCARG_ENTRYPOINT_VALUE, // Arg_2 value 166 | 2, 167 | IARG_END // No more args 168 | ); 169 | } 170 | else 171 | { 172 | INS_InsertCall( 173 | tail, 174 | IPOINT_BEFORE, 175 | AFUNPTR(LogIndirectCall), // Fn to jmp to 176 | IARG_BRANCH_TARGET_ADDR, // Well... target address? :) 177 | IARG_BRANCH_TAKEN, // Non zero if branch is taken 178 | IARG_END // No more args 179 | ); 180 | } 181 | } 182 | } // end "if INS_IsCall..." 183 | else 184 | { 185 | /* For the case code is not in an image but in a DLL or alike */ 186 | RTN rtn = TRACE_Rtn(trace); 187 | 188 | // Trace jmp into DLLs (.idata section that is, imports) 189 | if(RTN_Valid(rtn) && !INS_IsDirectBranchOrCall(tail) && SEC_Name(RTN_Sec(rtn)) == ".idata") 190 | { 191 | if(log_args) 192 | { 193 | INS_InsertCall( 194 | tail, 195 | IPOINT_BEFORE, 196 | AFUNPTR(LogIndirectCallAndArgs), // Fn to jmp to 197 | IARG_BRANCH_TARGET_ADDR, 198 | IARG_BRANCH_TAKEN, 199 | IARG_FUNCARG_ENTRYPOINT_VALUE, // Arg_0 value 200 | 0, 201 | IARG_FUNCARG_ENTRYPOINT_VALUE, // Arg_1 value 202 | 1, 203 | IARG_FUNCARG_ENTRYPOINT_VALUE, // Arg_2 value 204 | 2, 205 | IARG_END // No more args 206 | ); 207 | } 208 | else 209 | { 210 | INS_InsertCall( 211 | tail, 212 | IPOINT_BEFORE, 213 | AFUNPTR(LogIndirectCall), 214 | IARG_BRANCH_TARGET_ADDR, 215 | IARG_BRANCH_TAKEN, 216 | IARG_END 217 | ); 218 | } 219 | } 220 | } 221 | } // end "for bbl..." 222 | } // end "void Trace..." 223 | 224 | 225 | /* Help message */ 226 | INT32 Usage() 227 | { 228 | cerr << PIN_ERROR("Log addresses of every call ever made. Used in differential debugging.\n" 229 | + KNOB_BASE::StringKnobSummary() + "\n") << endl; 230 | 231 | return -1; 232 | } 233 | 234 | 235 | /* Main function - initialize and set instrumentation callbacks */ 236 | int main(int argc, char *argv[]) 237 | { 238 | /* Initialize Pin with symbol capabilities */ 239 | PIN_InitSymbols(); 240 | if(PIN_Init(argc, argv)) return Usage(); 241 | 242 | LogFile = fopen("functions_log.txt", "w"); 243 | 244 | /* Set callbacks */ 245 | TRACE_AddInstrumentFunction(Trace, 0); 246 | PIN_AddFiniFunction(Fini, 0); 247 | 248 | /* It never returns, sad :) */ 249 | PIN_StartProgram(); 250 | 251 | return 0; 252 | } 253 | -------------------------------------------------------------------------------- /PIN_hit_tracer/PIN_hit_tracer.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 52 | 55 | 58 | 61 | 68 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 90 | 98 | 101 | 104 | 107 | 110 | 113 | 124 | 127 | 130 | 133 | 142 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 164 | 165 | 166 | 167 | 168 | 173 | 176 | 177 | 178 | 183 | 184 | 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /PIN_trace.cpp/PIN_trace.cpp: -------------------------------------------------------------------------------- 1 | /* It starts a process and uses Intel's PIN to */ 2 | /* trace (at a Basic Block level) its execution. */ 3 | /* */ 4 | /* Dumps to a file that will be processed by IDA Pro. */ 5 | /* TODO: Attach to the process instead of opening it? */ 6 | 7 | 8 | #include "pin.H" 9 | #include 10 | #include 11 | 12 | 13 | 14 | /* Global Variables */ 15 | 16 | FILE *trace; 17 | std::vector functionIntervals; 18 | char outputFilename[] = "traceBBL.txt"; 19 | 20 | 21 | /* Command Line Switches */ 22 | KNOB KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", 23 | "o", outputFilename, "specify trace filename"); 24 | 25 | 26 | /* ============================================================================== */ 27 | /* Help Message */ 28 | /* ============================================================================== */ 29 | 30 | INT32 Usage() 31 | { 32 | cerr << 33 | "This tools produces a dynamic instruction trace.\n" 34 | "The trace saves only addresses of basic blocks hit\n" 35 | "which dramatically reduces the output size and the overhead of the tool.\n" 36 | "\n"; 37 | 38 | cerr << KNOB_BASE::StringKnobSummary(); 39 | 40 | cerr << endl; 41 | 42 | return -1; 43 | } 44 | 45 | 46 | /* ============================================================================== */ 47 | /* Auxiliary Functions */ 48 | /* ============================================================================== */ 49 | 50 | BOOL withinInterestingFunction(int ip) 51 | { 52 | unsigned int idx = 0; 53 | 54 | while (idx < functionIntervals.size()) 55 | { 56 | /* Check if the instruction is within the interesting function boundaries */ 57 | if(ip >= functionIntervals[idx] && ip <= functionIntervals[idx + 1]) 58 | return true; 59 | 60 | idx += 2; 61 | } 62 | 63 | return false; 64 | } 65 | 66 | 67 | 68 | VOID printip(VOID *ip) 69 | { 70 | /* Any elaborated logging capabilities would be implemented here */ 71 | if(withinInterestingFunction((int)ip)) 72 | { 73 | fprintf(trace, "$ %p\n", ip); // $ has no meaning, just a random token 74 | fflush(trace); 75 | } 76 | } 77 | 78 | 79 | /* ============================================================================== */ 80 | /* This is the meat and potatoes of the application */ 81 | /* ============================================================================== */ 82 | 83 | VOID Trace(TRACE trace, VOID *v) 84 | { 85 | for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) 86 | { 87 | 88 | INS_InsertCall(BBL_InsTail(bbl), IPOINT_BEFORE, AFUNPTR(printip), 89 | IARG_INST_PTR, IARG_END); 90 | } 91 | } 92 | 93 | 94 | /* ============================================================================== */ 95 | /* Any cleanup operations after the trace go here */ 96 | /* ============================================================================== */ 97 | VOID Fini(INT32 code, VOID *v) 98 | { 99 | fprintf(trace, "# eof\n"); 100 | fclose(trace); 101 | } 102 | 103 | 104 | /* ============================================================================== */ 105 | /* Main */ 106 | /* ============================================================================== */ 107 | 108 | int main(int argc, char *argv[]) 109 | { 110 | unsigned int x; 111 | 112 | 113 | string trace_header = string("#\n" 114 | "# Basic Block Level Trace Generated By PIN\n" 115 | "#\n"); 116 | 117 | if(PIN_Init(argc, argv)) 118 | { 119 | return Usage(); 120 | } 121 | 122 | 123 | /* Open trace log file for writing */ 124 | trace = fopen(KnobOutputFile.Value().c_str(), "w+"); 125 | fprintf(trace, trace_header.c_str(), trace_header.size()); 126 | 127 | 128 | /* ======================================================================= */ 129 | /* I process the interesting functions file here to get the ranges. */ 130 | /* ======================================================================= */ 131 | FILE *interestingFunctions = fopen("specific_functions_intervals.txt", "r"); 132 | 133 | if (interestingFunctions != NULL) 134 | { 135 | char line[128]; // Fixed maximum line size (UGLY) 136 | 137 | while(fgets(line, sizeof(line), interestingFunctions)) // read a line 138 | { 139 | /* Tokenize the line! (split it) */ 140 | char *token; 141 | token = strtok(line, "-"); // first token 142 | 143 | while(token != NULL) 144 | { 145 | // Convert hex string to uint32 146 | // Remember the values denoted by the string are in hex. 147 | // Therefore the 16 base at strtoul() :) 148 | x = strtoul(token, NULL, 16); 149 | 150 | /* Fill the vector */ 151 | functionIntervals.push_back(x); 152 | 153 | token = strtok(NULL, "-"); // next token(s) 154 | } 155 | } 156 | fclose(interestingFunctions); 157 | } 158 | else 159 | { 160 | perror("specific_functions.txt"); // what happened with fopen ? 161 | } 162 | 163 | 164 | // At this point the vector functionIntervals contains the addresses 165 | // in the following form: [f1_start, f1_end, f2_start, f2_end, ...] 166 | 167 | 168 | /* Here I point PIN to my processing functions */ 169 | TRACE_AddInstrumentFunction(Trace, 0); 170 | PIN_AddFiniFunction(Fini, 0); 171 | 172 | // It never returns. Sad, 173 | PIN_StartProgram(); 174 | 175 | return 0; 176 | } 177 | 178 | -------------------------------------------------------------------------------- /PIN_trace.cpp/PIN_trace.cpp.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 52 | 55 | 58 | 61 | 68 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 90 | 98 | 101 | 104 | 107 | 110 | 113 | 124 | 127 | 130 | 133 | 142 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 164 | 165 | 166 | 167 | 168 | 173 | 176 | 177 | 178 | 183 | 184 | 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /PinTools.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PIN_trace.cpp", "PIN_trace.cpp\PIN_trace.cpp.vcproj", "{70F63B8D-F405-4451-BB01-E6AE09BF8B07}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PIN_hit_tracer", "PIN_hit_tracer\PIN_hit_tracer.vcproj", "{BA09EDBD-6D28-4C98-9C74-7986104B0A6C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Release|Win32 = Release|Win32 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {70F63B8D-F405-4451-BB01-E6AE09BF8B07}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {70F63B8D-F405-4451-BB01-E6AE09BF8B07}.Debug|Win32.Build.0 = Debug|Win32 16 | {70F63B8D-F405-4451-BB01-E6AE09BF8B07}.Release|Win32.ActiveCfg = Release|Win32 17 | {70F63B8D-F405-4451-BB01-E6AE09BF8B07}.Release|Win32.Build.0 = Release|Win32 18 | {BA09EDBD-6D28-4C98-9C74-7986104B0A6C}.Debug|Win32.ActiveCfg = Debug|Win32 19 | {BA09EDBD-6D28-4C98-9C74-7986104B0A6C}.Debug|Win32.Build.0 = Debug|Win32 20 | {BA09EDBD-6D28-4C98-9C74-7986104B0A6C}.Release|Win32.ActiveCfg = Release|Win32 21 | {BA09EDBD-6D28-4C98-9C74-7986104B0A6C}.Release|Win32.Build.0 = Release|Win32 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | --------------------------------------------------------------------------------