/* * uass - User Agent String Switcher * * Inserts an arbitrary User Agent string into * Opera's opera.dll * * Tested: * Opera 9.52 for Windows on Windows XP and FreeBSD under Wine * * For now, we're going to insist that this UA * must be <= 73 bytes. This is the longest UA * found in the binary and starts at offset 0x6B2DD8 * and ends at 0x6B2E20 (after upx decompression). * */ #include #include #include #include #define D_OFFSET1 0x6B2DD8 #define D_OFFSET2 0x6B2E20 #define D_UA "Opera/9.52 (FreeBSD i386/Wine; U; en)" #define MAX_UA_LEN 73 void usage(char *name); void die(char *msg); void cleanup(void); int setup(void); int check_ua(char *ua, char **nua); int patch(long int offset1, long int offset2, char *ua, int recomp); int main(int argc, char *argv[]) { int ch = 0; char *ua = D_UA; char *nua = NULL; long int offset1 = D_OFFSET1; long int offset2 = D_OFFSET2; int recomp = 1; atexit(&cleanup); while((ch = getopt(argc, argv, "s:e:a:c")) != -1) { switch(ch) { case 's': offset1 = strtol(optarg, NULL, 0); break; case 'e': offset2 = strtol(optarg, NULL, 0); break; case 'a': ua = optarg; break; case 'c': recomp = 0; break; default: usage(argv[0]); } } argc -= optind; argv += optind; if((offset2 - offset1) >= MAX_UA_LEN || ((offset2 - offset1) < 1)) die("Invalid offsets!\n"); if(! check_ua(ua, &nua)) die("Invalid UA string!\n"); if(! setup()) die("Preparing opera.dll failed!\n"); if(! patch(offset1, offset2, ua, recomp)) die("Patching opera.dll failed!\n"); printf("UA slot 2 is now:\n%s\n" "Visit \"opera:config#UserAgent|SpoofUserAgentID\"\n" "And set the value to '2' if you haven't yet.\n", nua); free(nua); return 0; } void usage(char *name) { printf("USAGE: %s [-c] [-s offset] [-e offset] [-a \"UA\"]\n", name); exit(0); } void die(char *msg) { printf("%s", msg); exit(0); } int setup(void) { FILE *bak; FILE *cur; char ch; int ret = 0; if((bak = fopen("opera.bak.dll", "rb")) == NULL) { if((cur = fopen("opera.dll", "rb")) == NULL) die("Can't find opera.dll!\n"); if((bak = fopen("opera.bak.dll", "wb")) == NULL) die("Can't create a backup opera.dll!\n"); else { while(! feof(cur)) { ch = fgetc(cur); if(ferror(cur)) die("Error reading opera.dll!\n"); if(! feof(cur)) fputc(ch, bak); if(ferror(bak)) die("Can't write to opera.dll backup!\n"); } fclose(cur); fclose(bak); } } printf("Decompressing opera.dll\n"); ret = system("upx -d opera.dll > upxout"); if(ret == -1 || ret == 127 || ret == 1) die("upx decompression failed!\n"); return 1; } int patch(long int offset1, long int offset2, char *ua, int recomp) { FILE *fp; int ret = 0; if((fp = fopen("opera.dll", "r+b")) == NULL) return -1; printf("Inserting UA...\n"); if(fseek(fp, offset1, SEEK_SET) != 0) die("a mysterious death...\n"); if(fwrite(ua, sizeof(char), MAX_UA_LEN, fp) != MAX_UA_LEN) return -1; if(ferror(fp)) return -1; fclose(fp); if(recomp) { printf("Recompressing (may take a minute)...\n"); ret = system("upx -3 opera.dll > upxout"); if (ret == -1 || ret == 127 || ret == 1) die("upx compression seems to have failed!\n"); } return 1; } int check_ua(char *ua, char **nua) { int ua_len = 0; char *tmp = NULL; ua_len = strlen(ua); if(ua_len > MAX_UA_LEN) return 0; if((tmp = malloc(sizeof(char) * MAX_UA_LEN + 1)) == NULL) die("Memory allocation failed!\n"); *nua = (char *) memset(tmp, 0x00, MAX_UA_LEN + 1); *nua = (char *) memset(tmp, ' ', MAX_UA_LEN); strncpy(*nua, ua, ua_len); return 1; } void cleanup(void) { remove("upxout"); }