#include #include #include #include #include //Build with: gcc -o ropgadget_patternfinder ropgadget_patternfinder.c -lcrypto int patterntype = -1; unsigned int findtarget=1; unsigned int stride = 4; unsigned int baseaddr = 0; int plainout = 0; unsigned char *filebuf = NULL, *patterndata = NULL, *patternmask = NULL; size_t filebufsz=0, hashblocksize=0; size_t patterndata_size=0, patternmask_size=0; unsigned int dataload_offset = 0, dataload_enabled = 0; unsigned int addval=0; int enable_script = 0; char line_prefix[256]; char script_path[1024]; void hexdump(void *ptr, int buflen)//From ctrtool. { unsigned char *buf = (unsigned char*)ptr; int i, j; for (i=0; i= 0x20 && buf[i+j] <= 0x7e) ? buf[i+j] : '.'); } } printf("\n"); } } int load_bindata(char *arg, unsigned char **buf, unsigned int *size) { int i; unsigned int tmp=0; unsigned char *bufptr; FILE *f; struct stat filestat; bufptr = *buf; if(arg[0]!='@') { if(bufptr==NULL) { tmp = strlen(arg); if(tmp<2 || (tmp & 1)) { printf("The length of the input hex param is invalid.\n"); return 4; } *size = strlen(arg) / 2; *buf = (unsigned char*)malloc(*size); bufptr = *buf; if(bufptr==NULL) { printf("Failed to allocate memory for input buffer.\n"); return 1; } memset(bufptr, 0, *size); } for(i=0; i<*size; i++) { if(i>=strlen(arg))break; sscanf(&arg[i*2], "%02x", &tmp); bufptr[i] = (unsigned char)tmp; } } else { if(stat(&arg[1], &filestat)==-1) { printf("Failed to stat %s\n", &arg[1]); return 2; } f = fopen(&arg[1], "rb"); if(f==NULL) { printf("Failed to open %s\n", &arg[1]); return 2; } if(bufptr) { if(*size < filestat.st_size)*size = filestat.st_size; } else { *size = filestat.st_size; *buf = (unsigned char*)malloc(*size); bufptr = *buf; if(bufptr==NULL) { printf("Failed to allocate memory for input buffer.\n"); return 1; } memset(bufptr, 0, *size); } if(fread(bufptr, 1, *size, f) != *size) { printf("Failed to read file %s\n", &arg[1]); fclose(f); return 3; } fclose(f); } return 0; } int parse_param(char *param, int type) { int ret=0; unsigned int tmpsize=0; if(strncmp(param, "--patterntype=", 14)==0) { if(strncmp(¶m[14], "sha256", 6)==0) { patterntype = 0; } else if(strncmp(¶m[14], "datacmp", 7)==0) { patterntype = 1; } else { printf("Invalid pattern-type.\n"); ret = 5; } } if(strncmp(param, "--patterndata=", 14)==0) { if(patterndata) { free(patterndata); patterndata = NULL; } tmpsize = 0; ret = load_bindata(¶m[14], &patterndata, &tmpsize); patterndata_size = tmpsize; } if(strncmp(param, "--patterndatamask=", 18)==0) { if(patterndata) { free(patternmask); patternmask = NULL; } tmpsize = 0; ret = load_bindata(¶m[18], &patternmask, &tmpsize); patternmask_size = tmpsize; } if(strncmp(param, "--patternsha256size=", 20)==0) { sscanf(¶m[20], "0x%x", &tmpsize); hashblocksize = tmpsize; } if(strncmp(param, "--stride=", 9)==0) { sscanf(¶m[9], "0x%x", &stride); } if(strncmp(param, "--findtarget=", 13)==0) { sscanf(¶m[13], "0x%x", &findtarget); } if(strncmp(param, "--baseaddr=", 11)==0) { sscanf(¶m[11], "0x%x", &baseaddr); } if(strncmp(param, "--dataload=", 11)==0) { dataload_enabled = 1; sscanf(¶m[11], "0x%x", &dataload_offset); } if(strncmp(param, "--addval=", 9)==0) { sscanf(¶m[9], "0x%x", &addval); } if(strncmp(param, "--plainout", 10)==0) { plainout = 1; if(param[10] == '=') { strncpy(line_prefix, ¶m[11], sizeof(line_prefix)-1); } } if(type==0 && strncmp(param, "--script", 8)==0) { enable_script = 1; if(param[8] == '=') { strncpy(script_path, ¶m[9], sizeof(script_path)-1); } } return ret; } int verify_params_state() { int ret = 0; if(patterntype==-1) { printf("No pattern-type specified.\n"); ret = 5; } if(patterntype==0) { if(patterndata_size==0) { printf("--patternsha256size must be used when pattern-type is sha256.\n"); ret = 5; } if(patterndata_size != 0x20) { printf("Input hash size is invalid.\n"); ret = 5; } } return ret; } int locate_pattern() { int ret=0; size_t pos, i; unsigned int found=0, found2=0; unsigned int tmpval, tmpval2; unsigned char *tmpbuf = NULL; unsigned char calchash[0x20]; if(patterntype==0 && patternmask) { tmpbuf = malloc(hashblocksize); if(tmpbuf==NULL) { printf("Failed to alloc tmpbuf in locate_pattern().\n"); return 8; } memset(tmpbuf, 0, hashblocksize); } for(pos=0; pos below can be either hex with any byte-length(unless specified otherwise), or '@' followed by a file-path to load the data from.\n"); printf("Usage:\n"); printf("ropgadget_patternfinder \n"); printf("Options:\n"); printf("--patterntype= Selects the pattern-type, which must be one of the following(this option is required): sha256 or datacmp. sha256: Hash every --patternsha256size bytes in the binary, for locating the target pattern. The input bindata(sha256 hash) size must be 0x20-bytes.\n"); printf("--patterndata= Pattern data to use during searching the binary, see --patterntype.\n"); printf("--patterndatamask= Mask data to use with the data loaded from the file. The byte-size can be less than the size of patterndata / patternsha256size as well. The data loaded from the filebuf is &= with this mask data.\n"); printf("--patternsha256size=0x See --patterntype.\n"); printf("--stride=0x In the search loop, this is the value that the pos is increased by at the end of each interation. By default this is 0x4.\n"); printf("--findtarget=0x Stop searching once this number of matches were found, by default this is 0x1. When this is 0x0, this will not stop until the end of the binary is reached.\n"); printf("--baseaddr=0x This is the value which is added to the located offset when printing it, by default this is 0x0.\n"); printf("--dataload=0x When used, the u32 at the specified offset relative to the located pattern location, is returned instead of the pattern offset. --baseaddr does not apply to the loaded value.\n"); printf("--addval=0x Add the specified value to the value which gets printed.\n"); printf("--plainout[=] Only print the located offset/address, unless an error occurs. If '=' is specified, print that before printing the located offset/address.\n"); printf("--script= Specifies a script from which to load params from(identical to the cmd-line params), each line is for a different pattern to search for. Each param applies to the current line, and all the lines after that until that param gets specified on another line again. When '=' isn't specified, the script is read from stdin. When this --script option is used, all input-param state is reset to the defaults, except for --patterntype, --baseaddr, and --findtarget. When beginning processing each line, the --patterndatamask, --dataload, --addval, and --plainout state is reset to the default before parsing the params each time. When a line is empty, a newline will be printed then processing will skip to the next line. When the first char of a line is '#'(comment), processing will just skip to the next line.\n"); return 0; } ret = 0; memset(line_prefix, 0, sizeof(line_prefix)); memset(script_path, 0, sizeof(script_path)); for(argi=2; argi