private string deObfuscateImage(ObfuscationMode obfMode, string pathOfInputGif, string strGuid) { string pathToTemp = Path.GetTempPath(); string nameOfGifForOutputCompositeGif; int pixelYDestination; int pixelXDestination; DateTimeOffset now = DateTimeOffset.UtcNow; string strUtcTicks = now.UtcTicks.ToString(); string iso = DateTime.UtcNow.ToString("yyyy.MM.ddTHH.mm.ss.fffff"); if (obfMode == ObfuscationMode.DEOBFUSCATE) { nameOfGifForOutputCompositeGif = "{0}-TEMP-TEST-COMPOSITE-DEOBFUSCATE-OUTPUT-{1}-" + strGuid + "-{2}"; } else { nameOfGifForOutputCompositeGif = "{0}-TEMP-TEST-COMPOSITE-OBFUSCATE-OUTPUT-{1}-" + strGuid + "-{2}"; } string pathCompositeImageOutPreRotate = Path.Combine(pathToTemp, String.Format(nameOfGifForOutputCompositeGif, iso, "A-PRE-ROTATE", TESTIMAGE_OBFUSCATED)); string pathCompositeImageOutPostRotate = Path.Combine(pathToTemp, String.Format(nameOfGifForOutputCompositeGif, iso, "B-PST-ROTATE", TESTIMAGE_OBFUSCATED)); ql(String.Format("Starting deObfuscateImage - about to start writing multiple tiles to a single file. Tile width : {0} and tile height : {1}.", SMALLTILEWIDTH, SMALLTILEHEIGHT)); using (var image = new MagickImage(pathOfInputGif)) { if (obfMode == ObfuscationMode.OBFUSCATE) { image.Rotate(180); } int tilesHigh = image.Height / SMALLTILEHEIGHT; int tilesWide = image.Width / SMALLTILEWIDTH; int tileIndex = 0; //The 'Blue' background is just to highlight any problems with tile layout var imageout = new MagickImage(MagickColors.Blue, image.Width, image.Height); //Two steps to the List because I couldn't figure out a better way to do it ! IEnumerable <IMagickImage <byte> > enumerableTiles = image.CropToTiles(SMALLTILEWIDTH, SMALLTILEHEIGHT); List <IMagickImage <byte> > lstTiles = enumerableTiles.ToList <IMagickImage <byte> >(); // for (int ystepper = 0; ystepper < tilesHigh; ystepper++) { pixelYDestination = ystepper * SMALLTILEHEIGHT; for (int xstepper = 0; xstepper < tilesWide; xstepper++) { if ((ystepper % 2) == 0) { pixelXDestination = xstepper * SMALLTILEWIDTH; } else { pixelXDestination = ((((image.Width / SMALLTILEWIDTH) - 1) - xstepper) * SMALLTILEWIDTH); } //'Paste' the current tile onto the output image at the X/Y determined above imageout.Composite(lstTiles[tileIndex], pixelXDestination, pixelYDestination); ql(String.Format("Writing tile {0} at location ({1}, {2})", tileIndex, pixelXDestination, pixelYDestination)); tileIndex++; } } imageout.Write(pathCompositeImageOutPreRotate); if (obfMode == ObfuscationMode.DEOBFUSCATE) { imageout.Rotate(180); } imageout.Write(pathCompositeImageOutPostRotate); } //return Path.GetFileName(pathCompositeImageOutPostRotate).ToString(); return(pathCompositeImageOutPostRotate); }
public byte[] TransformWorkbookBytes(byte[] bytes, ObfuscationMode mode, string password = XorObfuscation.DefaultPassword) { VirtualStreamReader vsr = new VirtualStreamReader(new MemoryStream(bytes)); MemoryStream ms = new MemoryStream(); BinaryWriter bw = new BinaryWriter(ms); while (vsr.BaseStream.Position < vsr.BaseStream.Length) { BiffHeader bh; bh.id = (RecordType)vsr.ReadUInt16(); //Handle case where RecordId is empty if (bh.id == 0) { break; } bh.length = vsr.ReadUInt16(); //Taken from https://social.msdn.microsoft.com/Forums/en-US/3dadbed3-0e68-4f11-8b43-3a2328d9ebd5/xls-xor-data-transformation-method-1 byte XorArrayIndex = (byte)((vsr.BaseStream.Position + bh.length) % 16); //We remove the FilePass Record for the decrypted document if (mode == ObfuscationMode.Decrypt && bh.id == RecordType.FilePass) { //Skip the remaining FilePass bytes ushort encryptionMode = vsr.ReadUInt16(); if (encryptionMode != 0) { throw new NotImplementedException("FilePass EncryptionMode of " + encryptionMode + " is unsupported."); } ushort key = vsr.ReadUInt16(); ushort verify = vsr.ReadUInt16(); ushort passwordVerify = CreatePasswordVerifier_Method1(password); if (verify != passwordVerify) { throw new ArgumentException( "Incorrect decryption password. Try bruteforcing the password with another tool."); } continue; } ; bw.Write(Convert.ToUInt16(bh.id)); bw.Write(Convert.ToUInt16(bh.length)); //If we're encrypting, then use the byte writer for our current position rather than the read stream if (mode == ObfuscationMode.Encrypt) { XorArrayIndex = (byte)((bw.BaseStream.Position + bh.length) % 16); } //Nothing to decrypt for 0 length if (bh.length == 0) { continue; } switch (bh.id) { case RecordType.BOF: case RecordType.FilePass: case RecordType.UsrExcl: case RecordType.FileLock: case RecordType.InterfaceHdr: case RecordType.RRDInfo: case RecordType.RRDHead: byte[] recordBytes = vsr.ReadBytes(bh.length); bw.Write(recordBytes); //If this is the first BOF record, we inject the appropriate FilePass record if (mode == ObfuscationMode.Encrypt && bh.id == RecordType.BOF && vsr.BaseStream.Position == (bh.length + 4)) { ushort key = CreateXorKey_Method1(password); ushort verify = CreatePasswordVerifier_Method1(password); FilePass filePass = new FilePass(key, verify); byte[] filePassBytes = filePass.GetBytes(); bw.Write(filePassBytes); } continue; case RecordType.BoundSheet8: //Special Case - don't encrypt/decrypt the lbPlyPos Field uint lbPlyPos = vsr.ReadUInt32(); //For encryption we need to adjust this by the added FilePass record length //Decryption we auto-fix afterwards, but encrypted entries don't auto-fix well // if (mode == ObfuscationMode.Encrypt) // { // lbPlyPos += 10; // } bw.Write(lbPlyPos); //Since we are skipping lbPlyPos, we need to update the XorArrayIndex offset as well XorArrayIndex = (byte)((XorArrayIndex + 4) % 16); byte[] remainingBytes = vsr.ReadBytes(bh.length - 4); if (mode == ObfuscationMode.Decrypt) { byte[] decryptedBytes = DecryptData_Method1(password, remainingBytes, XorArrayIndex); bw.Write(decryptedBytes); } else { byte[] encryptedBytes = EncryptData_Method1(password, remainingBytes, XorArrayIndex); bw.Write(encryptedBytes); } continue; default: byte[] preTransformBytes = vsr.ReadBytes(bh.length); if (mode == ObfuscationMode.Decrypt) { byte[] decBytes = DecryptData_Method1(password, preTransformBytes, XorArrayIndex); bw.Write(decBytes); } else { byte[] encBytes = EncryptData_Method1(password, preTransformBytes, XorArrayIndex); bw.Write(encBytes); } continue; } } return(bw.GetBytesWritten()); }
/// <summary> /// /// This takes the path to input GIF which has been previously obfucscated by slicing up into tiles /// and then re-arranging the tiles before writing the de-obfucasted image to disk. /// /// Based on a previously known tile size and the width/height of the input image the process slices /// up the input image into a list of tiles. The list is then traversed and each tile is written to /// the output disk. The position of each tile in the output is determined by: in the odd numbered /// rows, writing out the tiles left to right and; in the even numbered rows writing out the tiles /// right to left. /// /// When the writing to output is finished the output image is rotated by 180 degrees. /// /// NOTE: The processing shown here may be thought to be weird but it emulates processing seen in /// another system so what it is is what it is ;-) /// /// </summary> /// <param name="pathOfInputGif">The path of input GIF.</param> private string deObfuscateImage(ObfuscationMode obfMode, string pathOfInputGif) { return(this.deObfuscateImage(obfMode, pathOfInputGif, System.Guid.NewGuid().ToString())); }