├── src ├── libx.so ├── obj-intel64 │ ├── taint.o │ ├── test.o │ ├── test.so │ └── taint.so ├── run ├── makefile ├── config.hpp ├── loop.cpp ├── test.cpp ├── wrapper.cpp ├── makefile.rules ├── pinobject.hpp ├── util.hpp ├── taint.cpp ├── taintengine.hpp └── logic.hpp ├── result ├── snap7 │ ├── output.png │ └── output.svg ├── auto-dnp3 │ └── output.png ├── freemodbus │ ├── output.png │ └── output.svg ├── gec-dnp3 │ └── output.png └── libmodbus │ ├── output.png │ ├── output.svg │ └── info.txt ├── LICENSE ├── send.py ├── README.md └── visualize.py /src/libx.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesclab/ProtocolTaint/HEAD/src/libx.so -------------------------------------------------------------------------------- /result/snap7/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesclab/ProtocolTaint/HEAD/result/snap7/output.png -------------------------------------------------------------------------------- /src/obj-intel64/taint.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesclab/ProtocolTaint/HEAD/src/obj-intel64/taint.o -------------------------------------------------------------------------------- /src/obj-intel64/test.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesclab/ProtocolTaint/HEAD/src/obj-intel64/test.o -------------------------------------------------------------------------------- /src/obj-intel64/test.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesclab/ProtocolTaint/HEAD/src/obj-intel64/test.so -------------------------------------------------------------------------------- /src/obj-intel64/taint.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesclab/ProtocolTaint/HEAD/src/obj-intel64/taint.so -------------------------------------------------------------------------------- /result/auto-dnp3/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesclab/ProtocolTaint/HEAD/result/auto-dnp3/output.png -------------------------------------------------------------------------------- /result/freemodbus/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesclab/ProtocolTaint/HEAD/result/freemodbus/output.png -------------------------------------------------------------------------------- /result/gec-dnp3/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesclab/ProtocolTaint/HEAD/result/gec-dnp3/output.png -------------------------------------------------------------------------------- /result/libmodbus/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nesclab/ProtocolTaint/HEAD/result/libmodbus/output.png -------------------------------------------------------------------------------- /src/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mkdir -p obj-intel64 3 | if [ "$1" = "compile" ];then 4 | touch $2.cpp 5 | make obj-intel64/$2.so 6 | fi 7 | 8 | if [ "$1" = "run" ];then 9 | LD_PRELOAD=./libx.so pin -t obj-intel64/$2.so -- $3 ${@:4} 10 | fi 11 | 12 | if [ "$1" = "all" ];then 13 | touch $2.cpp 14 | make obj-intel64/$2.so 15 | LD_PRELOAD=./libx.so pin -t obj-intel64/$2.so -- $3 ${@:4} 16 | fi 17 | 18 | -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | ############################################################## 2 | # 3 | # DO NOT EDIT THIS FILE! 4 | # 5 | ############################################################## 6 | # If the tool is built out of the kit, PIN_ROOT must be specified in the make invocation and point to the kit root. 7 | ifdef PIN_ROOT 8 | CONFIG_ROOT := $(PIN_ROOT)/source/tools/Config 9 | else 10 | CONFIG_ROOT := ../Config 11 | endif 12 | include $(CONFIG_ROOT)/makefile.config 13 | include makefile.rules 14 | include $(TOOLS_ROOT)/Config/makefile.default.rules 15 | 16 | ############################################################## 17 | # 18 | # DO NOT EDIT THIS FILE! 19 | # 20 | ############################################################## 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 nesclab 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 | -------------------------------------------------------------------------------- /src/config.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_H 2 | #define _CONFIG_H 3 | 4 | #include 5 | 6 | namespace config { 7 | 8 | const bool thread_flag = false; 9 | const int threadId = 2; 10 | 11 | // run mode 12 | const bool debugMode = true; 13 | 14 | const bool traceLog = false; 15 | 16 | // entry function name for filter out irrelavant functions 17 | const std::string start_entry = "main"; 18 | // const std::string start_entry = "init_codecs"; // for python 19 | // use IMG_Entry instead in future 20 | 21 | // flag for print miss assembly 22 | const bool missFlag = true; 23 | 24 | // flush immediately after print 25 | const bool isFlush = true; 26 | // logger print to console 27 | const bool print = true; 28 | 29 | // debug, info, verbose filenames 30 | const char *filenames[3] = {"debug.txt", "info.txt", "verbose.txt"}; 31 | const bool flags[3] = {true, true, true}; 32 | 33 | // use syscall 34 | const bool syscall = true; 35 | 36 | const bool use_interactive = false; 37 | 38 | // read size control 39 | const bool read_size_flag = false; 40 | // const bool read_size_flag = true; 41 | const int read_size_max = 0x30; 42 | const int read_size_min = 0x5; 43 | 44 | // read fd control 45 | // const bool read_fd_flag = true; 46 | const bool read_fd_flag = false; 47 | const int read_fd_max = 4; 48 | const int read_fd_min = 4; 49 | 50 | // max taint size 51 | const size_t maxsize = 1024; 52 | 53 | const bool demangle = true; 54 | // const bool demangle = false; 55 | 56 | const char *tetfuncs[] = { 57 | }; 58 | 59 | const char *blackfuncs[] = { 60 | "PyDict_GetItem", "PyDict_SetItem", "PyObject_Hash", 61 | "PyObject_Free", "PyFunction_New", "PyCode_New", 62 | "PyList_New", "PyTuple_New", "PyDict_New", 63 | }; 64 | 65 | const char *libs[] = { 66 | // "libstdc++", 67 | // "libc" 68 | // "libboost_system", 69 | "libopendnp3", 70 | "libsnap7", 71 | "libmodbus", 72 | "libtest", 73 | }; 74 | 75 | } // namespace config 76 | 77 | #endif -------------------------------------------------------------------------------- /src/loop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "pin.H" 4 | #include "pinobject.hpp" 5 | #include "util.hpp" 6 | 7 | class Block { 8 | public: 9 | 10 | Block() {} 11 | 12 | Block(uint64_t rsp, int id): _rsp(rsp), _id(id) {} 13 | 14 | void push(uint64_t head, size_t size) { 15 | blocks.push_back(std::make_pair(head, head + size)); 16 | } 17 | 18 | bool valid(uint64_t head, size_t size, size_t n) { 19 | n = std::min(blocks.size(), n); 20 | for (size_t i = 0; i < n; ++i) { 21 | if (head == blocks[n - 1 - i].first || head + size == blocks[n - 1 - i].second) return true; 22 | } 23 | return false; 24 | } 25 | 26 | bool exist(uint64_t head, size_t size) { 27 | return valid(head, size, blocks.size()); 28 | } 29 | 30 | uint64_t rsp() { return _rsp;} 31 | int id() {return _id;} 32 | 33 | private: 34 | std::vector > blocks; 35 | uint64_t _rsp; 36 | int _id; 37 | }; 38 | 39 | class BlockTrace { 40 | public: 41 | BlockTrace() {} 42 | void push(uint64_t head, size_t size, uint64_t rsp, int id) { 43 | while (!functions.empty() && functions.back().first < rsp) { 44 | trace.erase(functions.back().second); 45 | functions.pop_back(); 46 | } 47 | if (trace.count(id) == 0) { 48 | trace[id] = Block(rsp, id); 49 | functions.push_back(std::make_pair(rsp, id)); 50 | } 51 | trace[id].push(head, size); 52 | } 53 | 54 | bool exist(uint64_t head, size_t size, int id) { 55 | if (trace.count(id) == 0) return false; 56 | return trace[id].exist(head, size); 57 | } 58 | 59 | private: 60 | std::map trace; 61 | std::vector > functions; 62 | }; 63 | 64 | BlockTrace blocktrace; 65 | std::set loops; 66 | 67 | void LogBlock(uint64_t head, size_t size, uint64_t rsp, int id) { 68 | if (blocktrace.exist(head, size, id)) { 69 | if (loops.count(head) == 0) { 70 | logger::info("LOOP\t%lx\t%lx\n", head, size); 71 | loops.insert(head); 72 | } 73 | } 74 | blocktrace.push(head, size, rsp, id); 75 | } 76 | 77 | VOID Trace(TRACE trace, VOID *v) { 78 | RTN rtn = TRACE_Rtn(trace); 79 | if (!RTN_Valid(rtn)) return; 80 | bool plt = (RTN_Name(rtn).find("plt") != std::string::npos); 81 | if (plt) return; 82 | SEC sec = RTN_Sec(rtn); 83 | if (!SEC_Valid(sec)) return; 84 | IMG img = SEC_Img(sec); 85 | std::string imgName = IMG_Name(img); 86 | bool isMain = IMG_IsMainExecutable(img); 87 | bool isLib = filter::libs(imgName); 88 | if (!isMain && !isLib) return; 89 | 90 | int id = RTN_Id(rtn); 91 | for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl=BBL_Next(bbl)) { 92 | uint64_t addr = BBL_Address(bbl); 93 | size_t size = BBL_Size(bbl); 94 | // IPOINT_ANYWHERE loop插入位置会出错 95 | BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)LogBlock, 96 | IARG_ADDRINT, addr, 97 | IARG_ADDRINT, size, 98 | IARG_REG_VALUE, REG_RSP, 99 | IARG_ADDRINT, id, 100 | IARG_END); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "pin.H" 5 | #include "pinobject.hpp" 6 | #include 7 | #include 8 | 9 | class Block { 10 | public: 11 | 12 | Block() {} 13 | 14 | Block(uint64_t rsp, int id): _rsp(rsp), _id(id) {} 15 | 16 | void push(uint64_t head, size_t size) { 17 | blocks.push_back(std::make_pair(head, head + size)); 18 | } 19 | 20 | bool valid(uint64_t head, int n) { 21 | int size = blocks.size(); 22 | if (n > size) n = size; 23 | for (int i = 0; i < n; ++i) { 24 | if (head >= blocks[size - 1 - i].first && head < blocks[size - 1 - i].second) return true; 25 | } 26 | return false; 27 | } 28 | 29 | bool exist(uint64_t head) { 30 | return valid(head, blocks.size()); 31 | } 32 | 33 | uint64_t rsp() { return _rsp;} 34 | int id() {return _id;} 35 | 36 | private: 37 | std::vector > blocks; 38 | uint64_t _rsp; 39 | int _id; 40 | }; 41 | 42 | class BlockTrace { 43 | public: 44 | BlockTrace() {} 45 | void push(uint64_t head, size_t size, uint64_t rsp, int id) { 46 | if (trace.count(id) == 0) { 47 | trace[id] = Block(rsp, id); 48 | functions.push_back(std::make_pair(rsp, id)); 49 | } 50 | while (!functions.empty()) { 51 | if (functions.back().first >= rsp) break; 52 | trace.erase(functions.back().second); 53 | functions.pop_back(); 54 | } 55 | trace[id].push(head, size); 56 | } 57 | 58 | bool exist(uint64_t head, int id) { 59 | if (trace.count(id) == 0) return false; 60 | return trace[id].exist(head); 61 | } 62 | 63 | private: 64 | std::map trace; 65 | std::vector > functions; 66 | }; 67 | 68 | BlockTrace blocktrace; 69 | std::set loops; 70 | 71 | void LogBlock(uint64_t head, size_t size, uint64_t rsp, int id) { 72 | if (blocktrace.exist(head, id)) { 73 | if (loops.count(head) == 0) { 74 | printf("LOOP\t%lx\t%lx\n", head, size); 75 | loops.insert(head); 76 | } 77 | } 78 | blocktrace.push(head, size, rsp, id); 79 | } 80 | 81 | VOID Trace(TRACE trace, VOID *v) { 82 | RTN rtn = TRACE_Rtn(trace); 83 | if (!RTN_Valid(rtn)) return; 84 | bool plt = (RTN_Name(rtn).find("plt") != std::string::npos); 85 | if (plt) return; 86 | SEC sec = RTN_Sec(rtn); 87 | if (!SEC_Valid(sec)) return; 88 | IMG img = SEC_Img(sec); 89 | if (!IMG_IsMainExecutable(img)) return; 90 | std::string imgName = IMG_Name(img); 91 | int id = RTN_Id(rtn); 92 | for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl=BBL_Next(bbl)) { 93 | uint64_t addr = BBL_Address(bbl); 94 | size_t size = BBL_Size(bbl); 95 | BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)LogBlock, 96 | IARG_ADDRINT, addr, 97 | IARG_ADDRINT, size, 98 | IARG_REG_VALUE, REG_RSP, 99 | IARG_ADDRINT, id, 100 | IARG_END); 101 | } 102 | } 103 | 104 | INT32 Usage() { 105 | printf("error\n"); 106 | return -1; 107 | } 108 | 109 | /* ===================================================================== */ 110 | /* Main */ 111 | /* ===================================================================== */ 112 | 113 | int main(int argc, char *argv[]) { 114 | if (PIN_Init(argc, argv)) return Usage(); 115 | PIN_InitSymbols(); 116 | 117 | TRACE_AddInstrumentFunction(Trace, 0); 118 | 119 | PIN_StartProgram(); 120 | 121 | return 0; 122 | } -------------------------------------------------------------------------------- /send.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | import random 4 | import socket 5 | import time 6 | import sys 7 | 8 | modbus = [ 9 | "\x01\x11\x00\x00\x00\x06\x01\x03\x00\x02\x00\x08", 10 | "\x01\x11\x00\x00\x00\x06\x01\x03\x00\x02\x00\x01", 11 | "\x01\x11\x00\x00\x00\x06\x01\x03\x01\xc0\x00\x01", 12 | "\x20\x01\x00\x00\x00\x06\xff\x01\x00\x00\x00\x01", 13 | "\x00\x01\x00\x00\x00\x06\xff\x02\x00\x00\x00\x01", 14 | "\x00\x01\x00\x00\x00\x06\xff\x03\x00\x00\x00\x01", 15 | "\x00\x01\x00\x00\x00\x06\xff\x04\x00\x00\x00\x01", 16 | "\x00\x01\x00\x00\x00\x06\xff\x05\x00\x00\xff\x00", 17 | "\x00\x01\x00\x00\x00\x06\xff\x06\x00\x01\x00\x03", 18 | "\x00\x01\x00\x00\x00\x08\xff\x0f\x00\x01\x00\x01\x01\x01", 19 | "\x00\x01\x00\x00\x00\x09\xff\x10\x00\x01\x00\x01\x02\x00\x0a" 20 | ] 21 | 22 | modbustest = [0x01,0x11,0x00,0x00,0x00,0x06,0x01,0x03,0x00,0x01,0x00,0x01] 23 | 24 | dnp3 = [ 25 | "\x05\x64\x12\x44\x64\x00\x01\x00\xd6\x03\xc5\xc4\x81\x00\x00\x29\x02\x17\x01\x01\xa4\x4c\x00\x69\x13", 26 | "\x05\x64\x10\xc4\x01\x00\x64\x00\x09\x9b\xc6\xc5\x03\x29\x02\x17\x01\x02\xa5\x4c\x00\xc2\xd1", 27 | "\x05\x64\x12\x44\x64\x00\x01\x00\xd6\x03\xc6\xc5\x81\x00\x00\x29\x02\x17\x01\x02\xa5\x4c\x00\x3a\x0d", 28 | "\x05\x64\x10\xc4\x01\x00\x64\x00\x09\x9b\xc7\xc6\x04\x29\x02\x17\x01\x02\xa5\x4c\x00\x26\x4d", 29 | "\x05\x64\x12\x44\x64\x00\x01\x00\xd6\x03\xc7\xc6\x81\x00\x00\x29\x02\x17\x01\x02\xa5\x4c\x00\x51\x2a", 30 | "\x05\x64\x10\xc4\x01\x00\x64\x00\x09\x9b\xc8\xc7\x03\x29\x02\x17\x01\x03\xa6\x4c\x00\x0b\x31", 31 | "\x05\x64\x12\x44\x64\x00\x01\x00\xd6\x03\xc8\xc7\x81\x00\x00\x29\x02\x17\x01\x03\xa6\x4c\x00\x64\x9d", 32 | "\x05\x64\x10\xc4\x01\x00\x64\x00\x09\x9b\xc9\xc8\x04\x29\x02\x17\x01\x03\xa6\x4c\x00\x93\x8e", 33 | "\x05\x64\x12\x44\x64\x00\x01\x00\xd6\x03\xc9\xc8\x81\x00\x00\x29\x02\x17\x01\x03\xa6\x4c\x00\x36\x16", 34 | "\x05\x64\x10\xc4\x01\x00\x64\x00\x09\x9b\xca\xc9\x03\x29\x02\x17\x01\x04\xa7\x4c\x00\x04\x3b", 35 | "\x05\x64\x12\x44\x64\x00\x01\x00\xd6\x03\xca\xc9\x81\x00\x00\x29\x02\x17\x01\x04\xa7\x4c\x00\x4e\xd4", 36 | "\x05\x64\x10\xc4\x01\x00\x64\x00\x09\x9b\xcb\xca\x04\x29\x02\x17\x01\x04\xa7\x4c\x00\xe0\xa7", 37 | "\x05\x64\x12\x44\x64\x00\x01\x00\xd6\x03\xcb\xca\x81\x00\x00\x29\x02\x17\x01\x04\xa7\x4c\x00\x25\xf3", 38 | ] 39 | 40 | cip = [ 41 | "\x70\x00\x3a\x00\x00\x01\x02\x10\x00\x00\x00\x00\x1a\x39\x2f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x02\x00\xa1\x00\x04\x00\x09\x13\x35\x00\xb1\x00\x26\x00\xe4\x6a\x0a\x02\x20\x02\x24\x01\x02\x00\x06\x00\x12\x00\x4c\x02\x20\x72\x24\x00\x00\xce\x04\x00\x01\x00\x4c\x02\x20\x72\x24\x00\x2c\x3d\x04\x00\x01\x00\x0a\x02\x20\x02\x24\x01\x02\x00\x06\x00\x12\x00\x4c\x02\x20\x72\x24\x00\x00\xce\x04\x00\x01\x00\x4c\x02\x20\x72\x24\x00\x2c\x3d\x04\x00\x01\x00", 42 | "\x03\x02\x20\x73\x24\x01\x01\x00\x05\x00" 43 | ] 44 | 45 | s7 = [ 46 | "\x03\x00\x00\x1f\x02\xf0\x80\x32\x01\x00\x00\x00\x00\x00\x0e\x00\x00\x04\x01\x12\x0a\x10\x02\x00\x04\x00\x01\x84\x00\x00\x00" 47 | ] 48 | 49 | proto = sys.argv[1] 50 | 51 | if proto == "dnp3": 52 | data = dnp3 53 | port = 4999 54 | elif proto == "cip": 55 | data = cip 56 | port = 44818 57 | elif proto == "modbus": 58 | data = modbus 59 | port = 502 60 | elif proto == "s7": 61 | data = s7 62 | port = 102 63 | 64 | ip = "127.0.0.1" 65 | 66 | if len(sys.argv) >= 4: 67 | port = int(sys.argv[3]) 68 | 69 | print port 70 | 71 | def connect(ip, port): 72 | sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 73 | try: 74 | sock.connect((ip, port)) 75 | print("The connection is successful!") 76 | return sock 77 | except: 78 | print("The connection failed!") 79 | return False 80 | 81 | def wait_connect(ip, port): 82 | while 1: 83 | sock = connect(ip, port) 84 | if sock: break 85 | time.sleep(0.5) 86 | return sock 87 | 88 | 89 | def main(): 90 | if len(sys.argv) < 3: 91 | index = 0 92 | else: 93 | index = int(sys.argv[2]) 94 | while 1: 95 | sock = wait_connect(ip, port) 96 | d = data[index] 97 | sock.send(d) 98 | print("send {}".format(" ".join(hex(ord(c)) for c in d))) 99 | print("recv {}".format(" ".join(hex(ord(c)) for c in sock.recv(64)))) 100 | sock.close() 101 | _ = raw_input("wait....") 102 | index += 1 103 | 104 | main() 105 | -------------------------------------------------------------------------------- /src/wrapper.cpp: -------------------------------------------------------------------------------- 1 | // #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | extern "C" { 9 | 10 | typedef void* (*mallocFuncType)(size_t); 11 | typedef void (*freeFuncType)(void *); 12 | 13 | typedef void* (*memcpyFuncType)(void*, const void*, size_t); 14 | typedef void* (*memmoveFuncType)(void*, const void*, size_t); 15 | 16 | 17 | 18 | typedef ssize_t (*sendFuncType)(int, const void *, size_t, int); 19 | typedef ssize_t (*recvFuncType)(int, void *, size_t, int); 20 | 21 | typedef ssize_t (*sendmsgType)(int, const struct msghdr *, int); 22 | typedef ssize_t (*recvmsgFuncType)(int, struct msghdr*, int); 23 | 24 | typedef ssize_t (*sendtoType)(int, const void *, size_t, int, const struct sockaddr *, socklen_t); 25 | typedef ssize_t (*recvfromFuncType)(int, void*, size_t, int, struct sockaddr*, socklen_t*); 26 | 27 | typedef ssize_t (*readFuncType)(int, void*, size_t); 28 | typedef ssize_t (*writeFuncType)(int, const void*, size_t); 29 | 30 | // void *malloc(size_t size) { 31 | // mallocFuncType real_malloc = (mallocFuncType) dlsym(RTLD_NEXT, "malloc"); 32 | // void *p = real_malloc(size); 33 | // fprintf(stderr, "in malloc(size: 0x%lx) => %p\n", size, p); 34 | // return p; 35 | // } 36 | 37 | // void free(void *p) { 38 | // freeFuncType real_free = (freeFuncType) dlsym(RTLD_NEXT, "free"); 39 | // fprintf(stderr, "in free(p: %p)\n", p); 40 | // } 41 | 42 | void* memcpy(void *dst, const void *src, size_t size) { 43 | memcpyFuncType real_memcpy = (memcpyFuncType) dlsym(RTLD_NEXT, "memcpy"); 44 | // fprintf(stderr, "in memcpy(dst: %p, src: %p, size: 0x%lx)\n", dst, src, size); 45 | return real_memcpy(dst, src, size); 46 | } 47 | 48 | void* memmove(void *dst, const void *src, size_t size) { 49 | memmoveFuncType real_memmove = (memmoveFuncType) dlsym(RTLD_NEXT, "memmove"); 50 | fprintf(stderr, "in memmove(dst: %p, src: %p, size: 0x%lx)\n", dst, src, size); 51 | return real_memmove(dst, src, size); 52 | } 53 | 54 | 55 | ssize_t read(int fd, void *buf, size_t count) { 56 | readFuncType real_read = (readFuncType) dlsym(RTLD_NEXT, "read"); 57 | ssize_t ret = real_read(fd, buf, count); 58 | fprintf(stderr, "in read(fd: %d, buf: %p, size: 0x%lx) => %zd\n", fd, buf, count, ret); 59 | return ret; 60 | } 61 | 62 | 63 | // ssize_t write(int fd, const void *buf, size_t count) { 64 | // writeFuncType real_write = (writeFuncType) dlsym(RTLD_NEXT, "write"); 65 | // ssize_t ret = real_write(fd, buf, count); 66 | // fprintf(stderr, "in write(fd: %d, buf: %p, size: 0x%lx) => %zd\n", fd, buf, count, ret); 67 | // return ret; 68 | // } 69 | 70 | 71 | ssize_t send(int socket, const void *buffer, size_t length, int flags) { 72 | sendFuncType real_send = (sendFuncType) dlsym(RTLD_NEXT, "send"); 73 | ssize_t ret = real_send(socket, buffer, length, flags); 74 | fprintf(stderr, "in send(socket: %d, buffer: %p, length: 0x%lx, flags: %d) => %zd\n", socket, buffer, length, flags, ret); 75 | return ret; 76 | } 77 | 78 | ssize_t recv(int socket, void *buffer, size_t length, int flags) { 79 | recvFuncType real_recv = (recvFuncType) dlsym(RTLD_NEXT, "recv"); 80 | ssize_t ret = real_recv(socket, buffer, length, flags); 81 | fprintf(stderr, "in recv(socket: %d, buffer: %p, length: 0x%lx, flags: %d) => %zd\n", socket, buffer, length, flags, ret); 82 | return ret; 83 | } 84 | 85 | 86 | ssize_t sendto(int socket, const void *buffer, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len) { 87 | sendtoType real_sendto = (sendtoType) dlsym(RTLD_NEXT, "sendto"); 88 | ssize_t ret = real_sendto(socket, buffer, length, flags, dest_addr, dest_len); 89 | fprintf(stderr, "in sendto(socket: %d, buffer: %p, length: 0x%lx, flags: %d) => %zd\n", socket, buffer, length, flags, ret); 90 | return ret; 91 | } 92 | 93 | ssize_t recvfrom(int socket, void *buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len) { 94 | recvfromFuncType real_recvfrom = (recvfromFuncType) dlsym(RTLD_NEXT, "recvfrom"); 95 | ssize_t ret = real_recvfrom(socket, buffer, length, flags, address, address_len); 96 | fprintf(stderr, "in recvfrom(socket: %d, buffer: %p, length: 0x%lx, flags: %d) => %zd\n", socket, buffer, length, flags, ret); 97 | return ret; 98 | } 99 | 100 | 101 | ssize_t sendmsg(int socket, const struct msghdr *message, int flags) { 102 | sendmsgType real_sendmsg = (sendmsgType) dlsym(RTLD_NEXT, "sendmsg"); 103 | ssize_t ret = real_sendmsg(socket, message, flags); 104 | void *buffer = message->msg_iov[0].iov_base; 105 | fprintf(stderr, "in sendmsg(socket: %d, buffer: %p, flags: %d) => %zd\n", socket, buffer, flags, ret); 106 | return ret; 107 | } 108 | 109 | ssize_t recvmsg(int socket, struct msghdr *message, int flags) { 110 | recvmsgFuncType real_recvmsg = (recvmsgFuncType) dlsym(RTLD_NEXT, "recvmsg"); 111 | ssize_t ret = real_recvmsg(socket, message, flags); 112 | void *buffer = message->msg_iov[0].iov_base; 113 | fprintf(stderr, "in recvmsg(socket: %d, buffer: %p, flags: %d) => %zd\n", socket, buffer, flags, ret); 114 | return ret; 115 | } 116 | 117 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Prototype for Protocol Reverse Engineering 2 | 3 | ## Overview 4 | 5 | **ProtocolTaint** is a protocol-reverse-tool designed for industrial binary protocol analysis. It is based on a Dynamic Taint Analysis Framework, which is build with Pin from Intel. We have tested the tool with 5 different open source Industrial protocol implementation (*libmodbus*, *freemodbus*, *gec-dnp3*, *automatak-dnp3* and *snap7*) and so far, it does offer some results (listed in `/result`). The tool is written with C++ and Python2 and designed for Linux x86-64 platform. This is the very first try and we hope to produce a practical analysis tool eventually. 6 | 7 | ## Installation 8 | 9 | ### Set up Pin 10 | 11 | This prototype has been tested on **Ubuntu 16.04** and we recommend not to try other Linux OS in case of unnecessary problems. Docker is also a good choice to hold and isolate the whole environment. The guide is completed in docker, if you want to try outside, run in **root**. 12 | 13 | You need to install Pin first , the tool was build with pin-3.2 and the latest version is 3.11. But you may have to modify the source code and the Configure file to continue the compilation with Pin-3.11, so it's better to chose 3.2 :). 14 | 15 | ``` 16 | # download Pin 17 | wget https://software.intel.com/sites/landingpage/pintool/downloads/pin-3.2-81205-gcc-linux.tar.gz 18 | tar -xzf pin-3.2-81205-gcc-linux.tar.gz 19 | cd pin-3.2-81205-gcc-linux 20 | 21 | # configuration 22 | ln -s ${PWD}/pin /usr/local/bin 23 | echo export PIN_ROOT=${PWD} >> /.bashrc 24 | source ~/.bashrc 25 | 26 | # test Pin 27 | cd source/tools/ManualExamples/ && make all 28 | pin -t obj-intel64/inscount0.so -- /bin/ls 29 | cat inscount.out 30 | ``` 31 | 32 | There may be some error at the step `pin -t obj-intel64/inscount0.so -- /bin/ls` because pin-3.2 is designed for Kernel 3.X and Ubuntu 16.04 's Kernel is 4.15. To bypass the kernel check, the command should be modified to `pin -ifeellucky -t obj-intel64/inscount0.so -- /bin/ls`. If the pin is successfully set up, you will see the count number in terminal. 33 | 34 | ``` 35 | git clone https://github.com/nesclab/ProtocolTaint.git 36 | mv /ProtocolTaint/src ${PIN_ROOT}/source/tools/ProtocolTaint 37 | cd ${PIN_ROOT}/source/tools/ProtocolTaint 38 | ``` 39 | 40 | The compilation and run processes are integrated in `run`. Remember to add `-ifeellucky` in line 9 if you have encountered the VEX error when test pin. 41 | 42 | ``` 43 | # compile 44 | ./run compile taint 45 | 46 | # run 47 | ./run run taint {target_file} 48 | ``` 49 | 50 | 51 | 52 | ### Set up Test Object 53 | 54 | #### libmodbus 55 | 56 | libmodbus is a popular open source library for Modbus protocol. 57 | 58 | ``` 59 | git clone https://github.com/stephane/libmodbus 60 | cd libmodbus 61 | ./autogen.sh 62 | ./configure && make install 63 | cd .. 64 | # test 65 | ./libmodbus/tests/unit-test-server 66 | # experiment 67 | ./run run taint ./libmodbus/tests/.libs/unit-test-server 68 | ``` 69 | 70 | if `autogen.sh` fail to run, try: 71 | ``` 72 | apt-get install automake autoconf libtool 73 | ``` 74 | 75 | to perform the experiment, we need to modify the `tests/unit-test.h` first. 76 | 77 | ``` 78 | const uint16_t UT_BITS_ADDRESS = 0x0; 79 | const uint16_t UT_REGISTERS_ADDRESS = 0x0; 80 | ``` 81 | 82 | 83 | 84 | #### freemodbus 85 | 86 | Also a popular Modbus tool. 87 | 88 | ``` 89 | git clone https://github.com/cwalter-at/freemodbus 90 | cd freemodbus 91 | cd demo/LINUXTCP && make 92 | cd ../../../ 93 | # test 94 | ./freemodbus/demo/LINUXTCP/tcpmodbus 95 | # experiment 96 | ./run run taint ./freemodbus/demo/LINUXTCP/tcpmodbus 97 | ``` 98 | 99 | Some files need to be modified before `make`: 100 | 101 | `freemodbus/modbus/include/mbconfig.h`: 102 | 103 | ``` 104 | /*! \brief If Modbus ASCII support is enabled. */ 105 | #define MB_ASCII_ENABLED ( 1 ) 106 | /*! \brief If Modbus RTU support is enabled. */ 107 | #define MB_RTU_ENABLED ( 1 ) 108 | /*! \brief If Modbus TCP support is enabled. */ 109 | #define MB_TCP_ENABLED ( 0 ) 110 | /*! \brief The character timeout value for Modbus ASCII. 111 | ``` 112 | 113 | `freemodbus/demo/LINUXTCP/demo.c`: 114 | 115 | ``` 116 | #define REG_HOLDING_START 0 117 | ``` 118 | 119 | if the make returns: `undefined reference to ‘pthread_create’`, the `Makefile` need to be modified too. 120 | 121 | `freemodbus/demo/LINUXTCP/Makefile`: 122 | 123 | ``` 124 | $(BIN): $(OBJS) $(NOLINK_OBJS) $(CC) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@ 125 | # modified to: 126 | $(BIN): $(OBJS) $(NOLINK_OBJS) $(CC) $(OBJS) $(LDLIBS) -o $@ $(LDFLAGS) 127 | ``` 128 | 129 | It is interesting that we found the test with modbus message `\x01\x11\x00\x00\x00\x06\x01\x03\x00\x02\x00\x08` didn't come out with the right result, even with an offset as 65535, but after a deep inspection we figured it out that in /modbus/functions/mbfuncholding.c : line 185 130 | 131 | ``` 132 | usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] ); 133 | ``` 134 | it should be 135 | 136 | ``` 137 | usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] ); 138 | ``` 139 | Modifying and making, we now have the right result XD 140 | 141 | 142 | #### gec-dnp3 143 | 144 | A DNP3 protocol implementation using boost. Before make, we need to install the boost library, the source code of which can be downloaded on its official website. After many try, we confirmed that **boost_1_55** is the best choice. 145 | 146 | ``` 147 | git clone https://github.com/gec/dnp3 148 | mv dnp3 gec && cd gec 149 | autoreconf -f -i 150 | mkdir build && cd build 151 | ../configure && make install 152 | cd ../../ 153 | ./gec/build/.libs/demo-slave-cpp 154 | ``` 155 | 156 | During the `make` process, terminal may tell you that there are errors due to conflicting declaration of `boost::asio::io_service`. If so, you need to modify the corresponding head files: 157 | 158 | ``` 159 | #include // import the extern boost library 160 | 161 | // delete the following code 162 | namespace boost 163 | { 164 | namespace asio 165 | { 166 | class io_service; 167 | } 168 | } 169 | ``` 170 | 171 | There may still be some problems: 172 | 173 | ``` 174 | ./demo-slave-cpp: error while loading shared libraries: libboost_system.so.1.55.0: cannot open shared object file: No such file or directory 175 | ``` 176 | 177 | You can apt install `libboost-all-dev` and add soft link 178 | 179 | ``` 180 | sudo ln -s /usr/lib/x86_64-linux-gnu/libboost_system.so.1.58.0 /usr/lib/x86_64-linux-gnu/libboost_system.so.1.55.0 181 | ``` 182 | 183 | 184 | 185 | #### automatak-dnp3 186 | 187 | ``` 188 | git clone --recursive https://github.com/automatak/dnp3.git 189 | mv dnp3 automatak && cd automatak 190 | mkdir build && cd build 191 | cmake .. && make install 192 | cd ../cpp/examples/outstation/ 193 | ``` 194 | 195 | main.cpp need to be modified. In line 76 : IPEndPoint("127.0.0.1", 4999), which is the configuration of IP address and port. 196 | 197 | ``` 198 | cmake . 199 | make 200 | ./outstation-demo 201 | ``` 202 | 203 | 204 | #### snap7 205 | 206 | snap7 is a famous S7Comm protocol implement, which can be used to imitate a real Siemens PLC. 207 | 208 | ``` 209 | wget http://sourceforge.net/projects/snap7/files/1.2.1/snap7-full-1.2.1.tar.gz/download 210 | tar -zxvf snap7-full-1.2.1.tar.gz && cd snap7-full-1.2.1 211 | cd build/unix && make -f x86_64_linux.mk all 212 | cp ../bin/x86_64-linux/libsnap7.so /usr/lib/libsnap7.so 213 | cd ../../examples/cpp/x86_64-linux/ && make 214 | cd ../../../../ 215 | ./snap7/examples/cpp/x86_64-linux/server 216 | ``` 217 | 218 | -------------------------------------------------------------------------------- /src/makefile.rules: -------------------------------------------------------------------------------- 1 | ############################################################## 2 | # 3 | # This file includes all the test targets as well as all the 4 | # non-default build rules and test recipes. 5 | # 6 | ############################################################## 7 | 8 | 9 | ############################################################## 10 | # 11 | # Test targets 12 | # 13 | ############################################################## 14 | 15 | ###### Place all generic definitions here ###### 16 | 17 | # This defines tests which run tools of the same name. This is simply for convenience to avoid 18 | # defining the test name twice (once in TOOL_ROOTS and again in TEST_ROOTS). 19 | # Tests defined here should not be defined in TOOL_ROOTS and TEST_ROOTS. 20 | TEST_TOOL_ROOTS := inscount0 inscount1 inscount2 proccount imageload staticcount detach malloctrace replacesigprobed \ 21 | malloc_mt inscount_tls stack-debugger pinatrace itrace isampling safecopy invocation countreps \ 22 | nonstatica 23 | 24 | # This defines the tests to be run that were not already defined in TEST_TOOL_ROOTS. 25 | TEST_ROOTS := 26 | 27 | # This defines the tools which will be run during the the tests, and were not already defined in 28 | # TEST_TOOL_ROOTS. 29 | TOOL_ROOTS := 30 | 31 | # This defines the static analysis tools which will be run during the the tests. They should not 32 | # be defined in TEST_TOOL_ROOTS. If a test with the same name exists, it should be defined in 33 | # TEST_ROOTS. 34 | # Note: Static analysis tools are in fact executables linked with the Pin Static Analysis Library. 35 | # This library provides a subset of the Pin APIs which allows the tool to perform static analysis 36 | # of an application or dll. Pin itself is not used when this tool runs. 37 | SA_TOOL_ROOTS := 38 | 39 | # This defines all the applications that will be run during the tests. 40 | APP_ROOTS := fibonacci little_malloc thread_app 41 | 42 | # This defines any additional object files that need to be compiled. 43 | OBJECT_ROOTS := 44 | 45 | # This defines any additional dlls (shared objects), other than the pintools, that need to be compiled. 46 | DLL_ROOTS := 47 | 48 | # This defines any static libraries (archives), that need to be built. 49 | LIB_ROOTS := 50 | 51 | ###### Place OS-specific definitions here ###### 52 | 53 | # Android 54 | ifeq ($(TARGET_OS),android) 55 | TEST_TOOL_ROOTS += buffer_linux fork_jit_tool follow_child_tool strace emudiv 56 | TEST_ROOTS += statica 57 | SA_TOOL_ROOTS += statica 58 | APP_ROOTS += fork_app follow_child_app1 follow_child_app2 divide_by_zero 59 | endif 60 | 61 | # Linux 62 | ifeq ($(TARGET_OS),linux) 63 | TEST_TOOL_ROOTS += buffer_linux fork_jit_tool follow_child_tool strace emudiv 64 | TEST_ROOTS += statica 65 | SA_TOOL_ROOTS += statica 66 | APP_ROOTS += fork_app follow_child_app1 follow_child_app2 divide_by_zero 67 | endif 68 | 69 | # Mac OS X* 70 | ifeq ($(TARGET_OS),mac) 71 | TEST_TOOL_ROOTS += fork_jit_tool follow_child_tool strace 72 | TEST_ROOTS += statica 73 | SA_TOOL_ROOTS += statica 74 | APP_ROOTS += fork_app follow_child_app1 follow_child_app2 75 | endif 76 | 77 | # Windows 78 | ifeq ($(TARGET_OS),windows) 79 | TEST_TOOL_ROOTS += w_malloctrace buffer_windows emudiv 80 | APP_ROOTS += divide_by_zero 81 | endif 82 | 83 | ###### Handle exceptions here ###### 84 | 85 | # TODO: These tests fail - fix and remove the following: 86 | # See Mantis 2963 87 | ifeq ($(TARGET),mic) 88 | TEST_TOOL_ROOTS := $(filter-out nonstatica emudiv, $(TEST_TOOL_ROOTS)) 89 | TEST_ROOTS := $(filter-out statica, $(TEST_ROOTS)) 90 | SA_TOOL_ROOTS := $(filter-out statica, $(SA_TOOL_ROOTS)) 91 | endif 92 | 93 | ###### Define the sanity subset ###### 94 | 95 | # This defines the list of tests that should run in sanity. It should include all the tests listed in 96 | # TEST_TOOL_ROOTS and TEST_ROOTS excluding only unstable tests. 97 | SANITY_SUBSET := $(TEST_TOOL_ROOTS) $(TEST_ROOTS) 98 | 99 | ifeq ($(TARGET_OS),windows) 100 | ifeq ($(WIN_VER_MAJOR),10) 101 | # See Mantis 4004 102 | SANITY_SUBSET := $(filter-out replacesigprobed, $(SANITY_SUBSET)) 103 | endif 104 | endif 105 | 106 | 107 | ############################################################## 108 | # 109 | # Test recipes 110 | # 111 | ############################################################## 112 | 113 | # This section contains recipes for tests other than the default. 114 | # See makefile.default.rules for the default test rules. 115 | # All tests in this section should adhere to the naming convention: .test 116 | 117 | inscount_tls.test: $(OBJDIR)inscount_tls$(PINTOOL_SUFFIX) $(OBJDIR)thread_app$(EXE_SUFFIX) 118 | $(PIN) -t $(OBJDIR)inscount_tls$(PINTOOL_SUFFIX) -- $(OBJDIR)thread_app$(EXE_SUFFIX) > $(OBJDIR)inscount_tls.out 2>&1 119 | $(RM) $(OBJDIR)inscount_tls.out 120 | 121 | malloc_mt.test: $(OBJDIR)malloc_mt$(PINTOOL_SUFFIX) $(OBJDIR)thread_app$(EXE_SUFFIX) 122 | $(PIN) -t $(OBJDIR)malloc_mt$(PINTOOL_SUFFIX) -- $(OBJDIR)thread_app$(EXE_SUFFIX) > $(OBJDIR)malloc_mt.out 2>&1 123 | $(RM) $(OBJDIR)malloc_mt.out 124 | 125 | buffer_linux.test: $(OBJDIR)buffer_linux$(PINTOOL_SUFFIX) $(OBJDIR)thread_app$(EXE_SUFFIX) 126 | $(PIN) -t $(OBJDIR)buffer_linux$(PINTOOL_SUFFIX) -- $(OBJDIR)thread_app$(EXE_SUFFIX) > $(OBJDIR)buffer_linux.out 2>&1 127 | $(RM) $(OBJDIR)buffer_linux.out 128 | 129 | buffer_windows.test: $(OBJDIR)buffer_windows$(PINTOOL_SUFFIX) $(OBJDIR)thread_app$(EXE_SUFFIX) 130 | $(PIN) -t $(OBJDIR)buffer_windows$(PINTOOL_SUFFIX) -emit 0 \ 131 | -- $(OBJDIR)thread_app$(EXE_SUFFIX) > $(OBJDIR)buffer_windows.out 2>&1 132 | $(RM) $(OBJDIR)buffer_windows.out 133 | 134 | invocation.test: $(OBJDIR)invocation$(PINTOOL_SUFFIX) $(OBJDIR)little_malloc$(EXE_SUFFIX) 135 | $(PIN) -t $(OBJDIR)invocation$(PINTOOL_SUFFIX) -- $(OBJDIR)little_malloc$(EXE_SUFFIX) > $(OBJDIR)invocation.out 2>&1 136 | $(RM) $(OBJDIR)invocation.out 137 | 138 | # This tool is tested in "Debugger/makefile". However, leave this line because it is referenced in the user manual. 139 | # The user may invoke make stack-debugger.test to build the tool and app shown in the manual. 140 | # There is an intentional "empty" line which contains a tab character so this "test" will have an empty recipe. 141 | stack-debugger.test: $(OBJDIR)stack-debugger$(PINTOOL_SUFFIX) $(OBJDIR)fibonacci$(EXE_SUFFIX) 142 | 143 | 144 | # stand alone pin tool 145 | statica.test: $(OBJDIR)statica$(SATOOL_SUFFIX) 146 | $(SET_DLL_PATH) $(OBJDIR)statica$(SATOOL_SUFFIX) -i $(OBJDIR)statica$(SATOOL_SUFFIX) > $(OBJDIR)statica.dmp 147 | $(RM) $(OBJDIR)statica.dmp 148 | 149 | nonstatica.test: $(OBJDIR)nonstatica$(PINTOOL_SUFFIX) $(TESTAPP) 150 | $(PIN) -t $(OBJDIR)nonstatica$(PINTOOL_SUFFIX) \ 151 | -- $(TESTAPP) makefile $(OBJDIR)nonstatica.makefile.copy > $(OBJDIR)nonstatica.dmp 152 | $(DIFF) makefile $(OBJDIR)nonstatica.makefile.copy 153 | $(RM) $(OBJDIR)nonstatica.makefile.copy $(OBJDIR)nonstatica.dmp 154 | 155 | emudiv.test: $(OBJDIR)emudiv$(PINTOOL_SUFFIX) $(OBJDIR)divide_by_zero$(EXE_SUFFIX) 156 | $(PIN) -t $(OBJDIR)emudiv$(PINTOOL_SUFFIX) -- $(OBJDIR)divide_by_zero$(EXE_SUFFIX) > $(OBJDIR)emudiv.out 2>&1 157 | $(QGREP) "Caught divide by zero exception" $(OBJDIR)emudiv.out 158 | $(RM) $(OBJDIR)emudiv.out 159 | 160 | fork_jit_tool.test: $(OBJDIR)fork_jit_tool$(PINTOOL_SUFFIX) $(OBJDIR)fork_app$(EXE_SUFFIX) 161 | $(PIN) -t $(OBJDIR)fork_jit_tool$(PINTOOL_SUFFIX) -- $(OBJDIR)fork_app$(EXE_SUFFIX) 162 | 163 | follow_child_tool.test: $(OBJDIR)follow_child_tool$(PINTOOL_SUFFIX) $(OBJDIR)follow_child_app1$(EXE_SUFFIX) $(OBJDIR)follow_child_app2$(EXE_SUFFIX) 164 | $(PIN) -follow_execv 1 -t $(OBJDIR)follow_child_tool$(PINTOOL_SUFFIX) \ 165 | -- $(OBJDIR)follow_child_app1$(EXE_SUFFIX) $(OBJDIR)follow_child_app2$(EXE_SUFFIX) 166 | 167 | 168 | ############################################################## 169 | # 170 | # Build rules 171 | # 172 | ############################################################## 173 | 174 | # This section contains the build rules for all binaries that have special build rules. 175 | # See makefile.default.rules for the default build rules. 176 | 177 | ###### Special applications' build rules ###### 178 | 179 | $(OBJDIR)divide_by_zero$(EXE_SUFFIX): divide_by_zero_$(OS_TYPE).c 180 | $(APP_CC) $(APP_CXXFLAGS_NOOPT) $(COMP_EXE)$@ $< $(APP_LDFLAGS_NOOPT) $(APP_LIBS) 181 | 182 | $(OBJDIR)thread_app$(EXE_SUFFIX): thread_$(OS_TYPE).c 183 | $(APP_CC) $(APP_CXXFLAGS) $(COMP_EXE)$@ $< $(APP_LDFLAGS) $(APP_LIBS) 184 | -------------------------------------------------------------------------------- /src/pinobject.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _PIN_OBJECT_H 2 | #define _PIN_OBJECT_H 3 | 4 | #include "pin.H" 5 | 6 | class Ins { 7 | private: 8 | INS ins; 9 | 10 | public: 11 | 12 | Ins(INS ins) { 13 | this->ins = ins; 14 | } 15 | 16 | Ins& operator=(INS ins) { 17 | this->ins = ins; 18 | return *this; 19 | } 20 | 21 | operator INS() { 22 | return ins; 23 | } 24 | 25 | inline ADDRINT Address() { 26 | return INS_Address(ins); 27 | } 28 | 29 | inline std::string Name() { 30 | return INS_Disassemble(ins); 31 | } 32 | 33 | inline OPCODE OpCode() { 34 | return INS_Opcode(ins); 35 | } 36 | 37 | inline INT32 Category() { 38 | return INS_Category(ins); 39 | } 40 | 41 | inline INT32 Extention() { 42 | return INS_Extension(ins); 43 | } 44 | 45 | inline USIZE Size() { 46 | return INS_Size(ins); 47 | } 48 | 49 | inline RTN parent() { 50 | return INS_Rtn(ins); 51 | } 52 | 53 | inline UINT32 OpCount() { 54 | return INS_OperandCount(ins); 55 | } 56 | 57 | // mem 58 | inline UINT32 MemCount() { 59 | return INS_MemoryOperandCount(ins); 60 | } 61 | 62 | inline bool isMemoryRead() { 63 | return INS_IsMemoryRead(ins); 64 | } 65 | 66 | inline bool isMemoryWrite() { 67 | return INS_IsMemoryWrite(ins); 68 | } 69 | 70 | inline bool isMemOpRead(UINT32 i) { 71 | return INS_MemoryOperandIsRead(ins, i); 72 | } 73 | 74 | inline bool isMemOpWrite(UINT32 i) { 75 | return INS_MemoryOperandIsWritten(ins, i); 76 | } 77 | 78 | inline USIZE MemRSize() { 79 | return INS_MemoryReadSize(ins); 80 | } 81 | 82 | inline USIZE MemWSize() { 83 | return INS_MemoryWriteSize(ins); 84 | } 85 | 86 | inline USIZE MemSize(int i) { 87 | return INS_MemoryOperandSize(ins, i); 88 | } 89 | 90 | // operand 91 | inline bool isOpImm(int i) { 92 | return INS_OperandIsImmediate(ins, i); 93 | } 94 | 95 | inline UINT64 valueImm(int i){ 96 | return INS_OperandImmediate(ins, i); 97 | } 98 | 99 | inline bool isOpImplicit(int i) { 100 | return INS_OperandIsImplicit(ins, i); 101 | } 102 | 103 | inline bool isOpMem(int i) { 104 | return INS_OperandIsMemory(ins, i); 105 | } 106 | 107 | inline bool isOpReg(int i) { 108 | return INS_OperandIsReg(ins, i); 109 | } 110 | 111 | inline REG OpReg(int i) { 112 | return INS_OperandReg(ins, i); 113 | } 114 | 115 | // Effective Address = Displacement + BaseReg + IndexReg * Scale 116 | inline ADDRDELTA OpDisplacement(int i) { 117 | return INS_OperandMemoryDisplacement(ins, i); 118 | } 119 | 120 | inline REG OpBaseReg(int i) { 121 | return INS_OperandMemoryBaseReg(ins, i); 122 | } 123 | 124 | inline REG OpIndexReg(int i) { 125 | return INS_OperandMemoryIndexReg(ins, i); 126 | } 127 | 128 | inline UINT32 OpScale(int i) { 129 | return INS_OperandMemoryScale(ins, i); 130 | } 131 | 132 | // reg 133 | inline REG RegR(int i) { 134 | return INS_RegR(ins, i); 135 | } 136 | 137 | inline REG RegW(int i) { 138 | return INS_RegW(ins, i); 139 | } 140 | 141 | inline bool isMemR2() { 142 | return INS_HasMemoryRead2(ins); 143 | } 144 | 145 | // stack and ip 146 | inline bool isStackRead() { 147 | return INS_IsStackRead(ins); 148 | } 149 | 150 | inline bool isStackWrite() { 151 | return INS_IsStackWrite(ins); 152 | } 153 | 154 | inline bool isIpRelRead() { 155 | return INS_IsIpRelRead(ins); 156 | } 157 | 158 | inline bool isIpRelWrite() { 159 | return INS_IsIpRelWrite(ins); 160 | } 161 | 162 | // control 163 | inline bool isCall() { 164 | return INS_IsCall(ins); 165 | } 166 | 167 | inline bool isRet() { 168 | return INS_IsRet(ins); 169 | } 170 | 171 | inline bool isSyscall() { 172 | return INS_IsSyscall(ins); 173 | } 174 | 175 | inline bool isSysret() { 176 | return INS_IsSysret(ins); 177 | } 178 | 179 | inline bool isBranch() { 180 | return INS_IsBranch(ins); 181 | } 182 | 183 | // specific branch 184 | inline bool isBranchOrCall() { 185 | return INS_IsBranchOrCall(ins); 186 | } 187 | 188 | inline bool isDirectBranch() { 189 | return INS_IsDirectBranch(ins); 190 | } 191 | 192 | inline bool isDirectBranchOrCall() { 193 | return INS_IsDirectBranchOrCall(ins); 194 | } 195 | 196 | inline bool isDirectCall() { 197 | return INS_IsDirectCall(ins); 198 | } 199 | 200 | inline bool isIndirectBranchOrCall() { 201 | return INS_IsIndirectBranchOrCall(ins); 202 | } 203 | 204 | // other 205 | inline bool isMov() { 206 | return INS_IsMov(ins); 207 | } 208 | 209 | inline bool isLea() { 210 | return INS_IsLea(ins); 211 | } 212 | 213 | inline bool isSub() { 214 | return INS_IsSub(ins); 215 | } 216 | 217 | inline bool isNop() { 218 | return INS_IsNop(ins); 219 | } 220 | 221 | inline bool isOriginal() { 222 | return INS_IsOriginal(ins); 223 | } 224 | 225 | inline bool isPredicated() { 226 | return INS_IsPredicated(ins); 227 | } 228 | 229 | inline bool isPrefetch() { 230 | return INS_IsPrefetch(ins); 231 | } 232 | 233 | inline bool isProcedureCall() { 234 | return INS_IsProcedureCall(ins); 235 | } 236 | 237 | // iter 238 | inline bool Valid() { 239 | return INS_Valid(ins); 240 | } 241 | 242 | inline INS Next() { 243 | return INS_Next(ins); 244 | } 245 | 246 | 247 | std::string Tag(size_t opcount) { 248 | std::string tag = ""; 249 | for (size_t i = 0; i < opcount; ++i) { 250 | if (isOpReg(i)) { 251 | tag += "Reg "; 252 | } 253 | if (isOpMem(i)) { 254 | tag += "Mem "; 255 | } 256 | if (isOpImm(i)) { 257 | tag += "Imm "; 258 | } 259 | if (isOpImplicit(i)) { 260 | tag += "Implicit "; 261 | } 262 | if (i < opcount - 1) 263 | tag += ": "; 264 | } 265 | return tag; 266 | } 267 | 268 | const char *prettify() { 269 | static char buf[512]; 270 | UINT32 opcount = OpCount(); 271 | OPCODE opcode = OpCode(); 272 | std::string tag = Tag(opcount); 273 | int n = snprintf(buf, sizeof(buf), "%-16lx%-36sOpCode: %4d \t %s\n", Address(), Name().c_str(), opcode, tag.c_str()); 274 | buf[n] = 0; 275 | return buf; 276 | } 277 | }; 278 | 279 | 280 | class Bbl { 281 | private: 282 | BBL bbl; 283 | public: 284 | 285 | Bbl(BBL bbl) { 286 | this->bbl = bbl; 287 | } 288 | 289 | Bbl& operator=(BBL bbl) { 290 | this->bbl = bbl; 291 | return *this; 292 | } 293 | 294 | Ins InsHead() { 295 | return BBL_InsHead(bbl); 296 | } 297 | 298 | BBL Next() { 299 | return BBL_Next(bbl); 300 | } 301 | 302 | bool Valid() { 303 | return BBL_Valid(bbl); 304 | } 305 | 306 | operator BBL() { 307 | return bbl; 308 | } 309 | 310 | uint64_t Address() { 311 | return BBL_Address(bbl); 312 | } 313 | 314 | size_t Size() { 315 | return BBL_Size(bbl); 316 | } 317 | }; 318 | 319 | 320 | class Rtn { 321 | 322 | private: 323 | RTN rtn; 324 | 325 | public: 326 | Rtn(RTN rtn) { 327 | this->rtn = rtn; 328 | } 329 | 330 | Rtn& operator=(RTN rtn) { 331 | this->rtn = rtn; 332 | return *this; 333 | } 334 | 335 | operator RTN() { 336 | return rtn; 337 | } 338 | 339 | inline void Open() { 340 | RTN_Open(rtn); 341 | } 342 | 343 | inline void Close() { 344 | RTN_Close(rtn); 345 | } 346 | 347 | inline const std::string& Name() { 348 | return RTN_Name(rtn); 349 | } 350 | 351 | inline int Id() { 352 | return RTN_Id(rtn); 353 | } 354 | 355 | inline unsigned int Size() { 356 | return RTN_Size(rtn); 357 | } 358 | 359 | inline bool isDynamic() { 360 | return RTN_IsDynamic(rtn); 361 | } 362 | 363 | inline bool isArtificial() { 364 | return RTN_IsArtificial(rtn); 365 | } 366 | 367 | inline std::string getImageName() { 368 | if (RTN_Valid(rtn)) { 369 | SEC sec = RTN_Sec(rtn); 370 | if (SEC_Valid(sec)) { 371 | IMG img = SEC_Img(sec); 372 | if (IMG_Valid(img)) { 373 | return IMG_Name(img); 374 | } 375 | } 376 | } 377 | return ""; 378 | } 379 | 380 | // iter 381 | inline Ins InsHead() { 382 | return RTN_InsHead(rtn); 383 | } 384 | 385 | inline Ins InsTail() { 386 | return RTN_InsTail(rtn); 387 | } 388 | 389 | // Bbl BblHead() { 390 | // return RTN_BblHead(rtn); 391 | // } 392 | 393 | inline bool Valid() { 394 | return RTN_Valid(rtn); 395 | } 396 | 397 | inline RTN Next() { 398 | return RTN_Next(rtn); 399 | } 400 | }; 401 | 402 | 403 | class Context { 404 | 405 | private: 406 | const CONTEXT* ctxt; 407 | 408 | public: 409 | Context(const CONTEXT* ctxt) { 410 | this->ctxt = ctxt; 411 | } 412 | 413 | inline ADDRINT getReg(REG reg) { 414 | return PIN_GetContextReg(ctxt, reg); 415 | } 416 | 417 | }; 418 | 419 | #endif -------------------------------------------------------------------------------- /visualize.py: -------------------------------------------------------------------------------- 1 | #coding:utf8 2 | import pydot 3 | from collections import OrderedDict 4 | import sys 5 | 6 | file = "info.txt" 7 | threadId = 0 8 | if len(sys.argv) > 1: 9 | case = sys.argv[1] 10 | file = "results/{}/info.txt".format(case) 11 | if len(sys.argv) > 2: 12 | threadId = int(sys.argv[2]) 13 | 14 | 15 | with open(file, "r") as f: 16 | lines = f.readlines() 17 | 18 | loops = [] 19 | 20 | def findInLoop(addr): 21 | for head, size in loops: 22 | if addr >= head and addr < head + size: 23 | return True 24 | return False 25 | 26 | def mystrip(s): 27 | # return str(hash(s)) 28 | temp = [] 29 | count = 0 30 | for c in s: 31 | if c == '<': 32 | count += 1 33 | elif c == '>': 34 | count -= 1 35 | elif count == 0: 36 | temp.append(c) 37 | s = "".join(temp) 38 | s = s.split('(')[0] 39 | s = "-".join(s.split("::")[-2:]) 40 | return s 41 | 42 | 43 | def fold(s, n, maxline=3): 44 | ret = [] 45 | size = len(s) 46 | if size <= n: return s 47 | line = min(maxline, (size - 1)// n + 1) 48 | n = (size - 1) // line + 1 49 | for i in range(line): 50 | ret.append(s[n * i : n * (i+1)]) 51 | ret.append("\n") 52 | ret.pop() 53 | return "".join(ret) 54 | 55 | 56 | class Node(object): 57 | _id = 0 58 | 59 | def __init__(self): 60 | self._id = Node._id 61 | Node._id += 1 62 | self.parent = None 63 | self.children = [] 64 | 65 | def name(self): 66 | return "" 67 | 68 | def id(self): 69 | return "{}-{}".format(self.name(), self._id) 70 | 71 | def __getitem__(self, s): 72 | return self.children[s] 73 | 74 | def __len__(self): 75 | return len(self.children) 76 | 77 | def construct(self, graph): 78 | for child in self.children: 79 | # print child.name() 80 | graph.add_node(pydot.Node(child.id(), label=child.name())) 81 | edge = pydot.Edge(self.id(), child.id()) 82 | graph.add_edge(edge) 83 | child.construct(graph) 84 | 85 | 86 | class FuncNode(Node): 87 | 88 | def __init__(self, name): 89 | super(FuncNode, self).__init__() 90 | self.name_ = name 91 | 92 | def name(self): 93 | return fold(self.name_, 12) 94 | 95 | def add(self, c): 96 | c.parent = self 97 | self.children.append(c) 98 | 99 | def trim(self): 100 | self.children = [c for c in self.children if c.trim()] 101 | return len(self.children) > 0 102 | 103 | def collect(self, container): 104 | for c in self.children: 105 | c.collect(container) 106 | 107 | 108 | class DataNode(Node): 109 | 110 | def __init__(self): 111 | super(DataNode, self).__init__() 112 | self.data = [] 113 | 114 | def name(self): 115 | return fold(str(self.data)[1:-1], 12) 116 | 117 | def empty(self): 118 | return not self.data 119 | 120 | def trim(self): 121 | return len(self.data) > 0 122 | 123 | def add(self, c): 124 | size = len(c) 125 | if not size: return 126 | if size == 1: c = c[0] 127 | if c not in self.data: 128 | self.data.append(c) 129 | 130 | def collect(self, container): 131 | container.append(self.data) 132 | 133 | 134 | class MemoryBlock: 135 | 136 | def __init__(self): 137 | self.container = OrderedDict() 138 | self.max = None 139 | self.min = None 140 | self.thres = 0x40 141 | 142 | def valid(self, addr): 143 | return addr >= self.min - self.thres and addr <= self.max + self.thres 144 | 145 | def add(self, addr, offset, size): 146 | if not self.max or addr + size - 1 > self.max: 147 | self.max = addr + size -1 148 | if not self.min or addr < self.min: 149 | self.min = addr 150 | while size > 0: 151 | self.container[addr] = offset 152 | addr += 1 153 | offset += 1 154 | size -= 1 155 | 156 | def remove(self, addr, size): 157 | while size > 0: 158 | del self.container[addr] 159 | addr += 1 160 | size -= 1 161 | 162 | def snapshot(self): 163 | for k, v in self.container.items(): 164 | print(k, v) 165 | 166 | 167 | class Memory: 168 | 169 | def __init__(self): 170 | self.container = [] 171 | 172 | def index(self, addr): 173 | for c in self.container: 174 | if c.valid(addr): return c 175 | self.container.append(MemoryBlock()) 176 | return self.container[-1] 177 | 178 | def add(self, addr, offset, size): 179 | self.index(addr).add(addr, offset, size) 180 | 181 | def remove(self, addr, size): 182 | self.index(addr).remove(addr, size) 183 | 184 | def snapshot(self): 185 | for c in self.container: 186 | c.snapshot() 187 | 188 | 189 | root = FuncNode("") 190 | cur_f = root 191 | cur_d = DataNode() 192 | memory = Memory() 193 | 194 | trace = [] 195 | ips = [] 196 | 197 | 198 | def index(ret): 199 | i = 0 200 | while i < len(ips): 201 | begin, end, _ = ips[-i] 202 | if ret > begin and ret < end: break 203 | i += 1 204 | return i 205 | 206 | num = 0 207 | 208 | looplog = dict() 209 | cmplog = dict() 210 | xorlog = [] 211 | xortemp = [] 212 | lengthlog = [] 213 | 214 | 215 | for line in lines: 216 | content = line.strip().split('\t') 217 | size = len(content) 218 | if size <= 1: continue 219 | tag = content[0] 220 | if tag == "LENGTH": 221 | lengthlog.append(content[1]) 222 | if tag == "Function": 223 | thread = int(content[1]) 224 | if thread != threadId: continue 225 | state = content[2].strip() 226 | name = content[3] 227 | if "@plt" in name: continue 228 | name = mystrip(name) 229 | if state == "enter": 230 | if xortemp: 231 | xorlog.append(xortemp) 232 | xortemp = [] 233 | ip = [int(c, 16) for c in content[4].strip('()').split(',')] 234 | k = index(ip[2]) 235 | if k > 1 and k < 3: 236 | while k > 1 and len(ips) > 0: 237 | cur_f = cur_f.parent 238 | trace.pop() 239 | ips.pop() 240 | k -= 1 241 | trace.append(name) 242 | ips.append(ip) 243 | extra = "" 244 | if k > 1: 245 | extra = "\n" + str(k) 246 | node = FuncNode(name + extra) 247 | if not cur_d.empty(): 248 | cur_f.add(cur_d) 249 | cur_d = DataNode() 250 | cur_f.add(node) 251 | cur_f = node 252 | elif content[2].strip() == "exit": 253 | if not cur_d.empty(): 254 | cur_f.add(cur_d) 255 | cur_d = DataNode() 256 | try: 257 | cur_f = cur_f.parent 258 | trace.pop() 259 | ips.pop() 260 | except: 261 | print "error" 262 | elif tag.startswith("Instruction"): 263 | thread = int(content[1]) 264 | if thread != threadId: continue 265 | head = content[0].strip("Instruction ").split(",") 266 | addr, inst0 = head[0].split(':') 267 | addr = int(addr, 16) 268 | assembly = inst0.strip().split()[0] 269 | write = inst0.strip().split()[1] 270 | if len(head) == 1: 271 | read = None 272 | isnum = False 273 | else: 274 | read = head[1].strip() 275 | isnum = read.startswith("0x") 276 | data = content[2] 277 | iswrite, isread = True, True 278 | if data.count(';') == 0: 279 | isread = False 280 | elif data.startswith(';'): 281 | iswrite = False 282 | if isnum: 283 | writev = content[3] 284 | readv = read 285 | elif content[3].count(';') > 0: 286 | writev, readv = content[3].split(';') 287 | else: 288 | readv = content[3] 289 | if assembly.startswith("cmp"): 290 | data = data.strip(';') 291 | if data not in cmplog: 292 | cmplog[data] = set() 293 | if isread: 294 | cmpobj = "[{}]".format(writev) 295 | if iswrite: 296 | cmpobj = readv 297 | if not isnum: 298 | cmpobj = "[{}]".format(readv) 299 | cmplog[data].add(cmpobj) 300 | print "compare: ", data, cmpobj 301 | if assembly.startswith("xor"): 302 | data = data.strip(';') 303 | xortemp.append(data) 304 | if findInLoop(addr) and\ 305 | (((assembly.startswith("add") or assembly.startswith("sub")) and readv == "0x1") or\ 306 | (assembly.startswith("cmp") and not (readv.startswith("0x") and readv != "0x0")) ): 307 | key = " ".join(head) + " " + data.strip(';') 308 | print key 309 | if key not in looplog: 310 | looplog[key] = 0 311 | looplog[key] += 1 312 | print "Loop: ", head, data, readv 313 | for d in data.split(';'): 314 | if not d: continue 315 | cur_d.add([int(c) for c in d.split(",")]) 316 | elif tag == "LOOP": 317 | loops.append((int(content[1], 16), int(content[2], 16))) 318 | 319 | 320 | graph = pydot.Dot(graph_type='graph') 321 | root.trim() 322 | while len(root) == 1: 323 | root = root[0] 324 | graph.add_node(pydot.Node(root.id(), label=root.name())) 325 | root.construct(graph) 326 | graph.write_svg('output.svg') 327 | graph.write_png('output.png') 328 | memory.snapshot() 329 | container = [] 330 | root.collect(container) 331 | 332 | print "\nresult:" 333 | for d in container: 334 | print "\t", d 335 | 336 | print "\nlength:" 337 | for d in lengthlog: 338 | print "\t长度字段:\t", d 339 | 340 | print "\ncmp instructions:" 341 | for k, v in cmplog.items(): 342 | print "\t字段: {:6s}\t比较值: {}".format(k, " ".join(v)) 343 | 344 | print "\nloops:" 345 | for k, v in looplog.items(): 346 | d = k.split(" ") 347 | print "\t指令: {:40s}\t字段: {:10s}次数: {}".format(" ".join(d[:-1]), d[-1], v) 348 | 349 | print "\nxor instructions:" 350 | for d in xorlog: 351 | print "\txor 字节序列:\t", " ".join(d) 352 | 353 | -------------------------------------------------------------------------------- /src/util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_H 2 | #define _UTIL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include // for demangle 8 | #include "config.hpp" 9 | 10 | 11 | namespace monitor { 12 | 13 | bool _start = false; 14 | bool _end = false; 15 | 16 | inline bool valid() { 17 | return _start && !_end; 18 | } 19 | 20 | inline bool invalid(int threadId) { 21 | return !_start || _end || (config::thread_flag && threadId != config::threadId); 22 | } 23 | 24 | inline void start() { 25 | printf("instumentation start\n"); 26 | _start = true; 27 | } 28 | 29 | inline void end() { 30 | printf("instumentation end\n"); 31 | _end = true; 32 | } 33 | } // monitor namespace end 34 | 35 | namespace logger { 36 | 37 | 38 | bool _debug = false; 39 | FILE *_dout = stdout; 40 | bool _verbose = false; 41 | FILE *_vout = stdout; 42 | bool _info = false; 43 | FILE *_iout = stdout; 44 | 45 | void setDebug(bool b, FILE *out=stdout) {_debug = b; _dout = out;} 46 | void setVerbose(bool b, FILE *out=stdout) {_verbose = b; _vout = out;} 47 | void setInfo(bool b, FILE *out=stdout) {_info = b; _iout = out;} 48 | 49 | 50 | void debug(const char *fmt, ...) { 51 | if (!_debug) return; 52 | va_list arg; 53 | va_start(arg, fmt); 54 | vfprintf(_dout, fmt, arg); 55 | va_end(arg); 56 | if (config::isFlush) fflush(_dout); 57 | } 58 | 59 | void verbose(const char *fmt, ...) { 60 | if (!_verbose) return; 61 | va_list arg; 62 | va_start(arg, fmt); 63 | vfprintf(_vout, fmt, arg); 64 | va_end(arg); 65 | if (config::isFlush) fflush(_vout); 66 | } 67 | 68 | void info(const char *fmt, ...) { 69 | if (!_info) return; 70 | va_list arg; 71 | va_start(arg, fmt); 72 | vfprintf(_iout, fmt, arg); 73 | va_end(arg); 74 | if (config::isFlush) fflush(_iout); 75 | } 76 | 77 | void print(const char *fmt, ...) { 78 | if (!config::print) return; 79 | va_list arg; 80 | va_start(arg, fmt); 81 | vfprintf(stderr, fmt, arg); 82 | va_end(arg); 83 | if (config::isFlush) fflush(stdout); 84 | } 85 | 86 | void printline(const unsigned char *start, size_t size) { 87 | if (!config::print) return; 88 | size = std::min(size, (size_t)128); 89 | fprintf(stderr, "size %lx:\t", size); 90 | for (size_t i = 0; i < size; ++i) { 91 | fprintf(stderr, "(%x) ", *start++); 92 | } 93 | fprintf(stderr, "\n"); 94 | } 95 | 96 | } // log namespace end 97 | 98 | 99 | namespace debug { 100 | 101 | const char *assembly = NULL; 102 | // char assembly[256]; 103 | unsigned long address = 0; 104 | 105 | void log(unsigned long address_, const char *assembly_) { 106 | address = address_; 107 | assembly = assembly_; 108 | } 109 | 110 | void error() { 111 | printf("error : %lx\t:%s\n", address, assembly); 112 | } 113 | 114 | void info() { 115 | logger::info("error : %lx\t:%s\n", address, assembly); 116 | } 117 | 118 | void debug() { 119 | logger::debug("error : %lx\t:%s\n", address, assembly); 120 | } 121 | 122 | } // end of namespace debug 123 | 124 | 125 | namespace util { 126 | 127 | PIN_LOCK lock; 128 | 129 | class LockGuard { 130 | public: 131 | LockGuard(int threadId) { 132 | PIN_GetLock(&lock, threadId+1); 133 | } 134 | 135 | ~LockGuard() { 136 | PIN_ReleaseLock(&lock); 137 | } 138 | }; 139 | 140 | 141 | const REG regs[] = { 142 | REG_RAX, REG_EAX, REG_AX, REG_AH, REG_AL, // 10, 56, 29, 28, 27, 143 | REG_RBX, REG_EBX, REG_BX, REG_BH, REG_BL, // 7, 53, 38, 37, 36, 144 | REG_RCX, REG_ECX, REG_CX, REG_CH, REG_CL, // 9, 55, 32, 31, 30, 145 | REG_RDX, REG_EDX, REG_DX, REG_DH, REG_DL, // 8, 54, 35, 34, 33, 146 | REG_RDI, REG_EDI, REG_DI, REG_DIL, REG_INVALID_, // 3, 45, 41, 46, 0, 147 | REG_RSI, REG_ESI, REG_SI, REG_SIL, REG_INVALID_, // 4, 47, 40, 48, 0, 148 | REG_R8, REG_R8D, REG_R8W, REG_R8B, REG_INVALID_, // 11, 61, 60, 59, 0, 149 | REG_R9, REG_R9D, REG_R9W, REG_R9B, REG_INVALID_, // 12, 64, 63, 62, 0, 150 | REG_R10, REG_R10D, REG_R10W, REG_R10B, REG_INVALID_, // 13, 67, 66, 65, 0, 151 | REG_R11, REG_R11D, REG_R11W, REG_R11B, REG_INVALID_, // 14, 70, 69, 68, 0, 152 | REG_R12, REG_R12D, REG_R12W, REG_R12B, REG_INVALID_, // 15, 73, 72, 71, 0, 153 | REG_R13, REG_R13D, REG_R13W, REG_R13B, REG_INVALID_, // 16, 76, 75, 74, 0, 154 | REG_R14, REG_R14D, REG_R14W, REG_R14B, REG_INVALID_, // 17, 79, 78, 77, 0, 155 | REG_R15, REG_R15D, REG_R15W, REG_R15B, REG_INVALID_, // 18, 82, 81, 80, 0 156 | REG_RSP, REG_ESP, REG_SP, REG_INVALID_, REG_INVALID_, 157 | REG_RBP, REG_EBP, REG_BP, REG_INVALID_, REG_INVALID_ 158 | }; 159 | 160 | const char *regNames[] = { 161 | "RAX", "EAX", "AX", "AH", "AL", 162 | "RBX", "EBX", "BX", "BH", "BL", 163 | "RCX", "ECX", "CX", "CH", "CL", 164 | "RDX", "EDX", "DX", "DH", "DL", 165 | "RDI", "EDI", "DI", "DIL", "Invalid", 166 | "RSI", "ESI", "SI", "SIL", "Invalid", 167 | "R8", "R8D", "R8W", "R8B", "Invalid", 168 | "R9", "R9D", "R9W", "R9B", "Invalid", 169 | "R10", "R10D", "R10W", "R10B", "Invalid", 170 | "R11", "R11D", "R11W", "R11B", "Invalid", 171 | "R12", "R12D", "R12W", "R12B", "Invalid", 172 | "R13", "R13D", "R13W", "R13B", "Invalid", 173 | "R14", "R14D", "R14W", "R14B", "Invalid", 174 | "R15", "R15D", "R15W", "R15B", "Invalid", 175 | "RSP", "ESP", "SP", "Invalid", "Invalid", 176 | "RBP", "EBP", "BP", "Invalid", "Invalid" 177 | }; 178 | 179 | 180 | bool valiReg(REG reg) { 181 | if (reg <= 0 || reg >= 100) return false; 182 | for (uint16_t i = 0; i < sizeof(util::regs) / sizeof(REG); ++i) { 183 | if (util::regs[i] == reg) { 184 | return true; 185 | } 186 | } 187 | return false; 188 | } 189 | 190 | uint16_t indexOfReg(REG id) { 191 | for (uint16_t i = 0; i < sizeof(util::regs) / sizeof(REG); ++i) { 192 | if (util::regs[i] == id) { 193 | return i; 194 | } 195 | } 196 | printf("error index of reg: %d\n", id); 197 | return -1; 198 | } 199 | 200 | REG rawReg(REG reg) { 201 | int index = indexOfReg(reg); 202 | index -= index % 5; 203 | return regs[index]; 204 | } 205 | 206 | 207 | inline ADDRINT Value(UINT64 mem, size_t size) { // a bit weird 208 | ADDRINT value; 209 | PIN_SafeCopy((void*)(&value), (void *)mem, sizeof(ADDRINT)); 210 | switch (size) { 211 | case 1: value &= 0xff; break; 212 | case 2: value &= 0xffff; break; 213 | case 4: value &= 0xffffffff; break; 214 | } 215 | return value; 216 | } 217 | 218 | inline void ValueCopy(void *dst, uint64_t addr, size_t size) { 219 | PIN_SafeCopy(dst, (void *)addr, size); 220 | } 221 | 222 | #define swap16(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8)) 223 | 224 | #define swap32(n) (((((unsigned long)(n) & 0xFF)) << 24) | \ 225 | ((((unsigned long)(n) & 0xFF00)) << 8) | \ 226 | ((((unsigned long)(n) & 0xFF0000)) >> 8) | \ 227 | ((((unsigned long)(n) & 0xFF000000)) >> 24)) 228 | 229 | #define swap64(n) (((((unsigned long long)(n) & 0xFF)) << 56) | \ 230 | ((((unsigned long long)(n) & 0xFF00)) << 40) | \ 231 | ((((unsigned long long)(n) & 0xFF0000)) << 24) | \ 232 | ((((unsigned long long)(n) & 0xFF000000)) << 8) | \ 233 | ((((unsigned long long)(n) & 0xFF00000000)) >> 8) | \ 234 | ((((unsigned long long)(n) & 0xFF0000000000)) >> 24) | \ 235 | ((((unsigned long long)(n) & 0xFF000000000000)) >> 50) | \ 236 | ((((unsigned long long)(n) & 0xFF00000000000000)) >> 56)) 237 | 238 | uint64_t swap(uint64_t value, int size) { 239 | if (size == 1) return value; 240 | if (size == 2) return swap16(value); 241 | if (size == 3) return swap32(value) >> 8; 242 | if (size == 4) return swap32(value); 243 | if (size == 6) return swap64(value) >> 16; 244 | if (size == 8) return swap64(value); 245 | printf("error swap value size: %d\n", size); 246 | return value; 247 | } 248 | 249 | const char *nums(int start, int size) { 250 | static char buffer[256]; 251 | static int index = 0; 252 | char *buf = buffer + index; 253 | const int block = 32; 254 | 255 | int n = snprintf(buf, block, "%d", start); 256 | for (int i = start + 1; i < start + size; ++i) { 257 | buf[n++] = ','; 258 | n += snprintf(buf + n, block - n, "%d", i); 259 | } 260 | buf[n] = 0; 261 | index = (index + block) % 256; // split by 16 bytes each 262 | return buf; 263 | } 264 | 265 | 266 | void myassert(bool a, const char *info=0) { 267 | if (!a) { 268 | logger::debug("assert error %s\n", (info > 0) ? info: ""); 269 | } 270 | } 271 | 272 | 273 | const char *demangle(const char *name) { 274 | const static int maxsize = 1024; 275 | static char buf[maxsize+4]; 276 | int status; 277 | int size = strlen(name); 278 | char *realname; 279 | strncpy(buf, name, maxsize - 1); 280 | buf[maxsize - 1] = 0; 281 | bool isPlt = size > 4 && strcmp(name + size - 4, "@plt") == 0; 282 | if (isPlt) buf[size - 4] = 0; 283 | realname = abi::__cxa_demangle(buf, 0, 0, &status); 284 | if (!status) { 285 | strncpy(buf, realname, maxsize - 1); 286 | buf[maxsize - 1] = 0; 287 | } 288 | if (isPlt) { 289 | strcpy(buf + strlen(buf), "@plt"); 290 | } 291 | free(realname); 292 | return buf; 293 | } 294 | 295 | 296 | const char *displayRegs(CONTEXT *ctx) { 297 | static char buf[512]; 298 | int n = 0; 299 | n += sprintf(buf + n, "+--------------------------------------------------------------------------+\n"); 300 | n += sprintf(buf + n, " RAX = 0x%-16lx ", PIN_GetContextReg(ctx, LEVEL_BASE::REG_RAX)); 301 | n += sprintf(buf + n, " RBX = 0x%-16lx ", PIN_GetContextReg(ctx, LEVEL_BASE::REG_RBX)); 302 | n += sprintf(buf + n, " RCX = 0x%-16lx\n", PIN_GetContextReg(ctx, LEVEL_BASE::REG_RCX)); 303 | n += sprintf(buf + n, " RDX = 0x%-16lx ", PIN_GetContextReg(ctx, LEVEL_BASE::REG_RDX)); 304 | n += sprintf(buf + n, " RDI = 0x%-16lx ", PIN_GetContextReg(ctx, LEVEL_BASE::REG_RDI)); 305 | n += sprintf(buf + n, " RSI = 0x%-16lx\n", PIN_GetContextReg(ctx, LEVEL_BASE::REG_RSI)); 306 | n += sprintf(buf + n, " RBP = 0x%-16lx ", PIN_GetContextReg(ctx, LEVEL_BASE::REG_RBP)); 307 | n += sprintf(buf + n, " RSP = 0x%-16lx ", PIN_GetContextReg(ctx, LEVEL_BASE::REG_RSP)); 308 | n += sprintf(buf + n, " RIP = 0x%-16lx\n", PIN_GetContextReg(ctx, LEVEL_BASE::REG_RIP)); 309 | n += sprintf(buf + n, "+--------------------------------------------------------------------------+\n"); 310 | buf[n] = 0; 311 | return buf; 312 | } 313 | 314 | 315 | } // end of namespace util 316 | 317 | 318 | namespace filter { 319 | 320 | const char *entry = "entry"; 321 | const char *exit = "exit"; 322 | 323 | bool read(int fd, uint64_t addr, ssize_t size) { 324 | bool ret = (fd <= 2 || fd > 10 || addr <= 0x100 || size <= 2 || size >= 1024) // default pass rule 325 | || (config::read_size_flag && (size < config::read_size_min || size > config::read_size_max)) 326 | || (config::read_fd_flag && (fd < config::read_fd_min || fd > config::read_fd_max)); 327 | if (ret) { 328 | logger::print("filter read: fd: %d, addr: %lx, size: %zd\n", fd, addr, size); 329 | } 330 | return ret; 331 | } 332 | 333 | 334 | bool testfunc(const std::string& name) { 335 | size_t n = sizeof(config::tetfuncs) / sizeof(const char *); 336 | 337 | for (size_t i = 0; i < n; ++i) { 338 | if (name.find(config::tetfuncs[i]) != std::string::npos) { 339 | logger::print("filter test function: %s\n", config::tetfuncs[i]); 340 | return true; 341 | } 342 | } 343 | return false; 344 | } 345 | 346 | bool blackfunc(const std::string& name) { 347 | size_t n = sizeof(config::blackfuncs) / sizeof(const char *); 348 | 349 | for (size_t i = 0; i < n; ++i) { 350 | if (name.find(config::blackfuncs[i]) != std::string::npos) { 351 | logger::print("filter black function: %s\n", config::blackfuncs[i]); 352 | return true; 353 | } 354 | } 355 | return false; 356 | } 357 | 358 | 359 | bool libs(const std::string &name) { 360 | size_t n = sizeof(config::libs) / sizeof(const char *); 361 | 362 | for (size_t i = 0; i < n; ++i) { 363 | if (name.find(config::libs[i]) != std::string::npos) { 364 | return true; 365 | } 366 | } 367 | return false; 368 | } 369 | 370 | 371 | bool taint_start() { 372 | if (!config::use_interactive) return true; 373 | static bool ret = false; 374 | if (ret) return ret; 375 | printf("taint start?[y/n]"); 376 | char c = getchar(); 377 | getchar(); // for \n 378 | if (c == 'y') { 379 | printf("taint start\n"); 380 | ret = true; 381 | return true; 382 | } 383 | return false; 384 | } 385 | 386 | }// end of namespace filter 387 | 388 | #endif 389 | -------------------------------------------------------------------------------- /result/libmodbus/output.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | G 11 | 12 | 13 | _modbus_tc\np_receive-11 14 | 15 | _modbus_tc 16 | p_receive 17 | 18 | 19 | _modbus_re\nceive_msg-12 20 | 21 | _modbus_re 22 | ceive_msg 23 | 24 | 25 | _modbus_tc\np_receive-11--_modbus_re\nceive_msg-12 26 | 27 | 28 | 29 | modbus_reply-20 30 | 31 | modbus_reply 32 | 33 | 34 | _modbus_tc\np_receive-11--modbus_reply-20 35 | 36 | 37 | 38 | 0, 1, 2, 3,\n 4, 5, 6, 7-1 39 | 40 | 0, 1, 2, 3, 41 | 4, 5, 6, 7 42 | 43 | 44 | _modbus_re\nceive_msg-12--0, 1, 2, 3,\n 4, 5, 6, 7-1 45 | 46 | 47 | 48 | 8, 9, 10\n, 11, 7-16 49 | 50 | 8, 9, 10 51 | , 11, 7 52 | 53 | 54 | _modbus_re\nceive_msg-12--8, 9, 10\n, 11, 7-16 55 | 56 | 57 | 58 | 8, 6, 7, 9-19 59 | 60 | 8, 6, 7, 9 61 | 62 | 63 | modbus_reply-20--8, 6, 7, 9-19 64 | 65 | 66 | 67 | _modbus_tcp\n_prepare_re\nsponse_tid-21 68 | 69 | _modbus_tcp 70 | _prepare_re 71 | sponse_tid 72 | 73 | 74 | modbus_reply-20--_modbus_tcp\n_prepare_re\nsponse_tid-21 75 | 76 | 77 | 78 | [0, 1]-23 79 | 80 | [0, 1] 81 | 82 | 83 | modbus_reply-20--[0, 1]-23 84 | 85 | 86 | 87 | 7, 8, 9, [8\n, 9], 10, 1\n1, [10, 11]-25 88 | 89 | 7, 8, 9, [8 90 | , 9], 10, 1 91 | 1, [10, 11] 92 | 93 | 94 | modbus_reply-20--7, 8, 9, [8\n, 9], 10, 1\n1, [10, 11]-25 95 | 96 | 97 | 98 | _modbus_tcp\n_build_resp\nonse_basis-29 99 | 100 | _modbus_tcp 101 | _build_resp 102 | onse_basis 103 | 104 | 105 | modbus_reply-20--_modbus_tcp\n_build_resp\nonse_basis-29 106 | 107 | 108 | 109 | [10, 11], [8\n, 9], 11, 6-31 110 | 111 | [10, 11], [8 112 | , 9], 11, 6 113 | 114 | 115 | modbus_reply-20--[10, 11], [8\n, 9], 11, 6-31 116 | 117 | 118 | 119 | send_msg-32 120 | 121 | send_msg 122 | 123 | 124 | modbus_reply-20--send_msg-32 125 | 126 | 127 | 128 | 0, 1, [0, 1]-22 129 | 130 | 0, 1, [0, 1] 131 | 132 | 133 | _modbus_tcp\n_prepare_re\nsponse_tid-21--0, 1, [0, 1]-22 134 | 135 | 136 | 137 | [0, 1], 0\n, 1, 6, 7-30 138 | 139 | [0, 1], 0 140 | , 1, 6, 7 141 | 142 | 143 | _modbus_tcp\n_build_resp\nonse_basis-29--[0, 1], 0\n, 1, 6, 7-30 144 | 145 | 146 | 147 | 6, [8, 9]-33 148 | 149 | 6, [8, 9] 150 | 151 | 152 | send_msg-32--6, [8, 9]-33 153 | 154 | 155 | 156 | 0, 1, 6\n, 7, 11-35 157 | 158 | 0, 1, 6 159 | , 7, 11 160 | 161 | 162 | send_msg-32--0, 1, 6\n, 7, 11-35 163 | 164 | 165 | 166 | _modbus_\ntcp_send-36 167 | 168 | _modbus_ 169 | tcp_send 170 | 171 | 172 | send_msg-32--_modbus_\ntcp_send-36 173 | 174 | 175 | 176 | [8, 9], 6-37 177 | 178 | [8, 9], 6 179 | 180 | 181 | _modbus_\ntcp_send-36--[8, 9], 6-37 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /result/freemodbus/output.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | G 11 | 12 | 13 | pvPollin\ngThread-2 14 | 15 | pvPollin 16 | gThread 17 | 18 | 19 | eMBPoll-6 20 | 21 | eMBPoll 22 | 23 | 24 | pvPollin\ngThread-2--eMBPoll-6 25 | 26 | 27 | 28 | eMBPoll-13 29 | 30 | eMBPoll 31 | 32 | 33 | pvPollin\ngThread-2--eMBPoll-13 34 | 35 | 36 | 37 | eMBPoll-20 38 | 39 | eMBPoll 40 | 41 | 42 | pvPollin\ngThread-2--eMBPoll-20 43 | 44 | 45 | 46 | xMBPortE\nventGet-7 47 | 48 | xMBPortE 49 | ventGet 50 | 51 | 52 | eMBPoll-6--xMBPortE\nventGet-7 53 | 54 | 55 | 56 | xMBPort\nTCPPool-8 57 | 58 | xMBPort 59 | TCPPool 60 | 61 | 62 | xMBPortE\nventGet-7--xMBPort\nTCPPool-8 63 | 64 | 65 | 66 | 4, 5, [4, 5]-1 67 | 68 | 4, 5, [4, 5] 69 | 70 | 71 | xMBPort\nTCPPool-8--4, 5, [4, 5]-1 72 | 73 | 74 | 75 | eMBTCPR\neceive-15 76 | 77 | eMBTCPR 78 | eceive 79 | 80 | 81 | eMBPoll-13--eMBTCPR\neceive-15 82 | 83 | 84 | 85 | 2, 3, [2, 3]-11 86 | 87 | 2, 3, [2, 3] 88 | 89 | 90 | eMBTCPR\neceive-15--2, 3, [2, 3]-11 91 | 92 | 93 | 94 | 7-17 95 | 96 | 7 97 | 98 | 99 | eMBPoll-20--7-17 100 | 101 | 102 | 103 | eMBFuncRe\nadHolding\nRegister-22 104 | 105 | eMBFuncRe 106 | adHolding 107 | Register 108 | 109 | 110 | eMBPoll-20--eMBFuncRe\nadHolding\nRegister-22 111 | 112 | 113 | 114 | [10, 11]-27 115 | 116 | [10, 11] 117 | 118 | 119 | eMBPoll-20--[10, 11]-27 120 | 121 | 122 | 123 | eMBTCPSend-28 124 | 125 | eMBTCPSend 126 | 127 | 128 | eMBPoll-20--eMBTCPSend-28 129 | 130 | 131 | 132 | 8, 9, [8, \n9], 10, 11\n, [10, 11]-23 133 | 134 | 8, 9, [8, 135 | 9], 10, 11 136 | , [10, 11] 137 | 138 | 139 | eMBFuncRe\nadHolding\nRegister-22--8, 9, [8, \n9], 10, 11\n, [10, 11]-23 140 | 141 | 142 | 143 | eMBRegHo\nldingCB-24 144 | 145 | eMBRegHo 146 | ldingCB 147 | 148 | 149 | eMBFuncRe\nadHolding\nRegister-22--eMBRegHo\nldingCB-24 150 | 151 | 152 | 153 | [10, 11]-26 154 | 155 | [10, 11] 156 | 157 | 158 | eMBFuncRe\nadHolding\nRegister-22--[10, 11]-26 159 | 160 | 161 | 162 | [10, 11]\n, [8, 9]-25 163 | 164 | [10, 11] 165 | , [8, 9] 166 | 167 | 168 | eMBRegHo\nldingCB-24--[10, 11]\n, [8, 9]-25 169 | 170 | 171 | 172 | [10, 11]\n, 10, 11-29 173 | 174 | [10, 11] 175 | , 10, 11 176 | 177 | 178 | eMBTCPSend-28--[10, 11]\n, 10, 11-29 179 | 180 | 181 | 182 | xMBTCPPortS\nendResponse-30 183 | 184 | xMBTCPPortS 185 | endResponse 186 | 187 | 188 | eMBTCPSend-28--xMBTCPPortS\nendResponse-30 189 | 190 | 191 | 192 | [10, 11]-31 193 | 194 | [10, 11] 195 | 196 | 197 | xMBTCPPortS\nendResponse-30--[10, 11]-31 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /result/libmodbus/info.txt: -------------------------------------------------------------------------------- 1 | Function 0 enter main (40ad06,40b3f8,7fd1e8590830) 2 | Function 0 enter modbus_new_tcp (40d410,40d51d,40ad4b) 3 | Function 0 enter malloc@plt (401820,40182b,40d42a) 4 | Function 0 enter _modbus_init_common (402760,40279b,40d43e) 5 | Function 0 exit _modbus_init_common 6 | Function 0 enter malloc@plt (401820,40182b,40d456) 7 | Function 0 enter strlcpy (404b30,404b71,40d47c) 8 | Function 0 exit strlcpy 9 | Function 0 exit modbus_new_tcp 10 | Function 0 enter malloc@plt (401820,40182b,40ad5c) 11 | Function 0 enter modbus_set_debug (404910,404933,40ad77) 12 | Function 0 exit modbus_set_debug 13 | Function 0 enter modbus_mapping_new_start_address (404940,404ab9,40ada3) 14 | Function 0 enter malloc@plt (401820,40182b,40496a) 15 | Function 0 enter calloc@plt (401760,40176b,404a41) 16 | Function 0 enter calloc@plt (401760,40176b,404a6c) 17 | Function 0 enter calloc@plt (401760,40176b,404a98) 18 | Function 0 enter calloc@plt (401760,40176b,404a09) 19 | Function 0 exit modbus_mapping_new_start_address 20 | Function 0 enter modbus_tcp_listen (40cf50,40d07f,40ae97) 21 | Function 0 enter socket@plt (4019b0,4019bb,40cf96) 22 | Function 0 enter setsockopt@plt (4015d0,4015db,40cfbd) 23 | Function 0 enter bind@plt (401890,40189b,40d01c) 24 | Function 0 enter listen@plt (401850,40185b,40d02d) 25 | Function 0 exit modbus_tcp_listen 26 | Function 0 enter select@plt (401800,40180b,40b065) 27 | Function 0 enter modbus_tcp_accept (40d2d0,40d36f,40b0e1) 28 | Function 0 enter accept@plt (401910,40191b,40d309) 29 | Function 0 enter inet_ntoa@plt (401600,40160b,40d339) 30 | Function 0 enter __printf_chk@plt (401880,40188b,40d34d) 31 | Function 0 enter malloc@plt (401820,40182b,7fd1e85dd1d5) 32 | Function 0 exit modbus_tcp_accept 33 | Function 0 enter select@plt (401800,40180b,40b065) 34 | Function 0 enter modbus_receive (402730,402758,40b2cd) 35 | Function 0 enter _modbus_tcp_receive (40cd30,40cd32,40b2cd) 36 | Function 0 enter _modbus_receive_msg (4036f0,403c0e,40b2cd) 37 | Function 0 enter puts@plt (4015a0,4015ab,40373b) 38 | Function 0 enter __fdelt_chk@plt (401690,40169b,403755) 39 | Function 0 enter _modbus_tcp_select (40c980,40ca4c,4037e3) 40 | Function 0 enter select@plt (401800,40180b,40c9e9) 41 | Function 0 exit _modbus_tcp_select 42 | Function 0 enter _modbus_tcp_recv (40ca50,40ca58,403805) 43 | Function 0 enter recv@plt (401530,40153b,403805) 44 | Taint (0x1abc080, 8) 45 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 0 0x1abc080 0x1 46 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 47 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 1 0x1abc081 0x11 48 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 49 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 2 0x1abc082 0x0 50 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 51 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 3 0x1abc083 0x0 52 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 53 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 4 0x1abc084 0x0 54 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 55 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 5 0x1abc085 0x6 56 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 57 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 6 0x1abc086 0x1 58 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 59 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 7 0x1abc087 0x3 60 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 61 | Instruction 0x403a30: movzx ecx, byte ptr [rdi+rcx*1] 0 7 0x1abc087 0x3 62 | Instruction 0x403a3c: movzx esi, cl 0 7 0x1abc087 0x3 63 | Instruction 0x403a3f: cmp esi, 0x6 0 7 0x3 64 | Function 0 enter _modbus_tcp_select (40c980,40ca4c,4037e3) 65 | Function 0 enter select@plt (401800,40180b,40c9e9) 66 | Function 0 exit _modbus_tcp_select 67 | Function 0 enter _modbus_tcp_recv (40ca50,40ca58,403805) 68 | Function 0 enter recv@plt (401530,40153b,403805) 69 | Taint (0x1abc088, 4) 70 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 8 0x1abc088 0x0 71 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 72 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 9 0x1abc089 0x2 73 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 74 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 10 0x1abc08a 0x0 75 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 76 | Instruction 0x4038a0: movzx edx, byte ptr [rbx+r15*1] 0 11 0x1abc08b 0x8 77 | Function 0 enter __printf_chk@plt (401880,40188b,4038ba) 78 | Instruction 0x40391e: movzx ecx, byte ptr [rdi+rcx*1] 0 7 0x1abc087 0x3 79 | Instruction 0x403a70: cmp cl, 0xf 0 7 0x3 80 | Function 0 enter putchar@plt (401540,40154b,403b96) 81 | Function 0 enter _modbus_tcp_check_integrity (40c810,40c812,4038fc) 82 | Function 0 exit _modbus_tcp_check_integrity 83 | Function 0 exit _modbus_receive_msg 84 | Function 0 enter modbus_reply (402c80,403626,40b2ff) 85 | Instruction 0x402cc4: movzx edi, byte ptr [rsi+rbp*1+0x1] 0 8 0x1abc088 0x0 86 | Instruction 0x402ccd: movzx r13d, byte ptr [rsi+rbp*1-0x1] 0 6 0x1abc086 0x1 87 | Instruction 0x402cd3: movzx edx, byte ptr [r12] 0 7 0x1abc087 0x3 88 | Memory: Taint addr:7ffeaf7c7a4c src:1abc088 offset:8 size:1 bigendian:0 89 | Instruction 0x402cd8: mov byte ptr [rsp+0x1c], dil 0 8 0x1abc088 0x0 90 | Instruction 0x402cdd: movzx edi, byte ptr [rsi+rbp*1+0x2] 0 9 0x1abc089 0x2 91 | Memory: Taint addr:7ffeaf7c7a60 src:1abc086 offset:6 size:1 bigendian:0 92 | Instruction 0x402ce7: mov dword ptr [rsp+0x30], r13d 0 6 0x1abc086 0x1 93 | Memory: Taint addr:7ffeaf7c7a38 src:1abc087 offset:7 size:1 bigendian:0 94 | Instruction 0x402cec: mov byte ptr [rsp+0x8], dl 0 7 0x1abc087 0x3 95 | Memory: Taint addr:7ffeaf7c7a64 src:1abc087 offset:7 size:1 bigendian:0 96 | Instruction 0x402cf0: mov dword ptr [rsp+0x34], edx 0 7 0x1abc087 0x3 97 | Memory: Taint addr:7ffeaf7c7a30 src:1abc087 offset:7 size:1 bigendian:0 98 | Instruction 0x402cf4: mov dword ptr [rsp], edx 0 7 0x1abc087 0x3 99 | Memory: Taint addr:7ffeaf7c7a58 src:1abc089 offset:9 size:1 bigendian:0 100 | Instruction 0x402cf7: mov byte ptr [rsp+0x28], dil 0 9 0x1abc089 0x2 101 | Function 0 enter _modbus_tcp_prepare_response_tid (40c7e0,40c7ec,402d02) 102 | Instruction 0x40c7e0: movzx eax, byte ptr [rdi] 0 0 0x1abc080 0x1 103 | Instruction 0x40c7e3: movzx edx, byte ptr [rdi+0x1] 0 1 0x1abc081 0x11 104 | Instruction 0x40c7e7: shl eax, 0x8 0 0 0x1 105 | Instruction 0x40c7ea: add eax, edx 0 0 0x100 106 | Instruction 0x40c7ea: add eax, edx 0 1 0x11 107 | Instruction 0x40c7ea: add eax, edx 0 0,1 0x100 108 | Function 0 exit _modbus_tcp_prepare_response_tid 109 | Memory: Taint addr:7ffeaf7c7a68 src:1abc080 offset:0 size:2 bigendian:1 110 | Instruction 0x402d09: mov dword ptr [rsp+0x38], eax 0 0,1 0x1abc080 0x111 111 | Function 0 enter validate (406861,406c46,402d14) 112 | Function 0 enter validate_init (406701,406729,40687d) 113 | Function 0 enter init_func_mem (404bcf,404cb5,406723) 114 | Function 0 enter memset@plt (4016f0,4016fb,404beb) 115 | Function 0 enter memset@plt (4016f0,4016fb,404bff) 116 | Function 0 exit init_func_mem 117 | Function 0 exit validate_init 118 | Function 0 enter check_update (40672a,406860,406887) 119 | Function 0 enter fopen@plt (4018d0,4018db,406752) 120 | Function 0 enter malloc@plt (401820,40182b,7fd1e85ddcdd) 121 | Function 0 enter free@plt (401520,40152b,7fd1e85ddd5d) 122 | Function 0 exit check_update 123 | Function 0 enter fwrite@plt (401940,40194b,4068a9) 124 | Function 0 exit validate 125 | Instruction 0x402d16: mov edx, dword ptr [rsp] 0 7 0x1abc087 0x3 126 | Instruction 0x402d19: movzx r8d, byte ptr [rsp+0x8] 0 7 0x1abc087 0x3 127 | Instruction 0x402d26: movzx r15d, word ptr [rsp+0x1c] 0 8 0x1abc088 0x0 128 | Instruction 0x402d2c: movzx r12d, byte ptr [rsp+0x28] 0 9 0x1abc089 0x2 129 | Instruction 0x402d32: shl r15d, 0x8 0 8 0x0 130 | Instruction 0x402d36: add r12d, r15d 0 9 0x2 131 | Instruction 0x402d36: add r12d, r15d 0 8 0x0 132 | Instruction 0x402d36: add r12d, r15d 0 8,9 0x2 133 | Instruction 0x402d39: cmp r8b, 0x17 0 7 0x3 134 | Instruction 0x402d43: movzx eax, r8b 0 7 0x1abc087 0x3 135 | Instruction 0x402eb0: cmp edx, 0x4 0 7 0x3 136 | Instruction 0x402ecc: movzx edx, byte ptr [rbx+rbp*1+0x3] 0 10 0x1abc08a 0x0 137 | Instruction 0x402ed1: movzx edi, byte ptr [rbx+rbp*1+0x4] 0 11 0x1abc08b 0x8 138 | Instruction 0x402ed6: shl edx, 0x8 0 10 0x0 139 | Instruction 0x402ed9: add edx, edi 0 10 0x0 140 | Instruction 0x402ed9: add edx, edi 0 11 0x8 141 | Instruction 0x402ed9: add edx, edi 0 10,11 0x0 142 | Instruction 0x402ee7: movzx r15d, r12w 0 8,9 0x1abc088 0x2 143 | Instruction 0x402eeb: mov ebx, r15d 0 8,9 0x1abc088 0x2 144 | Instruction 0x402eee: sub ebx, eax 0 8,9 0x2 145 | Memory: Taint addr:7ffeaf7c7a38 src:1abc08a offset:a size:2 bigendian:1 146 | Instruction 0x40346a: mov dword ptr [rsp+0x8], edx 0 10,11 0x1abc08a 0x8 147 | Memory: Untaint addr:7ffeaf7c7a30 src:1abc087 offset:7 size:1 bigendian:0 148 | Function 0 enter _modbus_tcp_build_response_basis (40c7b0,40c7d6,40347d) 149 | Instruction 0x40c7b0: mov eax, dword ptr [rdi+0x8] 0 0,1 0x1abc080 0x111 150 | Instruction 0x40c7b3: sar eax, 0x8 0 0 0x111 151 | Memory: Taint addr:7ffeaf7c7a70 src:1abc080 offset:0 size:1 bigendian:1 152 | Instruction 0x40c7b6: mov byte ptr [rsi], al 0 0 0x1abc080 0x1 153 | Instruction 0x40c7b8: mov eax, dword ptr [rdi+0x8] 0 0,1 0x1abc080 0x111 154 | Memory: Taint addr:7ffeaf7c7a71 src:1abc081 offset:1 size:1 bigendian:1 155 | Instruction 0x40c7c3: mov byte ptr [rsi+0x1], al 0 1 0x1abc081 0x11 156 | Instruction 0x40c7c6: mov eax, dword ptr [rdi] 0 6 0x1abc086 0x1 157 | Memory: Taint addr:7ffeaf7c7a76 src:1abc086 offset:6 size:1 bigendian:0 158 | Instruction 0x40c7c8: mov byte ptr [rsi+0x6], al 0 6 0x1abc086 0x1 159 | Instruction 0x40c7cb: mov eax, dword ptr [rdi+0x4] 0 7 0x1abc087 0x3 160 | Memory: Taint addr:7ffeaf7c7a77 src:1abc087 offset:7 size:1 bigendian:0 161 | Instruction 0x40c7ce: mov byte ptr [rsi+0x7], al 0 7 0x1abc087 0x3 162 | Function 0 exit _modbus_tcp_build_response_basis 163 | Instruction 0x40347d: mov edx, dword ptr [rsp+0x8] 0 10,11 0x1abc08a 0x8 164 | Instruction 0x403488: add edx, edx 0 10,11 0x8 165 | Instruction 0x403488: add edx, edx 0 10,11 0x8 166 | Instruction 0x40348a: cmp ebx, ebp 0 8,9 0x2 167 | Memory: Taint addr:7ffeaf7c7a78 src:1abc08b offset:b size:1 bigendian:1 168 | Instruction 0x40348c: mov byte ptr [rsp+rcx*1+0x40], dl 0 11 0x1abc08b 0x10 169 | Instruction 0x40349c: movsxd rdx, ebx 0 8,9 0x1abc088 0x2 170 | Instruction 0x40349f: sub ecx, ebx 0 8,9 0x2 171 | Instruction 0x403158: test r13d, r13d 0 6 0x1 172 | Instruction 0x403158: test r13d, r13d 0 6 0x1 173 | Function 0 enter send_msg (4029e0,402b20,40316f) 174 | Memory: Taint addr:7ffeaf7c7a18 src:1abc086 offset:6 size:1 bigendian:0 175 | Instruction 0x4029e2: push r13 0 6 0x1abc086 0x1 176 | Memory: Taint addr:7ffeaf7c7a00 src:1abc088 offset:8 size:2 bigendian:1 177 | Instruction 0x4029ea: push rbx 0 8,9 0x1abc088 0x2 178 | Function 0 enter _modbus_tcp_send_msg_pre (40c7f0,40c800,4029fe) 179 | Function 0 exit _modbus_tcp_send_msg_pre 180 | Instruction 0x402a20: movzx edx, byte ptr [r13] 0 0 0x1abc080 0x1 181 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 182 | Instruction 0x402a20: movzx edx, byte ptr [r13] 0 1 0x1abc081 0x11 183 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 184 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 185 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 186 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 187 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 188 | Instruction 0x402a20: movzx edx, byte ptr [r13] 0 6 0x1abc086 0x1 189 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 190 | Instruction 0x402a20: movzx edx, byte ptr [r13] 0 7 0x1abc087 0x3 191 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 192 | Instruction 0x402a20: movzx edx, byte ptr [r13] 0 11 0x1abc08b 0x10 193 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 194 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 195 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 196 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 197 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 198 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 199 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 200 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 201 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 202 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 203 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 204 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 205 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 206 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 207 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 208 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 209 | Function 0 enter __printf_chk@plt (401880,40188b,402a3a) 210 | Function 0 enter putchar@plt (401540,40154b,402a49) 211 | Function 0 enter _modbus_tcp_send (40cd40,40cd4b,402a58) 212 | Function 0 enter send@plt (401660,40166b,402a58) 213 | Instruction 0x402a71: pop rbx 0 8,9 0x1abc088 0x2 214 | Instruction 0x402a75: pop r13 0 6 0x1abc086 0x1 215 | Function 0 exit send_msg 216 | Function 0 exit modbus_reply 217 | Function 0 enter select@plt (401800,40180b,40b065) 218 | Function 0 enter modbus_receive (402730,402758,40b2cd) 219 | Function 0 enter _modbus_tcp_receive (40cd30,40cd32,40b2cd) 220 | Function 0 enter _modbus_receive_msg (4036f0,403c0e,40b2cd) 221 | Function 0 enter puts@plt (4015a0,4015ab,40373b) 222 | Function 0 enter __fdelt_chk@plt (401690,40169b,403755) 223 | Function 0 enter _modbus_tcp_select (40c980,40ca4c,4037e3) 224 | Function 0 enter select@plt (401800,40180b,40c9e9) 225 | Function 0 exit _modbus_tcp_select 226 | Function 0 enter _modbus_tcp_recv (40ca50,40ca58,403805) 227 | Function 0 enter recv@plt (401530,40153b,403805) 228 | Taint (0x1abc080, 0) 229 | Function 0 enter __errno_location@plt (401570,40157b,403810) 230 | Function 0 enter _error_print (4021d0,40223d,403823) 231 | Function 0 enter __errno_location@plt (401570,40157b,4021e9) 232 | Function 0 enter modbus_strerror (4020b0,4021c0,4021f0) 233 | Function 0 enter strerror@plt (401980,40198b,4021f0) 234 | Function 0 enter __fprintf_chk@plt (401950,40195b,40220b) 235 | Function 0 enter __fprintf_chk@plt (401950,40195b,403823) 236 | Function 0 exit _modbus_receive_msg 237 | Function 0 enter close@plt (401710,40171b,40b38e) 238 | Function 0 enter select@plt (401800,40180b,40b065) 239 | -------------------------------------------------------------------------------- /src/taint.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "config.hpp" 5 | #include "logic.hpp" 6 | #include "pin.H" 7 | #include "pinobject.hpp" 8 | #include "util.hpp" 9 | #include "loop.cpp" 10 | 11 | void Test(Ins ins) { 12 | UINT32 opcount = ins.OpCount(); 13 | OPCODE opcode = ins.OpCode(); 14 | INT32 ext = ins.Extention(); 15 | 16 | if (ins.isCall() || ins.isRet() || ins.isBranch() || ins.isNop() || 17 | opcount <= 1) 18 | return; 19 | 20 | if (ext >= 40) return; // sse TODO 21 | 22 | if (opcount == 2 || (opcode >= 83 && opcode <= 98)) { 23 | if (ins.isLea()) return; 24 | if (ins.isOpImplicit(0) || ins.isOpImplicit(1)) return; 25 | if (ins.isOpReg(0) && ins.isOpReg(1)) return; 26 | if (ins.isOpReg(0) && ins.isOpImm(1)) return; 27 | if (ins.isOpReg(0) && ins.isOpMem(1)) return; 28 | if (ins.isOpMem(0) && ins.isOpReg(1)) return; 29 | logger::verbose("0 %s", ins.prettify()); return; 30 | // if (ins.isOpMem(0) && ins.isOpImm(1)) return; 31 | // if ((ins.isMemoryWrite() || ins.isMemoryRead())) return; 32 | } else if (opcount == 3) { 33 | logger::verbose("1 %s", ins.prettify()); return; 34 | // if (opcode != XED_ICLASS_XOR) return; 35 | // add sub adc(carry) sbb(borrow) 36 | // sar shr shl ror(rotate) or and 37 | // test cmp bt 38 | } else if (opcount == 4) { 39 | logger::verbose("2 %s", ins.prettify()); return; 40 | // push pop 41 | // mul div imul idiv 42 | } else { 43 | logger::verbose("3 %s", ins.prettify()); return; 44 | } 45 | // INS_OperandImmediate 46 | // INS_OperandRead 47 | // INS_OperandReadAndWritten 48 | // INS_OperandReg 49 | // INS_OperandWritten 50 | // INS_OperandReadOnly 51 | // INS_OperandWrittenOnly 52 | } 53 | 54 | bool filter_ins(Ins ins) { 55 | // filter rules 56 | // if (opcount == 2 && (ins.isOpImplicit(0) || ins.isOpImplicit(1))) return; 57 | // TODO neg inc, dec cgo setx 58 | UINT32 opcount = ins.OpCount(); 59 | bool ret = ins.isCall() || ins.isRet() || ins.isBranch() || ins.isNop() || opcount <= 1 || opcount >= 5 60 | || ins.Extention() >= 40 // TODO sse instructions 61 | // || (ins.isOpReg(0) && (ins.OpReg(0) == REG_RBP || ins.OpReg(0) == REG_RSP || ins.OpReg(0) == REG_RIP)) 62 | // || (ins.isOpReg(0) && (ins.OpReg(0) == REG_EBP || ins.OpReg(0) == REG_ESP || ins.OpReg(0) == REG_EIP)) 63 | ; 64 | static std::vector cache; 65 | if (ret) { 66 | OPCODE opcode = ins.OpCode(); 67 | if (std::find(cache.begin(), cache.end(), opcode) == cache.end()) { 68 | cache.push_back(opcode); 69 | logger::debug("assembly not taint included : %s\n", 70 | ins.Name().c_str()); 71 | } 72 | } 73 | return ret; 74 | } 75 | 76 | void LogInst(Ins ins) { 77 | if (!config::debugMode) return; 78 | if ( filter_ins(ins) ) { 79 | INS_InsertPredicatedCall( 80 | ins, IPOINT_BEFORE, (AFUNPTR)print_instructions0, 81 | IARG_PTR, new std::string(ins.Name()), IARG_INST_PTR, 82 | IARG_END); 83 | return; 84 | } 85 | if (ins.isOpMem(0)) { 86 | if (ins.isOpMem(1)) { 87 | INS_InsertPredicatedCall( 88 | ins, IPOINT_BEFORE, (AFUNPTR)print_instructions1, 89 | IARG_PTR, new std::string(ins.Name()), IARG_INST_PTR, 90 | IARG_CONST_CONTEXT, 91 | 92 | IARG_ADDRINT, ins.OpReg(0), 93 | IARG_ADDRINT, ins.OpReg(1), 94 | 95 | IARG_MEMORYOP_EA, 0, 96 | 97 | IARG_MEMORYOP_EA, 1, 98 | 99 | IARG_END); 100 | } else { 101 | INS_InsertPredicatedCall( 102 | ins, IPOINT_BEFORE, (AFUNPTR)print_instructions1, 103 | IARG_PTR, new std::string(ins.Name()), IARG_INST_PTR, 104 | IARG_CONST_CONTEXT, 105 | 106 | IARG_ADDRINT, ins.OpReg(0), 107 | IARG_ADDRINT, ins.OpReg(1), 108 | 109 | IARG_MEMORYOP_EA, 0, 110 | 111 | IARG_ADDRINT, 0, 112 | 113 | IARG_END); 114 | } 115 | } else { 116 | INS_InsertPredicatedCall( 117 | ins, IPOINT_BEFORE, (AFUNPTR)print_instructions1, 118 | IARG_PTR, new std::string(ins.Name()), IARG_INST_PTR, 119 | IARG_CONST_CONTEXT, 120 | 121 | IARG_ADDRINT, ins.OpReg(0), 122 | IARG_ADDRINT, ins.OpReg(1), 123 | 124 | IARG_ADDRINT, 0, 125 | 126 | IARG_ADDRINT, 0, 127 | 128 | IARG_END); 129 | } 130 | } 131 | 132 | 133 | void Instruction(Ins ins) { 134 | 135 | UINT32 opcount = ins.OpCount(); 136 | 137 | if ( filter_ins(ins) ) { 138 | return; 139 | } 140 | 141 | bool miss = false; 142 | 143 | OPCODE opcode = ins.OpCode(); 144 | 145 | REG reg_w = ins.OpReg(0); 146 | REG reg_r = ins.OpReg(1); 147 | 148 | if (opcount == 2) { // condition mov 149 | if (ins.isLea()) { // reg calculation 150 | InsertCall(ins, reg_w); // deleteReg #TODO 151 | } else if (ins.isOpReg(0) && ins.isOpMem(1)) { 152 | InsertCall(ins, reg_w, 0); // ReadMem 153 | } else if (ins.isOpMem(0) && ins.isOpReg(1)) { 154 | InsertCall(ins, 0, reg_r); // WriteMem 155 | } else if (ins.isOpMem(0) && ins.isOpImm(1)) { 156 | InsertCall(ins, 0); // deleteMem 157 | } else if (ins.isOpReg(0) && ins.isOpReg(1)) { 158 | InsertCall(ins, reg_w, reg_r); // spreadReg 159 | } else if (ins.isOpReg(0) && ins.isOpImm(1)) { 160 | InsertCall(ins, reg_w); // deleteReg 161 | } else { 162 | miss = true; 163 | } 164 | } else if (opcount == 3) { 165 | if (ins.isOpReg(0) && ins.isOpReg(1)) { 166 | InsertCallExtra(ins, reg_w, reg_r); 167 | } else if (ins.isOpReg(0) && ins.isOpMem(1)) { 168 | InsertCallExtra(ins, reg_w, 0); 169 | } else if (ins.isOpReg(0) && ins.isOpImm(1)) { 170 | InsertCallExtra(ins, reg_w); 171 | } else if (ins.isOpMem(0) && ins.isOpImm(1)) { 172 | InsertCallExtra(ins, 0); 173 | } else if (ins.isOpMem(0) && ins.isOpReg(1)) { 174 | InsertCallExtra(ins, 0, reg_r); 175 | } else { 176 | miss = true; 177 | } 178 | // add sub adc(carry) sbb(borrow) 179 | // sar shr shl ror(rotate) or and 180 | // test cmp bt 181 | } else if (opcount == 4) { 182 | if (opcode == XED_ICLASS_PUSH) { // push 183 | if (ins.isOpReg(0)) { 184 | InsertCall(ins, 0, reg_w); // WriteMem // note reg_w is the 185 | // first reg op in push 186 | } else if (ins.isOpMem(0)) { 187 | InsertCall(ins, 0, 1); // spreadMem 188 | } else if (ins.isOpImm(0)) { 189 | InsertCall(ins, 0); // deleteMem 190 | } else { 191 | miss = true; 192 | } 193 | } else if (opcode == XED_ICLASS_POP) { // pop 194 | if (ins.isOpReg(0)) { 195 | InsertCall(ins, reg_w, 0); // ReadMem 196 | } else { 197 | miss = true; 198 | } 199 | } else { 200 | miss = true; 201 | } 202 | // mul div imul idiv 203 | } 204 | if (config::missFlag && miss) { 205 | static std::vector cache; 206 | if (std::find(cache.begin(), cache.end(), opcode) == cache.end()) { 207 | cache.push_back(opcode); 208 | logger::debug("assembly not taint included : %s %d %d\n", 209 | ins.Name().c_str(), reg_w, reg_r); 210 | } 211 | } 212 | } 213 | 214 | void Image(IMG img, VOID *v) { 215 | std::string imgName = IMG_Name(img); 216 | 217 | logger::verbose("image: %s\n", imgName.c_str()); 218 | const bool isMain = IMG_IsMainExecutable(img); 219 | const bool isWrapper = (imgName.find("libx.so") != std::string::npos); 220 | const bool isLib = filter::libs(imgName); 221 | if (!(isMain || isWrapper || isLib)) return; 222 | for (SEC sec = IMG_SecHead(img); SEC_Valid(sec); sec = SEC_Next(sec)) { 223 | logger::verbose("sec: %s\n", SEC_Name(sec).c_str()); 224 | for (Rtn rtn = SEC_RtnHead(sec); rtn.Valid(); rtn = rtn.Next()) { 225 | if (rtn.isArtificial()) continue; 226 | std::string *rtnName = new std::string(rtn.Name()); 227 | if (filter::blackfunc(*rtnName)) continue; 228 | logger::verbose("function %s\t%s\n", rtnName->c_str(), util::demangle(rtnName->c_str())); 229 | 230 | rtn.Open(); 231 | 232 | if (config::debugMode) { 233 | RTN_InsertCall( 234 | rtn, IPOINT_BEFORE, (AFUNPTR)print_functions, 235 | IARG_PTR, rtnName, 236 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, 237 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, 238 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, 239 | IARG_FUNCARG_ENTRYPOINT_VALUE, 3, 240 | IARG_END); 241 | } 242 | 243 | if (isMain || isLib) { 244 | RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)function_entry, 245 | IARG_THREAD_ID, IARG_PTR, rtnName, 246 | IARG_ADDRINT, rtn.InsHead().Address(), 247 | IARG_ADDRINT, rtn.InsTail().Address(), 248 | IARG_RETURN_IP, 249 | IARG_END); 250 | 251 | RTN_InsertCall(rtn, IPOINT_AFTER, (AFUNPTR)function_exit, 252 | IARG_THREAD_ID, IARG_PTR, rtnName, 253 | IARG_END); 254 | for (Ins ins = rtn.InsHead(); ins.Valid(); 255 | ins = ins.Next()) { 256 | LogInst(ins); 257 | Instruction(ins); 258 | } 259 | } else if (isWrapper) { 260 | if (*rtnName == "read") { 261 | RTN_InsertCall( 262 | rtn, IPOINT_BEFORE, (AFUNPTR)read_point, 263 | IARG_ADDRINT, filter::entry, 264 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // fd 265 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 266 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 267 | IARG_REG_VALUE, REG_RAX, // ret 268 | IARG_END); 269 | RTN_InsertCall( 270 | rtn, IPOINT_AFTER, (AFUNPTR)read_point, 271 | IARG_ADDRINT, filter::exit, 272 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // fd 273 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 274 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 275 | IARG_REG_VALUE, REG_RAX, // ret 276 | IARG_END); 277 | } else if (*rtnName == "recv") { 278 | RTN_InsertCall( 279 | rtn, IPOINT_BEFORE, (AFUNPTR)recv_point, 280 | IARG_ADDRINT, filter::entry, 281 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 282 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 283 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 284 | IARG_FUNCARG_ENTRYPOINT_VALUE, 3, // flags 285 | IARG_REG_VALUE, REG_RAX, // ret 286 | IARG_END); 287 | RTN_InsertCall( 288 | rtn, IPOINT_AFTER, (AFUNPTR)recv_point, 289 | IARG_ADDRINT, filter::exit, 290 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 291 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 292 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 293 | IARG_FUNCARG_ENTRYPOINT_VALUE, 3, // flags 294 | IARG_REG_VALUE, REG_RAX, // ret 295 | IARG_END); 296 | } else if (*rtnName == "recvfrom") { 297 | RTN_InsertCall( 298 | rtn, IPOINT_BEFORE, (AFUNPTR)recvfrom_point, 299 | IARG_ADDRINT, filter::entry, 300 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 301 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 302 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 303 | IARG_FUNCARG_ENTRYPOINT_VALUE, 3, // flags 304 | IARG_FUNCARG_ENTRYPOINT_VALUE, 4, // address 305 | IARG_FUNCARG_ENTRYPOINT_VALUE, 5, // address_len 306 | IARG_REG_VALUE, REG_RAX, // ret 307 | IARG_END); 308 | RTN_InsertCall( 309 | rtn, IPOINT_AFTER, (AFUNPTR)recvfrom_point, 310 | IARG_ADDRINT, filter::exit, 311 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 312 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 313 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 314 | IARG_FUNCARG_ENTRYPOINT_VALUE, 3, // flags 315 | IARG_FUNCARG_ENTRYPOINT_VALUE, 4, // address 316 | IARG_FUNCARG_ENTRYPOINT_VALUE, 5, // address_len 317 | IARG_REG_VALUE, REG_RAX, // ret 318 | IARG_END); 319 | } else if (*rtnName == "recvmsg") { 320 | RTN_InsertCall( 321 | rtn, IPOINT_BEFORE, (AFUNPTR)recvmsg_point, 322 | IARG_ADDRINT, filter::entry, 323 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 324 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // msghdr 325 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // flags 326 | IARG_REG_VALUE, REG_RAX, // ret 327 | IARG_END); 328 | RTN_InsertCall( 329 | rtn, IPOINT_AFTER, (AFUNPTR)recvmsg_point, 330 | IARG_ADDRINT, filter::exit, 331 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 332 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // msghdr 333 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // flags 334 | IARG_REG_VALUE, REG_RAX, // ret 335 | IARG_END); 336 | } else if (*rtnName == "write") { 337 | RTN_InsertCall( 338 | rtn, IPOINT_BEFORE, (AFUNPTR)write_point, 339 | IARG_ADDRINT, filter::entry, 340 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // fd 341 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 342 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 343 | IARG_REG_VALUE, REG_RAX, // ret 344 | IARG_END); 345 | RTN_InsertCall( 346 | rtn, IPOINT_AFTER, (AFUNPTR)read_point, 347 | IARG_ADDRINT, filter::exit, 348 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // fd 349 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 350 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 351 | IARG_REG_VALUE, REG_RAX, // ret 352 | IARG_END); 353 | } else if (*rtnName == "send") { 354 | RTN_InsertCall( 355 | rtn, IPOINT_BEFORE, (AFUNPTR)send_point, 356 | IARG_ADDRINT, filter::entry, 357 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 358 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 359 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 360 | IARG_FUNCARG_ENTRYPOINT_VALUE, 3, // flags 361 | IARG_REG_VALUE, REG_RAX, // ret 362 | IARG_END); 363 | RTN_InsertCall( 364 | rtn, IPOINT_AFTER, (AFUNPTR)send_point, 365 | IARG_ADDRINT, filter::exit, 366 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 367 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 368 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 369 | IARG_FUNCARG_ENTRYPOINT_VALUE, 3, // flags 370 | IARG_REG_VALUE, REG_RAX, // ret 371 | IARG_END); 372 | } else if (*rtnName == "sendto") { 373 | RTN_InsertCall( 374 | rtn, IPOINT_BEFORE, (AFUNPTR)sendto_point, 375 | IARG_ADDRINT, filter::entry, 376 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 377 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 378 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 379 | IARG_FUNCARG_ENTRYPOINT_VALUE, 3, // flags 380 | IARG_FUNCARG_ENTRYPOINT_VALUE, 4, // address 381 | IARG_FUNCARG_ENTRYPOINT_VALUE, 5, // address_len 382 | IARG_REG_VALUE, REG_RAX, // ret 383 | IARG_END); 384 | RTN_InsertCall( 385 | rtn, IPOINT_AFTER, (AFUNPTR)sendto_point, 386 | IARG_ADDRINT, filter::exit, 387 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 388 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // buf 389 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 390 | IARG_FUNCARG_ENTRYPOINT_VALUE, 3, // flags 391 | IARG_FUNCARG_ENTRYPOINT_VALUE, 4, // address 392 | IARG_FUNCARG_ENTRYPOINT_VALUE, 5, // address_len 393 | IARG_REG_VALUE, REG_RAX, // ret 394 | IARG_END); 395 | } else if (*rtnName == "sendmsg") { 396 | RTN_InsertCall( 397 | rtn, IPOINT_BEFORE, (AFUNPTR)sendmsg_point, 398 | IARG_ADDRINT, filter::entry, 399 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 400 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // msghdr 401 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // flags 402 | IARG_REG_VALUE, REG_RAX, // ret 403 | IARG_END); 404 | RTN_InsertCall( 405 | rtn, IPOINT_AFTER, (AFUNPTR)sendmsg_point, 406 | IARG_ADDRINT, filter::exit, 407 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // socket 408 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // msghdr 409 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // flags 410 | IARG_REG_VALUE, REG_RAX, // ret 411 | IARG_END); 412 | } else if (*rtnName == "memcpy") { // memcpy use xmm registers to copy 413 | RTN_InsertCall( 414 | rtn, IPOINT_BEFORE, (AFUNPTR)memcpy_point, 415 | IARG_ADDRINT, filter::entry, 416 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // dest 417 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // src 418 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 419 | IARG_END); 420 | } else if (*rtnName == "memmove") { 421 | RTN_InsertCall( 422 | rtn, IPOINT_BEFORE, (AFUNPTR)memmove_point, 423 | IARG_ADDRINT, filter::entry, 424 | IARG_FUNCARG_ENTRYPOINT_VALUE, 0, // dest 425 | IARG_FUNCARG_ENTRYPOINT_VALUE, 1, // src 426 | IARG_FUNCARG_ENTRYPOINT_VALUE, 2, // len 427 | IARG_END); 428 | } 429 | } 430 | rtn.Close(); 431 | } 432 | } 433 | } 434 | 435 | FILE *files[3]; 436 | 437 | void Init() { 438 | // PIN_InitLock(&util::lock); 439 | files[0] = fopen(config::filenames[0], "w"); 440 | files[1] = fopen(config::filenames[1], "w"); 441 | files[2] = fopen(config::filenames[2], "w"); 442 | logger::setDebug(config::flags[0], files[0]); 443 | logger::setInfo(config::flags[1], files[1]); 444 | logger::setVerbose(config::flags[2], files[2]); 445 | } 446 | 447 | void Fini(INT32 code, VOID *v) { 448 | printf("program end\n"); 449 | fprintf(files[0], "#eof\n"); 450 | fclose(files[0]); 451 | fprintf(files[1], "#eof\n"); 452 | fclose(files[1]); 453 | fprintf(files[2], "#eof\n"); 454 | fclose(files[2]); 455 | } 456 | 457 | INT32 Usage() { 458 | printf("error\n"); 459 | return -1; 460 | } 461 | 462 | /* ===================================================================== */ 463 | /* Main */ 464 | /* ===================================================================== */ 465 | 466 | int main(int argc, char *argv[]) { 467 | if (PIN_Init(argc, argv)) return Usage(); 468 | Init(); 469 | // Initialize symbol table code, needed for rtn instrumentation 470 | PIN_InitSymbols(); 471 | PIN_InitLock(&util::lock); 472 | // PIN_SetSyntaxIntel(); 473 | IMG_AddInstrumentFunction(Image, 0); 474 | TRACE_AddInstrumentFunction(Trace, 0); 475 | // if (config::syscall) { 476 | // if (config::use_entry) PIN_AddSyscallEntryFunction(Syscall_point, 477 | // (void*)filter::entry); if (config::use_exit) 478 | // PIN_AddSyscallExitFunction(Syscall_point , (void*)filter::exit); 479 | // } 480 | 481 | PIN_StartProgram(); 482 | // PIN_StartProgramProbed(); 483 | PIN_AddFiniFunction(Fini, 0); 484 | 485 | return 0; 486 | } 487 | -------------------------------------------------------------------------------- /src/taintengine.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TAINTENGINE_H 2 | #define _TAINTENGINE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "util.hpp" 8 | 9 | namespace TaintEngine { 10 | 11 | // Taint Memory 12 | class Inits { 13 | private: 14 | struct MemI { 15 | uint64_t start; 16 | size_t size; 17 | uint8_t bytes[config::maxsize]; 18 | 19 | uint64_t begin() { return start; } 20 | 21 | uint64_t end() { return start + size; } 22 | 23 | bool valid(uint64_t addr) { 24 | return addr >= start && addr < start + size; 25 | } 26 | 27 | uint8_t value(size_t pos) { return bytes[pos]; } 28 | 29 | uint64_t value(uint64_t pos, size_t len, bool bigendian) { 30 | if (pos + len > size) { 31 | logger::print( 32 | "length overflow: pos: %lx, len: %lx, size: %lx\n", pos, 33 | len, size); 34 | debug::error(); 35 | } 36 | uint64_t value = *(uint64_t *)(bytes + pos); 37 | switch (len) { 38 | case 1: 39 | value &= 0xff; 40 | break; 41 | case 2: 42 | value &= 0xffff; 43 | break; 44 | case 3: 45 | value &= 0xffffff; 46 | break; 47 | case 4: 48 | value &= 0xffffffff; 49 | break; 50 | case 6: 51 | value &= 0xffffffffffff; 52 | break; 53 | case 8: 54 | break; 55 | default: 56 | logger::print( 57 | "length unexpected: pos: %lx, len: %lx, size: %lx\n", 58 | pos, len, size); 59 | } 60 | if (bigendian) value = util::swap(value, len); 61 | return value; 62 | } 63 | }; 64 | 65 | std::vector inits; 66 | 67 | void taintValue(uint64_t start, size_t size) { 68 | for (size_t i = 0; i < inits.size(); 69 | ++i) { // merge continuous taint memory 70 | if (inits[i].valid(start)) { 71 | int offset = start - inits[i].start; 72 | util::ValueCopy(inits[i].bytes + offset, start, size); 73 | logger::printline(inits[i].bytes, inits[i].size); 74 | } 75 | } 76 | } 77 | 78 | public: 79 | int offset(uint64_t addr) { 80 | for (size_t i = 0; i < inits.size(); ++i) { 81 | if (inits[i].valid(addr)) return addr - inits[i].start; 82 | } 83 | logger::print("address error in offset: addr: %lx\n", addr); 84 | return -1; 85 | } 86 | 87 | bool valid(uint64_t addr) { 88 | for (size_t i = 0; i < inits.size(); ++i) { 89 | if (inits[i].valid(addr)) return true; 90 | } 91 | return false; 92 | } 93 | 94 | // use in exit entry function 95 | void taint(uint64_t start, size_t size) { 96 | logger::debug("taint start: %lx, size: %lx\n", start, size); 97 | if (size > config::maxsize) { 98 | logger::print("taint size: %lx exceed maxsize: %lx\n", size, 99 | config::maxsize); 100 | size = config::maxsize; 101 | } 102 | for (size_t i = 0; i < inits.size(); 103 | ++i) { // merge continuous taint memory 104 | if (start == inits[i].begin()) { 105 | inits[i].size = size; // TODO 106 | taintValue(start, size); 107 | return; 108 | } 109 | if (start == inits[i].end()) { 110 | inits[i].size += size; 111 | taintValue(start, size); 112 | return; 113 | } 114 | } 115 | MemI e = {start, size}; 116 | inits.push_back(e); 117 | taintValue(start, size); 118 | } 119 | 120 | uint64_t value(uint64_t addr, size_t size, bool bigendian) { 121 | if (size > config::maxsize) { 122 | logger::print("value size: %lx exceed maxsize: %lx\n", size, 123 | config::maxsize); 124 | size = config::maxsize; 125 | } 126 | for (size_t i = 0; i < inits.size(); ++i) { 127 | if (inits[i].valid(addr)) { 128 | return inits[i].value(addr - inits[i].begin(), size, bigendian); 129 | } 130 | } 131 | logger::print("address error in value: addr: %lx, size: %lx\n", addr, 132 | size); 133 | return -1; 134 | } 135 | }; 136 | 137 | Inits inits; 138 | 139 | class Memory { 140 | public: 141 | struct MemT { 142 | private: 143 | uint64_t src_; 144 | uint16_t offset_; 145 | uint8_t size_; 146 | uint8_t shift_; 147 | bool bigendian_; 148 | bool tainted_; 149 | 150 | void set(uint64_t src, size_t size, bool bigendian, uint8_t shift, bool tainted) { 151 | src_ = src; 152 | size_ = size; 153 | offset_ = 0; 154 | bigendian_ = bigendian; 155 | shift_ = shift; 156 | tainted_ = tainted; 157 | } 158 | 159 | void clear() { 160 | src_ = 0; 161 | size_ = 0; 162 | offset_ = 0; 163 | shift_ = 0; 164 | tainted_ = false; 165 | bigendian_ = false; 166 | } 167 | 168 | public: 169 | MemT() {} 170 | 171 | void copy(MemT &rhs) { 172 | tainted_ = rhs.isTainted(); 173 | src_ = rhs.src(); 174 | offset_ = rhs.offset(); 175 | size_ = rhs.size(); 176 | shift_ = rhs.shift(); 177 | bigendian_ = rhs.isBigendian(); 178 | } 179 | 180 | inline bool isTainted() { return tainted_; } 181 | 182 | void taint(uint64_t src, size_t size, bool bigendian, uint8_t shift) { 183 | set(src, size - 1, bigendian, shift, true); // mark size 184 | } 185 | 186 | void untaint() { clear(); } 187 | 188 | inline bool isBigendian() { return bigendian_; } 189 | 190 | inline uint64_t src() { return src_; } 191 | 192 | inline size_t offset() { 193 | if (offset_ == 0) { 194 | offset_ = inits.offset(src_); 195 | } 196 | return offset_; 197 | } 198 | 199 | inline size_t size() { 200 | return size_ + 1; // mark size 201 | } 202 | 203 | inline int shift() { 204 | return shift_; 205 | } 206 | 207 | inline uint64_t value(size_t s = 0) { 208 | if (s == 0) s = size(); 209 | if (s > size()) { 210 | logger::print( 211 | "size overflow in value: memory size %lx, input size %lx\n", 212 | size(), s); 213 | } 214 | return inits.value(src_, s, bigendian_); 215 | } 216 | 217 | const char *debug() { 218 | static char buf[256]; 219 | int n = snprintf(buf, sizeof(buf), 220 | "memory :\t\tsrc: %lx, size: %lx, offset: %lx, " 221 | "bigendian: %d, value: %lx\n", 222 | src_, size(), offset(), bigendian_, value()); 223 | buf[n] = 0; 224 | return buf; 225 | } 226 | }; 227 | 228 | MemT &get(uint64_t addr, bool init = false) { 229 | if (memories.count(addr) > 0) { 230 | return memories[addr]; 231 | } 232 | if (init) { 233 | // MemT e; 234 | memories[addr] = MemT(); 235 | return memories[addr]; 236 | } 237 | logger::print("memory invalid addr: %lx\n", addr); 238 | return empty; 239 | } 240 | 241 | bool isTainted(uint64_t addr) { 242 | return memories.count(addr) > 0 && memories[addr].isTainted(); 243 | } 244 | 245 | // init 246 | void taint(uint64_t start, size_t size) { 247 | for (uint64_t addr = start; addr < start + size; ++addr) { 248 | get(addr, true).taint(addr, 1, false, 0); 249 | } 250 | } 251 | 252 | void taint(uint64_t addr, uint64_t src, size_t size, bool bigendian, uint8_t shift) { 253 | logger::info( 254 | "Memory:\tTaint\taddr:%lx\tsrc:%lx\toffset:%lx\tsize:%" 255 | "lx\tbigendian:%d\n", 256 | addr, src, inits.offset(src), size, bigendian); 257 | if (size > 1 && (size & 0x01)) { 258 | logger::print("unexpected size in memory taint: %lx\n", size); 259 | } 260 | size_t n = 0; 261 | while (size > n) { 262 | get(addr + n, true).taint(src + n, size - n, bigendian, shift); 263 | n += 2; 264 | } 265 | } 266 | 267 | void untaint(uint64_t addr) { 268 | MemT &mem = get(addr); 269 | uint64_t src = mem.src(); 270 | size_t size = mem.size(); 271 | size_t offset = mem.offset(); 272 | bool bigendian = mem.isBigendian(); 273 | 274 | logger::info( 275 | "Memory:\tUntaint\taddr:%lx\tsrc:%lx\toffset:%lx\tsize:%" 276 | "lx\tbigendian:%d\n", 277 | addr, src, offset, size, bigendian); 278 | size_t n = 0; 279 | while (size > n) { 280 | get(addr + n).untaint(); 281 | n += 2; 282 | } 283 | } 284 | 285 | uint64_t src(uint64_t addr) { return get(addr).src(); } 286 | 287 | int offset(uint64_t addr) { return get(addr).offset(); } 288 | 289 | size_t size(uint64_t addr) { return get(addr).size(); } 290 | 291 | uint64_t value(uint64_t addr, size_t size = 0) { 292 | return get(addr).value(size); 293 | } 294 | 295 | const char *offsets(uint64_t addr) { 296 | MemT &mem = get(addr); 297 | return util::nums(mem.offset(), mem.size()); 298 | } 299 | 300 | const char *debug(uint64_t addr) { return get(addr).debug(); } 301 | 302 | private: 303 | MemT empty; 304 | std::map memories; 305 | }; 306 | 307 | Memory mems; 308 | 309 | 310 | class Register { 311 | public: 312 | struct RegT { 313 | private: 314 | uint64_t src_; 315 | int8_t shift_; 316 | uint8_t size_; 317 | bool tainted_; 318 | bool bigendian_; 319 | uint16_t index_; 320 | uint16_t offset_; 321 | 322 | void set(uint64_t src, size_t size, bool bigendian, int shift, 323 | bool tainted) { 324 | src_ = src; 325 | size_ = size; 326 | bigendian_ = bigendian; 327 | shift_ = shift; 328 | tainted_ = tainted; 329 | offset_ = 0; 330 | } 331 | 332 | void clear() { 333 | src_ = 0; 334 | size_ = 0; 335 | offset_ = 0; 336 | tainted_ = false; 337 | bigendian_ = false; 338 | shift_ = 0; 339 | } 340 | 341 | size_t regSize() { 342 | const static size_t table[5] = {8, 4, 2, 1, 1}; 343 | size_t regsize = table[index_ % 5]; 344 | return regsize; 345 | } 346 | 347 | const char *name() { return util::regNames[index_]; } 348 | 349 | public: 350 | RegT() { index_ = 3; }; 351 | 352 | RegT(uint16_t index) : index_(index){}; 353 | 354 | void copy(RegT &rhs) { 355 | src_ = rhs.src(); 356 | shift_ = rhs.shift(); 357 | size_ = rhs.size() - 1; // mark size 358 | offset_ = 0; 359 | tainted_ = rhs.isTainted(); 360 | bigendian_ = rhs.isBigendian(); 361 | } 362 | 363 | void taint(uint64_t src, size_t size, bool bigendian, int shift) { 364 | set(src, size - 1, bigendian, shift, true); // mark size 365 | } 366 | 367 | void untaint() { clear(); } 368 | 369 | inline bool isTainted() { return tainted_; } 370 | 371 | inline bool isBigendian() { return bigendian_; } 372 | 373 | void setBigendian(bool b) { bigendian_ = b; } 374 | 375 | inline uint64_t src() { // fix offset bug when ref AL, bug-prone 376 | int diff = size_ + 1 - regSize(); 377 | if (diff <= 0) return src_; 378 | return src_ + diff; 379 | } 380 | 381 | inline size_t offset() { 382 | offset_ = inits.offset(src()); 383 | return offset_; 384 | } 385 | 386 | size_t size() { 387 | size_t regsize = regSize(); 388 | size_t size = size_ + 1; 389 | if (regsize < size) { 390 | logger::print("%s reg size unmatch, reg size %lx, size %lx\n", 391 | name(), regsize, size); 392 | return regsize; 393 | } 394 | return size; 395 | } 396 | 397 | uint64_t value(size_t s = 0) { 398 | if (s == 0) s = size(); 399 | if (s > size()) { 400 | logger::print( 401 | "reg %s size overflow in value: size %lx, input size %lx\n", 402 | name(), size(), s); 403 | } 404 | uint64_t ret = inits.value(src(), s, bigendian_); 405 | if (shift_ > 0) { 406 | ret <<= 8 * shift_; 407 | } else if (shift_ < 0) { 408 | ret >>= 8 * shift_; 409 | } 410 | return ret; 411 | } 412 | 413 | size_t index() { return index_; } 414 | 415 | int shift() { return shift_; } 416 | 417 | void setShift(int shift) { shift_ = shift; } 418 | 419 | void lshift(int8_t s) { 420 | if (s % 8 != 0) return; 421 | shift_ += s / 8; 422 | } 423 | 424 | void rshift(int8_t s) { 425 | if (s % 8 != 0) return; 426 | s /= 8; 427 | shift_ = std::max(shift_ - s, 0); 428 | size_ = std::max(size_ - s, 0); 429 | if (!bigendian_) { 430 | src_ += s; 431 | offset_ += s; 432 | } 433 | } 434 | 435 | const char *debug() { 436 | static char buf[256]; 437 | int n = snprintf(buf, sizeof(buf), 438 | "register %s:\tsrc: %lx, size: %lx, offset: %lx, " 439 | "bigendian: %d, value: %lx, shift: %d\n", 440 | name(), src(), size(), offset(), bigendian_, 441 | value(), shift_); 442 | buf[n] = 0; 443 | return buf; 444 | } 445 | }; 446 | 447 | RegT &get(REG id) { 448 | if (registers.count(id) > 0) { 449 | return registers[id]; 450 | } 451 | RegT e(util::indexOfReg(id)); 452 | registers[id] = e; 453 | return registers[id]; 454 | } 455 | 456 | bool isTainted(REG id) { 457 | return registers.count(id) > 0 && registers[id].isTainted(); 458 | } 459 | 460 | void taint(REG id, uint64_t src, size_t size, bool bigendian, int shift) { 461 | int index = get(id).index(); 462 | index -= index % 5; 463 | for (int i = 0; i < 5; ++i) { 464 | id = util::regs[index + i]; 465 | if (id == 0) continue; 466 | get(id).taint(src, size, bigendian, shift); 467 | } 468 | } 469 | 470 | void untaint(REG id) { 471 | int index = get(id).index() / 5 * 5; 472 | for (int i = 0; i < 5; ++i) { 473 | id = util::regs[index + i]; 474 | if (id == 0) continue; 475 | get(id).untaint(); 476 | } 477 | } 478 | 479 | uint64_t src(REG id) { return get(id).src(); } 480 | 481 | int offset(REG id) { return get(id).offset(); } 482 | 483 | size_t size(REG id) { return get(id).size(); } 484 | 485 | uint64_t value(REG id, size_t size = 0) { return get(id).value(size); } 486 | 487 | void shift(REG id, int offset) { 488 | int index = get(id).index() / 5 * 5; 489 | for (int i = 0; i < 5; ++i) { 490 | id = util::regs[index + i]; 491 | if (id == 0) continue; 492 | RegT ® = get(id); 493 | if (offset >= 0) { 494 | reg.lshift(offset); 495 | } else { 496 | reg.rshift(-offset); 497 | } 498 | } 499 | } 500 | 501 | const char *offsets(REG id) { 502 | RegT ® = get(id); 503 | return util::nums(reg.offset(), reg.size()); 504 | } 505 | 506 | const char *debug(REG id) { return get(id).debug(); } 507 | 508 | private: 509 | RegT empty; 510 | // RegT registers[REG_LAST]; 511 | std::map registers; 512 | }; 513 | 514 | Register regs; 515 | 516 | template 517 | bool adjacent(T1& lhs, T2& rhs) { 518 | int lhs_lower = lhs.shift(); 519 | int lhs_upper = lhs.shift() + lhs.size() - 1; 520 | int rhs_lower = rhs.shift(); 521 | int rhs_upper = rhs.shift() + rhs.size() - 1; 522 | return (lhs_lower - rhs_upper == 1) || (rhs_lower - lhs_upper == 1); 523 | } 524 | 525 | // Wrapper API 526 | 527 | bool isTainted(REG reg) { return regs.isTainted(reg); } 528 | 529 | bool isTainted(uint64_t addr) { return mems.isTainted(addr); } 530 | 531 | int offset(REG reg) { return regs.offset(reg); } 532 | 533 | int offset(uint64_t mem) { return mems.offset(mem); } 534 | 535 | const char *offsets(REG reg) { return regs.offsets(reg); } 536 | 537 | const char *offsets(uint64_t addr) { return mems.offsets(addr); } 538 | 539 | uint64_t value(REG reg, size_t size = 0) { return regs.value(reg, size); } 540 | 541 | uint64_t value(uint64_t addr, size_t size = 0) { 542 | return mems.value(addr, size); 543 | } 544 | 545 | const char *debug(REG reg) { return regs.debug(reg); } 546 | 547 | const char *debug(uint64_t addr) { return mems.debug(addr); } 548 | 549 | uint64_t src(REG reg) { return regs.src(reg); } 550 | 551 | uint64_t src(uint64_t addr) { return mems.src(addr); } 552 | 553 | // init 554 | // use in exit entry point 555 | void Init(size_t start, size_t size) { 556 | if (size > config::maxsize) { 557 | logger::print("Init size exceed maxsize: %lx\n", size); 558 | return; 559 | } 560 | logger::print("Taint\t(%p, %lx)\n", start, size); 561 | logger::info("Taint\t(%p, %lx)\n", start, size); 562 | inits.taint(start, size); 563 | mems.taint(start, size); 564 | } 565 | 566 | // move 567 | void move(REG w, REG r) { 568 | Register::RegT ® = regs.get(r); 569 | regs.taint(w, reg.src(), reg.size(), reg.isBigendian(), reg.shift()); 570 | } 571 | 572 | void move(REG id, uint64_t addr, size_t size) { 573 | Memory::MemT &mem = mems.get(addr, true); 574 | if (!inits.valid(addr)) { 575 | size = std::min(size, mem.size()); 576 | } 577 | regs.taint(id, mem.src(), size, mem.isBigendian(), mem.shift()); 578 | } 579 | 580 | void move(uint64_t addr, REG id, size_t size) { 581 | Register::RegT ® = regs.get(id); 582 | mems.taint(addr, reg.src(), std::min(size, reg.size()), 583 | reg.isBigendian(), reg.shift()); // regsize < size 584 | } 585 | 586 | void move(uint64_t w, uint64_t r, size_t size) { 587 | Memory::MemT &mem_r = mems.get(r); 588 | if (!inits.valid(r)) { 589 | // original source address's size come from input size 590 | size = std::min(size, mem_r.size()); 591 | } 592 | mems.taint(w, mem_r.src(), size, mem_r.isBigendian(), mem_r.shift()); 593 | } 594 | 595 | // remove 596 | 597 | void remove(uint64_t addr) { mems.untaint(addr); } 598 | 599 | void remove(REG id) { regs.untaint(id); } 600 | 601 | // add 602 | bool merge(REG w, REG r) { 603 | char buf[1024]; 604 | if (w == r) return false; 605 | Register::RegT &lhs = regs.get(w); 606 | Register::RegT &rhs = regs.get(r); 607 | int diff_shift = lhs.shift() - rhs.shift(); 608 | int diff_src = lhs.src() - rhs.src(); 609 | if (abs(diff_src) > 3 || !adjacent(lhs, rhs)) { 610 | return false; 611 | } 612 | int n = 0; 613 | n = sprintf(buf + n, "before\n%s%s", debug(w), debug(r)); 614 | 615 | uint64_t src = std::min(lhs.src(), rhs.src()); 616 | size_t size = lhs.size() + rhs.size(); 617 | bool bigendian = 618 | (diff_src > 0 && diff_shift < 0) || (diff_src < 0 && diff_shift > 0); 619 | int shift = std::min(lhs.shift(), rhs.shift()); 620 | 621 | regs.taint(w, src, size, bigendian, shift); 622 | n += sprintf(buf + n, "%s", debug(r)); 623 | buf[n] = 0; 624 | logger::debug("%s", buf); 625 | return true; 626 | } 627 | 628 | 629 | bool merge(REG w, uint64_t r) { 630 | char buf[1024]; 631 | if (w == r) return false; 632 | Register::RegT &lhs = regs.get(w); 633 | Memory::MemT &rhs = mems.get(r); 634 | int diff_shift = lhs.shift() - rhs.shift(); 635 | int diff_src = lhs.src() - rhs.src(); 636 | if (abs(diff_src) > 3 || !adjacent(lhs, rhs)) { 637 | return false; 638 | } 639 | int n = 0; 640 | n = sprintf(buf + n, "before\n%s%s", debug(w), debug(r)); 641 | 642 | uint64_t src = std::min(lhs.src(), rhs.src()); 643 | size_t size = lhs.size() + rhs.size(); 644 | bool bigendian = 645 | (diff_src > 0 && diff_shift < 0) || (diff_src < 0 && diff_shift > 0); 646 | int shift = std::min(lhs.shift(), rhs.shift()); 647 | 648 | regs.taint(w, src, size, bigendian, shift); 649 | n += sprintf(buf + n, "%s", debug(r)); 650 | buf[n] = 0; 651 | logger::debug("%s", buf); 652 | return true; 653 | } 654 | 655 | 656 | bool merge(uint64_t w, REG r) { 657 | char buf[1024]; 658 | if (w == r) return false; 659 | Memory::MemT &lhs = mems.get(w); 660 | Register::RegT &rhs = regs.get(r); 661 | int diff_shift = lhs.shift() - rhs.shift(); 662 | int diff_src = lhs.src() - rhs.src(); 663 | if (abs(diff_src) > 3 || !adjacent(lhs, rhs)) { 664 | return false; 665 | } 666 | int n = 0; 667 | n = sprintf(buf + n, "before\n%s%s", debug(w), debug(r)); 668 | 669 | uint64_t src = std::min(lhs.src(), rhs.src()); 670 | size_t size = lhs.size() + rhs.size(); 671 | bool bigendian = 672 | (diff_src > 0 && diff_shift < 0) || (diff_src < 0 && diff_shift > 0); 673 | int shift = std::min(lhs.shift(), rhs.shift()); 674 | 675 | mems.taint(w, src, size, bigendian, shift); 676 | n += sprintf(buf + n, "%s", debug(r)); 677 | buf[n] = 0; 678 | logger::debug("%s", buf); 679 | return true; 680 | } 681 | 682 | 683 | void shift(REG id, int offset) { regs.shift(id, offset); } 684 | 685 | void and_(REG id, size_t mask) { // uncheck 686 | Register::RegT ® = regs.get(id); 687 | uint64_t src = reg.src(); 688 | 689 | bool bigendian = reg.isBigendian(); 690 | int shift = reg.shift(); 691 | if (shift > 0) { 692 | logger::print("unhandle shift %d, mask %lx\n", shift, mask); 693 | } 694 | if (mask == 0xff) { 695 | if (bigendian) src += 3; 696 | regs.taint(id, src, 1, false, 0); 697 | } else if (mask == 0xff00) { 698 | if (bigendian) 699 | src += 2; 700 | else 701 | src += 1; 702 | regs.taint(id, src, 1, false, 1); 703 | } else if (mask == 0xff0000) { 704 | if (bigendian) 705 | src += 1; 706 | else 707 | src += 2; 708 | regs.taint(id, src, 1, false, 2); 709 | } else if (mask == 0xff000000) { 710 | if (!bigendian) src += 3; 711 | regs.taint(id, src, 1, false, 3); 712 | } else if (mask == 0xffff) { 713 | if (bigendian) src += 2; 714 | regs.taint(id, src, 2, bigendian, 0); 715 | } else if (mask == 0xffff0000) { 716 | if (!bigendian) src += 2; 717 | regs.taint(id, src, 2, bigendian, 2); 718 | } else { 719 | logger::print("unhandle mask %lx\n", mask); 720 | } 721 | } 722 | 723 | } // namespace TaintEngine 724 | 725 | #endif 726 | -------------------------------------------------------------------------------- /src/logic.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _TAINTLOGIC_H 2 | #define _TAINTLOGIC_H 3 | 4 | #include "pin.H" 5 | #include "taintengine.hpp" 6 | #include "util.hpp" 7 | #include "pinobject.hpp" 8 | 9 | // IARG_MEMORYWRITE_SIZE 10 | // IARG_FUNCARG_ENTRYPOINT_VALUE, 0 函数参数 11 | 12 | 13 | std::vector > functraces; 14 | std::vector threadIds; 15 | 16 | void printTrace(int index) { 17 | std::vector::iterator it; 18 | for (it = functraces[index].begin(); it != functraces[index].end(); ++it) { 19 | logger::debug("%s -> ", (*it).c_str()); 20 | } 21 | logger::debug("\n"); 22 | } 23 | 24 | 25 | void enterTrace(int threadId, const std::string* name) { 26 | if (!config::traceLog) return; 27 | const int size = threadIds.size(); 28 | int index; 29 | for (int i = 0; i < size; ++i) { 30 | if (threadIds[i] == threadId) { 31 | index = i; 32 | break; 33 | } 34 | } 35 | if (index == size) { 36 | threadIds.push_back(threadId); 37 | functraces.push_back(std::vector()); 38 | } 39 | functraces[index].push_back(*name); 40 | } 41 | 42 | void exitTrace(int threadId, const std::string* name) { 43 | if (!config::traceLog) return; 44 | const int size = threadIds.size(); 45 | int index; 46 | for (int i = 0; i < size; ++i) { 47 | if (threadIds[i] == threadId) { 48 | index = i; 49 | break; 50 | } 51 | } 52 | if (index == size) { 53 | logger::print("trace exit error\n"); 54 | return; 55 | } 56 | // while (!functraces[index].empty() && functraces[index].back() != *name) { 57 | // functraces[index].pop_back(); 58 | // } 59 | util::myassert(functraces[index].back() == *name); 60 | functraces[index].pop_back(); 61 | } 62 | 63 | void function_entry(int threadId, const std::string* name, uint64_t begin, uint64_t end, uint64_t ret) { 64 | if (*name == config::start_entry) monitor::start(); 65 | if (monitor::invalid(threadId)) return; 66 | enterTrace(threadId, name); 67 | logger::debug("thread id: %d, enter function: %s\n", threadId, util::demangle(name->c_str())); 68 | logger::info("Function\t%d\tenter\t%s\t(%lx,%lx,%lx)\n", threadId, util::demangle(name->c_str()), begin, end, ret); 69 | } 70 | 71 | 72 | void function_exit(int threadId, const std::string* name) { 73 | if (monitor::invalid(threadId)) return; 74 | exitTrace(threadId, name); 75 | logger::debug("thread id: %d, exit function: %s\n", threadId, util::demangle(name->c_str())); 76 | logger::info("Function\t%d\texit \t%s\n", threadId, util::demangle(name->c_str())); 77 | if (*name == config::start_entry) monitor::end(); 78 | } 79 | 80 | void print_functions(const std::string *name, uint64_t para1, uint64_t para2, uint64_t para3, uint64_t para4) { 81 | logger::verbose("%s: %lx %lx %lx %lx\t%s\n", util::demangle(name->c_str()), para1, para2, para3, para4, name->c_str()); 82 | } 83 | 84 | void print_instructions0(const std::string *name, uint64_t address) { 85 | logger::verbose("%p: %s\n", address, name->c_str()); 86 | } 87 | 88 | void print_instructions1(const std::string *name, uint64_t address, const CONTEXT *ctxt, REG r1, REG r2, uint64_t m1, uint64_t m2) { 89 | static char buf[64]; 90 | int n = 0; 91 | if (util::valiReg(r1)) { 92 | n += sprintf(buf + n, " reg(%d, %lx) ", r1, PIN_GetContextReg(ctxt, util::rawReg(r1))); 93 | } 94 | if (util::valiReg(r2)) { 95 | n += sprintf(buf + n, " reg(%d, %lx) ", r2, PIN_GetContextReg(ctxt, util::rawReg(r2))); 96 | } 97 | if (m1 > 0) { 98 | n += sprintf(buf + n, " mem(%lx, %lx) ", m1, util::Value(m1, 8)); 99 | } 100 | if (m2 > 0) { 101 | n += sprintf(buf + n, " mem(%lx, %lx) ", m2, util::Value(m2, 8)); 102 | } 103 | buf[n] = 0; 104 | logger::verbose("%p: %s %s\n", address, name->c_str(), buf); 105 | } 106 | 107 | 108 | void Syscall_point(THREADID thread_id, CONTEXT *ctx, SYSCALL_STANDARD std, void *v) { 109 | if (!monitor::valid()) return; 110 | const char *point = (const char *)v; 111 | ADDRINT number = PIN_GetSyscallNumber(ctx, std); 112 | logger::print("system number: %p in %s\n", number, point); 113 | if (number == __NR_read) { 114 | int fd = static_cast((PIN_GetSyscallArgument(ctx, std, 0))); 115 | uint64_t start = static_cast((PIN_GetSyscallArgument(ctx, std, 1))); 116 | size_t size = static_cast((PIN_GetSyscallArgument(ctx, std, 2))); 117 | if (filter::read(fd, start, size)) return; 118 | logger::print("%s read: fd: %d, start: %p, size: %p\n", point, fd, start, size); 119 | if (!filter::taint_start()) return; 120 | logger::debug("[TAINT]\t %p bytes tainted from %p to %p (via read %s fd: %d)\n", size, start, start+size, point, fd); 121 | TaintEngine::Init(start, size); 122 | } 123 | } 124 | 125 | 126 | static int cur_sock = -1; 127 | 128 | 129 | void read_point(const char *point, int fd, uint64_t buffer, size_t length, ssize_t ret) { 130 | static int _fd; 131 | static uint64_t _buffer; 132 | static size_t _length; 133 | if (!monitor::valid() || !filter::taint_start()) return; 134 | 135 | if (point == filter::entry) { 136 | _fd = fd; 137 | _buffer = buffer; 138 | _length = length; 139 | } 140 | 141 | if (filter::read(_fd, _buffer, _length)) return; 142 | 143 | if (point == filter::exit) { 144 | logger::print("read(fd: %d, buffer: %p, length: %p) => %zd\n", _fd, _buffer, _length, ret); 145 | logger::debug("[TAINT]\t %p bytes tainted from %p to %p (via recv socket: %d)\n", _length, _buffer, _buffer+_length, _fd); 146 | TaintEngine::Init(_buffer, ret); 147 | } 148 | } 149 | 150 | 151 | void write_point(const char *point, int fd, uint64_t buffer, size_t length, ssize_t ret) { 152 | static int _fd; 153 | static uint64_t _buffer; 154 | static size_t _length; 155 | if (monitor::valid() || !filter::taint_start()) return; 156 | 157 | if (point == filter::entry) { 158 | _fd = fd; 159 | _buffer = buffer; 160 | _length = length; 161 | } 162 | if (_fd != cur_sock) return; 163 | 164 | if (point == filter::exit) { 165 | logger::info("Trace Address (write) :\t%lx\t%d\t%d\n", _buffer, _length, ret); 166 | } 167 | } 168 | 169 | 170 | void send_point(const char *point, int socket, uint64_t buffer, size_t length, int flags, ssize_t ret) { 171 | static int _socket; 172 | static uint64_t _buffer; 173 | static size_t _length; 174 | if (!monitor::valid() || !filter::taint_start()) return; 175 | 176 | if (point == filter::entry) { 177 | _socket = socket; 178 | _buffer = buffer; 179 | _length = length; 180 | } 181 | 182 | if (_socket != cur_sock) return; 183 | 184 | if (point == filter::exit) { 185 | logger::info("Trace Address (send) :\t%lx\t%d\t%d\n", _buffer, _length, ret); 186 | } 187 | } 188 | 189 | 190 | void sendto_point(const char *point, int socket, uint64_t buffer, size_t length, int flags, struct sockaddr *address, socklen_t address_len, ssize_t ret){ 191 | static int _socket; 192 | static uint64_t _buffer; 193 | static size_t _length; 194 | if (!monitor::valid() || !filter::taint_start()) return; 195 | 196 | if (point == filter::entry) { 197 | _socket = socket; 198 | _buffer = buffer; 199 | _length = length; 200 | } 201 | 202 | if (_socket != cur_sock) return; 203 | 204 | if (point == filter::exit) { 205 | logger::info("Trace Address (sendto) :\t%lx\t%d\t%d\n", _buffer, _length, ret); 206 | } 207 | } 208 | 209 | 210 | void sendmsg_point(const char *point, int socket, struct msghdr* mhdr, int flags, ssize_t ret) { 211 | static int _socket; 212 | static uint64_t _buffer; 213 | static size_t _length; 214 | if (!monitor::valid() || !filter::taint_start()) return; 215 | if (point == filter::entry) { 216 | _socket = socket; 217 | _buffer = (uint64_t) mhdr->msg_iov[0].iov_base; 218 | _length = mhdr->msg_iov->iov_len; 219 | } 220 | 221 | if (_socket != cur_sock) return; 222 | 223 | if (point == filter::exit) { 224 | logger::info("Trace Address (sendmsg) :\t%lx\t%d\t%d\n", _buffer, _length, ret); 225 | } 226 | } 227 | 228 | 229 | void recv_point(const char *point, int socket, uint64_t buffer, size_t length, int flags, ssize_t ret) { 230 | static int _socket; 231 | static uint64_t _buffer; 232 | static size_t _length; 233 | static int _flags; 234 | if (!monitor::valid() || !filter::taint_start()) return; 235 | 236 | if (point == filter::entry) { 237 | _socket = socket; 238 | _buffer = buffer; 239 | _length = length; 240 | } 241 | if (filter::read(_socket, _buffer, _length)) return; 242 | 243 | if (point == filter::exit) { 244 | cur_sock = _socket; 245 | logger::print("recv(socket: %d, buffer: %p, length: %p, flags: %d) => %zd\n", _socket, _buffer, _length, _flags, ret); 246 | logger::debug("[TAINT]\t %p bytes tainted from %p to %p (via recv socket: %d)\n", _length, _buffer, _buffer+_length, _socket); 247 | if (TaintEngine::isTainted(REG_RDX)) { // log if size is tainted 248 | logger::info("LENGTH\t%s\n", TaintEngine::offsets(REG_RDX)); 249 | } 250 | TaintEngine::Init(_buffer, ret); 251 | } 252 | } 253 | 254 | 255 | void recvfrom_point(const char *point, int socket, uint64_t buffer, size_t length, int flags, struct sockaddr *address, socklen_t *address_len, ssize_t ret){ 256 | static int _socket; 257 | static uint64_t _buffer; 258 | static size_t _length; 259 | static int _flags; 260 | if (!monitor::valid() || !filter::taint_start()) return; 261 | 262 | if (point == filter::entry) { 263 | _socket = socket; 264 | _buffer = buffer; 265 | _length = length; 266 | } 267 | 268 | if (filter::read(_socket, _buffer, _length)) return; 269 | 270 | if (point == filter::exit) { 271 | cur_sock = _socket; 272 | logger::print("recvfrom(socket: %d, buffer: %p, length: %p, flags: %d) => %zd\n", _socket, _buffer, _length, _flags, ret); 273 | logger::debug("[TAINT]\t %p bytes tainted from %p to %p (via recvfrom socket: %d)\n", _length, _buffer, _buffer+_length, _socket); 274 | if (TaintEngine::isTainted(REG_RDX)) { // log if size is tainted 275 | logger::info("LENGTH\t%s\n", TaintEngine::offsets(REG_RDX)); 276 | } 277 | TaintEngine::Init(_buffer, ret); 278 | } 279 | } 280 | 281 | 282 | void recvmsg_point(const char *point, int socket, struct msghdr* mhdr, int flags, ssize_t ret) { 283 | static int _socket; 284 | static struct msghdr* _mhdr; 285 | static int _flags; 286 | static uint64_t _buffer; 287 | if (!monitor::valid() || !filter::taint_start()) return; 288 | 289 | if (point == filter::entry) { 290 | _socket = socket; 291 | _mhdr = mhdr; 292 | _flags = flags; 293 | _buffer = (uint64_t) mhdr->msg_iov[0].iov_base; 294 | // size_t len = message->msg_iovlen; 295 | } 296 | 297 | if (point == filter::exit) { 298 | ssize_t _length = ret; 299 | if (filter::read(_socket, _buffer, _length)) return; 300 | cur_sock = _socket; 301 | if (_length > 0) { 302 | logger::print("recvmsg(socket: %d, mhdr: %p, flags: %d) => %zd\n", _socket, _mhdr, _flags, _length); 303 | logger::debug("[TAINT]\t %p bytes tainted from %p to %p (via recvmsg socket: %d)\n", _length, _buffer, _buffer+_length, _socket); 304 | TaintEngine::Init(_buffer, _length); 305 | } 306 | } 307 | } 308 | 309 | 310 | void memcpy_point(const char *point, uint64_t dst, uint64_t src, size_t size) { 311 | if (!monitor::valid()) return; 312 | logger::info("Trace Copy:\t%lx\t%lx\t%d\n", dst, src, size); 313 | for (size_t i = 0; i < size;) { 314 | if (TaintEngine::isTainted(src + i)) { 315 | size_t s = i; 316 | while (i < size && TaintEngine::isTainted(src + i)) ++i; 317 | logger::print("memcpy(dst: %p, src: %p, size: %p)\n", dst + s, src + s, i - s); 318 | logger::debug("[COPY]\t %p bytes from %p to %p (via memcpy)\n", i - s, src + s, dst + s); 319 | TaintEngine::Init(dst + s, i - s); 320 | } else { 321 | ++i; 322 | } 323 | } 324 | } 325 | 326 | 327 | void memmove_point(const char *point, uint64_t dst, uint64_t src, size_t size) { 328 | if (!monitor::valid()) return; 329 | logger::info("Trace Copy:\t%lx\t%lx\t%d\n", dst, src, size); 330 | for (size_t i = 0; i < size;) { 331 | if (TaintEngine::isTainted(src + i)) { 332 | size_t s = i; 333 | while (i < size && TaintEngine::isTainted(src + i)) ++i; 334 | logger::print("memmove(dst: %p, src: %p, size: %p)\n", dst + s, src + s, i - s); 335 | logger::debug("[COPY]\t %p bytes from %p to %p (via memcpy)\n", i - s, src + s, dst + s); 336 | TaintEngine::Init(dst + s, i - s); 337 | } else { 338 | ++i; 339 | } 340 | } 341 | } 342 | 343 | 344 | // reg <- mem 345 | void ReadMem(int threadId, const std::string* assembly, unsigned long address, REG reg, UINT64 mem, USIZE size) { 346 | if (monitor::invalid(threadId)) return; 347 | bool taint_w = TaintEngine::isTainted(reg); 348 | bool taint_r = TaintEngine::isTainted(mem); 349 | ADDRINT value = util::Value(mem, size); 350 | if (!taint_w && !taint_r) { 351 | logger::debug("Not Taint %p: %s\t mem: %p\tvalue: %p\n", address, assembly->c_str(), mem, value); 352 | return; 353 | } 354 | debug::log(address, assembly->c_str()); 355 | util::LockGuard lock(threadId); 356 | if (taint_r) { // retaint 357 | TaintEngine::move(reg, mem, size); 358 | logger::debug("thread: %d [+ Reg <- Mem]\t%p: %s\t addr: %p value: (%p, %p)\n%s%s\n", 359 | threadId, 360 | address, assembly->c_str(), mem, TaintEngine::src(mem), value, 361 | TaintEngine::debug(mem), 362 | TaintEngine::debug(reg) 363 | ); 364 | 365 | logger::info("Instruction %p: %s\t%d\t%s\t%p\t%p\n", 366 | address, assembly->c_str(), threadId, 367 | TaintEngine::offsets(mem), TaintEngine::src(mem), value); 368 | } else if (taint_w && !taint_r) { // untaint 369 | logger::debug("thread: %d [- Reg <- Mem]\t%p: %s\t addr: %p\n%s\n", 370 | threadId, 371 | address, assembly->c_str(), mem, 372 | TaintEngine::debug(reg) 373 | ); 374 | TaintEngine::remove(reg); 375 | } 376 | } 377 | 378 | // mem <- reg 379 | void WriteMem(int threadId, const std::string* assembly, unsigned long address, UINT64 mem, REG reg, ADDRINT value, USIZE size) { 380 | if (monitor::invalid(threadId)) return; 381 | bool taint_w = TaintEngine::isTainted(mem); 382 | bool taint_r = TaintEngine::isTainted(reg); 383 | 384 | int offset = taint_r ? TaintEngine::offset(reg) : -1; 385 | logger::info("Trace %p: %s\t%lx\t%d\t%lx\t%d\n", address, assembly->c_str(), mem, size, value, offset); 386 | 387 | if (!taint_w && !taint_r) { 388 | logger::debug("Not Taint %p: %s\tmem: %p\tvalue: %p\n", address, assembly->c_str(), mem, value); 389 | return; 390 | } 391 | 392 | debug::log(address, assembly->c_str()); 393 | util::LockGuard lock(threadId); 394 | if (taint_r) { // retaint 395 | TaintEngine::move(mem, reg, size); // change src 396 | logger::debug("thread: %d [+ Mem <- Reg]\t%p: %s\t addr: %p value: (%p, %p)\n%s%s\n", 397 | threadId, 398 | address, assembly->c_str(), mem, TaintEngine::src(reg), value, 399 | TaintEngine::debug(reg), 400 | TaintEngine::debug(mem) 401 | ); 402 | logger::info("Instruction %p: %s\t%d\t%s\t%p\t%p\n", 403 | address, assembly->c_str(), threadId, 404 | TaintEngine::offsets(reg), TaintEngine::src(reg), value); 405 | } else if (taint_w && !taint_r) { // untaint 406 | logger::debug("thread: %d [- Mem <- Reg]\t%p: %s\t addr: %p\n%s\n", 407 | threadId, 408 | address, assembly->c_str(), mem, 409 | TaintEngine::debug(mem) 410 | ); 411 | TaintEngine::remove(mem); 412 | } 413 | } 414 | 415 | // reg <- reg 416 | void spreadReg(int threadId, const std::string* assembly, unsigned long address, REG reg_w, REG reg_r, ADDRINT value) { 417 | if (monitor::invalid(threadId)) return; 418 | bool taint_w = TaintEngine::isTainted(reg_w); 419 | bool taint_r = TaintEngine::isTainted(reg_r); 420 | if (!taint_w && !taint_r) { 421 | logger::debug("Not Taint %p: %s\tvalue: %p\n", address, assembly->c_str(), value); 422 | return; 423 | } 424 | 425 | debug::log(address, assembly->c_str()); 426 | util::LockGuard lock(threadId); 427 | if (taint_r) { // retaint 428 | TaintEngine::move(reg_w, reg_r); 429 | logger::debug("thread: %d [+ Reg <- Reg]\t%p: %s value: (%p, %p)\n%s%s\n", 430 | threadId, 431 | address, assembly->c_str(), TaintEngine::src(reg_r), value, 432 | TaintEngine::debug(reg_r), 433 | TaintEngine::debug(reg_w) 434 | ); 435 | 436 | logger::info("Instruction %p: %s\t%d\t%s\t%p\t%p\n", 437 | address, assembly->c_str(), threadId, 438 | TaintEngine::offsets(reg_r), TaintEngine::src(reg_r), value); 439 | } else if (taint_w && !taint_r) { // untaint 440 | logger::debug("thread: %d [- Reg <- Reg]\t%p: %s\n%s\n", 441 | threadId, 442 | address, assembly->c_str(), 443 | TaintEngine::debug(reg_w) 444 | ); 445 | TaintEngine::remove(reg_w); 446 | } 447 | } 448 | 449 | // mem <- mem 450 | void spreadMem(int threadId, const std::string* assembly, unsigned long address, UINT64 mem_w, UINT64 mem_r, USIZE size) { 451 | if (monitor::invalid(threadId)) return; 452 | bool taint_w = TaintEngine::isTainted(mem_w); 453 | bool taint_r = TaintEngine::isTainted(mem_r); 454 | ADDRINT value = util::Value(mem_r, size); 455 | 456 | int offset = taint_r ? TaintEngine::offset(mem_r) : -1; 457 | logger::info("Trace %p: %s\t%lx\t%d\t%lx\t%d\n", 458 | address, assembly->c_str(), mem_w, size, value, offset); 459 | 460 | if (!taint_w && !taint_r) { 461 | logger::debug("Not Taint %p: %s\t mem: %p <- %p\tvalue: %p\n", address, assembly->c_str(), mem_w, mem_r, value); 462 | return; 463 | } 464 | 465 | debug::log(address, assembly->c_str()); 466 | util::LockGuard lock(threadId); 467 | if (taint_r) { // retaint 468 | TaintEngine::move(mem_w, mem_r, size); 469 | 470 | logger::debug("thread: %d [+ Mem <- Mem]\t%p: %s\t mem_w: %p mem_r: %p value: (%p, %p)\n%s%s\n", 471 | threadId, 472 | address, assembly->c_str(), mem_w, mem_r, TaintEngine::src(mem_r), value, 473 | TaintEngine::debug(mem_r), 474 | TaintEngine::debug(mem_w) 475 | ); 476 | 477 | logger::info("Instruction %p: %s\t%d\t%s\t%p\t%p\n", 478 | address, assembly->c_str(), threadId, 479 | TaintEngine::offsets(mem_r), TaintEngine::src(mem_r), value); 480 | } else if (taint_w && !taint_r) { // untaint 481 | TaintEngine::remove(mem_w); 482 | 483 | logger::debug("thread: %d [- Mem <- Mem]\t%p: %s\t mem_w: %p mem_r: %p\n%s\n", 484 | threadId, 485 | address, assembly->c_str(), mem_w, mem_r, 486 | TaintEngine::debug(mem_w) 487 | ); 488 | } 489 | } 490 | 491 | // reg <- imm 492 | void deleteReg(int threadId, const std::string* assembly, unsigned long address, REG reg) { 493 | if (monitor::invalid(threadId)) return; 494 | if (TaintEngine::isTainted(reg)) { 495 | debug::log(address, assembly->c_str()); 496 | util::LockGuard lock(threadId); 497 | logger::debug("thread: %d [DELETE Reg]\t%p : %s\n%s\n", 498 | threadId, 499 | address, assembly->c_str(), 500 | TaintEngine::debug(reg) 501 | ); 502 | TaintEngine::remove(reg); 503 | } 504 | } 505 | 506 | // mem <- imm 507 | void deleteMem(int threadId, const std::string* assembly, unsigned long address, UINT64 mem, USIZE size) { 508 | if (monitor::invalid(threadId)) return; 509 | logger::info("Trace %p: %s\t%lx\t%d\t%d\n", address, assembly->c_str(), mem, size, -2); 510 | if (TaintEngine::isTainted(mem)) { 511 | debug::log(address, assembly->c_str()); 512 | util::LockGuard lock(threadId); 513 | ADDRINT value = util::Value(mem, size); 514 | 515 | logger::debug("thread: %d [DELETE Mem]\t\t%p: %s value: %p\n%s\n", 516 | threadId, 517 | address, assembly->c_str(), value, 518 | TaintEngine::debug(mem) 519 | ); 520 | 521 | TaintEngine::remove(mem); 522 | } 523 | } 524 | 525 | 526 | //Insert Logic 527 | 528 | // ReadMem 529 | void InsertCall(Ins ins, REG reg, int mem) { 530 | const std::string *insName = new std::string(ins.Name()); 531 | INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)ReadMem, 532 | IARG_THREAD_ID, 533 | IARG_PTR, insName, IARG_INST_PTR, 534 | IARG_ADDRINT, reg, 535 | IARG_MEMORYOP_EA, mem, 536 | IARG_ADDRINT, ins.MemRSize(), 537 | IARG_END); 538 | } 539 | 540 | // WriteMem 541 | void InsertCall(Ins ins, int mem, REG reg) { 542 | const std::string *insName = new std::string(ins.Name()); 543 | INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)WriteMem, 544 | IARG_THREAD_ID, 545 | IARG_PTR, insName, IARG_INST_PTR, 546 | IARG_MEMORYOP_EA, mem, 547 | IARG_ADDRINT, reg, 548 | IARG_REG_VALUE, reg, 549 | IARG_ADDRINT, ins.MemWSize(), 550 | IARG_END); 551 | } 552 | 553 | // spreadMem 554 | void InsertCall(Ins ins, int mem_w, int mem_r) { 555 | const std::string *insName = new std::string(ins.Name()); 556 | INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)spreadMem, 557 | IARG_THREAD_ID, 558 | IARG_PTR, insName, IARG_INST_PTR, 559 | IARG_MEMORYOP_EA, mem_w, 560 | IARG_MEMORYOP_EA, mem_r, 561 | IARG_ADDRINT, ins.MemRSize(), 562 | IARG_END); 563 | } 564 | 565 | // spreadReg 566 | void InsertCall(Ins ins, REG reg_w, REG reg_r) { 567 | const std::string *insName = new std::string(ins.Name()); 568 | INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)spreadReg, 569 | IARG_THREAD_ID, 570 | IARG_PTR, insName, IARG_INST_PTR, 571 | IARG_ADDRINT, reg_w, 572 | IARG_ADDRINT, reg_r, 573 | IARG_REG_VALUE, reg_r, 574 | IARG_END); 575 | } 576 | 577 | // delete mem 578 | void InsertCall(Ins ins, int mem) { 579 | const std::string *insName = new std::string(ins.Name()); 580 | INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)deleteMem, 581 | IARG_THREAD_ID, 582 | IARG_PTR, insName, IARG_INST_PTR, 583 | IARG_MEMORYOP_EA, mem, 584 | IARG_ADDRINT, ins.MemWSize(), 585 | IARG_END); 586 | } 587 | 588 | // delete reg 589 | void InsertCall(Ins ins, REG reg) { 590 | const std::string *insName = new std::string(ins.Name()); 591 | INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)deleteReg, 592 | IARG_THREAD_ID, 593 | IARG_PTR, insName, IARG_INST_PTR, 594 | IARG_ADDRINT, reg, 595 | IARG_END); 596 | } 597 | 598 | 599 | // 3 Ops 600 | 601 | // reg <- reg 602 | void Op3RegReg(int threadId, const std::string* assembly, unsigned long address, int opcode, REG reg_w, REG reg_r, ADDRINT value_w, ADDRINT value_r) { 603 | if (monitor::invalid(threadId)) return; 604 | bool taint_w = TaintEngine::isTainted(reg_w); 605 | bool taint_r = TaintEngine::isTainted(reg_r); 606 | if (!taint_w && !taint_r) return; 607 | debug::log(address, assembly->c_str()); 608 | util::LockGuard lock(threadId); 609 | 610 | char buf[32]; 611 | int n = 0; 612 | if (taint_w) { 613 | n += sprintf(buf + n, "%s", TaintEngine::offsets(reg_w)); 614 | } 615 | if (taint_r) { 616 | n += sprintf(buf + n, ";%s", TaintEngine::offsets(reg_r)); 617 | } 618 | buf[n] = 0; 619 | 620 | logger::info("Instruction %p: %s\t%d\t%s\t%p;%p\n", 621 | address, assembly->c_str(), threadId, 622 | buf, value_w, value_r); 623 | 624 | 625 | if (taint_w && taint_r && (opcode == XED_ICLASS_ADD || opcode == XED_ICLASS_OR) && reg_w != reg_r) { 626 | if (TaintEngine::merge(reg_w, reg_r)) { 627 | logger::info("Instruction %p: %s\t%d\t%s\t%p\n", 628 | address, assembly->c_str(), 629 | threadId, 630 | TaintEngine::offsets(reg_w), value_w); 631 | } 632 | } else if ((opcode == XED_ICLASS_XOR || opcode == XED_ICLASS_SUB) && reg_w == reg_r) { 633 | TaintEngine::remove(reg_w); 634 | } 635 | 636 | logger::debug("[USE RegReg]\t\t%p: %s value: %p, opcode: %d\n%s%s\n", 637 | address, assembly->c_str(), value_w, opcode, 638 | taint_w ? TaintEngine::debug(reg_w) : "", 639 | taint_r ? TaintEngine::debug(reg_r) : "" 640 | ); 641 | } 642 | 643 | void InsertCallExtra(Ins ins, REG reg_w, REG reg_r) { // Reg Reg 644 | const std::string *insName = new std::string(ins.Name()); 645 | INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Op3RegReg, 646 | IARG_THREAD_ID, 647 | IARG_PTR, insName, IARG_INST_PTR, 648 | IARG_ADDRINT, ins.OpCode(), 649 | IARG_ADDRINT, reg_w, 650 | IARG_ADDRINT, reg_r, 651 | IARG_REG_VALUE, reg_w, 652 | IARG_REG_VALUE, reg_r, 653 | IARG_END); 654 | } 655 | 656 | void Op3RegImm(int threadId, const std::string* assembly, unsigned long address, int opcode, REG reg, ADDRINT value, int imm) { 657 | if (monitor::invalid(threadId)) return; 658 | if (TaintEngine::isTainted(reg)) { 659 | debug::log(address, assembly->c_str()); 660 | util::LockGuard lock(threadId); 661 | if (opcode == XED_ICLASS_SHL) { 662 | TaintEngine::shift(reg, imm); 663 | } else if (opcode == XED_ICLASS_SHR || opcode == XED_ICLASS_SAR || opcode == XED_ICLASS_ROR) { 664 | TaintEngine::shift(reg, -imm); 665 | // ror uncheck 666 | // add ROL switch: rol ax 667 | } else if (opcode == XED_ICLASS_AND) { // and uncheck 668 | TaintEngine::and_(reg, imm); 669 | } 670 | logger::debug("[USE RegImm]\t\t%p: %s value: %p, opcode: %d, imm: %d\n%s\n", 671 | address, assembly->c_str(), value, opcode, imm, 672 | TaintEngine::debug(reg) 673 | ); 674 | logger::info("Instruction %p: %s\t%d\t%s\t%p\n", 675 | address, assembly->c_str(), threadId, 676 | TaintEngine::offsets(reg), value); 677 | } 678 | } 679 | 680 | void InsertCallExtra(Ins ins, REG reg) { // Reg Imm 681 | const std::string *insName = new std::string(ins.Name()); 682 | INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Op3RegImm, 683 | IARG_THREAD_ID, 684 | IARG_PTR, insName, IARG_INST_PTR, 685 | IARG_ADDRINT, ins.OpCode(), 686 | IARG_ADDRINT, reg, 687 | IARG_REG_VALUE, reg, 688 | IARG_ADDRINT, ins.valueImm(1), 689 | IARG_END); 690 | } 691 | 692 | void Op3RegMem(int threadId, const std::string* assembly, unsigned long address, int opcode, REG reg, ADDRINT value_w, UINT64 mem, USIZE size) { 693 | if (monitor::invalid(threadId)) return; 694 | bool taint_w = TaintEngine::isTainted(reg); 695 | bool taint_r = TaintEngine::isTainted(mem); 696 | if (!taint_w && !taint_r) return; 697 | debug::log(address, assembly->c_str()); 698 | util::LockGuard lock(threadId); 699 | ADDRINT value_r = util::Value(mem, size); 700 | 701 | char buf[32]; 702 | int n = 0; 703 | if (taint_w) { 704 | n += sprintf(buf + n, "%s", TaintEngine::offsets(reg)); 705 | } 706 | if (taint_r) { 707 | n += sprintf(buf + n, ";%s", TaintEngine::offsets(mem)); 708 | } 709 | buf[n] = 0; 710 | 711 | logger::info("Instruction %p: %s\t%d\t%s\t%p;%p\n", 712 | address, assembly->c_str(), threadId, 713 | buf, value_w, value_r); 714 | 715 | if (taint_w && taint_r && (opcode == XED_ICLASS_ADD || opcode == XED_ICLASS_OR)) { 716 | if (TaintEngine::merge(reg, mem)) { 717 | logger::info("Instruction %p: %s\t%d\t%s\t%p\n", 718 | address, assembly->c_str(), threadId, 719 | TaintEngine::offsets(reg), value_w); 720 | } 721 | } 722 | logger::debug("[USE RegMem]\t\t%p: %s value: %p, opcode: %d\n%s%s\n", 723 | address, assembly->c_str(), value_w, opcode, 724 | taint_w ? TaintEngine::debug(reg) : "", 725 | taint_r ? TaintEngine::debug(mem) : "" 726 | ); // TODO 727 | } 728 | 729 | void InsertCallExtra(Ins ins, REG reg, int mem) { // Reg Mem 730 | const std::string *insName = new std::string(ins.Name()); 731 | INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Op3RegMem, 732 | IARG_THREAD_ID, 733 | IARG_PTR, insName, IARG_INST_PTR, 734 | IARG_ADDRINT, ins.OpCode(), 735 | IARG_ADDRINT, reg, 736 | IARG_REG_VALUE, reg, 737 | IARG_MEMORYOP_EA, mem, 738 | IARG_ADDRINT, ins.MemRSize(), 739 | IARG_END); 740 | } 741 | 742 | 743 | void Op3MemReg(int threadId, const std::string* assembly, unsigned long address, int opcode, UINT64 mem, REG reg, ADDRINT value_r, USIZE size) { 744 | if (monitor::invalid(threadId)) return; 745 | bool taint_w = TaintEngine::isTainted(mem); 746 | bool taint_r = TaintEngine::isTainted(reg); 747 | if (!taint_w && !taint_r) return; 748 | debug::log(address, assembly->c_str()); 749 | util::LockGuard lock(threadId); 750 | ADDRINT value_w = util::Value(mem, size); 751 | 752 | char buf[32]; 753 | int n = 0; 754 | if (taint_w) { 755 | n += sprintf(buf + n, "%s", TaintEngine::offsets(mem)); 756 | } 757 | if (taint_r) { 758 | n += sprintf(buf + n, ";%s", TaintEngine::offsets(reg)); 759 | } 760 | buf[n] = 0; 761 | 762 | logger::info("Instruction %p: %s\t%d\t%s\t%p;%p\n", 763 | address, assembly->c_str(), threadId, 764 | buf, value_w, value_r); 765 | 766 | if (taint_w && taint_r && (opcode == XED_ICLASS_ADD || opcode == XED_ICLASS_OR)) { 767 | if (TaintEngine::merge(mem, reg)) { 768 | logger::info("Instruction %p: %s\t%d\t%s\t%p\n", 769 | address, assembly->c_str(), threadId, 770 | TaintEngine::offsets(mem), value_w); 771 | } 772 | } 773 | logger::debug("[USE RegMem]\t\t%p: %s value: %p, opcode: %d\n%s%s\n", 774 | address, assembly->c_str(), value_w, opcode, 775 | taint_w ? TaintEngine::debug(mem) : "", 776 | taint_r ? TaintEngine::debug(reg) : "" 777 | ); // TODO 778 | } 779 | 780 | void InsertCallExtra(Ins ins, int mem, REG reg) { // Mem Reg 781 | const std::string *insName = new std::string(ins.Name()); 782 | INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Op3MemReg, 783 | IARG_THREAD_ID, 784 | IARG_PTR, insName, IARG_INST_PTR, 785 | IARG_ADDRINT, ins.OpCode(), 786 | IARG_MEMORYOP_EA, mem, 787 | IARG_ADDRINT, reg, 788 | IARG_REG_VALUE, reg, 789 | IARG_ADDRINT, ins.MemWSize(), 790 | IARG_END); 791 | } 792 | 793 | void Op3MemImm(int threadId, const std::string* assembly, unsigned long address, int opcode, UINT64 mem, USIZE size) { 794 | if (monitor::invalid(threadId)) return; 795 | if (TaintEngine::isTainted(mem)) { 796 | debug::log(address, assembly->c_str()); 797 | util::LockGuard lock(threadId); 798 | ADDRINT value = util::Value(mem, size); 799 | logger::debug("[USE MemImm]\t\t%p: %s value: %p, opcode: %d\n%s\n", 800 | address, assembly->c_str(), value, opcode, 801 | TaintEngine::debug(mem) 802 | ); 803 | logger::info("Instruction %p: %s\t%d\t%s\t%p\n", 804 | address, assembly->c_str(), threadId, 805 | TaintEngine::offsets(mem), value); 806 | } 807 | } 808 | 809 | 810 | void InsertCallExtra(Ins ins, int mem) { // Mem Imm 811 | const std::string *insName = new std::string(ins.Name()); 812 | INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)Op3MemImm, 813 | IARG_THREAD_ID, 814 | IARG_PTR, insName, IARG_INST_PTR, 815 | IARG_ADDRINT, ins.OpCode(), 816 | IARG_MEMORYOP_EA, mem, 817 | IARG_ADDRINT, ins.MemWSize(), 818 | IARG_END); 819 | } 820 | 821 | #endif 822 | // taint logic end 823 | -------------------------------------------------------------------------------- /result/snap7/output.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | G 11 | 12 | 13 | TIsoTcpWo\nrker-Exec\nuteRecv-7 14 | 15 | TIsoTcpWo 16 | rker-Exec 17 | uteRecv 18 | 19 | 20 | TIsoTcpSocke\nt-isoRecvPDU-9 21 | 22 | TIsoTcpSocke 23 | t-isoRecvPDU 24 | 25 | 26 | TIsoTcpWo\nrker-Exec\nuteRecv-7--TIsoTcpSocke\nt-isoRecvPDU-9 27 | 28 | 29 | 30 | TIsoTcpSock\net-IsoPeek-39 31 | 32 | TIsoTcpSock 33 | et-IsoPeek 34 | 35 | 36 | TIsoTcpWo\nrker-Exec\nuteRecv-7--TIsoTcpSock\net-IsoPeek-39 37 | 38 | 39 | 40 | TS7Worker\n-IsoPerfo\nrmCommand-43 41 | 42 | TS7Worker 43 | -IsoPerfo 44 | rmCommand 45 | 46 | 47 | TIsoTcpWo\nrker-Exec\nuteRecv-7--TS7Worker\n-IsoPerfo\nrmCommand-43 48 | 49 | 50 | 51 | TIsoTcpSoc\nket-isoRec\nvFragment-11 52 | 53 | TIsoTcpSoc 54 | ket-isoRec 55 | vFragment 56 | 57 | 58 | TIsoTcpSocke\nt-isoRecvPDU-9--TIsoTcpSoc\nket-isoRec\nvFragment-11 59 | 60 | 61 | 62 | 6, [2, 3]-37 63 | 64 | 6, [2, 3] 65 | 66 | 67 | TIsoTcpSocke\nt-isoRecvPDU-9--6, [2, 3]-37 68 | 69 | 70 | 71 | 6-1 72 | 73 | 6 74 | 75 | 76 | TIsoTcpSoc\nket-isoRec\nvFragment-11--6-1 77 | 78 | 79 | 80 | TIsoTcpSock\net-PDUSize-19 81 | 82 | TIsoTcpSock 83 | et-PDUSize 84 | 85 | 86 | TIsoTcpSoc\nket-isoRec\nvFragment-11--TIsoTcpSock\net-PDUSize-19 87 | 88 | 89 | 90 | [2, 3]-21 91 | 92 | [2, 3] 93 | 94 | 95 | TIsoTcpSoc\nket-isoRec\nvFragment-11--[2, 3]-21 96 | 97 | 98 | 99 | TIsoTcpSock\net-CheckPDU-22 100 | 101 | TIsoTcpSock 102 | et-CheckPDU 103 | 104 | 105 | TIsoTcpSoc\nket-isoRec\nvFragment-11--TIsoTcpSock\net-CheckPDU-22 106 | 107 | 108 | 109 | [2, 3]-27 110 | 111 | [2, 3] 112 | 113 | 114 | TIsoTcpSoc\nket-isoRec\nvFragment-11--[2, 3]-27 115 | 116 | 117 | 118 | TMsgSocket-\nRecvPacket-28 119 | 120 | TMsgSocket- 121 | RecvPacket 122 | 123 | 124 | TIsoTcpSoc\nket-isoRec\nvFragment-11--TMsgSocket-\nRecvPacket-28 125 | 126 | 127 | 128 | [2, 3]-36 129 | 130 | [2, 3] 131 | 132 | 133 | TIsoTcpSoc\nket-isoRec\nvFragment-11--[2, 3]-36 134 | 135 | 136 | 137 | 2, 3, [2, 3]-20 138 | 139 | 2, 3, [2, 3] 140 | 141 | 142 | TIsoTcpSock\net-PDUSize-19--2, 3, [2, 3]-20 143 | 144 | 145 | 146 | TIsoTcpSock\net-PDUSize-25 147 | 148 | TIsoTcpSock 149 | et-PDUSize 150 | 151 | 152 | TIsoTcpSock\net-CheckPDU-22--TIsoTcpSock\net-PDUSize-25 153 | 154 | 155 | 156 | [2, 3], 4, 5-26 157 | 158 | [2, 3], 4, 5 159 | 160 | 161 | TIsoTcpSock\net-CheckPDU-22--[2, 3], 4, 5-26 162 | 163 | 164 | 165 | 2, 3, [2, 3]-23 166 | 167 | 2, 3, [2, 3] 168 | 169 | 170 | TIsoTcpSock\net-PDUSize-25--2, 3, [2, 3]-23 171 | 172 | 173 | 174 | TMsgSocket-\nWaitForData-30 175 | 176 | TMsgSocket- 177 | WaitForData 178 | 179 | 180 | TMsgSocket-\nRecvPacket-28--TMsgSocket-\nWaitForData-30 181 | 182 | 183 | 184 | [2, 3]-29 185 | 186 | [2, 3] 187 | 188 | 189 | TMsgSocket-\nWaitForData-30--[2, 3]-29 190 | 191 | 192 | 193 | [2, 3]-32 194 | 195 | [2, 3] 196 | 197 | 198 | TMsgSocket-\nWaitForData-30--[2, 3]-32 199 | 200 | 201 | 202 | 5-38 203 | 204 | 5 205 | 206 | 207 | TIsoTcpSock\net-IsoPeek-39--5-38 208 | 209 | 210 | 211 | TS7Worker-C\nheckPDU_in-44 212 | 213 | TS7Worker-C 214 | heckPDU_in 215 | 216 | 217 | TS7Worker\n-IsoPerfo\nrmCommand-43--TS7Worker-C\nheckPDU_in-44 218 | 219 | 220 | 221 | 8-51 222 | 223 | 8 224 | 225 | 226 | TS7Worker\n-IsoPerfo\nrmCommand-43--8-51 227 | 228 | 229 | 230 | TS7Worker\n-PerformP\nDURequest-52 231 | 232 | TS7Worker 233 | -PerformP 234 | DURequest 235 | 236 | 237 | TS7Worker\n-IsoPerfo\nrmCommand-43--TS7Worker\n-PerformP\nDURequest-52 238 | 239 | 240 | 241 | 13-41 242 | 243 | 13 244 | 245 | 246 | TS7Worker-C\nheckPDU_in-44--13-41 247 | 248 | 249 | 250 | TSnapBase\n-SwapWord-45 251 | 252 | TSnapBase 253 | -SwapWord 254 | 255 | 256 | TS7Worker-C\nheckPDU_in-44--TSnapBase\n-SwapWord-45 257 | 258 | 259 | 260 | 15-47 261 | 262 | 15 263 | 264 | 265 | TS7Worker-C\nheckPDU_in-44--15-47 266 | 267 | 268 | 269 | TSnapBase\n-SwapWord-48 270 | 271 | TSnapBase 272 | -SwapWord 273 | 274 | 275 | TS7Worker-C\nheckPDU_in-44--TSnapBase\n-SwapWord-48 276 | 277 | 278 | 279 | [15, 16], 8-50 280 | 281 | [15, 16], 8 282 | 283 | 284 | TS7Worker-C\nheckPDU_in-44--[15, 16], 8-50 285 | 286 | 287 | 288 | [13, 14]-46 289 | 290 | [13, 14] 291 | 292 | 293 | TSnapBase\n-SwapWord-45--[13, 14]-46 294 | 295 | 296 | 297 | [15, 16]-49 298 | 299 | [15, 16] 300 | 301 | 302 | TSnapBase\n-SwapWord-48--[15, 16]-49 303 | 304 | 305 | 306 | 17-53 307 | 308 | 17 309 | 310 | 311 | TS7Worker\n-PerformP\nDURequest-52--17-53 312 | 313 | 314 | 315 | TS7Worker-\nPerformFun\nctionRead-54 316 | 317 | TS7Worker- 318 | PerformFun 319 | ctionRead 320 | 321 | 322 | TS7Worker\n-PerformP\nDURequest-52--TS7Worker-\nPerformFun\nctionRead-54 323 | 324 | 325 | 326 | 18-55 327 | 328 | 18 329 | 330 | 331 | TS7Worker-\nPerformFun\nctionRead-54--18-55 332 | 333 | 334 | 335 | TS7Worker\n-ReadArea-56 336 | 337 | TS7Worker 338 | -ReadArea 339 | 340 | 341 | TS7Worker-\nPerformFun\nctionRead-54--TS7Worker\n-ReadArea-56 342 | 343 | 344 | 345 | 18, 11, \n[11, 12]-68 346 | 347 | 18, 11, 348 | [11, 12] 349 | 350 | 351 | TS7Worker-\nPerformFun\nctionRead-54--18, 11, \n[11, 12]-68 352 | 353 | 354 | 355 | 17, 18-70 356 | 357 | 17, 18 358 | 359 | 360 | TS7Worker-\nPerformFun\nctionRead-54--17, 18-70 361 | 362 | 363 | 364 | TIsoTcpSo\ncket-isoS\nendBuffer-72 365 | 366 | TIsoTcpSo 367 | cket-isoS 368 | endBuffer 369 | 370 | 371 | TS7Worker-\nPerformFun\nctionRead-54--TIsoTcpSo\ncket-isoS\nendBuffer-72 372 | 373 | 374 | 375 | 18, 27, \n[25, 26]-78 376 | 377 | 18, 27, 378 | [25, 26] 379 | 380 | 381 | TS7Worker-\nPerformFun\nctionRead-54--18, 27, \n[25, 26]-78 382 | 383 | 384 | 385 | TS7Worker\n-DoEvent-79 386 | 387 | TS7Worker 388 | -DoEvent 389 | 390 | 391 | TS7Worker-\nPerformFun\nctionRead-54--TS7Worker\n-DoEvent-79 392 | 393 | 394 | 395 | 18, 27, 25-57 396 | 397 | 18, 27, 25 398 | 399 | 400 | TS7Worker\n-ReadArea-56--18, 27, 25-57 401 | 402 | 403 | 404 | TSnapBase\n-SwapWord-58 405 | 406 | TSnapBase 407 | -SwapWord 408 | 409 | 410 | TS7Worker\n-ReadArea-56--TSnapBase\n-SwapWord-58 411 | 412 | 413 | 414 | [25, 26], 27-60 415 | 416 | [25, 26], 27 417 | 418 | 419 | TS7Worker\n-ReadArea-56--[25, 26], 27-60 420 | 421 | 422 | 423 | TS7Worker\n-GetArea-61 424 | 425 | TS7Worker 426 | -GetArea 427 | 428 | 429 | TS7Worker\n-ReadArea-56--TS7Worker\n-GetArea-61 430 | 431 | 432 | 433 | 18-65 434 | 435 | 18 436 | 437 | 438 | TS7Worker\n-ReadArea-56--18-65 439 | 440 | 441 | 442 | [25, 26]-59 443 | 444 | [25, 26] 445 | 446 | 447 | TSnapBase\n-SwapWord-58--[25, 26]-59 448 | 449 | 450 | 451 | 27, [25, 26]-62 452 | 453 | 27, [25, 26] 454 | 455 | 456 | TS7Worker\n-GetArea-61--27, [25, 26]-62 457 | 458 | 459 | 460 | TSnap7Serv\ner-FindDB-63 461 | 462 | TSnap7Serv 463 | er-FindDB 464 | 465 | 466 | TS7Worker\n-GetArea-61--TSnap7Serv\ner-FindDB-63 467 | 468 | 469 | 470 | [25, 26]-64 471 | 472 | [25, 26] 473 | 474 | 475 | TSnap7Serv\ner-FindDB-63--[25, 26]-64 476 | 477 | 478 | 479 | 18-73 480 | 481 | 18 482 | 483 | 484 | TIsoTcpSo\ncket-isoS\nendBuffer-72--18-73 485 | 486 | 487 | 488 | 18-75 489 | 490 | 18 491 | 492 | 493 | TIsoTcpSo\ncket-isoS\nendBuffer-72--18-75 494 | 495 | 496 | 497 | [25, 26], 27-80 498 | 499 | [25, 26], 27 500 | 501 | 502 | TS7Worker\n-DoEvent-79--[25, 26], 27-80 503 | 504 | 505 | 506 | TCustomMsgSe\nrver-DoEvent-81 507 | 508 | TCustomMsgSe 509 | rver-DoEvent 510 | 511 | 512 | TS7Worker\n-DoEvent-79--TCustomMsgSe\nrver-DoEvent-81 513 | 514 | 515 | 516 | 18, 27, \n[25, 26]-82 517 | 518 | 18, 27, 519 | [25, 26] 520 | 521 | 522 | TCustomMsgSe\nrver-DoEvent-81--18, 27, \n[25, 26]-82 523 | 524 | 525 | 526 | 18-84 527 | 528 | 18 529 | 530 | 531 | TCustomMsgSe\nrver-DoEvent-81--18-84 532 | 533 | 534 | 535 | 536 | --------------------------------------------------------------------------------