/// puzzlebox.c: Inputs are read from a file on the command line. The /// inputs are modified in various ways to checked to match specific /// patterns associated with "phases". Each set of correct inputs /// "passes" a phase and scores points. /// /// USING THE DEBUGGER is almost essential to understand what is /// happening in the source code. Compile with debug flags and run in /// the gdb debugger as in /// /// > gcc -g -o puzzlebox puzzlebox.c /// > gdb -tui ./puzzlebox /// /// is a good policy. /// /// Original DebugMe.java version and rhymes by Mark Snyder <msnyde14@gmu.edu> /// C Port/Adaptation by Chris Kauffman <kauffman@umn.edu> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <math.h> #include <ctype.h> #define BUFSIZE 128 #define NSTAGES 10 int points[NSTAGES+1] = { 0, 8, 8, 8, 8, 5, 5, 4, 4, 5, 5, }; int score = 0; int max_score = 50; char *userID = NULL; int hash = 0; void setup(); void end_now(); void phase01(); void phase02(); void phase03(); void phase04(); void phase05(); void phase06(); void phase07(); void phase08(); void phase09(); void phase10(); int main(int argc, char *argv[]){ printf("========================================\n"); printf("PROBLEM 2: Puzzlebox\n"); if(sizeof(int)!=4 || sizeof(long)!=8){ printf("Unexpected byte sizes of int or long\n"); printf(" %5s %5s\n","EXPECT","ACTUAL"); printf(" int: %5d %5lu\n",4,sizeof(int)); printf("long: %5d %5lu\n",8,sizeof(long)); printf("\n"); printf("puzzlebox must be run on a 64-bit architecture. Bailing out\n"); return 1; } if(argc < 2){ printf("usage: %s <infile>\n",argv[0]); printf(" Provide a text file to read from on the command line\n"); printf(" The first token in the input file is your Internet ID like kauf0095\n"); printf(" Bailing out.\n"); return 1; } setup(argv[1]); printf("PHASE 1: A puzzle you say? Challenge accepted!\n"); phase01(); score += points[1]; printf("PHASE 2: That was cake by the ocean! Wait: the cake is a lie!\n"); phase02(); score+=points[2]; printf("PHASE 3: Warm-up is over. This $#!^ just go real.\n"); phase03(); score+=points[3]; printf("PHASE 4: Tired yet? Nope? There's more in phase four.\n"); phase04(); score+=points[4]; printf("PHASE 5: You're doing well. But can you break through this secret technique of darkness?\n"); phase05(); score+=points[5]; printf("PHASE 6: Watch out, here comes a wall of bricks! It's time for you to solve phase six.\n"); phase06(); score+=points[6]; printf("PHASE 7: Next it's phase eleven! oops, seven. (off-by-4 errors don't lose credit, right?)\n"); phase07(); score+=points[7]; printf("PHASE 8: You're doing great, now try phase 1000!\n"); phase08(); score+=points[8]; printf("PHASE 9: Finally, the finish line; Can you solve phase nine?\n"); phase09(); score+=points[9]; printf("PHASE 10: Rule #1: The doctor lies. Next time a message mentions 'finish line,' check the source code.\n"); phase10(); score+=points[10]; printf("***Achievement Unlocked***\n"); printf("gdb? Yeah you know me!\n"); end_now(); return 0; } void setup_signal_handlers(); void failure(char *msg); void end_now(); void setup_input(char *fname); void close_input(); char *next_input(); void setup(char *infile_name){ setup_signal_handlers(); setup_input(infile_name); userID = next_input(); int len = strlen(userID); if(len != 8){ printf("'%s' is a userID and must be 8 characters\n", userID); exit(1); } for(int i=0; i<len; i++){ userID[i] = toupper(userID[i]); } hash = 0; int *hash1 = (int *) (userID); int *hash2 = (int *) (userID+4); hash = (*hash1) ^ (*hash2); if(hash < 0){ hash = -hash; } printf("UserID '%s' accepted: hash value = %d\n",userID,hash); } #define NSIGNALS 35 char *signal_names[NSIGNALS] = { "", "SIGHUP", /// 1 Hangup "SIGINT", /// 2 Interrupt "SIGQUIT", /// 3 Quit "SIGILL", /// 4 Illegal Instruction "SIGTRAP", /// 5 Trace/Breakpoint Trap "SIGABRT", /// 6 Abort "SIGEMT", /// 7 Emulation Trap "SIGFPE (usually divide by 0)", /// 8 Arithmetic Exception "SIGKILL", /// 9 Killed "SIGBUS", /// 10 Bus Error "SIGSEGV (out of bounds memory)", /// 11 Segmentation Fault "SIGSYS", /// 12 Bad System Call "SIGPIPE", /// 13 Broken Pipe "SIGALRM", /// 14 Alarm Clock "SIGTERM", /// 15 Terminated "SIGUSR1", /// 16 User Signal 1 "SIGUSR2", /// 17 User Signal 2 "SIGCHLD", /// 18 Child Status "SIGPWR", /// 19 Power Fail/Restart "SIGWINCH", /// 20 Window Size Change "SIGURG", /// 21 Urgent Socket Condition "SIGPOLL", /// 22 Socket I/O Possible "SIGSTOP", /// 23 Stopped (signal) "SIGTSTP", /// 24 Stopped (user) "SIGCONT", /// 25 Continued "SIGTTIN", /// 26 Stopped (tty input) "SIGTTOU", /// 27 Stopped (tty output) "SIGVTALRM", /// 28 Virtual Timer Expired "SIGPROF", /// 29 Profiling Timer Expired "SIGXCPU", /// 30 CPU time limit exceeded "SIGXFSZ", /// 31 File size limit exceeded "SIGWAITING", /// 32 All LWPs blocked "SIGLWP", /// 33 Virtual Interprocessor Interrupt for Threads Library "SIGAIO", /// 34 Asynchronous I/O }; void handle_signals(int signum){ char msg[BUFSIZE]; snprintf(msg,BUFSIZE,"Fatal signal %d (%s) received", signum,signal_names[signum]); failure(msg); } void setup_signal_handlers(){ for(int i=1; i<NSIGNALS; i++){ if(i != SIGKILL && i != SIGSTOP) { signal(i, handle_signals); } } } char inputs[BUFSIZE][BUFSIZE] = {}; int input_idx = -1; FILE *input_fh = NULL; void setup_input(char *fname){ input_fh = fopen(fname,"r"); if(input_fh == NULL){ perror("Couldn't open input file"); exit(1); } } void close_input(){ if(input_fh == NULL){ fprintf(stderr,"Input file not open\n"); exit(1); } fclose(input_fh); } char *next_input(){ input_idx++; int ret = fscanf(input_fh, "%s", inputs[input_idx]); if(ret != 1){ fprintf(stderr, "!! No more input: assuming \"\" for input %d\n", input_idx); inputs[input_idx][0] = '\0'; } return inputs[input_idx]; } void failure(char *msg){ printf("\n"); printf("Ah ah ah, you didn't say the magic word...\n"); printf("Failure: %s\n",msg); end_now(); } void end_now(){ printf("\nRESULTS: %d / %d points\n",score,max_score); close_input(); exit(0); } void phase01(){ int a = atoi(next_input()); int b = atoi(next_input()); int c = atoi(next_input()); a += hash % 41; if (a<b && b>c && a<c) { return; } failure("Double debugger burger, order up!"); } void phase02(){ int a = atoi(next_input()); int b = atoi(next_input()); int c = atoi(next_input()); if(a==0){ goto FAIL2; } a += hash%26; int v = a+b; v *= a; v /= b; v += 14; if (c==v){ return; } FAIL2: failure("These aren't the ints you're looking for. Move along."); } void phase03(){ int a = atoi(next_input()); int b = atoi(next_input()); int c = atoi(next_input()); int d = atoi(next_input()); int targ = 1 << ((hash % 7)+24) | 1 << (hash % 17) | 1 << (hash % 19); int shot = 0; shot |= 1 << a; shot |= 1 << b; shot |= 1 << c; shot |= 1 << d; int hit = shot ^ targ; hit = !hit; if(hit){ return; } failure("Shifty bits hit? Xor not it seems..."); } void substring(char *dest, char *src, int start, int stop, int max){ int i; for(i=0; i<(stop-start) && i<max; i++){ dest[i] = src[start+i]; } if(i==max){ fprintf(stderr,"ERROR: substring reached max %d for source string '%s' start:%d end:%d\n", max,src,start,stop); exit(1); } dest[i] = '\0'; } void phase04(){ char *s = next_input(); int a = atoi(next_input()); int b = atoi(next_input()); int c = atoi(next_input()); int len = strlen(s); for(int i=0; i<len-1; i++){ if(s[i]==s[i+1]){ failure("I petition for less repetition!"); } } char temp1[BUFSIZE]={}, temp2[BUFSIZE]={}; substring(temp1, s, a, b, BUFSIZE); substring(temp2, s, b, c, BUFSIZE); int len1 = strlen(temp1); int len2 = strlen(temp2); int idx = 0; while(idx<len1 && idx<len2){ if(temp1[idx] != temp2[idx]){ break; } idx++; } int targ = (hash % 5)+3; if(idx==targ){ return; } failure("Over here and over there, I need a certain kind of pair..."); } void phase05(){ int n = atoi(next_input()); int m = atoi(next_input()); int t = (hash % 30) + 21; int s = 0; while(n>1){ if(n & 1){ n = (n<<2) - n + 1; } else { n = n >> 1; } if(s == t && m == t){ return; } s++; } failure("Seems you forgatz the essence of Collatz"); } void phase06(){ int a = atoi(next_input()); int b = atoi(next_input()); int c = atoi(next_input()); int d = atoi(next_input()); char expect[BUFSIZE] = "There are 10 kinds of people in the world: those who understand binary and those who don't"; char actual[BUFSIZE] = {}; strcpy(actual,expect); int slen = strlen(expect); int ilen = slen / sizeof(int) - 1; int location1 = (hash % 211) % ilen; int location2 = (hash % 311) % ilen; ((int *)actual)[location1] = 0x58585858; ((int *)actual)[location2] = 0x59595959; *(((int *)actual) + a) = b; *(((int *)actual) + c) = d; if(strncmp(expect,actual,BUFSIZE) == 0){ return; } failure("Here are hints:\n- use two ints with 4 bytes to make the message right\n- beware of endian ordering angst\n"); } void phase07(){ float a = atof(next_input()); union { char c[9]; float f; } flar; strcpy(flar.c, userID); if( fabs(a-flar.f) < 1e-8 ){ return; } char *msg = "Ugly cousin to the struct: if you don't know unions, then on this phase you're ...\n" "stuck.\n" "What did you think was going to rhyme with 'struct'? A curseword?\n" "Keep it PG: there are little bits 'n bytes with ears around here.\n" ; failure(msg); } void phase08() { int n = atoi(next_input()); int m = atoi(next_input()); int t = (hash % 83) + 21; int s = 0; char *msg = "Do you like spaghetti? Try some spaghetti! It's good, right?\n" "What, you prefer structured loops? How mundane.\n"; goto LTOP; LEND: failure(msg); LOM1: n = (n<<2) - n + 1; LCHK: if(s == t && m == t){ goto LAFT; } s++; goto LTOP; LOC1: if(n & 1){ goto LOM1; } goto LEM1; LTOP: if(!(n>1)){ goto LEND; } goto LOC1; LEM1: n = n >> 1; goto LCHK; LAFT: return; } unsigned long state = 1; unsigned int pb_rand() { state = state * 1103515245 + 12345; return (unsigned int)(state/65536) % 32768; } void pb_srand(unsigned long seed){ state = seed; } void scramble(char *str, int rounds){ int len = strlen(str); for(int i=0; i<rounds; i++){ unsigned int idx = pb_rand() % len; unsigned int jdx = pb_rand() % len; char tmp = str[idx]; str[idx] = str[jdx]; str[jdx] = tmp; } } char letters[BUFSIZE] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; void phase09(){ int idxs[5] = {}; int len = strlen(letters); for(int i=0; i<5; i++){ idxs[i] = atoi(next_input()); if(idxs[i] >= len){ char *msg = "\"My, what big ints you have, Granny!\" " "\"All the better to overflow your buffers my dear\"\n"; failure(msg); } } long seed = (((long) hash) << 32) + ~hash; pb_srand(seed); scramble(letters, 100); char buf[BUFSIZE] = {}; for(int i=0; i<5; i++){ buf[i] = letters[idxs[i]]; } union{ long l; char s[8]; } chong; chong.l = 478426194263; if(strcmp(buf,chong.s)==0){ return; } char *msg = "Where's that stripey hipster with the lame hat and cane?\n" "He's all spread around in there. Find him."; failure(msg); } void phase10(){ long a = atol(next_input()); char ans[] = " "; for(int i=0; i<8; i++){ ans[i] = (char) ((a >> (6*i) & 0x3F) + 48); } if(strcmp(ans,userID)==0){ printf("OMG %s, the answers were inside you the the whole time!\n",userID); return; } char msg[BUFSIZE] = {}; snprintf(msg, BUFSIZE, "'%s' it is not. Look within, you must.\n", ans); failure(msg); }