├── bin └── tainttracer.dll ├── .gitattributes ├── .gitignore ├── pin_taint_trace.py ├── src └── tainttracer.cpp └── example-output └── vulnserver_trace_localhost.txt /bin/tainttracer.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrjr/taint-parade/HEAD/bin/tainttracer.dll -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # ========================= 18 | # Operating System Files 19 | # ========================= 20 | 21 | # OSX 22 | # ========================= 23 | 24 | .DS_Store 25 | .AppleDouble 26 | .LSOverride 27 | 28 | # Icon must ends with two \r. 29 | Icon 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | -------------------------------------------------------------------------------- /pin_taint_trace.py: -------------------------------------------------------------------------------- 1 | # Copyright 2014 James Ritchey 2 | # GNU GPLv3 3 | 4 | #KNOB KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", 5 | # "o", "tainttracer.txt", "specify trace output file name"); 6 | #KNOB KnobFileRead(KNOB_MODE_WRITEONCE, "pintool", 7 | # "f", "", "specify which file name to trace"); 8 | #KNOB KnobNetworkRead(KNOB_MODE_WRITEONCE, "pintool", 9 | # "n", "", "specify which IP address to trace"); 10 | #KNOB KnobSleep(KNOB_MODE_WRITEONCE, "pintool", 11 | # "s", "10000", "specify sleep for process in milliseconds"); 12 | #KNOB KnobOracle(KNOB_MODE_WRITEONCE, "pintool", 13 | # "z", "0", "only as oracle 0 or 1"); // only check for fatal unhandled exception 14 | #KNOB KnobImplicit(KNOB_MODE_WRITEONCE, "pintool", 15 | # "i", "0", "specify how many levels of implicit taints (EIP taints), 0 Default only explicit, -1 is unlimited"); 16 | #KNOB KnobDereference(KNOB_MODE_WRITEONCE, "pintool", 17 | # "d", "0", "specify whether to dereference read memory or not, 0 or 1; can cause crash"); 18 | 19 | from pydbg import * 20 | from pydbg.defines import * 21 | import shutil 22 | from datetime import datetime 23 | import subprocess 24 | import os 25 | from os.path import join 26 | 27 | sleeptime = 0 # how many milliseconds to sleep for 28 | outputfile = r'C:\Users\user\Desktop\tainttracer.txt' # output file information 29 | program = r'C:\Program Files\DAEMON Tools Lite\DTLite.exe' # program to start from beginning 30 | service = r'DTLite.exe' # service to attach to 31 | inputfile = r'' # filter file read by file name 32 | inputip = r'127.0.0.1' # filter recv by peer IP address 33 | crashdir = r'C:\newcrashes' # where to store crash information 34 | implicit = 0 # how many implicit taints to do 35 | doattach = True # attach to program or start program from beginning 36 | dereferencememory = 0 # whether to dereference read memory or not 37 | pinbat = r'C:\Users\user\Downloads\pin-2.13-65163-msvc10-windows\pin-2.13-65163-msvc10-windows\pin_bat.bat' 38 | pintool = r'C:\Users\user\Downloads\pin-2.13-65163-msvc10-windows\pin-2.13-65163-msvc10-windows\source\tools\ManualExamples\obj-ia32\tainttracer.dll' 39 | 40 | def getTimeStamp(): 41 | return datetime.now().strftime("%Y_%m_%d_%H_%M_%S") 42 | 43 | def process(retv): 44 | if retv == 3: 45 | print " program crashed, now copying outfile: " + outputfile 46 | print " program name: " + os.path.basename(program) 47 | print " input file name: " + os.path.basename(inputfile) 48 | crashimage="UnknownImage" 49 | crashrva="UnknownCrashRVA" 50 | 51 | #get program name (without path), inputfile, parse crashed module, parse crash rva, get timestamp, write outfile and input crashfile 52 | try: 53 | f = open(outputfile, "r") 54 | for line in f: 55 | tokens = line.split("::", 2) 56 | if (len(tokens) == 2): 57 | name = tokens[0].lstrip().rstrip() 58 | value = tokens[1].lstrip().rstrip() 59 | if name == "IMG name": 60 | if value: 61 | print "IMG name is " + value 62 | crashimage = value 63 | elif name == "CrashRVA": 64 | if value: 65 | print "Crash RVA is " + value 66 | crashrva = value 67 | except IOError: 68 | print " Problems opening outputfile" 69 | finally: 70 | f.close() 71 | print "IMG: " + crashimage 72 | print "RVA: " + crashrva 73 | print "Input: " + os.path.basename(inputfile) 74 | print "Program: " + os.path.basename(program) 75 | try: 76 | os.makedirs(crashdir + "\\" + os.path.basename(program) + "\\" + os.path.basename(inputfile) + "\\" + os.path.basename(crashimage) + "\\" + crashrva) 77 | except Exception: 78 | print "Couldn't make directories, or already exists" 79 | try: 80 | filename, fileext = os.path.splitext(inputfile) 81 | print "name: " + filename 82 | print "ext: " + fileext 83 | print "inputfile: " + inputfile 84 | print "target: " + crashdir + "\\"+ os.path.basename(program) + "\\" + os.path.basename(inputfile) + "\\" + os.path.basename(crashimage) + "\\" + crashrva + "\\crashsynop_" + thetime + fileext 85 | 86 | shutil.copyfile(outputfile, crashdir + "\\"+ os.path.basename(program) + "\\" + os.path.basename(inputfile) + "\\" + os.path.basename(crashimage) + "\\" + crashrva + "\\crash_" + thetime + ".out") 87 | except IOError, (errno, strerror): 88 | print "Couldn't copy fuzzed filename to crash directory" 89 | print "%s %s" % (errno, strerror) 90 | elif retv == 5: 91 | print getTimeStamp() + " program ended from timer" 92 | else: 93 | print getTimeStamp() + " program ended naturally??" 94 | 95 | # MAIN # 96 | dbg = pydbg() 97 | found = 0 98 | for (pid, name) in dbg.enumerate_processes(): 99 | if name == service: 100 | found=1 101 | break 102 | 103 | print getTimeStamp() + "executing pin tool" 104 | 105 | if (doattach): 106 | if (found): 107 | returnv = subprocess.call(pinbat + ' -follow_execv -pid '+ str(pid) +' -t ' + pintool + ' -n ' + inputip + ' -d ' + str(dereferencememory) + ' -i ' + str(implicit) + ' -o ' + outputfile + ' -s ' + str(sleeptime) + ' --' , shell=True) 108 | thetime = getTimeStamp() 109 | print thetime + " return code " + str(returnv) 110 | process(returnv) 111 | else: 112 | print getTimeStamp() + " couldn't find service" 113 | else: 114 | returnv = subprocess.call(pinbat + ' -follow_execv -t ' + pintool + ' -n ' + inputip + ' -d ' + str(dereferencememory) + ' -i ' + str(implicit) + ' -s ' + str(sleeptime) + ' -o ' + outputfile + ' -- "' + program + '" ' + inputfile, shell=True) 115 | thetime = getTimeStamp() 116 | print thetime + " return code " + str(returnv) 117 | process(returnv) -------------------------------------------------------------------------------- /src/tainttracer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 James Ritchey 3 | * GNU GPLv3 4 | * 5 | */ 6 | #include "pin.H" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | extern "C" { 18 | #include "xed-interface.h" 19 | #include "xed-flags.h" 20 | #include "xed-types.h" 21 | #include "xed-portability.h" 22 | #include "xed-flag-enum.h" 23 | #include "xed-flag-action-enum.h" 24 | #include "xed-gen-table-defs.h" 25 | } 26 | 27 | namespace WINDOWS 28 | { 29 | #pragma comment (lib, "WS2_32.lib") 30 | #include 31 | #include 32 | #include 33 | 34 | typedef struct _IO_STATUS_BLOCK { 35 | union { 36 | NTSTATUS Status; 37 | PVOID Pointer; 38 | }; 39 | ULONG_PTR Information; 40 | } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; 41 | 42 | typedef VOID(WINAPI *PIO_APC_ROUTINE) ( 43 | IN PVOID ApcContext, 44 | IN PIO_STATUS_BLOCK IoStatusBlock, 45 | IN ULONG Reserved 46 | ); 47 | 48 | } 49 | 50 | #define BUFSIZE 1024 51 | #define STATUS_ACCESS_VIOLATION 0xc0000005 52 | #define STATUS_STACK_BUFFER_OVERRUN 0xc0000409 53 | #define BREAKPOINT 0x80000003 54 | #define GUARD_PAGE 0x80000001 55 | #define SINGLE_STEP 0x80000004 56 | #define CONTEXT_CONTROL 0x00010001 57 | #define CONTEXT_INTEGER 0x00010002 58 | #define CONTEXT_SEGMENTS 0x00010004 59 | #define CONTEXT_FULL 0x00010007 60 | #define CONTEXT_DEBUG_REGISTERS 0x00010010 61 | 62 | xed_state_t xedstate; 63 | static bool canstartimplicit = false; // Bool for if can start implicit tainting, only after first tainted flag is read 64 | static int implicitcount=0; 65 | std::ofstream TraceFile; 66 | static stringstream outfilestream; 67 | 68 | class ThreadInfo { 69 | public: 70 | struct taintedflagsinfo { 71 | unsigned int flags; 72 | unsigned int value; 73 | }; 74 | struct taintedregsinfo { 75 | unsigned int value; 76 | }; 77 | set readreg; // read registers for this address, use xed to get which registers 78 | set writtenreg; //written registers for this address, use xed to get which registers 79 | setmemoryaddressesread; // address read, and length 80 | setmemoryaddresseswritten; // address written, and length 81 | bool flagsw; 82 | bool flagsr; 83 | xed_flag_set_t readflags; 84 | xed_flag_set_t writtenflags; 85 | char instmap[50]; //disassembly for this address 86 | bool istainted; 87 | bool decoded; 88 | unsigned char itext[XED_MAX_INSTRUCTION_BYTES]; // hex opcodes 89 | xed_decoded_inst_t decodedinstruction; 90 | IMG img; //module which this address belongs 91 | RTN rtn; // routine that the instruction is on 92 | map taintedregs; // current map of tainted registers for a thread, [reg][value] 93 | taintedflagsinfo taintedflags; // current map of tainted flags for a thread id, [tainted flags][flag value] 94 | 95 | ThreadInfo() 96 | { 97 | istainted=false; 98 | decoded=false; 99 | flagsr=false; 100 | flagsw=false; 101 | taintedflags.flags = 0; 102 | taintedflags.value = 0; 103 | } 104 | 105 | void clean() 106 | { 107 | istainted=false; 108 | decoded=false; 109 | flagsr=false; 110 | flagsw=false; 111 | readreg.clear(); 112 | writtenreg.clear(); 113 | memoryaddressesread.clear(); 114 | memoryaddresseswritten.clear(); 115 | } 116 | 117 | string ImgToString() 118 | { 119 | string imgname; 120 | if (IMG_Valid(img)) 121 | imgname = IMG_Name(img); 122 | else 123 | imgname = "Unknown"; 124 | return imgname; 125 | } 126 | 127 | string RtnToString() 128 | { 129 | string rtnname; 130 | if (RTN_Valid(rtn)) 131 | rtnname = RTN_Name(rtn); 132 | else 133 | rtnname="Unknown"; 134 | return rtnname; 135 | } 136 | 137 | void addRegs(REG reg, bool isread) 138 | { 139 | if (isread) 140 | { 141 | switch (reg) 142 | { 143 | case REG_EAX: 144 | readreg.insert(REG_AH); 145 | readreg.insert(REG_AL); 146 | readreg.insert(REG_AX); 147 | break; 148 | case REG_AX: 149 | readreg.insert(REG_AH); 150 | readreg.insert(REG_AL); 151 | readreg.insert(REG_EAX); 152 | break; 153 | case REG_AH: 154 | case REG_AL: 155 | readreg.insert(REG_AX); 156 | readreg.insert(REG_EAX); 157 | break; 158 | case REG_EBX: 159 | readreg.insert(REG_BH); 160 | readreg.insert(REG_BL); 161 | readreg.insert(REG_BX); 162 | break; 163 | case REG_BX: 164 | readreg.insert(REG_BH); 165 | readreg.insert(REG_BL); 166 | readreg.insert(REG_EBX); 167 | break; 168 | case REG_BH: 169 | case REG_BL: 170 | readreg.insert(REG_BX); 171 | readreg.insert(REG_EBX); 172 | break; 173 | case REG_ECX: 174 | readreg.insert(REG_CH); 175 | readreg.insert(REG_CL); 176 | readreg.insert(REG_CX); 177 | break; 178 | case REG_CX: 179 | readreg.insert(REG_CH); 180 | readreg.insert(REG_CL); 181 | readreg.insert(REG_ECX); 182 | break; 183 | case REG_CH: 184 | case REG_CL: 185 | readreg.insert(REG_ECX); 186 | readreg.insert(REG_CX); 187 | break; 188 | case REG_EDX: 189 | readreg.insert(REG_DH); 190 | readreg.insert(REG_DL); 191 | readreg.insert(REG_DX); 192 | break; 193 | case REG_DX: 194 | readreg.insert(REG_DH); 195 | readreg.insert(REG_DL); 196 | readreg.insert(REG_EDX); 197 | break; 198 | case REG_DH: 199 | case REG_DL: 200 | readreg.insert(REG_DX); 201 | readreg.insert(REG_EDX); 202 | break; 203 | case REG_ESI: 204 | readreg.insert(REG_SI); 205 | break; 206 | case REG_SI: 207 | readreg.insert(REG_ESI); 208 | break; 209 | case REG_EDI: 210 | readreg.insert(REG_DI); 211 | break; 212 | case REG_DI: 213 | readreg.insert(REG_EDI); 214 | break; 215 | case REG_EBP: 216 | readreg.insert(REG_BP); 217 | break; 218 | case REG_BP: 219 | readreg.insert(REG_EBP); 220 | break; 221 | case REG_ESP: 222 | readreg.insert(REG_SP); 223 | break; 224 | case REG_SP: 225 | readreg.insert(REG_ESP); 226 | break; 227 | case REG_EIP: 228 | readreg.insert(REG_IP); 229 | break; 230 | case REG_IP: 231 | readreg.insert(REG_EIP); 232 | break; 233 | default: 234 | break; 235 | } 236 | } 237 | else // written regs 238 | { 239 | switch (reg) 240 | { 241 | case REG_EAX: 242 | writtenreg.insert(REG_AH); 243 | writtenreg.insert(REG_AL); 244 | writtenreg.insert(REG_AX); 245 | break; 246 | case REG_AX: 247 | writtenreg.insert(REG_AH); 248 | writtenreg.insert(REG_AL); 249 | writtenreg.insert(REG_EAX); 250 | break; 251 | case REG_AH: 252 | case REG_AL: 253 | writtenreg.insert(REG_AX); 254 | writtenreg.insert(REG_EAX); 255 | break; 256 | case REG_EBX: 257 | writtenreg.insert(REG_BH); 258 | writtenreg.insert(REG_BL); 259 | writtenreg.insert(REG_BX); 260 | break; 261 | case REG_BX: 262 | writtenreg.insert(REG_BH); 263 | writtenreg.insert(REG_BL); 264 | writtenreg.insert(REG_EBX); 265 | break; 266 | case REG_BH: 267 | case REG_BL: 268 | writtenreg.insert(REG_BX); 269 | writtenreg.insert(REG_EBX); 270 | break; 271 | case REG_ECX: 272 | writtenreg.insert(REG_CH); 273 | writtenreg.insert(REG_CL); 274 | writtenreg.insert(REG_CX); 275 | break; 276 | case REG_CX: 277 | writtenreg.insert(REG_CH); 278 | writtenreg.insert(REG_CL); 279 | writtenreg.insert(REG_ECX); 280 | break; 281 | case REG_CH: 282 | case REG_CL: 283 | writtenreg.insert(REG_ECX); 284 | writtenreg.insert(REG_CX); 285 | break; 286 | case REG_EDX: 287 | writtenreg.insert(REG_DH); 288 | writtenreg.insert(REG_DL); 289 | writtenreg.insert(REG_DX); 290 | break; 291 | case REG_DX: 292 | writtenreg.insert(REG_DH); 293 | writtenreg.insert(REG_DL); 294 | writtenreg.insert(REG_EDX); 295 | break; 296 | case REG_DH: 297 | case REG_DL: 298 | writtenreg.insert(REG_DX); 299 | writtenreg.insert(REG_EDX); 300 | break; 301 | case REG_ESI: 302 | writtenreg.insert(REG_SI); 303 | break; 304 | case REG_SI: 305 | writtenreg.insert(REG_ESI); 306 | break; 307 | case REG_EDI: 308 | writtenreg.insert(REG_DI); 309 | break; 310 | case REG_DI: 311 | writtenreg.insert(REG_EDI); 312 | break; 313 | case REG_EBP: 314 | writtenreg.insert(REG_BP); 315 | break; 316 | case REG_BP: 317 | writtenreg.insert(REG_EBP); 318 | break; 319 | case REG_ESP: 320 | writtenreg.insert(REG_SP); 321 | break; 322 | case REG_SP: 323 | writtenreg.insert(REG_ESP); 324 | break; 325 | case REG_EIP: 326 | writtenreg.insert(REG_IP); 327 | break; 328 | case REG_IP: 329 | writtenreg.insert(REG_EIP); 330 | break; 331 | default: 332 | break; 333 | } 334 | } 335 | } 336 | 337 | bool disassembleInst(unsigned int instructionpointer) 338 | { 339 | if (xed_format_intel(&decodedinstruction, instmap, 50, instructionpointer)) 340 | { 341 | return true; 342 | } 343 | return false; 344 | } 345 | 346 | bool decodeInstruction(unsigned int size) 347 | { 348 | xed_decoded_inst_zero_set_mode(&decodedinstruction, &xedstate); 349 | xed_error_enum_t e = xed_decode(&decodedinstruction, itext, XED_MAX_INSTRUCTION_BYTES); 350 | if ( e == XED_ERROR_NONE ) 351 | { 352 | return true; 353 | } 354 | outfilestream <<"decode failure: " << xed_error_enum_t2str(e)<::iterator writtenregit = writtenreg.begin(); 457 | for (; writtenregit != writtenreg.end();writtenregit++) 458 | { 459 | if (taintedregs.find(*writtenregit) != taintedregs.end()) 460 | { 461 | delete taintedregs[(*writtenregit)]; 462 | taintedregs.erase(*writtenregit); 463 | } 464 | } 465 | } 466 | 467 | void TaintWrittenRegisters(const CONTEXT *ctx) 468 | { 469 | set::iterator writtenregit = writtenreg.begin(); 470 | for (; writtenregit != writtenreg.end();writtenregit++) 471 | { 472 | // do not taint the stack pointer register? 473 | if (REG_FullRegName(*writtenregit) == REG_STACK_PTR) 474 | { 475 | continue; 476 | } 477 | 478 | unsigned int val; 479 | if (!REG_is_fr_or_x87(REG_FullRegName(*writtenregit))) 480 | { 481 | val = (unsigned int)PIN_GetContextReg(ctx, REG_FullRegName(*writtenregit)); 482 | } else 483 | { 484 | if (REG_is_fr_for_get_context(REG_FullRegName(*writtenregit))) 485 | { 486 | val = (unsigned int)PIN_GetContextReg(ctx, REG_FullRegName(*writtenregit)); 487 | } 488 | else 489 | { 490 | val =0; 491 | } 492 | } 493 | 494 | // if the written register is not in the tainted set already, then add it there 495 | if (taintedregs.find((*writtenregit)) == taintedregs.end()) 496 | { 497 | taintedregs.insert(pair(*writtenregit, new taintedregsinfo)); 498 | } 499 | taintedregs[(*writtenregit)]->value = val; 500 | } 501 | } 502 | 503 | string TaintedAndReadRegsToString(const CONTEXT *ctx) 504 | { 505 | stringstream result; 506 | set::iterator readregit = readreg.begin(); 507 | //for each read register 508 | for (; readregit != readreg.end();readregit++) 509 | { 510 | // this can cause "duplicates" for nested registers 511 | result << REG_StringShort(*readregit); 512 | // if it's in list of tainted registers, show that it's tainted 513 | if (taintedregs.find(*readregit) != taintedregs.end()) 514 | { 515 | result << "[T]"; 516 | } 517 | result << ": "; 518 | 519 | if (REG_is_xmm(REG_FullRegName(*readregit)) || REG_is_ymm(REG_FullRegName(*readregit)) || REG_is_fr_or_x87(*readregit)) 520 | { 521 | if (REG_is_fr_for_get_context(REG_FullRegName(*readregit))) 522 | { 523 | result <::iterator writtenregit = writtenreg.begin(); 544 | //for each read register 545 | for (; writtenregit != writtenreg.end();writtenregit++) 546 | { 547 | // this can cause "duplicates" for nested registers 548 | result << REG_StringShort(*writtenregit); 549 | // if it's in list of tainted registers, show that it's tainted 550 | if (taintedregs.find(*writtenregit) != taintedregs.end()) 551 | { 552 | result << "[T]"; 553 | } 554 | result << ": "; 555 | 556 | if (REG_is_xmm(REG_FullRegName(*writtenregit)) || REG_is_ymm(REG_FullRegName(*writtenregit)) || REG_is_fr_or_x87(*writtenregit)) 557 | { 558 | if (REG_is_fr_for_get_context(REG_FullRegName(*writtenregit))) 559 | { 560 | result <::iterator readregit = readreg.begin(); 581 | //for each read register 582 | for (; readregit != readreg.end();readregit++) 583 | { 584 | // if it's in list of tainted registers 585 | if (taintedregs.find(*readregit) != taintedregs.end()) 586 | { 587 | return true; 588 | } 589 | } 590 | return false; 591 | } 592 | }; 593 | 594 | struct taintedmeminfo { 595 | uint8_t value; 596 | }; 597 | 598 | struct readinfo { 599 | WINDOWS::LONGLONG offset; 600 | bool gotread; 601 | unsigned int buffer; 602 | WINDOWS::PIO_STATUS_BLOCK Iosb; 603 | unsigned int length; 604 | }; 605 | 606 | KNOB KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", 607 | "o", "tainttracer.txt", "specify trace output file name"); 608 | KNOB KnobFileRead(KNOB_MODE_WRITEONCE, "pintool", 609 | "f", "", "specify which file name to trace"); 610 | KNOB KnobNetworkRead(KNOB_MODE_WRITEONCE, "pintool", 611 | "n", "", "specify which IP address to trace"); 612 | KNOB KnobSleep(KNOB_MODE_WRITEONCE, "pintool", 613 | "s", "10000", "specify sleep for process in milliseconds"); 614 | KNOB KnobOracle(KNOB_MODE_WRITEONCE, "pintool", 615 | "z", "0", "only as oracle 0 or 1"); // only check for fatal unhandled exception 616 | KNOB KnobImplicit(KNOB_MODE_WRITEONCE, "pintool", 617 | "i", "0", "specify how many levels of implicit taints (EIP taints), 0 Default only explicit, -1 is unlimited"); 618 | KNOB KnobDereference(KNOB_MODE_WRITEONCE, "pintool", 619 | "d", "0", "specify whether to dereference read memory or not, 0 or 1; can cause crash"); 620 | 621 | static maptaintedmem; // current map of tainted memory with byte value 622 | static map threadinfo; // per thread information 623 | static string inputfilename = "filename"; 624 | static string inputipaddress = "ipaddress"; 625 | static bool checkingip=false; 626 | static bool begintaint=false; 627 | static map treadinfo; // per thread read information 628 | static unsigned int sleepthreadid; 629 | static unsigned int onlyasoracle=0; 630 | static unsigned int dereferencememory=0; 631 | 632 | PIN_LOCK lock; 633 | 634 | VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v) 635 | { 636 | PIN_GetLock(&lock, threadid+1); 637 | outfilestream << "thread begin " << threadid <(threadid, new ThreadInfo())); 639 | PIN_ReleaseLock(&lock); 640 | } 641 | 642 | VOID ThreadFini(THREADID threadid, const CONTEXT *ctxt, INT32 code, VOID *v) 643 | { 644 | PIN_GetLock(&lock, threadid+1); 645 | outfilestream << "thread end "<in_avail() != 0) 654 | { 655 | TraceFile << outfilestream.str(); 656 | outfilestream.str(""); 657 | } 658 | TraceFile.flush(); 659 | TraceFile.close(); 660 | PIN_ExitProcess(5); 661 | } 662 | */ 663 | } 664 | 665 | VOID BeforeUnhandledExceptionFilter(THREADID threadid, CHAR *name, WINDOWS::EXCEPTION_POINTERS *exceptionpointer) 666 | { 667 | PIN_GetLock(&lock, threadid+1); 668 | 669 | outfilestream << "Unhandled Exception Thread "<ExceptionRecord->ExceptionCode; 672 | outfilestream <<": Is not continuable? "<ExceptionRecord->ExceptionFlags; 673 | outfilestream <<": address "<ExceptionRecord->ExceptionAddress<ExceptionRecord->NumberParameters;i++) 676 | { 677 | outfilestream <<"Exception param "<ExceptionRecord->ExceptionInformation[i]<ExceptionRecord->ExceptionCode) 689 | { 690 | case STATUS_ACCESS_VIOLATION: 691 | outfilestream << "Access Violation"<ExceptionRecord->NumberParameters;i++) 693 | { 694 | if (i == 0) 695 | if (exceptionpointer->ExceptionRecord->ExceptionInformation[i] == 0) 696 | outfilestream <<"Read exception"<ExceptionRecord->ExceptionInformation[i] == 1) 698 | outfilestream <<"Write exception"<ExceptionRecord->ExceptionInformation[i]<ContextRecord->ContextFlags & CONTEXT_CONTROL) 711 | { 712 | outfilestream <<"EIP: " << exceptionpointer->ContextRecord->Eip<ContextRecord->Eip; 714 | outfilestream <<"EBP: " << exceptionpointer->ContextRecord->Ebp<ContextRecord->Esp<ContextRecord->EFlags<ContextRecord->SegCs<ContextRecord->SegSs<ContextRecord->ContextFlags & CONTEXT_INTEGER) 721 | { 722 | outfilestream <<"ESI: " << exceptionpointer->ContextRecord->Esi<ContextRecord->Edi<ContextRecord->Eax<ContextRecord->Ebx<ContextRecord->Ecx<ContextRecord->Edx<ContextRecord->ContextFlags & CONTEXT_SEGMENTS) 730 | { 731 | outfilestream <<"SegDs: " << exceptionpointer->ContextRecord->SegDs<ContextRecord->SegEs<ContextRecord->SegFs<ContextRecord->SegGs<ExceptionRecord->ExceptionFlags) //if exception is non-continueable, then exit 783 | outfilestream << "Exception, exiting application"<in_avail() != 0) 786 | { 787 | TraceFile << outfilestream.str(); 788 | outfilestream.str(""); 789 | } 790 | 791 | TraceFile.close(); 792 | PIN_ReleaseLock(&lock); 793 | PIN_ExitProcess(3); 794 | } 795 | 796 | VOID BeforeWSARecv(THREADID tid, CHAR * name, int s, unsigned int buf, unsigned int bufcount, unsigned int length, int flags, WINDOWS::LPOVERLAPPED lpOverlapped, WINDOWS::LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) 797 | { 798 | PIN_GetLock(&lock, tid+1); 799 | outfilestream << "Before: " << name << hex << s << ", " << buf << ", " << bufcount << ", "<gotread=true; 828 | tem->offset = 0; 829 | tem->buffer = buf; 830 | treadinfo[tid]=tem; 831 | } 832 | } 833 | PIN_ReleaseLock(&lock); 834 | } 835 | 836 | VOID AfterRecv(THREADID tid, CHAR * name, ADDRINT ret) 837 | { 838 | PIN_GetLock(&lock, tid+1); 839 | outfilestream << "TID: " << tid << " After: " << name << " returns " << ret << endl; 840 | 841 | if (ret>0 && treadinfo[tid] && treadinfo[tid]->gotread) 842 | { 843 | outfilestream << "Recv on tid: " << tid<gotread = false; 845 | treadinfo[tid]->length = ret; 846 | 847 | outfilestream << "Read length: " << treadinfo[tid]->length<buffer<length ;i++) 850 | { 851 | if (taintedmem.find( (unsigned int)treadinfo[tid]->buffer + i) == taintedmem.end()) 852 | taintedmem.insert(pair(treadinfo[tid]->buffer+i, new taintedmeminfo)); 853 | 854 | taintedmem[(unsigned int) treadinfo[tid]->buffer+i]->value = *(uint8_t *)treadinfo[tid]->buffer+i; 855 | } 856 | begintaint=true; 857 | } 858 | 859 | PIN_ReleaseLock(&lock); 860 | } 861 | 862 | VOID BeforeReadFile(THREADID tid, CHAR * name, WINDOWS::HANDLE hFile, WINDOWS::LPVOID lpBuffer, WINDOWS::DWORD nNumberOfBytesToRead, WINDOWS::LPDWORD lpNumberOfBytesRead, WINDOWS::LPOVERLAPPED lpOverlapped) 863 | { 864 | PIN_GetLock(&lock, tid+1); 865 | char Path[BUFSIZE]; 866 | 867 | outfilestream << "TID "< StackRange(CONTEXT *ctx) 895 | { 896 | unsigned int fs = (unsigned int)PIN_GetContextReg(ctx, REG_SEG_FS_BASE); 897 | unsigned int topofstack = *(unsigned int *)(fs +4); 898 | unsigned int bottomofstack = *(unsigned int *)(fs + 8); 899 | return make_pair(topofstack, bottomofstack); 900 | } 901 | 902 | void UnwindStack(CONTEXT *ctx) 903 | { 904 | pair stackrange = StackRange(ctx); 905 | unsigned int ebpframe = (unsigned int)PIN_GetContextReg(ctx, REG_EBP); 906 | unsigned int top = get<0>(stackrange); 907 | unsigned int bottom = get<1>(stackrange); 908 | outfilestream << "Stack Trace: " << ebpframe<QuadPart <gotread=true; 963 | if (ByteOffset) 964 | tem->offset = ByteOffset->QuadPart; 965 | else 966 | tem->offset = 0; 967 | tem->Iosb = IoStatusBlock; 968 | tem->buffer = (unsigned int)Buffer; 969 | treadinfo[tid]=tem; 970 | } 971 | } 972 | PIN_ReleaseLock(&lock); 973 | } 974 | 975 | VOID AfterNtReadFile(THREADID tid, CHAR * name, ADDRINT ret) 976 | { 977 | PIN_GetLock(&lock, tid+1); 978 | outfilestream << "After: " << name << " returns " << hex << ret << endl; 979 | if (ret==0 && treadinfo[tid] && treadinfo[tid]->gotread) 980 | { 981 | outfilestream << "Read on tid: " << tid<gotread = false; 983 | if (treadinfo[tid]->Iosb->Information > 0) // if read length is greater than 0 984 | { 985 | outfilestream << "File offset: " << treadinfo[tid]->offset<Iosb->Status<Iosb->Information<buffer<Iosb->Information ;i++) 990 | { 991 | if (taintedmem.find( (unsigned int)treadinfo[tid]->buffer + i) == taintedmem.end()) 992 | taintedmem.insert(pair(treadinfo[tid]->buffer+i, new taintedmeminfo)); 993 | 994 | taintedmem[(unsigned int) treadinfo[tid]->buffer+i]->value = *(uint8_t *)treadinfo[tid]->buffer+i; 995 | } 996 | begintaint=true; 997 | } 998 | } 999 | PIN_ReleaseLock(&lock); 1000 | } 1001 | 1002 | VOID BeforeIsDebuggerPresent(THREADID tid,CHAR * name) 1003 | { 1004 | PIN_GetLock(&lock, tid+1); 1005 | 1006 | outfilestream << "TID "<::iterator writtenmemit; 1035 | for (writtenmemit=threadinfo[tid]->memoryaddresseswritten.begin();writtenmemit != threadinfo[tid]->memoryaddresseswritten.end();writtenmemit++) 1036 | { 1037 | map::iterator taintedit; 1038 | taintedit = taintedmem.find(*writtenmemit); 1039 | //if it's in the tainted set, remove it 1040 | if (taintedit != taintedmem.end()) 1041 | { 1042 | delete taintedmem[taintedit->first]; 1043 | taintedmem.erase(taintedit); 1044 | } 1045 | } 1046 | } 1047 | 1048 | void TaintWrittenMemory(THREADID tid) 1049 | { 1050 | set::iterator writtenmemit; 1051 | for (writtenmemit=threadinfo[tid]->memoryaddresseswritten.begin();writtenmemit != threadinfo[tid]->memoryaddresseswritten.end();writtenmemit++) 1052 | { 1053 | if (taintedmem.find(*writtenmemit) == taintedmem.end()) 1054 | { 1055 | taintedmem.insert(pair(*writtenmemit, new taintedmeminfo)); 1056 | } 1057 | taintedmem[*writtenmemit]->value = *(uint8_t *)(*writtenmemit); 1058 | } 1059 | } 1060 | 1061 | string TaintedAndReadMemoryToString(THREADID tid) 1062 | { 1063 | stringstream result; 1064 | set::iterator readmemit; 1065 | for (readmemit=threadinfo[tid]->memoryaddressesread.begin();readmemit != threadinfo[tid]->memoryaddressesread.end();readmemit++) 1066 | { 1067 | result <::iterator readmemit; 1083 | for (readmemit=threadinfo[tid]->memoryaddressesread.begin();readmemit != threadinfo[tid]->memoryaddressesread.end();readmemit++) 1084 | { 1085 | if ( taintedmem.find(*readmemit) != taintedmem.end()) 1086 | { 1087 | return true; 1088 | } 1089 | } 1090 | return false; 1091 | } 1092 | 1093 | bool IsImplicitTainted(THREADID tid) 1094 | { 1095 | if (((implicitcount > 0) && canstartimplicit) || implicitcount == -1) 1096 | { 1097 | //if ((threadinfo[tid]->taintedregs.find(REG_EIP) != threadinfo[tid]->taintedregs.end())) 1098 | //{ 1099 | implicitcount--; 1100 | return true; 1101 | //} 1102 | } 1103 | return false; 1104 | } 1105 | 1106 | VOID Image(IMG img, VOID *v) 1107 | { 1108 | if (outfilestream.rdbuf()->in_avail() != 0) 1109 | { 1110 | outfilestream.flush(); 1111 | TraceFile << outfilestream.str(); 1112 | TraceFile.flush(); 1113 | outfilestream.str(""); 1114 | } 1115 | if (IMG_Valid(img)) 1116 | { 1117 | outfilestream << "Image loaded: " <memoryaddressesread.insert(i); 1301 | } 1302 | 1303 | PIN_ReleaseLock(&lock); 1304 | } 1305 | 1306 | VOID BuildReadReg(THREADID tid, REG reg) 1307 | { 1308 | PIN_GetLock(&lock, tid+1); 1309 | 1310 | threadinfo[tid]->readreg.insert(reg); 1311 | threadinfo[tid]->addRegs(reg, true); 1312 | 1313 | PIN_ReleaseLock(&lock); 1314 | } 1315 | 1316 | VOID BuildWrittenMemory(unsigned int addr, unsigned int size, THREADID tid) 1317 | { 1318 | PIN_GetLock(&lock, tid+1); 1319 | for (unsigned int i = addr; i < addr + size;i++) 1320 | { 1321 | threadinfo[tid]->memoryaddresseswritten.insert(i); 1322 | } 1323 | PIN_ReleaseLock(&lock); 1324 | } 1325 | 1326 | VOID BuildWrittenReg(unsigned int addr, THREADID tid, REG reg) 1327 | { 1328 | PIN_GetLock(&lock, tid+1); 1329 | threadinfo[tid]->writtenreg.insert(reg); 1330 | threadinfo[tid]->addRegs(reg, false); 1331 | 1332 | PIN_ReleaseLock(&lock); 1333 | } 1334 | 1335 | VOID Taint(THREADID tid, unsigned int ip, const CONTEXT *ctx) 1336 | { 1337 | PIN_GetLock(&lock, tid+1); 1338 | 1339 | if (IsReadMemoryTainted(tid) || threadinfo[tid]->IsReadRegistersTainted() || threadinfo[tid]->IsReadFlagsTainted() || IsImplicitTainted(tid)) 1340 | { 1341 | threadinfo[tid]->istainted=true; 1342 | outfilestream << "TID: " <instmap; 1345 | outfilestream << ":IMG: " << threadinfo[tid]->ImgToString(); 1346 | outfilestream << ":RTN: " << threadinfo[tid]->RtnToString(); 1347 | outfilestream << ":Read Regs: " << threadinfo[tid]->TaintedAndReadRegsToString(ctx); 1348 | outfilestream << ":Read Flags: " << threadinfo[tid]->TaintedAndReadFlagsToString(ctx); 1349 | outfilestream << ":Read Memory: "<< TaintedAndReadMemoryToString(tid) <TaintedAndWrittenRegsToString(ctx) <TaintWrittenFlags(); // will update flag values after instruction is executed 1354 | threadinfo[tid]->TaintWrittenRegisters(ctx); 1355 | } 1356 | else 1357 | { 1358 | UnTaintWrittenMemory(tid); 1359 | threadinfo[tid]->UnTaintWrittenFlags(); 1360 | threadinfo[tid]->UnTaintWrittenRegs(); 1361 | } 1362 | 1363 | if (outfilestream.rdbuf()->in_avail() != 0) 1364 | { 1365 | outfilestream.flush(); 1366 | TraceFile << outfilestream.str(); 1367 | TraceFile.flush(); 1368 | outfilestream.str(""); 1369 | } 1370 | 1371 | PIN_ReleaseLock(&lock); 1372 | } 1373 | 1374 | VOID RegWriteAfter(THREADID tid,const CONTEXT *ctx) 1375 | { 1376 | PIN_GetLock(&lock, tid+1); 1377 | 1378 | threadinfo[tid]->UpdateTaintedWrittenFlagsValues(ctx); 1379 | 1380 | PIN_ReleaseLock(&lock); 1381 | } 1382 | 1383 | VOID cleanAndDecode(unsigned int ip, THREADID tid, unsigned int instructionlength) 1384 | { 1385 | PIN_GetLock(&lock, tid+1); 1386 | 1387 | if (outfilestream.rdbuf()->in_avail() != 0) 1388 | { 1389 | outfilestream.flush(); 1390 | TraceFile << outfilestream.str(); 1391 | TraceFile.flush(); 1392 | outfilestream.str(""); 1393 | } 1394 | 1395 | threadinfo[tid]->clean(); 1396 | 1397 | PIN_LockClient(); 1398 | threadinfo[tid]->img = IMG_FindByAddress(ip); 1399 | threadinfo[tid]->rtn = RTN_FindByAddress(ip); 1400 | PIN_UnlockClient(); 1401 | 1402 | threadinfo[tid]->setInstructionTextOpcodes(ip, instructionlength); 1403 | 1404 | if (threadinfo[tid]->decodeInstruction(instructionlength)) 1405 | { 1406 | //outfilestream << "decoded ok "; 1407 | if (threadinfo[tid]->disassembleInst(ip)) 1408 | { 1409 | // outfilestream << "disassembly ok"; 1410 | // decoded fine 1411 | } 1412 | threadinfo[tid]->setFlags(ip); 1413 | } 1414 | 1415 | PIN_ReleaseLock(&lock); 1416 | } 1417 | 1418 | //for each instruction 1419 | VOID EachInstruction(INS ins, VOID *v) 1420 | { 1421 | if (begintaint) 1422 | { 1423 | INS_InsertCall( 1424 | ins, 1425 | IPOINT_BEFORE, 1426 | (AFUNPTR)cleanAndDecode, 1427 | IARG_INST_PTR, 1428 | IARG_THREAD_ID, 1429 | IARG_UINT32, 1430 | INS_Size(ins), 1431 | IARG_END); 1432 | 1433 | UINT32 memOperands = INS_MemoryOperandCount(ins); 1434 | //build memory read, reg read, memory write, reg write 1435 | for (UINT32 memOp = 0; memOp < memOperands; memOp++) 1436 | { 1437 | if (INS_MemoryOperandIsRead(ins, memOp)) 1438 | { 1439 | INS_InsertPredicatedCall( 1440 | ins, 1441 | IPOINT_BEFORE, 1442 | (AFUNPTR)BuildMemRead, 1443 | IARG_MEMORYOP_EA, 1444 | memOp, 1445 | IARG_MEMORYREAD_SIZE, 1446 | IARG_THREAD_ID, 1447 | IARG_END); 1448 | } 1449 | } 1450 | 1451 | //Build read registers 1452 | // Handle Stack pointer read on push? 1453 | for (UINT32 r=0; rin_avail() != 0) 1529 | { 1530 | TraceFile << outfilestream.str(); 1531 | outfilestream.str(""); 1532 | } 1533 | TraceFile.close(); 1534 | } 1535 | 1536 | VOID ContextChange(THREADID threadid, CONTEXT_CHANGE_REASON reason, const CONTEXT *from, CONTEXT *to, INT32 info, VOID *v) 1537 | { 1538 | PIN_GetLock(&lock, threadid+1); 1539 | if (outfilestream.rdbuf()->in_avail() != 0) 1540 | { 1541 | outfilestream.flush(); 1542 | TraceFile << outfilestream.str(); 1543 | TraceFile.flush(); 1544 | outfilestream.str(""); 1545 | } 1546 | // outfilestream << "Thread "<in_avail() != 0) 1576 | { 1577 | TraceFile << outfilestream.str(); 1578 | outfilestream.str(""); 1579 | } 1580 | TraceFile.close(); 1581 | PIN_ExitProcess(5); 1582 | } 1583 | 1584 | /* 1585 | VOID SyscallEntry(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, void *v) 1586 | { 1587 | PIN_GetLock(&lock, thread_id+1); 1588 | if (PIN_GetSyscallNumber(ctx, std) == 0x3) // if read syscall 1589 | { 1590 | outfilestream << "system call: "<