//------------------------------------------------ //--- 010 Editor Script File // // File: XORSelection.1sc // Authors: Didier Stevens // Version: 6.0 // Purpose: Xors the current selection with a set of bytes, // which causes the bytes to be encoded so they // cannot be read by a human. Run the Xor again on // the encoded selection to decode the data. // Category: Binary // History: // 6.0 2020-11-04 D Stevens: added option c // 5.0 2020-05-07 D Stevens: added options // 4.0 2018-03-25 D Stevens: refactoring to handle keys with null bytes and hex keys with whitespace // 3.1 2016-02-10 SweetScape Software: Updated header for repository submission. // 3.0 2014-12-11 D Stevens: Added hex processing; refactoring // 1.0 2009-05-26 D Stevens: start // // Source code put in public domain by Didier Stevens, no Copyright // https://DidierStevens.com // Use at your own risk //------------------------------------------------ #define TITLE "XORSelection" unsigned int uiOptionsReverse = 0; unsigned int uiOptionsLiteral = 0; int iOptionsShift = 0; unsigned int uiOptionsChangeKeyWithValueBeforeXOR = 0; unsigned int uiOptionsChangeKeyWithValueAfterXOR = 0; int HexDigitToInt(int digit) { if (digit >= '0' && digit <= '9') return digit - '0'; if (digit >= 'a' && digit <= 'f') return digit - 'a' + 10; if (digit >= 'A' && digit <= 'F') return digit - 'A' + 10; return -1; } string RemoveWhitespace(string sInput) { int iIter; string sResult = ""; for (iIter = 0; iIter < Strlen(sInput); iIter++) if (sInput[iIter] != ' ' && sInput[iIter] != '\n' && sInput[iIter] != '\r' && sInput[iIter] != '\t') sResult = sResult + sInput[iIter]; return sResult; } unsigned int CalculateKeyIndex(int iIter, int iKeyLength) { if (1 == uiOptionsReverse) return iKeyLength - 1 - (iIter + iOptionsShift) % iKeyLength; else return (iIter + iOptionsShift) % iKeyLength; } unsigned int ParseOptions(string sInput) { string sOption; unsigned int uiReturn = 0; uiOptionsReverse = 0; uiOptionsLiteral = 0; iOptionsShift = 0; uiOptionsChangeKeyWithValueBeforeXOR = 0; uiOptionsChangeKeyWithValueAfterXOR = 0; while (sInput != "") { sOption = SubStr(sInput, 0, 1); sInput = SubStr(sInput, 1); if ("r" == sOption) uiOptionsReverse = 1; else if ("l" == sOption) uiOptionsLiteral = 1; else if ("s" == sOption) { int iSign = 1; if ('-' == sInput[0]) { sInput = SubStr(sInput, 1); iSign = -1; } iOptionsShift = 0; while (sInput[0] >= '0' && sInput[0] <= '9') { iOptionsShift = iOptionsShift * 10 + sInput[0] - '0'; sInput = SubStr(sInput, 1); } iOptionsShift = iOptionsShift * iSign; } else if ("c" == sOption) { if ('b' == sInput[0]) uiOptionsChangeKeyWithValueBeforeXOR = 1; else if ('a' == sInput[0]) uiOptionsChangeKeyWithValueAfterXOR = 1; else uiReturn = 1; sInput = SubStr(sInput, 1); } else uiReturn = 1; } return uiReturn; } void Main(void) { int iIter, iStart, iSize, iKeyLength; string sKey; string sOptions; uchar ucRead; // Check that a file is open if(FileCount() == 0) { MessageBox(idOk, TITLE, "XORSelection can only be executed when a file is loaded."); return; } // Initializes the variables iSize = GetSelSize(); iStart = GetSelStart(); // Check that bytes were selected if(iSize == 0) { iSize = FileSize(); iStart = 0; } sOptions = ""; sKey = InputString(TITLE, "Input XOR key (start with 0x for hex), or leave empty for options", ""); if (sKey == "") { sOptions = InputString(TITLE, "Options (h for help)", ""); if (sOptions == "") { return; } else if (sOptions == "h") { MessageBox(idOk, TITLE, "r: reverse key\nl: literal key\ns: shift value (signed integer)\ncb: change key with value before XOR\nca: change key with value after XOR"); return; } if (ParseOptions(sOptions)) { MessageBox(idOk, TITLE, "Please enter valid options."); return; } sKey = InputString(TITLE, "Input the key (start with 0x for hex)", ""); if (sKey == "") { MessageBox(idOk, TITLE, "Please enter a valid key."); return; } } if (SubStr(sKey, 0, 2) == "0x" && 0 == uiOptionsLiteral) { string sHex = RemoveWhitespace(SubStr(sKey, 2)); int iIter2; int iHexDigit1; int iHexDigit2; if (Strlen(sHex) % 2 != 0) { MessageBox(idOk, TITLE, "Please enter a valid hex value (uneven digits)."); return; } iKeyLength = Strlen(sHex) / 2; if (iKeyLength == 0) { MessageBox(idOk, TITLE, "Please enter a valid hex value (no digits)."); return; } uchar aucKey[iKeyLength]; for (iIter2 = 0; iIter2 < Strlen(sHex); iIter2 += 2) { iHexDigit1 = HexDigitToInt(sHex[iIter2]); if (iHexDigit1 == -1) { MessageBox(idOk, TITLE, "Please enter a valid hex value: digit %c is not hexadecimal.", sHex[iIter2]); return; } iHexDigit2 = HexDigitToInt(sHex[iIter2 + 1]); if (iHexDigit2 == -1) { MessageBox(idOk, TITLE, "Please enter a valid hex value: digit %c is not hexadecimal.", sHex[iIter2 + 1]); return; } aucKey[iIter2 / 2] = iHexDigit1 * 0x10 + iHexDigit2; } } else { string aucKey = sKey; iKeyLength = Strlen(sKey); } if (iOptionsShift < 0) iOptionsShift = (iOptionsShift % iKeyLength) + iKeyLength; // Modify the selection for (iIter = 0; iIter < iSize; iIter++) { // Modify the current byte ucRead = ReadUByte(iStart + iIter); WriteUByte(iStart + iIter, ucRead ^ aucKey[CalculateKeyIndex(iIter, iKeyLength)]); if (1 == uiOptionsChangeKeyWithValueBeforeXOR) aucKey[CalculateKeyIndex(iIter, iKeyLength)] = ucRead; if (1 == uiOptionsChangeKeyWithValueAfterXOR) aucKey[CalculateKeyIndex(iIter, iKeyLength)] = ucRead ^ aucKey[CalculateKeyIndex(iIter, iKeyLength)]; } } Main();