#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; int disable_locatefail_halt = 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; unsigned int printrawval = 0; int blacklist_set = 0; unsigned int blacklist_addrs[2] = {0}; int enable_script = 0; char line_prefix[256]; char line_suffix[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, "--blacklist=", 12)==0) { blacklist_set = 1; sscanf(¶m[12], "0x%x-0x%x", &blacklist_addrs[0], &blacklist_addrs[1]); } 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(strncmp(param, "--plainsuffix=", 14)==0)strncpy(line_suffix, ¶m[14], sizeof(line_suffix)-1); if(strncmp(param, "--printrawval", 13)==0)printrawval = 1; if(strncmp(param, "--disablelocatehalt", 19)==0)disable_locatefail_halt = 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; } unsigned int check_address_allowed(unsigned int address) { if(blacklist_set) { if(address >= blacklist_addrs[0] && address < blacklist_addrs[1])return 0; } return 1; } 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>8) & 0xff, (tmpval>>16) & 0xff, (tmpval>>24) & 0xff, line_suffix); } if(!plainout)printf("."); } } else { tmpval = *((unsigned int*)&filebuf[((unsigned int)pos) + dataload_offset]); tmpval+= addval; found2 = check_address_allowed(tmpval); if(found2) { if(!plainout) { printf("Found the pattern at "); printf("%s0x%08x", line_prefix, ((unsigned int)pos) + baseaddr); printf(", u32 value at +0x%x, value added with 0x%x: 0x%x.", dataload_offset, addval, tmpval); } else { if(!printrawval) { printf("%s0x%08x%s", line_prefix, tmpval, line_suffix); } else { printf("%s%02x%02x%02x%02x%s", line_prefix, (tmpval & 0xff), (tmpval>>8) & 0xff, (tmpval>>16) & 0xff, (tmpval>>24) & 0xff, line_suffix); } } } } if(found2) { printf("\n"); found++; if(found==findtarget)break; } } } if(!found) { printf("Failed to find the pattern.\n"); if(!disable_locatefail_halt)ret = 7; } else { if(!plainout)printf("Found 0x%x matches.\n", found); } if(patterntype==0 && patternmask)free(tmpbuf); return ret; } int parse_script(FILE *fscript) { int pos, pos2; int ret=0; int linenum = 0; char *strptr, *strptr2; char linebuf[1024]; char tmpbuf[1024]; memset(linebuf, 0, sizeof(linebuf)); while(fgets(linebuf, 1023, fscript)) { linenum++; strptr = strchr(linebuf, '\n'); if(strptr)*strptr = 0; strptr = strchr(linebuf, '\r'); if(strptr)*strptr = 0; if(strlen(linebuf)==0 || linebuf[0]=='#') { if(linebuf[0]==0)printf("\n"); continue; } strptr = linebuf; if(patternmask_size) { free(patternmask); patternmask = NULL; patternmask_size=0; } dataload_enabled = 0; dataload_offset = 0; plainout = 0; memset(line_prefix, 0, sizeof(line_prefix)); addval = 0; printrawval = 0; while(*strptr) { if(strptr[0] == ' ') { strptr++; continue; } if(strptr[0] == '"' || strptr[0] == '\'') { strptr++; memset(tmpbuf, 0, sizeof(tmpbuf)); 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("--blacklist=0x-0x When used, any final located output addresses under the specified blacklisted range are ignored.\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("--plainsuffix=[suffix text] When --plainout was used, print the specified text immediately after printing the located offset/address.\n"); printf("--printrawval Instead of printing 0x for the final value, print the raw bytes in little-endian form.\n"); printf("--disablelocatehalt When the pattern wasn't found, don't return an error + immediately exit.\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, --findtarget, --plainsuffix, and --blacklist. When beginning processing each line, the --patterndatamask, --dataload, --addval, --printrawval, 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(line_suffix, 0, sizeof(line_suffix)); memset(script_path, 0, sizeof(script_path)); for(argi=2; argi