/* * Program to obscure the meaning of a MICRO-C source file by * removing comments, indenting, and line spacing. All non-reserved * words are replaced with meaningless numeric names. * * Syntax: obscure [output_file] [options] * * Options: k= - File of names to KEEP (1 per line). * d= - File of names to PRE-DEFINE (1 per line). * p= - Prefix pre-pended to generated numeric names. * * Use 'k=' to prevent certain names from being obscured. * Use 'd=' to insure that certain names will have the same obscured * name in several modules (For "extern"s etc.). * Default 'p=' prefix is '_'. * * For MAXIMUM obscuring, use the pre-processor (MCP) before processing * with this program. This will remove all pre-processor directives, but BE * WARNED that this will make the program LESS PORTABLE, since key system * header files (Such as ) will not be re-used when moving to a * a new system. * * Copyright 1989-1995 Dave Dunfield * All rights reserved. * * Permission granted for personal (non-commercial) use only. * * Compile command: cc obscure -fop */ #include #define NUMNEW 500 /* maximum number of unique words */ #define NUMKEEP 100 /* maximum number of kept words */ #define FREEPOOL 15000 /* size of free storage pool */ #define MAXWIDTH 70 /* maximum width of output line */ /* table of reserved words to keep without changing */ char *resword[] = { /* MICRO-C keywords */ "break", "case", "char", "continue", "default", "do", "else", "extern", "for", "goto", "if", "int", "register", "return", "static", "switch", "unsigned", "while", "include", "define", "endif" ,"ifdef", "ifndef", "undef", "forget", "file", "struct", "union", "sizeof", "void", /* MICRO-C library functions */ "abort", "abs", "atoi", "atox", "bsearch", "calloc", "cd", "chdir", "clearerr", "close", "concat", "coreleft", "create", "delete", "dup", "dup2", "exit", "ferror", "fclose", "fflush", "fget", "fgetc", "fgets", "findfirst", "find_first", "findnext", "find_next", "fopen", "fprintf", "fput", "fputc", "fputs", "fread", "free", "freopen", "fscanf", "fseek", "ftell", "fwrite", "getc", "getchar", "getdir", "getenv", "gets", "in", "inw", "isalnum", "isalpha", "isascii", "iscntrl", "isdigit", "isgraph", "islower", "isprint", "ispunct", "isspace", "isupper", "isxdigit", "itoa", "lgetc", "lgets", "longjmp", "longadd", "longsub", "longmul", "longdiv", "longshr", "longshl", "longcpy", "longset", "longtst", "longcmp", "lprintf", "lputc", "lputs", "lrewind", "lscanf", "lsearch", "lseek", "ltell", "malloc", "max", "memchr", "memcmp", "memcpy", "memmove", "memset", "min", "mkdir", "nargs", "open", "out", "outw", "peek", "peekw", "poke", "pokew", "printf", "putc", "putchar", "puts", "qsort", "rand", "random", "read", "realloc", "remove", "rename", "rewind", "rmdir", "scanf", "setbuf", "setjmp", "sprintf", "sqrt", "sscanf", "stpcpy", "strbeg", "strcat", "strchr", "strcmp", "strcpy", "strcspn", "strdup", "stricmp", "strlen", "strlwr", "strncat", "strncmp", "strncpy", "strnicmp", "strnset", "strpbrk", "strrchr", "strrev", "strset", "strspn", "strstr", "strtok", "strupr", "system", "tolower", "toupper", "unlink", "write", "_format_", "alloca", "alloc_seg", "beep", "cbreak", "Cclose", "Cgetc", "Copen", "copy_seg", "cpu", "Cputc", "Csignals", "Ctestc", "delay", "disable", "enable", "exec", "free_seg", "get_attr", "get_cs", "get_date", "get_drive", "get_ds", "get_es", "get_time", "get_vector", "int86", "joystick", "kbget", "kbhit", "kbtst", "resize_seg", "restore_video", "save_video", "set_attr", "set_date", "set_drive", "set_es", "set_time", "set_vector", "sound", "sound_off", "tsr", "vclear_box", "vcleol", "vcleos", "vclscr", "vcursor_block", "vcursor_line", "vcursor_off", "vdraw_box", "version", "vgetc", "vgets", "vgotoxy", "vmenu", "vmessage", "vopen", "vprintf", "vputc", "vputf", "vputs", "vtstc", "vupdatexy", "wcleol", "w_cleol", "wcleow", "w_cleow", "wclose", "w_close", "wclwin", "w_clwin", "wcursor_block", "wcursor_line", "wcursor_off", "wform", "wgetc", "w_getc", "wgets", "wgotoxy", "w_gotoxy", "wmenu", "wopen", "wprintf", "w_printf", "wputc", "w_putc", "wputf", "wputs", "w_puts", "wtstc", "w_tstc", "wupdatexy", "w_updatexy", /* Common header file definitions */ "FILE", "EOF", "NULL", "stdin", "stdout", "stderr", "mc", "h", "comm", "console", "ctype", "file", "stdio", "window", "video", "main", 0 }; unsigned new_count = 0, keep_count = 0, width = 0; int inpos = -1; char *new_text[NUMNEW], *keep_text[NUMKEEP], buffer[200], free_text[FREEPOOL], *free_ptr, *prefix = "_", pflag = 0; FILE *fpr = 0, *fpw; /* * Main program */ main(int argc, char *argv[]) { int chr, chr1, i; char *ptr; FILE *fp; free_ptr = free_text; fpw = stdout; for(i=1; i < argc; ++i) { ptr = argv[i]; switch((*ptr++ << 8) | *ptr++) { case 'p=' : /* define generation prefix */ prefix = ptr; break; case 'd=' : /* define symbols in advance */ fp = fopen(ptr, "rvq"); while(fgets(buffer, 100, fp)) { new_text[new_count++] = free_ptr; ptr = buffer; do *free_ptr++ = *ptr; while(*ptr++); } fclose(fp); break; case 'k=' : /* define names to keep */ fp = fopen(ptr, "rvq"); while(fgets(buffer, 100, fp)) { keep_text[keep_count++] = free_ptr; ptr = buffer; do *free_ptr++ = *ptr; while(*ptr++); } fclose(fp); break; default: /* filename */ if(!fpr) fpr = fopen(argv[i], "rvq"); else if(fpw == stdout) fpw = fopen(argv[i], "wvq"); else abort("Too many operands\n"); } } /* if no input file specified, report error */ if(!fpr) { fputs("\nUse: obscure [output_file d=definefile k=keepfile p=prefix]\n", stderr); abort("\nCopyright 1989-1995 Dave Dunfield\nAll rights reserved.\n"); } keep_text[keep_count] = new_text[new_count] = 0; while((chr = read_char()) >= 0) { top: switch(chr) { case '\n' : /* newline */ if(pflag) { putc('\n', fpw); pflag = width = 0; } case '\t' : /* ignore tab */ case ' ' : /* ignore space */ break; case '/' : /* starting comment */ if((chr = read_char()) == '*') { do if((chr1 = read_char()) < 0) abort("End of file in comment\n"); while((chr = (chr << 8) + chr1) != '*/'); } else { write_char('/'); goto top; } break; case '"' : /* string input */ case '\'': /* character input */ buffer[i=0] = chr; do { buffer[++i] = chr1 = read_char(); if(chr1 == '\\') buffer[++i] = read_char(); } while(chr1 != chr); buffer[++i] = 0; check_width(width+i); write_string(buffer); break; case '#' : /* pre-processor statements */ if(!inpos) { pflag = -1; if(width) { putc('\n', fpw); width = 0; } } default: /* all other characters */ if(isvar(chr)) { /* Variable name */ check_width(width); buffer[i = 0] = chr; do buffer[++i] = chr = read_char(); while(isvar(chr) || isdigit(chr)); buffer[i] = 0; if((!lookup(resword)) && !lookup(keep_text)) { if(!(chr1 = lookup(new_text))) { new_text[new_count++] = free_ptr; ptr = buffer; do *free_ptr++ = *ptr; while(*ptr++); new_text[chr1 = new_count] = 0; } sprintf(buffer, "%s%u", prefix, chr1); } write_string(buffer); while(isspace(chr)) { if(pflag && (chr == '\n')) break; chr = read_char(); } if(isvar(chr) || isdigit(chr)) write_char(' '); goto top; } else if(isdigit(chr)) { /* number */ check_width(width); do write_char(chr); while(isdigit(chr = read_char())); if(chr == 'x') { do { write_char(chr); chr = read_char(); } while(isxdigit(chr)); } goto top; } else write_char(chr); } } fclose(fpw); } /* * Lookup the buffered word in a table */ lookup(char *table[]) { int i; char *ptr; i = 0; while(ptr = table[i++]) if(!strcmp(buffer, ptr)) return i; return 0; } /* * Test for valid variable character */ isvar(char c) { return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || (c == '_'); } /* * Read a character from the input file */ read_char() { char chr; inpos = ((chr = getc(fpr)) == '\n') ? -1 : inpos + 1; return chr; } /* * Write a character to the file */ write_char(char c) { putc(c, fpw); ++width; } /* * Write a string to the file */ write_string(char *string) { while(*string) { putc(*string++, fpw); ++width; } } /* * Check for over width in output file */ check_width(unsigned value) { if(value >= MAXWIDTH) { putc('\n', fpw); width = 0; } }