/* * Copyright (C) 2021 National University of Singapore * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * NOTE: As a special exception, this file is under the MIT license. The * rest of the E9Patch/E9Tool source code is under the GPLv3 license. */ /* * This is an example E9Tool plugin. It implements a limit on control-flow * transfer instructions such as calls, jumps, and returns. When the limit * is reached, it will execute the int3 instruction generating a SIGTRAP. * * To compile: * $ g++ -std=c++11 -fPIC -shared -o example.so -O2 \ * examples/plugins/example.cpp -I src/e9tool/ * * To use: * $ ./e9tool -M 'plugin(example).match()' \ * -P 'plugin(example).patch()' program * $ ./a.out * Trace/breakpoint trap */ #include <sstream> #include <string> #include <sys/mman.h> #include <getopt.h> #include "e9plugin.h" #include "stdio.h" using namespace e9tool; #define COUNTERS 0x789a0000 // Arbitrary #define OPTION_ADDRESS 1 #define OPTION_LIMIT 2 static intptr_t address = COUNTERS; /* * Initialize the counters and the trampoline. */ extern void *e9_plugin_init(const Context *cxt) { printf("[*] init...\n"); char *function_arr[]={"malloc"} intptr_t target_addr[10]; bool end = false; intptr_t val = getELFObject(cxt->elf, symbol, end); if (val == -1) { warning("symbol \"%s\" is undefined and therefore has value 0x0",symbol); } else if (val == INTPTR_MIN) { warning("failed to match \"%s\" against any section or symbol name",symbol); } // construct target addr list return nullptr; } /* * We match all control-flow transfer instructions. */ extern intptr_t e9_plugin_match(const Context *cxt) { printf("[*] matching..\n"); intptr_t intr_addr=0; // The e9_plugin_match() function is invoked once by E9Tool for each // disassembled instruction. The function should return a value that is // used for matching. // For this example we return a non-zero value for all // control-flow-transfer instructions: switch (cxt->I->mnemonic) { // append case MNEMONIC_RET: return 1; case MNEMONIC_JB: case MNEMONIC_JBE: case MNEMONIC_JCXZ: case MNEMONIC_JECXZ: case MNEMONIC_JKNZD: case MNEMONIC_JKZD: case MNEMONIC_JL: case MNEMONIC_JLE: case MNEMONIC_JMP: case MNEMONIC_JNB: case MNEMONIC_JNBE: case MNEMONIC_JNL: case MNEMONIC_JNLE: case MNEMONIC_JNO: case MNEMONIC_JNP: case MNEMONIC_JNS: case MNEMONIC_JNZ: case MNEMONIC_JO: case MNEMONIC_JP: case MNEMONIC_JRCXZ: case MNEMONIC_JS: case MNEMONIC_JZ: return 2; case MNEMONIC_CALL: // if (cxt->I->count.op != 1 || cxt->I->op[0].type != OPTYPE_IMM){ // ; // undefine address // } // else{ // intr_addr=(intptr_t)cxt->I->op[0].imm + (intptr_t)cxt->I->address +(intptr_t)cxt->I->size; // // if addr in target list // } return 3; default: return 0; } } /* * Emit the patch template code. */ extern void e9_plugin_code(const Context *cxt) { // The e9_plugin_code() function is invoked once by E9tool. // The function specifies the "code" part of the trampoline template that // will be executed for each matching instruction. // In this example, the code simply invokes the $limit template // (defined above): fputs("\"$limit\",", cxt->out); } /* * Emit the patch template data. */ extern void e9_plugin_data(const Context *cxt) { // The e9_plugin_code() function is invoked once by E9tool. // The function specifies the "data" part of the trampoline template that // will be attached to each matching instruction. // In this example, there is no data so this function does nothing. // The function could also be removed from the plugin. } /* * Patch the selected instructions. */ extern void e9_plugin_patch(const Context *cxt) { printf("[*] patching..\n"); // The e9_plugin_patch() function is invoked by E9Tool once per // matching instruction. The function specifies the "metadata" which // instantiates any macros in the trampoline template (both code or data). // The metadata is specified in as comma-separated "$key":VALUE pairs, // where $key is a macro name and VALUE is a value in the template // template format. // In this example, the metadata instantiates the $counter macro with // the counter address corresponding to the instruction type: intptr_t counter = e9_plugin_match(cxt); }