/* 29/12/2006 - 08/08/2007 XORSearch V1.2, search for a XOR or ROL encoded string in a file Use -s to save the XOR or ROL encoded file containing the string Use -l length to limit the number of printed characters (50 by default) Use -i to ignore the case when searching Source code put in public domain by Didier Stevens, no Copyright https://DidierStevens.com Use at your own risk Shortcommings, or todo's ;-) - no pipe support (file redirection) - file must fit in memory History: 15/01/2007: multiple hits, only printable characters, length argument 08/08/2007: 1.2: added ROL 1 to 7 encoding */ #include #include #include #include #include #include #define XSIZE 1024 #define OPR_XOR "XOR" #define OPR_ROL "ROL" int *piFound; int compare(char cX, char cY, int iFlagIgnoreCase) { if (iFlagIgnoreCase && isalpha(cX) && isalpha(cY)) return tolower(cX) == tolower(cY); else return cX == cY; } // Search algorithm: http://www-igm.univ-mlv.fr/~lecroq/string/node8.html#SECTION0080 void preKmp(char *pcX, int m, int kmpNext[], int iFlagIgnoreCase) { int i, j; i = 0; j = kmpNext[0] = -1; while (i < m) { while (j > -1 && !compare(pcX[i], pcX[j], iFlagIgnoreCase)) j = kmpNext[j]; i++; j++; if (compare(pcX[i], pcX[j], iFlagIgnoreCase)) kmpNext[i] = kmpNext[j]; else kmpNext[i] = j; } } int KMP(char *pcX, int m, char *pcY, int n, int iFlagIgnoreCase) { int i, j, kmpNext[XSIZE]; int iCountFinds = 0; /* Preprocessing */ preKmp(pcX, m, kmpNext, iFlagIgnoreCase); /* Searching */ i = j = 0; while (j < n) { while (i > -1 && !compare(pcX[i], pcY[j], iFlagIgnoreCase)) i = kmpNext[i]; i++; j++; if (i >= m) { piFound[iCountFinds++] = j-i; i = kmpNext[i]; } } return iCountFinds; } long ParseNumericArg(char *szArg) { char *szError; long lResult; lResult = strtol(szArg, &szError, 0); if (*szError != '\0' || lResult == LONG_MIN || lResult == LONG_MAX) return -1; else return lResult; } int ParseArgs(int argc, char **argv, int *piSave, int *piLength, int *piIgnoreCase, char **ppcFile, char **ppcSearch) { int iIterArgv; int iCountParameters; int iFlagLength; char *pcFlags; iCountParameters = 0; iFlagLength = 0; *piSave = 0; *piLength = -1; *piIgnoreCase = 0; for (iIterArgv = 1; iIterArgv < argc; iIterArgv++) { if (argv[iIterArgv][0] == '-') { if (iFlagLength) return 1; pcFlags = argv[iIterArgv] + 1; while (*pcFlags) switch (*pcFlags++) { case 's': *piSave = 1; break; case 'i': *piIgnoreCase = 1; break; case 'l': iFlagLength = 1; break; default: return 1; } } else if (iFlagLength) { *piLength = ParseNumericArg(argv[iIterArgv]); if (*piLength < 1) return 1; iFlagLength = 0; } else if (iCountParameters == 0) { *ppcFile = argv[iIterArgv]; iCountParameters++; } else if (iCountParameters == 1) { *ppcSearch = argv[iIterArgv]; iCountParameters++; } else iCountParameters++; } if (iCountParameters != 2) return 1; else return 0; } void XOR(unsigned char *pcBuffer, long lSize, unsigned char cXOR) { unsigned char *pcBufferEnd; pcBufferEnd = pcBuffer + lSize; while (pcBuffer < pcBufferEnd) *pcBuffer++ ^= cXOR; } void ROL(unsigned char *pcBuffer, long lSize) { unsigned char *pcBufferEnd; pcBufferEnd = pcBuffer + lSize; while (pcBuffer < pcBufferEnd) { *pcBuffer = *pcBuffer << 1 | *pcBuffer >> 7; pcBuffer++; } } void SaveFile(char *pcFile, char *sOperation, unsigned char ucXOR, void *pBuffer, long lSize) { char szFileNameSave[XSIZE]; FILE *fOut; snprintf(szFileNameSave, XSIZE, "%s.%s.%02X", pcFile, sOperation, ucXOR); if ((fOut = fopen(szFileNameSave, "wb")) == NULL) fprintf(stderr, "error opening file %s\n", szFileNameSave); else { if (fwrite(pBuffer, lSize, 1, fOut) != 1) fprintf(stderr, "error writing file %s\n", szFileNameSave); fclose (fOut); } } void PrintFinds(int iCountFinds, int iLength, char *sOperation, unsigned char ucOperand, struct stat statFile, void *pBuffer) { int iIter1, iIter2; int iMaxPrint; for (iIter1 = 0; iIter1 < iCountFinds; iIter1++) { printf("Found %s %02X position %04X: ", sOperation, ucOperand, piFound[iIter1]); iMaxPrint = iLength; for (iIter2 = piFound[iIter1]; iIter2 < statFile.st_size && ((char *)pBuffer)[iIter2]; iIter2++) { if (isprint(((char *)pBuffer)[iIter2])) putchar(((char *)pBuffer)[iIter2]); else putchar('.'); if (iLength > 0 && --iMaxPrint == 0) break; } putchar('\n'); } } main(int argc, char **argv) { FILE *fIn; struct stat statFile; void *pBuffer; unsigned char ucOPRIter; char *pcArgFile; char *pcArgSearch; int iFlagSave; int iFlagIgnoreCase; int iLength; int iCountFinds; if (ParseArgs(argc, argv, &iFlagSave, &iLength, &iFlagIgnoreCase, &pcArgFile, &pcArgSearch)) { fprintf(stderr, "Usage: XORSearch [-si] [-l length] file string\n" "XORSearch V1.2, search for a XOR or ROL encoded string in a file\n" "Use -s to save the XOR or ROL encoded file containing the string\n" "Use -l length to limit the number of printed characters (50 by default)\n" "Use -i to ignore the case when searching\n" "Source code put in the public domain by Didier Stevens, no Copyright\n" "Use at your own risk\n" "https://DidierStevens.com\n"); return -1; } if (iLength == -1) iLength = 50; if (strlen(pcArgFile) >= XSIZE-1) { fprintf(stderr, "Error: filename is too long\n"); return -1; } if (strlen(pcArgSearch) >= XSIZE-2) { fprintf(stderr, "Error: search string is too long\n"); return -1; } if (stat(pcArgFile, &statFile) != 0) { fprintf(stderr, "error opening file %s\n", pcArgFile); return -1; } if ((pBuffer = malloc(statFile.st_size)) == NULL) { fprintf (stderr, "file %s is too large %ld\n", pcArgFile, statFile.st_size); return -1; } if ((fIn = fopen(pcArgFile, "rb")) == NULL) { fprintf(stderr, "error opening file %s\n", pcArgFile); free (pBuffer); return -1; } if (fread(pBuffer, statFile.st_size, 1, fIn) != 1) { fprintf(stderr, "error reading file %s\n", pcArgFile); fclose (fIn); free (pBuffer); return -1; } fclose (fIn); if ((piFound = (int *)malloc(statFile.st_size * sizeof(int))) == NULL) { fprintf (stderr, "file %s is too large %ld\n", pcArgFile, statFile.st_size); free (pBuffer); return -1; } ucOPRIter = 0; do { XOR((unsigned char *) pBuffer, statFile.st_size, ucOPRIter); iCountFinds = KMP(pcArgSearch, strlen(pcArgSearch), pBuffer, statFile.st_size, iFlagIgnoreCase); if (iCountFinds > 0) { PrintFinds(iCountFinds, iLength, OPR_XOR, ucOPRIter, statFile, pBuffer); if (iFlagSave) SaveFile(pcArgFile, OPR_XOR, ucOPRIter, pBuffer, statFile.st_size); } XOR((unsigned char *) pBuffer, statFile.st_size, ucOPRIter); } while (++ucOPRIter); for (ucOPRIter = 1; ucOPRIter < 8; ucOPRIter++) { ROL((unsigned char *) pBuffer, statFile.st_size); iCountFinds = KMP(pcArgSearch, strlen(pcArgSearch), pBuffer, statFile.st_size, iFlagIgnoreCase); if (iCountFinds > 0) { PrintFinds(iCountFinds, iLength, OPR_ROL, ucOPRIter, statFile, pBuffer); if (iFlagSave) SaveFile(pcArgFile, OPR_ROL, ucOPRIter, pBuffer, statFile.st_size); } } free (pBuffer); free (piFound); return 0; }