#include #include int getInFile(char* ExeIn, FILE **ExeInF); int checkFileType(FILE *ExeInF); int getOutFile(char* filetypeString, char* ExeIn, char* ExeOut, FILE **ExeOutF); int patch(FILE *ExeInF, FILE *ExeOutF, char *patchdata); char extractDriveLetter(char *pathname); int getTmpFile(char *tmpFilename, FILE **ExeOutF, char driveLetter); #define ChipFileSize 267776 #define BugPatch1Loc 0x00007C93L #define BugPatch1Len 82 char Patch1Before[BugPatch1Len] = {0x8A, 0xD8, 0x2A, 0xFF, 0x8B, 0xC3, 0xD1, 0xE3, 0x03, 0xD8, 0xD1, 0xE3, 0x8D, 0x7E, 0xF6, 0x8D, 0xB7, 0x6C, 0x06, 0x8C, 0xD0, 0x8E, 0xC0, 0xA5, 0xA5, 0xA5, 0x8A, 0x46, 0xF7, 0x2A, 0xE4, 0x8B, 0x5E, 0x0E, 0x89, 0x07, 0x80, 0x7E, 0xF6, 0x01, 0x75, 0x07, 0xB8, 0x01, 0x00, 0xE9, 0xD8, 0x01, 0x90, 0x80, 0x7E, 0xF6, 0x02, 0x74, 0x03, 0xE9, 0xC7, 0x01, 0x80, 0x7E, 0xFD, 0x40, 0x72, 0x09, 0x80, 0x7E, 0xFD, 0x6F, 0x77, 0x03, 0xE9, 0x98, 0x01, 0x80, 0x7E, 0xFD, 0x0A, 0x75, 0x03, 0xE9, 0x8F, 0x01}; char Patch1After[BugPatch1Len] = {0xB3, 0x06, 0xF6, 0xE3, 0x89, 0xC3, 0x8D, 0x7E, 0xF6, 0x8D, 0xB7, 0x6C, 0x06, 0x8C, 0xD0, 0x8E, 0xC0, 0xA5, 0xA5, 0xA5, 0x8A, 0x46, 0xF7, 0x28, 0xE4, 0x8B, 0x5E, 0x0E, 0x89, 0x07, 0x80, 0x7E, 0xF6, 0x01, 0x75, 0x08, 0xB8, 0x01, 0x00, 0xE9, 0xDE, 0x01, 0xEB, 0xF8, 0x80, 0x7E, 0xF6, 0x02, 0x74, 0x03, 0xE9, 0xCC, 0x01, 0x80, 0x7E, 0xFD, 0x40, 0x72, 0x0F, 0x80, 0x7E, 0xFD, 0x6F, 0x77, 0x09, 0x83, 0x7E, 0x12, 0x00, 0x74, 0xDD, 0xE9, 0x97, 0x01, 0x80, 0x7E, 0xFD, 0x0A, 0x75, 0x02, 0xEB, 0xEF}; #define FF_Invalid 0 #define FF_Original 1 #define FF_Patched 2 /* while not necessarily relevant here, DOS imposes a 64-character limit on the "current directory" path; together with 3 letters for the drive letter, and 12 characters for the 8.3 filename, plus the null terminating character, and we get 80.*/ #define ExeLen 80 char ExeIn[ExeLen]; char ExeOut[ExeLen]; char ExeTemp[L_tmpnam+3]; /* hold the temporary filename used during saving */ char YesNo[2] = {0,0}; #define AnswerYes (YesNo[0] == 'Y' || YesNo[0] == 'y') #define ExeOutF_CREATE 0 #define ExeOutF_REPLACE 1 unsigned int tmpCount = 0; int main() { int status, outStatus; FILE *ExeInF = NULL, *ExeOutF = NULL; char *newstuff; status = getInFile(ExeIn, &ExeInF); switch (status) { case FF_Original: newstuff = Patch1After; outStatus = getOutFile("patched", ExeIn, ExeOut, &ExeOutF); break; case FF_Patched: newstuff = Patch1Before; outStatus = getOutFile("unpatched", ExeIn, ExeOut, &ExeOutF); break; default: return status; } switch (outStatus) { case ExeOutF_REPLACE: printf ("\nCreating temporary file..."); if (getTmpFile(ExeTemp, &ExeOutF, extractDriveLetter(ExeOut)) == 0) { printf ("success!\n" "Now writing to temporary file %s...", ExeTemp); if (patch(ExeInF, ExeOutF, newstuff) == 0) { printf ("success!\n" "Now deleting your old %s file...", ExeOut); fclose(ExeInF); fclose(ExeOutF); if (remove(ExeOut) == 0) { printf ("success!\n"); printf ("And finally, renaming the new file %s to %s...", ExeTemp, ExeOut); if (rename(ExeTemp, ExeOut) == 0) { printf ("success!\n"); status = 0; break; } else printf ("FAILED!\n"); } else { printf ("\nError! Cannot delete file!\n"); } printf ("\nAs a result, the new file has been written to %s instead of %s.\n" "Sorry for the inconvenience!\n", ExeTemp, ExeOut); return -1; } else printf ("\nError while writing to temporary file %s!\n", ExeTemp); } else printf ("\nError creating temporary file!\n"); printf ("Program must directly overwrite %s! Proceed (Y/N)? ", ExeOut); scanf (" %1s", YesNo); if (!AnswerYes) { status = -1; break; } /* purposely no BREAK here */ case ExeOutF_CREATE: fclose(ExeOutF); if ((ExeOutF = fopen(ExeOut, "wb")) != NULL) { printf ("\nWriting to file %s...", ExeOut); if ((status = patch(ExeInF, ExeOutF, newstuff)) == 0) { printf ("success!\n"); break; } } printf ("\nError writing to file %s! Program gives up!\n", ExeOut); status = -1; break; default: /* defensive programming; code should never reached here */ printf ("Internal error occurred in program during SAVE!\n" "Please e-mail a bug report to ccexplore@yahoo.com\n"); return -1; } fclose (ExeInF); fclose (ExeOutF); if (status == 0) { printf ("%s has been successfully patched/unpatched.\n", ExeIn); return 0; } else { printf ("%s was NOT successfully patched/unpatched!\n", ExeIn); return -1; } } int getInFile(char* ExeIn, FILE **ExeInF) { int status; do { fclose(*ExeInF); printf ("\nEnter file to patch/unpatch: "); scanf (" %79s",ExeIn); if ((*ExeInF = fopen(ExeIn,"rb")) == NULL) { printf ("\nError opening %s for input!",ExeIn); status = -1; } else { printf ("\nFile successfully opened! Examining file...\n"); status = checkFileType(*ExeInF); switch (status) { case FF_Invalid: printf ("%s does not appear to be a valid CHIPS.EXE file!", ExeIn); status = -1; break; case -FF_Original: printf ("%s looks similar to the original CHIPS.EXE file, but\n" "the filesize is different!\n" "Proceed to patch anyway (Y/N)? ", ExeIn); scanf (" %1s", YesNo); if (AnswerYes) return FF_Original; else { status = -1; break; } case FF_Original: printf ("%s has been recognized as an original CHIPS.EXE file.\n" "Proceed to patch it so it won't crash anymore (Y/N)? ", ExeIn); scanf (" %1s", YesNo); if (AnswerYes) return FF_Original; else { status = 0; break; } case -FF_Patched: printf ("%s looks similar to the patched CHIPS.EXE file, but\n" "the filesize is different!\n" "Proceed to unpatch anyway (Y/N)? ", ExeIn); scanf (" %1s", YesNo); if (AnswerYes) return FF_Patched; else { status = -1; break; } case FF_Patched: printf ("%s has been recognized as a patched CHIPS.EXE file.\n" "Proceed to unpatch (revert back to original CHIPS.EXE) " "(Y/N)? ", ExeIn); scanf (" %1s", YesNo); if (AnswerYes) return FF_Patched; else { status = 0; break; } default: /* defensive programming; code should never reached here */ printf ("Internal error occurred in program during OPEN!\n" "Please e-mail a bug report to ccexplore@yahoo.com\n"); return -1; } } printf ("\nTry a different file (Y/N)? "); scanf (" %1s",YesNo); if (AnswerYes) continue; else return status; } while (1); } int checkFileType(FILE *ExeInF) { int returnCode; long int i; int b; char *signature; for (i=0; i < BugPatch1Loc; i++) if ((b = getc(ExeInF)) == EOF) return FF_Invalid; /* file size too small */ b = getc(ExeInF); if ((char)b == Patch1Before[0]) { signature = Patch1Before; returnCode = FF_Original; } else if ((char)b == Patch1After[0]) { signature = Patch1After; returnCode = FF_Patched; } else return FF_Invalid; /* file size too small, or bad signature */ for (i=1; i < BugPatch1Len; i++) { b = getc(ExeInF); if (b == EOF || (char)b != signature[i]) return FF_Invalid; /* file size too small, or signature not recognized */ } /* valid signature at patching location, but file size smaller than expected */ for (i = BugPatch1Loc + BugPatch1Len; i < ChipFileSize; i++) if ((b = getc(ExeInF)) == EOF) return -returnCode; /* valid signature at patching location, but file size too large */ if ((b = getc(ExeInF)) != EOF) return -returnCode; else return returnCode; } int getOutFile(char* filetypeString, char* ExeIn, char* ExeOut, FILE **ExeOutF){ int fileExist; do { printf("\nEnter pathname to save this %s CHIPS.EXE to: ", filetypeString, ExeIn); scanf(" %79s", ExeOut); fileExist = 0; /* if (ExeOut[0] == 0) { strncpy(ExeOut, ExeIn, ExeLen); fileExist = 1; }*/ fclose(*ExeOutF); *ExeOutF = fopen(ExeOut,"rb"); if (!fileExist) fileExist = (*ExeOutF != NULL); else if (*ExeOutF != NULL) return 1; /* skips over the confirmation to overwrite */ else fileExist = 0; if (fileExist) { printf("\nFile already exists! Overwrite (Y/N)? "); scanf(" %1s", YesNo); if (!AnswerYes) continue; } else { if ((*ExeOutF = fopen(ExeOut,"ab")) == NULL) { printf("\nTrouble creating new file %s. " "You must try a different pathname.\n", ExeOut); continue; } } return fileExist; } while (1); } int patch(FILE *ExeInF, FILE *ExeOutF, char *patchdata) { long int i; int b; if (fseek(ExeInF, 0L, SEEK_SET) != 0) return -1; if (fseek(ExeOutF, 0L, SEEK_SET) != 0) return -1; for(i=0; i