// gdbhelper by gynvael.coldwind//vx // http://gynvael.coldwind.pl // http://vexillium.org // mailto: gynvael@vexillium.org // // License (BSD): // Copyright (c) 2009, Gynvael Coldwind of Vexillium // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of the Gynvael Coldwind nor Vexillium nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY Gynvael Coldwind ''AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL Gynvael Coldwind BE LIABLE FOR ANY // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include #include #include using namespace std; struct bp { uint32_t addr; vector commands; }; vector GDBBreakPoints; bool HandleSourceFile(const char *name); bool HandleBinaryFile(const char *name, const char *hexoffset); bool ProduceGDBScript(); int main(int argc, char **argv) { fprintf(stderr, "gdbhelper by gynvael.coldwind//vx\n"); if(argc != 4) { puts("usage: ./gdbhelper \n" " f.e.: ./gdbhelper gosucode.nasm gosucode 0x12345678\n" "Important: gdbhelper will seek 90909090 sequence in the\n" " binary asm file, and replace the first 90 with a CC.\n" " gdbhelper will look for GDB_BP string in the source file\n" " and it will acquire gdb commands from the line after\n" " GDB_BP (the command has to be after a comment sign)\n" " until it reaches the ---GDB_BP sequance (three dashes)\n" " For example:\n" " GDB_BP\n" " ; echo Some breakpoint\\n\n" " ; info reg eax edx\n" " ; ---GDB_BP\n" " It's a good idea to define the GDB_BP as four nop's\n" " using the following macro (or similar)\n" " %macro GDB_BP 0\n" " times 4 nop\n" " %endmacro"); return 1; } if(!HandleSourceFile(argv[1])) { fputs("error handling source file, terminating\n", stderr); return 1; } if(!HandleBinaryFile(argv[2], argv[3])) { fputs("error handling binary file, terminating\n", stderr); return 2; } if(!ProduceGDBScript()) { fputs("error producing script\n", stderr); return 3; } return 0; } bool HandleSourceFile(const char *name) { // Read the script first FILE *f = fopen(name, "r"); if(!f) { puts("could not open source file"); return false; } for(;;) { // Get the line char LineBuffer[256]; fgets(LineBuffer, sizeof(LineBuffer), f); if(feof(f)) break; // Any GDB_BP? if(!strstr(LineBuffer, "GDB_BP") || strstr(LineBuffer, "%macro")) continue; // There is a GDB_BP! Let's create an object for it bp *b = new bp; b->addr = 0; #ifdef DEBUG_VERBOSE // Some dbg msg fprintf(stderr, "Found GDB_BP!\n"); #endif // Now, let's read the GDB commands until the end for(;;) { // Get the line fgets(LineBuffer, sizeof(LineBuffer), f); // Time to end it? if(feof(f) || strstr(LineBuffer, "---GDB_BP")) break; // Get the command char Command[256]; sscanf(LineBuffer, "%*[^;]; %255[^\n]", Command); b->commands.push_back(strdup(Command)); #ifdef DEBUG_VERBOSE // Some info fprintf(stderr, " -> '%s'\n", Command); #endif } // Add it to the list GDBBreakPoints.push_back(b); } fprintf(stderr, "Found %u GDB_BP snippets in source file.\n", GDBBreakPoints.size()); fclose(f); return true; } bool HandleBinaryFile(const char *name, const char *hexoffset) { // Convert the hexoffset uint32_t StartAddr; sscanf(hexoffset, "%i", &StartAddr); // Open the file FILE *f = fopen(name, "r+b"); if(!f) { fputs("error opening binary file for read/write\n", stderr); return false; } // Get file size fseek(f, 0, SEEK_END); size_t FileSize = ftell(f); fseek(f, 0, SEEK_SET); // Alloc mem uint8_t *Data = new uint8_t[FileSize]; // Read the file fread(Data, 1, FileSize, f); fseek(f, 0, SEEK_SET); // Return cursor to the start // Seek the 90909090 sequence size_t i; int SigNo = 0; for(i = 0; i <= FileSize - 4; i++) { // Compare if(*(uint32_t*)&Data[i] != 0x90909090) continue; // Ypii, we found a signature! // Let's check if we have enough GDB_BP in the list if(SigNo >= GDBBreakPoints.size()) { fprintf(stderr, "ups! to many sigs found! how come? a nop-field somewhere?\n"); break; } // Let's correct the address in the library GDBBreakPoints[SigNo]->addr = StartAddr + i; // Write an int3 there Data[i] = 0xCC; #ifdef DEBUG_VERBOSE // Some dbg msg fprintf(stderr, "GDB_BP binary sig %i found at VA %.8x\n", SigNo, StartAddr + i); #endif // Next sig.. SigNo++; } // OK, now write the file back to the disk fwrite(Data, 1, FileSize, f); // Close the file fclose(f); return true; } bool ProduceGDBScript() { // Let's do this! puts("define gdbhelpfunc"); puts(" set disassembly-flavor intel"); puts(" set logging file gdbhelplog.txt"); puts(" set logging overwrite"); puts(" set logging on"); puts(" display/1i $eip"); puts(" set $endautoscan=0"); puts(" while $endautoscan==0"); puts(" c"); // continue puts(" set $endautoscan=1"); int i, j; // Now for the checks for(i = 0; i < GDBBreakPoints.size(); i++) { printf(" if ($eip)==(0x%x)\n", GDBBreakPoints[i]->addr + 1); for(j = 0; j < GDBBreakPoints[i]->commands.size(); j++) printf(" %s\n", GDBBreakPoints[i]->commands[j]); puts( " set $endautoscan=0"); puts( " end"); } puts(" end"); puts(" set logging off"); puts("end"); return true; }