CLR managed ESD Decryption

Discussion in 'Scripting' started by Superfly, Jul 5, 2015.

  1. Superfly

    Superfly MDL Expert

    Jan 12, 2010
    1,143
    543
    60
    #1 Superfly, Jul 5, 2015
    Last edited by a moderator: Apr 20, 2017
    For those that want a .Net version I thought I'd share this which is entirely managed (unlike qad's that is native API)
    NB: It doesn't update the integrity table's hash as I'm not sure that's really necessary.

    This one references a GUI - This is my prototype (the download section just loads products.xml from the media creator tool)
    [​IMG]

    - so change Main() for console if required.

    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Security.Cryptography;
    using System.Text;
    using System.IO;
    using System.Xml;
    using System.Collections;
    using CSWebDownloader;
    using DiscUtils.Iso9660;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Threading;
    using System.Reflection;
    
    namespace DecryptESD
    {
        //Class to provide feedback - needs a delegate in the GUI
        public class Progress{
            public static string Msg {get;set;}
        }
    
        static class Program
        {
            //Declare a static path to used across methods in the class
            private static string ESDfile = string.Empty;
    
            //Determine whether install.wim or install.esd is to be included
            private static bool esdFlag = true;
    
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new frmDecrypt());
                
            }
            public static bool Decrypt(string esdfile)
            {        
                    //Declare an array of cryptokeys - the correct one picked according to edition and build from XML in ESD    
                string[] Crytokeys = {
                     //0 = Windows 10 Preview - new
                     "BwIAAACkAABSU0EyAAgAAAEAAQCf1EyRJa6EtwRlee0ClaLRcEhgNGS4jfVouO+MuuTnTV3avzNwgoXpQvQf4CQdsCQhBWyUUbvwbNnYG+ESsOtAiw7p7+jRrHAAR5rWRBCNeJTnKSBpz254JnjSVFMRczulrigEhSRz5bidP6SRbPK9/sKWopCND34cNNddjADibpdw7oW1g7Chb9snAjpoLv+cpSA0IWXURiT5Nz4vdQ3NPTkvH4v9MwH//JUuv19irf3QYUJSN+QkmLX65cKxxKmcUYe0/MbrxUu7KK3OM/nDpmKuKbjbUdeY4PD2uBwPQ4Ha91+bx4i7aWhqC5MYpN9PjSI+2C3mJ6uYobz5WUK/J7+MzvWOcPOgsR5RYynyZOmnD7x1cLQncA1ZgkaXkhwZXswTQGy9KRdcuZ3wIHwdzeOLbFgZu8dyj9eSuMbNPLlWFI7Ciurh1bHCMr81LiG5KWa4jy54MwD+NUkVOXbiBsjSijcfEvSFP1B4w0PPWXEf9OS9+wI5a2YZ0O0NoPLJqdbQDLlNL/bkOmdIBXs9OMEwbMZP0vhPyY19jotBsrIxQUyc5ThXr8uDzTh+J2dl03j2wpqRwykseKqp8HVjAPNYabnOSaq2/aPYIGXt6KPn/C+7xz4hyY3tTJcHK7xYAMEaJmKmqaiOR5+yO1zpevO04CYmZdFo6wRbbmrNyVu/p5dAFZyFyyglW7ieFKSgAz/isIPh+G3p8m3YF9grQ2TIQNNIN1pLJPvWvzqDIinr8gzTwzER9ZXlH9U26m8aiXptTRlXK2ws8LyVYKPqNHM9DwPJS9PuvcOykCBdeB7JvopdBU1jJUBWBsDMve0jvTWai9pujkRFsG61oclHMc1E635g+hjRxbKv7L/P2kvg5RXa6J+rpVo5jgJQ70CBgtqpNHLf6QteU8sDIlxKet1+lw7YRvfq9Wi6rmxlGqwrA9zWlCZLvnCFl8q//0a6Q+68yn5325zy67oz/X7FTWgoUU9sDDDprSwvYukrT3BlU3ntY1YAiXQtZsg6LknToQZdtj4z/bUP7sHMkds96MNRj+/+iuzEEyJaQPNGWOlzJkMa7Yujbq+5ScsxoXC5Iy8v1mi10hzYC54ByX1L9yfwi6F0rklsshl5IPSgIH+MOoZM0W+5/KlQCYeKZsIGJfyV+cVbkjLsVsFMOV+f3I+GKrJMoU8zg0vBP1SMIaEXxE5R7hd2lnzX2wIZwJvKhyHV2KSgyAQ0vpFbopB64Y1dkC/kDvEpluQ/WHjqHzwTKJyXBnFAKRNQO4BqmyNMib5N21l96Mm2nUHcxmd+KeXMuZNavvVds40FL/rOid/ROc8fK6SG/3YI+XbO4L28nPmEQPYHTfxBfkefRtUqaxC5K7QMX5LTI/ZaB+ZgJtbOXtvhUaVfyFlEzr1RBqFXXe6NhpP052qI16G7C0Sx7CT+aMv+16zqcBLb/1r4rqGhDTJjcxnkesZdc/gbDJt44RzdGo+FiZZItD3TmnyKOPjNExgA0qxdoFnwnxb5lp+qmlNi0XaOBwgSHSdiPhw=",
                     //1 = Windows 10 Preview - old
                    "BwIAAACkAABSU0EyAAgAAAEAAQCb7Jceg+YeJXNdb7HHJ0irxNsGSWu7itcuEQkfS+znxm6XwxmfINt8SGzbIIka2eOB2t9L0lGwSM0uP3UPyhBzzc8FL735OL+RnimL4SVKDb5AsYpREOcNQgKsk6OOeo8q8+4+swvwfe6+VloNqCrjiE6bCS7TrC+haV+eabj1QaT+aSXNWrukmrvi1VFoQIVeet5BqHzciVV+bv3/iSG/EEkxV6Yqq4Y2o9bvSDIbE+lGc1bKPlT9zy+lYx+WMB0Nfzo7nIrKs7qCw8GbeRTsHo5GMWxrLNltFsDpoO0C62pSvxEGB/id2TwESrd7brudppjjJ+LdbCBUNam6zx2lhZmjconDvvWLYC6KXVVgTh5WHjv8z0dxkD+Hc6o6OhdXuxAA5xtZYgIah8t2ZVK5V2PEFnusqZP7fqbSUJOp6sZe3AZWWVZz6dg6VqYpDMbKBz8rhHXXHjkaqIMrmxnSmHoB4fsxelWre9oxQoQJUkASAUhflDPKtFVe30oLsN6fNwBBNVKywJogPsClqIuNiQDpsXRFg8PYBgvqDQz8DRfDpu5WyhQjdD+eVQpeczWmTyPuwfGB0TscKDhzIhSwebKK0NwCn2LunmdJEOjJsnsYLrE63rsQdcXimzPifQ5XWlV9GUqo5ce+AlX0IMmw7DSZJBe9Sr1adBFuHQvRvQ1tGyQ5oD7WxKshS8WbvKT6cZb0XBE0Ru82gl9uSvJAgOJG9E8g7BApwCfaWAMEVj/Xd8DZSjZ0VWxRlsVkhjxWeiiQWg85J08JdjC2soG14IiXRTVAGogUTcUVlOPkovrWoRVqTMLAA+Vh0R6BpcAexwUv4YVmw2661iDUmnkYWyXMcSBQP43h5SjdLirO19b/1UD9lvaCaZpyokKMD6+GNJyCX9stVuS7c1ow/nsuVDgx3Rv7wE0as5h9WSheM5p6Lzf1UTHy1Mg2XpJAn37amw7rUnOkz4qqJ5ItRwAAhRn2Cn+PUtp5Ti1vfHmPd0PodAdTUo+5lYOGmXJxx0SHTh3dSCkSIJWjoAFYnrtEWMTszcenxYlZc2e6dWNZUPO4VyftrGkF4FpWxFC63Gd15uf3vUlStFXRArMh9KQ14sf4PGmpxmoXNZBWNsa7xizW83lkS3sbtnHtLEk6xyJ01sj+HWPoEuTzSbs6v3P8NstpN37xJui+hafIA5ILpB04qlxrxIRKEow31QzrMINyiwjCnxzIrXFuEQq9aY1930q5XgYfoV8OZirdIWKYtvPWzBgEkmi5w930kqjRyA81XwhH74guWww7A1lImbygBDl5wyE8GRVg2Emy7pU2sybyvtjMLSBgmTK8h6UqEXaupvuVCYjC8BzkUGWfTG9eh50TPpFZMO4vB2l2tbfwA2oTBwvjuwaDwdUIFXYjmdti3A+EGuhvDAeGzGxZhOmQir84CYXEKMj4yaqFvaKecMCtOOwWWpAEIzRWxXJIXN6EPqiZGEauZUAXjicVI/jpkKGhWUnaLZhNFTYD6Nl/eBMA2TPj6w4AiOnr21bDjgE=", 
                    //2 = Windows 8
                    "BwIAAACkAABSU0EyAAgAAAEAAQD1uPI7ZDwMsPbQSyrXDZblLcBf9VNiOSYNOWsLhHkyqpipeo7uOdXrONjHU2MQLZyobpVyunYMUgmU8vaBRMJHyW+Dj0xJqb9urwYFfoExrVDQVpDOOy0kDG1cGus8utua9d64n4vwRwHM4Mtta7T4sQ/o1J9L4QYUQ9xvDc8sWSA2T47n0y3Sj4OCY0RQeQFMke6+3cdnsAYevx4wL8aRS9PKHa8ItyazQJLxmKpb8HnOJn2Ws2ycr4ClGAjT4mqaflEvZ93DWZrk2RyWos0y20NmQ7mAWrVMSSuuINExN5PcvmAuMmvU2N/sCyNa2jPlaQTjJtm0DKoADRfu+W66vTHTwyJ+P2vKQv7HtbsNZMXN0cnhxSnUlwB1C5vnYRkh3tQItJu3OR5EfbF1a3Skx9g6fhCFKbZyjNWZbVxmfn9GDYmeviJiVsp2c0Wf5qg7QT5MJZtzHFB4T+/fV9TQetBCW9LKctFclCjgrw0aaqxNUHaDBvsR/uOG7KchmsuZa7DXvCc4vo15ZSVrCD5kGYhv+PzRfT4ht8r8S/GxAaPi8gZZsQBl/iOEAdhnWwTYwyZvxgkWegQw+guYfdZzi8JZmcoFA/OTognIG2SHMBu5nM8RpBfP8MKjP7UatbGPRo5+lNx26nxiw84bLVFokSxf5JcwhMP4CTHtR7tp6jnOaVHM3ANZ/Pk9mDuo9UBoLKt6amieTK+X9fvszpLbKpp9GKlp8bb4mk96Tgs1YP4108X1fMOJNrawn67OGXhJ+MqpiPs0ORDi5ILTCdfsxb+DLuAAyp/fcWuPnZEdC/VGFL/3Ydj9yqLuk3JFvwpSVD8nI+gZdFYI/qpRV4Q5mWoqzEyzObSj4yt8Do1FL1xgDEvdSxOqmLOB9Mer1DLzzTaE3O1Is3yvPerXJN7gqgpQ69k7if1a6H23AAeEVknNj6rQof2rBrFvnkquf/4uq01jVpQqW6Pez70eYPOuLyVRrdg/X8fSrXHiWdS/df9J0jRjFleHqJy9OI7MMyUK0OTfg1ZxBc8aSEkYaZ/u5G8BKJvhhySgiQvf+j4oAuPibIvZQZ3NF90Bso9hYL8HsvPB2CiYrNzTBuIafLJ6GfHT0dxamSSzP6rW+x+LnbUersORYhx65WekmTQM1Nh8+rFRTgKLQZAS9nVnc9GZ/aZ0SIN5+wWCAFwmLcpReuEcfFBKfdnItS8426wuRKIxzC9YkrQnTQkVuOpc/IUAFoVxApqMIWZYmFFpFGm5MWUiUYlq/Pb2rEgRyYhlASYxjL4QqERC2Aq1Fi8LOQ/TfTbkqyWZQqpWVWurlnMYCf5q8B1k21JwsCYbk/waosnRvbysiCJxzk4XbQ6vBrWiDurLh1KCGeFz8XFmhoudbdAjPWyB6TgY3K9OEHmVeHRbpCosy0gCuac5N6HGAqK9H1UpqgVGOqiSFC/EyRDUSXg14d8w7CZvZEsuMgPz29LGgGx0u2pLsWTsC5XHzgqT8vfJqFHm8w+0+rf9CO70eNcrkzVqn0ubtYDPHcTzdw8=", 
                    //3 = Unknown
                    "BwIAAACkAABSU0EyAAgAAAEAAQA5WQn9lTT4Ci679UcfZW6y8GkbeGTN9bKbgjnigtWmb7pPkifbr3ihmmtJ1ZWJmZCyDyeRNHwHDieOiM8zfgRJr575RKQI8yWi6wNAZVhUZDzKlch4BgABut2lcjZRT5o/Iyotd0tKW7Np1ur8D/HawdmHXdhN42hjg7PKNfvbgXICNNK+uschVzA39HWejEowO5ppaXBObLpN28Ipun3+s0xPNePHNVKD/4azFGd11ZZWmoh3NpnZXBGW3Jk2fn6hmrQ434Mrw4qdpIfTqh/d0aWGE7CseZPYR0F9Gd6DWyXn6JzkvPBPRNtdU7SK5Xeh+pDmTnme5av3c1XNBka2hScgqAT/BOAwaIvufA6QZXccHkeHnOVO/XHEi339OT0FJLNWearerYzfHtHh6D8+d7fIdHBsgMCMd/O2suhNVBWsipzA8UPnhy4+4uPAhoV7fqaYjPbE0fUTXT82SUG11W4tjs8+kTflzwX1qoNezfLdG6++h7LJSGJNPe2QfsQlB8NxLTReIHsyW5Fv5Q0LZH/Z5tJsOeu0P39z9k/oW30TGHIVnipOkdfA1PREFFwDWJ7MKsTQkW2ikSo9Y1HbUhIAb2xI9M28GAxGxdaPa69vAepfqiPOfEFOiZcUhVkLs6vv8GVOsLRMHFalKhwNi6bWX32R76OKmRHLPPl47dkHCBy/nBVSLaVyUo25gEX3pVgGDpoiHOTzeq1qvPdguBMXHtgvpvEMTBEMDFpp1hMqWkNcapPA25oGQmJr5LouRsfaHXe52LoJpniCA/Lf7cFSCbx+Wkh1bl/4uepz45bZGpjde4WvPnKPBOsi+EZ30lYi0mfKGBQ7HS6RE9iQSbOJYZ2djnY+ok8VkGrXU28l1kQParu3mnXOcQdviIJhtH6nor3GjXYbMml40/b3lGPn6qPjf0UW9glD2apdQMyTTxO2YzLlpiW96d5SwsPTDfP83YTZUZd6Er4cvmlb7G4qidlF7xIdVzzmGx5PPAuv6oLzMf3qFHKgo8nGC3ZcHfTsHz62eTvDFfCxuqTSbZYby+SraGvez3gZSKnbmvkfaBumgMPULGjsPC0FGMf1PXzxHQ3Y5chnpxYXF86h9NRRf9efeByhj3cS1AQGNidgIfo1l0CdNDtWegcZC/0U8+0O/lMGUnemt8a+Zl6jb+XHB9czxWjfetE3KcLXlfXrIBMM7Ve3JNEU1dL01vZ7THJXYWS6mIvGnOK+nW4GxsgReW8an5HlE1qF3O0r0vmpttZ6tK0NjxZFrUIVJwE+X/rJrRIS7eJJsgLoI4HD37AMcQ3rGY4/mnR7JitqNj4TNq+P/XNNl7wkjmRLOruLrOdShKON1ZvmaZ9BKUYI02FjxRntO8MPOrR2ImdRpTp+1rGtLlWWe0MxmPOkIQIsPKocIeitjWXIgNErcdzulagizd+cmcf2PPOyNkOd7yVv1xxxLy2ePYsHdGaYxIgM0xJ+NNrNpLz9/3W2quhEt4JL6jIhnIuvIUd67SQLwf7qy2jS3lLwbkBqPJpalAE="
                    };
    
                try
                {
                    //Check file validity
                    XmlDocument doc = new XmlDocument();
                    XmlNodeList nl;
                    ESDfile = esdfile;
    
                    //Get WIM data from file
                    Progress.Msg = "Checking the ESD for validity...";
                    string WIMXML = Decryption.GetXMLdata("<WIM>");
                    if (!WIMXML.Contains("<WIM>"))
                    {
                        Progress.Msg += Environment.NewLine + DateTime.Now.ToString("HH:mm:ss") + " ESD does not contain valid WIM data";
                        return true;
                    }
                    else if (!WIMXML.Contains("<ESD>"))
                    {
                        Progress.Msg += Environment.NewLine + DateTime.Now.ToString("HH:mm:ss") + " ESD is not encrypted";
                       return true;
                        
                    }
    
                    //Create an XML document to hold XML data from ESD
                    doc.LoadXml(WIMXML);
    
                    // Get the private key..
                    string xmlKey = doc.GetElementsByTagName("KEY").Item(0).InnerText;
    
                    //Get the offsets and byte range combination into array (makes it easier to iterate)
                    nl = doc.GetElementsByTagName("RANGE");
                    int arraylength = Convert.ToInt32(nl.Item(0).ParentNode.Attributes.Item(0).InnerText);
                    Int64[] OffsetBytes = new Int64[arraylength * 2];
                    int i = 0;
                    foreach (XmlNode nd in nl)
                    {
                        OffsetBytes = Convert.ToInt64(nd.Attributes.Item(0).InnerText);
                        OffsetBytes[i + 1] = Convert.ToInt64(nd.Attributes.Item(1).InnerText);
                        i += 2;
                    }
    
                    //Create byte arrays to hold original encrypted and decrypted data.
                    byte[] encryptedData;
                    byte[] decryptedData;
    
                    //Create a new instance of the RSACryptoServiceProvider class 
                    RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();
    
                    // get version and associate cryptokey
                    string getEdition = doc.GetElementsByTagName("DISPLAYNAME").Item(0).InnerText;
                    string build = doc.GetElementsByTagName("BUILD").Item(0).InnerText;
                    byte[] CryptoKey = new byte[Crytokeys[0].Length];
                    if (getEdition.Contains("Windows 10"))
                    {
                        if (Convert.ToInt32(build) > 10150)
                        {
                            CryptoKey = Convert.FromBase64String(Crytokeys[0]);
                        }
                        else
                        {
                            CryptoKey = Convert.FromBase64String(Crytokeys[1]);
                        }
                    }
                    else if (getEdition.Contains("Windows 8"))
                    {
                        CryptoKey = Convert.FromBase64String(Crytokeys[2]);
                    }
                    else
                    {
                        MessageBox.Show("Invalid cryptokey");
                    }
    
                    //Decrypt private key to get session key...
                    byte[] PrivateKey = Convert.FromBase64String(xmlKey);
                    RSAalg.ImportCspBlob(CryptoKey);
                    byte[] AESkey = RSAalg.Decrypt(PrivateKey, true);
                    RSAalg.Dispose();
    
                    //Loop through each block of encrypted data and write decrypted data back to file
                    Progress.Msg = "Decryption in progress...";
                    for (int j = 0; j < OffsetBytes.Length; j += 2)
                    {
                        encryptedData = Decryption.GetEncryptedData(OffsetBytes[j], OffsetBytes[j + 1]);
                        decryptedData = Decryption.DecryptIt(encryptedData, AESkey);
                        Decryption.WriteEncryptedData(OffsetBytes[j], decryptedData);
                    }
                    //Update WIM header,XML and integrity table data for validation
                    FixWim.UpdateWIM();
                    Progress.Msg = "Decryption completed...";
                    return true;
                }
                catch (CryptographicException e)
                {
                    //To Do: some exception handling in case the decryption did not succeed.
                    Progress.Msg = "Error(s) during decryption: " + Environment.NewLine + e.Message;
                    //MessageBox.Show(e.Message);
                    return false;
                }
                finally
                {
                    //return something innocuous;
                }
                
            }
            static class Decryption
            {
                internal static byte[] DecryptIt(byte[] encryptchunk, byte[] AESkey)
                {
                    try
                    {
                        int OriginalSize = encryptchunk.Length;
                        // Chunk needs to be in equal blocksizes of 16 bytes(determined by IV) 
                        // round up original size to nearest multiple of 16 bytes and add another +1  for IV
                        int NewBlockSize = ((encryptchunk.Length - 1) | 15) + 17;
    
                        Array.Resize(ref encryptchunk, NewBlockSize);
                        byte[] result = new byte[encryptchunk.Length];
    
                        //Get unencrypted remainder bytes outside the last 16-byte block
                        double size = (double)(OriginalSize) / 16;
                        size = (size - Math.Truncate(size)) * 16;
    
                        if (size < 0) size = 0;
                        byte[] finalBytes = new byte[(int)size];
                        Buffer.BlockCopy(encryptchunk, OriginalSize - finalBytes.Length, finalBytes, 0, finalBytes.Length);
                        
                        //Create a new instance of the AesCryptoServiceProvider managed class 
                        AesManaged AES = new AesManaged();
                        AES.Mode = CipherMode.CBC;
                        AES.Padding = PaddingMode.Zeros;
                        AES.Key = AESkey;
                        AES.BlockSize = 128;
    
                        using (MemoryStream msDecrypt = new MemoryStream(encryptchunk))
                        {
                            using (ICryptoTransform decryptor = AES.CreateDecryptor(AESkey, AES.IV))
                            {
                                int transed = 0;
                                for (int i = 0; i < encryptchunk.Length; i += transed)
                                {
                                    transed = decryptor.TransformBlock(encryptchunk, i, 16, result, i);
                                }
                                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
                                {
                                    csDecrypt.Write(encryptchunk, 0, encryptchunk.Length);
                                    csDecrypt.FlushFinalBlock();
                                    csDecrypt.Close();
                                }
                            }
                            result = msDecrypt.ToArray();
                            Array.Resize(ref result, OriginalSize);
    
                            //Write back excess bytes if original chunk size not a complete array of 16-byte blocksizes
                            if ((OriginalSize % 16) > 0)
                                Buffer.BlockCopy(finalBytes, 0, result, result.Length - finalBytes.Length, finalBytes.Length);
    
                            //Cleanup
                            msDecrypt.Close();
                        }
                        AES.Clear();
                        AES.Dispose();
                        return result;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    return null;
                }
                internal static byte[] GetEncryptedData(long startoffset, long encryptedbytes)
                {
                    byte[] ret = new byte[encryptedbytes];
                    using (BinaryReader BinRead = new BinaryReader(File.Open(ESDfile, FileMode.Open), Encoding.Default))
                    {
                        // Seek the required index.
                        BinRead.BaseStream.Seek(startoffset, SeekOrigin.Begin);
                        ret = BinRead.ReadBytes((int)encryptedbytes);
                        BinRead.Dispose();
                    }
                    return ret;
                }
                internal static void WriteEncryptedData(long startoffset, byte[] decryptedbytes)
                {
                    using (BinaryWriter BinWrite = new BinaryWriter(File.Open(ESDfile, FileMode.Open, FileAccess.Write), Encoding.Unicode))
                    {
                        // Seek the required index.
                        BinWrite.BaseStream.Seek(startoffset, SeekOrigin.Begin);
                        BinWrite.Write(decryptedbytes);
                        BinWrite.Dispose();
                    }
                }
                internal static string GetXMLdata(string strXML)
                {
                    byte[] StringBytes = Encoding.Unicode.GetBytes(strXML);
    
                    using (BinaryReader BinRead = new BinaryReader(File.Open(ESDfile, FileMode.Open, FileAccess.Read)))
                    {
                        int i = 0;
                        int j = 0;
                        int bytesRead;
                        string str = "";
                        Int64[] xmloffset = FixWim.WimHeader(BinRead);
                        byte[] ByteBuffer = new byte[Convert.ToInt32(xmloffset[1])];
    
                        BinRead.BaseStream.Seek(xmloffset[0], SeekOrigin.Begin);
    
                        Int64 WIMoffset = xmloffset[2] - Encoding.Unicode.GetBytes("</WIM>").Length;
                        Int64 WimEOF = BinRead.BaseStream.Length;
                        Int64 StartESDoffset = 0;
                        Int64 EndESDoffset = 0;
                        if (!strXML.Contains("WIM"))
    
                            while ((bytesRead = BinRead.Read(ByteBuffer, 0, ByteBuffer.Length)) > 0)
                            {
                                for (i = 0; i <= (ByteBuffer.Length - StringBytes.Length); i++)
                                {
                                    if (ByteBuffer == StringBytes[0])
                                    {
                                        for (j = 1; j < StringBytes.Length && ByteBuffer[i + j] == StringBytes[j]; j++) ;
                                        if (j == StringBytes.Length)
                                        {
                                            //Return the start ESD tag offset and send WIM tag offset
                                            if (!strXML.Contains("/"))
                                            {
                                                if (StartESDoffset == 0)
                                                    StartESDoffset = (xmloffset[0] + i + j) - StringBytes.Length;
                                            }
                                            else
                                            {
                                                EndESDoffset = (xmloffset[0] + i + j);
                                            }
                                            str = StartESDoffset.ToString() + "," + EndESDoffset.ToString() + "," + WIMoffset.ToString() + "," + WimEOF.ToString();
                                        }
                                    }
                                }
                            }
                        else if (strXML.Contains("WIM"))
                        {
                            ByteBuffer = BinRead.ReadBytes((int)xmloffset[1]).Skip(2).ToArray();
                            str = ASCIIEncoding.Unicode.GetString(ByteBuffer);
                        }
                        BinRead.Dispose();
                        return str;
                    }
                }
            }
            static class FixWim
            {
                static Int64 xmloffset;
                static Int64 xmlsize;
                static Int64 integrityoffset;
                static Int64 integritysize;
    
                static internal Int64[] WimHeader(BinaryReader BinRead)
                {
                    //Retrieves wim header
                    byte[] HdrBuffer = new byte[208];
                    BinRead.Read(HdrBuffer, 0, 208);
                    var WimHdr = new Utils.Wim.FileHeader();
                    WimHdr.Read(HdrBuffer, 0);
    
                    //Return an array with only the data we need -> NB: Compressed size = Original size so only need one
                    Int64[] HdrArray = new Int64[6];
    
                    if (WimHdr.IsValid())
                            {
                                //Get XML header data buffer
                                HdrArray[0] = xmloffset = WimHdr.XmlDataHeader.FileOffset;
                                HdrArray[1] = xmlsize = WimHdr.XmlDataHeader.CompressedSize;
                                //Get Integrity table header data buffer
                                HdrArray[2] = integrityoffset = WimHdr.IntegrityHeader.FileOffset;
                                HdrArray[3] = integritysize = WimHdr.IntegrityHeader.CompressedSize;
                            }
                    return HdrArray;
                }
    
                static internal void UpdateWIM()
                {
                    string[] temp = Decryption.GetXMLdata("<ESD>").Split(',');
    
                    //Get <ESD> tag offset
                    Int64 ESDoffset = Convert.ToInt64(temp[0]);
    
                    //Get </WIM> tag offset
                    Int64 WimEndoffset = Convert.ToInt64(temp[1]);
    
                    //Get <TOTALBYTES> tag offset
                    temp = Decryption.GetXMLdata("<TOTALBYTES>").Split(',');
                    Int64 FirstTotalbytesoffset = Convert.ToInt64(temp[0]);
    
                    //Get </ESD> tag offset
                    temp = Decryption.GetXMLdata("</ESD>").Split(',');
                    Int64 ESDoffset2 = Convert.ToInt64(temp[1]);
                    Int64 oldEOF = Convert.ToInt64(temp[3]);
    
                    //Delete ESD table from XML
                    Int64 newXMLsize = xmlsize - (ESDoffset2 - ESDoffset);
                    Int64 newEOF = ESDoffset;
    
                    //Calculate the new WIM size
                    Int64 TotalBytes = xmloffset + newXMLsize + integritysize;
    
                    //Set new </WIM> position
                    Int64 newIntegrityoffset = integrityoffset - (ESDoffset2 - ESDoffset);
    
                    //Create streams for new header and new XML data
                    byte[] newHeaderData = new byte[208];
                    BinaryReader BinWrite = new BinaryReader(File.Open(ESDfile, FileMode.Open, FileAccess.ReadWrite));
                    BinWrite.Read(newHeaderData, 0, 208);
                    var fh = new Utils.Wim.FileHeader();
                    UInt64[] val = { Convert.ToUInt64(newXMLsize), Convert.ToUInt64(newIntegrityoffset) };
                    fh.Write(val,newHeaderData);
                    BinWrite.Close();
    
                    byte[] Totalbytes = Encoding.Unicode.GetBytes(TotalBytes.ToString());
    
                    byte[] newAppendData = Decryption.GetEncryptedData(ESDoffset2, oldEOF - ESDoffset2);
    
                    using (BinaryWriter bw = new BinaryWriter(File.Open(ESDfile, FileMode.Open, FileAccess.Write)))
                    {
                        //Write new header data
                        bw.Seek(0, SeekOrigin.Begin);
                        bw.Write(newHeaderData);
                        bw.Flush();
                        
                        //Write new <TOTALBYTES> data
                        bw.BaseStream.Seek(FirstTotalbytesoffset + Encoding.Unicode.GetBytes("<TOTALBYTES>").Length, SeekOrigin.Begin);
                        bw.Write(Totalbytes);
                        bw.Flush();
    
                        //Write new append data
                        bw.BaseStream.SetLength(newEOF);
                        bw.BaseStream.Seek(newEOF, SeekOrigin.Begin);
                        bw.Write(newAppendData);
                        bw.Flush();
                        bw.Dispose();
                    }
                }
            }
            public static class CreateISO [...]
      }
    }
    
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  2. Tito

    Tito Super Mod / Adviser
    Staff Member

    Nov 30, 2009
    18,681
    18,589
    340
    Moved.

    :D
     
  3. sevenacids

    sevenacids MDL Addicted

    Aug 17, 2012
    667
    232
    30
    Don't wanna be nit-picky and I understand that this is a prototype ;) but this code need serious refactoring. Especially all the statics cringe my dev's heart... this is C#, not C. :D But fair enough. :)
     
  4. Superfly

    Superfly MDL Expert

    Jan 12, 2010
    1,143
    543
    60
    #4 Superfly, Jul 5, 2015
    Last edited: Jul 5, 2015
    (OP)
    What's wrong with sharing if it's contained?


    For reference:
    In fact I'd like too see some of your expert code...
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  5. sevenacids

    sevenacids MDL Addicted

    Aug 17, 2012
    667
    232
    30
    It's not good OOP practice.

    Now look at your FixWim class, for example...

    Don't get me wrong, as long as the code works and you're fine with it, don't worry, be happy. I just wouldn't want to be the person to maintain this code later on.
     
  6. Superfly

    Superfly MDL Expert

    Jan 12, 2010
    1,143
    543
    60
    #6 Superfly, Jul 10, 2015
    Last edited by a moderator: Apr 20, 2017
    (OP)
    I realise there are some that think ALL C# has to be OOP, but in this instance keeping it procedural is more efficient (TBH... if one can't mainain 1000 lines of code, then I dunno... ) but to be fair one should not pass parameters across objects, thus I changed it to instantiation.. I retained the classes as sealed tho' as there is no need for inheritance etc...

    Tested with the latest ESD...ok

    Code:
    
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading;
    using System.Windows.Forms;
    using System.Xml;
    using DiscUtils.Iso9660;
    
    namespace DecryptESD
    {
        //Class to provide feedback - needs a delegate in the GUI
        public static class Progress{
            public static string Msg {get;set;}
        }
    
        class Program
        {
            //Declare a static path to used across methods in the class
            private static string ESDfile = string.Empty;
    
            //Determine whether install.wim or install.esd is to be included
            private static bool esdFlag = true;
    
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new frmDecrypt());
            }
            public bool Decrypt(string esdfile)
            {        
                    //Declare an array of cryptokeys - the correct one picked according to edition and build from XML in ESD    
                    string[] Cryptokeys = {
                     //0 = Windows 10 Preview - new
                     "BwIAAACkAABSU0EyAAgAAAEAAQCf1EyRJa6EtwRlee0ClaLRcEhgNGS4jfVouO+MuuTnTV3avzNwgoXpQvQf4CQdsCQhBWyUUbvwbNnYG+ESsOtAiw7p7+jRrHAAR5rWRBCNeJTnKSBpz254JnjSVFMRczulrigEhSRz5bidP6SRbPK9/sKWopCND34cNNddjADibpdw7oW1g7Chb9snAjpoLv+cpSA0IWXURiT5Nz4vdQ3NPTkvH4v9MwH//JUuv19irf3QYUJSN+QkmLX65cKxxKmcUYe0/MbrxUu7KK3OM/nDpmKuKbjbUdeY4PD2uBwPQ4Ha91+bx4i7aWhqC5MYpN9PjSI+2C3mJ6uYobz5WUK/J7+MzvWOcPOgsR5RYynyZOmnD7x1cLQncA1ZgkaXkhwZXswTQGy9KRdcuZ3wIHwdzeOLbFgZu8dyj9eSuMbNPLlWFI7Ciurh1bHCMr81LiG5KWa4jy54MwD+NUkVOXbiBsjSijcfEvSFP1B4w0PPWXEf9OS9+wI5a2YZ0O0NoPLJqdbQDLlNL/bkOmdIBXs9OMEwbMZP0vhPyY19jotBsrIxQUyc5ThXr8uDzTh+J2dl03j2wpqRwykseKqp8HVjAPNYabnOSaq2/aPYIGXt6KPn/C+7xz4hyY3tTJcHK7xYAMEaJmKmqaiOR5+yO1zpevO04CYmZdFo6wRbbmrNyVu/p5dAFZyFyyglW7ieFKSgAz/isIPh+G3p8m3YF9grQ2TIQNNIN1pLJPvWvzqDIinr8gzTwzER9ZXlH9U26m8aiXptTRlXK2ws8LyVYKPqNHM9DwPJS9PuvcOykCBdeB7JvopdBU1jJUBWBsDMve0jvTWai9pujkRFsG61oclHMc1E635g+hjRxbKv7L/P2kvg5RXa6J+rpVo5jgJQ70CBgtqpNHLf6QteU8sDIlxKet1+lw7YRvfq9Wi6rmxlGqwrA9zWlCZLvnCFl8q//0a6Q+68yn5325zy67oz/X7FTWgoUU9sDDDprSwvYukrT3BlU3ntY1YAiXQtZsg6LknToQZdtj4z/bUP7sHMkds96MNRj+/+iuzEEyJaQPNGWOlzJkMa7Yujbq+5ScsxoXC5Iy8v1mi10hzYC54ByX1L9yfwi6F0rklsshl5IPSgIH+MOoZM0W+5/KlQCYeKZsIGJfyV+cVbkjLsVsFMOV+f3I+GKrJMoU8zg0vBP1SMIaEXxE5R7hd2lnzX2wIZwJvKhyHV2KSgyAQ0vpFbopB64Y1dkC/kDvEpluQ/WHjqHzwTKJyXBnFAKRNQO4BqmyNMib5N21l96Mm2nUHcxmd+KeXMuZNavvVds40FL/rOid/ROc8fK6SG/3YI+XbO4L28nPmEQPYHTfxBfkefRtUqaxC5K7QMX5LTI/ZaB+ZgJtbOXtvhUaVfyFlEzr1RBqFXXe6NhpP052qI16G7C0Sx7CT+aMv+16zqcBLb/1r4rqGhDTJjcxnkesZdc/gbDJt44RzdGo+FiZZItD3TmnyKOPjNExgA0qxdoFnwnxb5lp+qmlNi0XaOBwgSHSdiPhw=",
                     //1 = Windows 10 Preview - old
                     "BwIAAACkAABSU0EyAAgAAAEAAQCb7Jceg+YeJXNdb7HHJ0irxNsGSWu7itcuEQkfS+znxm6XwxmfINt8SGzbIIka2eOB2t9L0lGwSM0uP3UPyhBzzc8FL735OL+RnimL4SVKDb5AsYpREOcNQgKsk6OOeo8q8+4+swvwfe6+VloNqCrjiE6bCS7TrC+haV+eabj1QaT+aSXNWrukmrvi1VFoQIVeet5BqHzciVV+bv3/iSG/EEkxV6Yqq4Y2o9bvSDIbE+lGc1bKPlT9zy+lYx+WMB0Nfzo7nIrKs7qCw8GbeRTsHo5GMWxrLNltFsDpoO0C62pSvxEGB/id2TwESrd7brudppjjJ+LdbCBUNam6zx2lhZmjconDvvWLYC6KXVVgTh5WHjv8z0dxkD+Hc6o6OhdXuxAA5xtZYgIah8t2ZVK5V2PEFnusqZP7fqbSUJOp6sZe3AZWWVZz6dg6VqYpDMbKBz8rhHXXHjkaqIMrmxnSmHoB4fsxelWre9oxQoQJUkASAUhflDPKtFVe30oLsN6fNwBBNVKywJogPsClqIuNiQDpsXRFg8PYBgvqDQz8DRfDpu5WyhQjdD+eVQpeczWmTyPuwfGB0TscKDhzIhSwebKK0NwCn2LunmdJEOjJsnsYLrE63rsQdcXimzPifQ5XWlV9GUqo5ce+AlX0IMmw7DSZJBe9Sr1adBFuHQvRvQ1tGyQ5oD7WxKshS8WbvKT6cZb0XBE0Ru82gl9uSvJAgOJG9E8g7BApwCfaWAMEVj/Xd8DZSjZ0VWxRlsVkhjxWeiiQWg85J08JdjC2soG14IiXRTVAGogUTcUVlOPkovrWoRVqTMLAA+Vh0R6BpcAexwUv4YVmw2661iDUmnkYWyXMcSBQP43h5SjdLirO19b/1UD9lvaCaZpyokKMD6+GNJyCX9stVuS7c1ow/nsuVDgx3Rv7wE0as5h9WSheM5p6Lzf1UTHy1Mg2XpJAn37amw7rUnOkz4qqJ5ItRwAAhRn2Cn+PUtp5Ti1vfHmPd0PodAdTUo+5lYOGmXJxx0SHTh3dSCkSIJWjoAFYnrtEWMTszcenxYlZc2e6dWNZUPO4VyftrGkF4FpWxFC63Gd15uf3vUlStFXRArMh9KQ14sf4PGmpxmoXNZBWNsa7xizW83lkS3sbtnHtLEk6xyJ01sj+HWPoEuTzSbs6v3P8NstpN37xJui+hafIA5ILpB04qlxrxIRKEow31QzrMINyiwjCnxzIrXFuEQq9aY1930q5XgYfoV8OZirdIWKYtvPWzBgEkmi5w930kqjRyA81XwhH74guWww7A1lImbygBDl5wyE8GRVg2Emy7pU2sybyvtjMLSBgmTK8h6UqEXaupvuVCYjC8BzkUGWfTG9eh50TPpFZMO4vB2l2tbfwA2oTBwvjuwaDwdUIFXYjmdti3A+EGuhvDAeGzGxZhOmQir84CYXEKMj4yaqFvaKecMCtOOwWWpAEIzRWxXJIXN6EPqiZGEauZUAXjicVI/jpkKGhWUnaLZhNFTYD6Nl/eBMA2TPj6w4AiOnr21bDjgE=", 
                     //2 = Windows 8
                     "BwIAAACkAABSU0EyAAgAAAEAAQD1uPI7ZDwMsPbQSyrXDZblLcBf9VNiOSYNOWsLhHkyqpipeo7uOdXrONjHU2MQLZyobpVyunYMUgmU8vaBRMJHyW+Dj0xJqb9urwYFfoExrVDQVpDOOy0kDG1cGus8utua9d64n4vwRwHM4Mtta7T4sQ/o1J9L4QYUQ9xvDc8sWSA2T47n0y3Sj4OCY0RQeQFMke6+3cdnsAYevx4wL8aRS9PKHa8ItyazQJLxmKpb8HnOJn2Ws2ycr4ClGAjT4mqaflEvZ93DWZrk2RyWos0y20NmQ7mAWrVMSSuuINExN5PcvmAuMmvU2N/sCyNa2jPlaQTjJtm0DKoADRfu+W66vTHTwyJ+P2vKQv7HtbsNZMXN0cnhxSnUlwB1C5vnYRkh3tQItJu3OR5EfbF1a3Skx9g6fhCFKbZyjNWZbVxmfn9GDYmeviJiVsp2c0Wf5qg7QT5MJZtzHFB4T+/fV9TQetBCW9LKctFclCjgrw0aaqxNUHaDBvsR/uOG7KchmsuZa7DXvCc4vo15ZSVrCD5kGYhv+PzRfT4ht8r8S/GxAaPi8gZZsQBl/iOEAdhnWwTYwyZvxgkWegQw+guYfdZzi8JZmcoFA/OTognIG2SHMBu5nM8RpBfP8MKjP7UatbGPRo5+lNx26nxiw84bLVFokSxf5JcwhMP4CTHtR7tp6jnOaVHM3ANZ/Pk9mDuo9UBoLKt6amieTK+X9fvszpLbKpp9GKlp8bb4mk96Tgs1YP4108X1fMOJNrawn67OGXhJ+MqpiPs0ORDi5ILTCdfsxb+DLuAAyp/fcWuPnZEdC/VGFL/3Ydj9yqLuk3JFvwpSVD8nI+gZdFYI/qpRV4Q5mWoqzEyzObSj4yt8Do1FL1xgDEvdSxOqmLOB9Mer1DLzzTaE3O1Is3yvPerXJN7gqgpQ69k7if1a6H23AAeEVknNj6rQof2rBrFvnkquf/4uq01jVpQqW6Pez70eYPOuLyVRrdg/X8fSrXHiWdS/df9J0jRjFleHqJy9OI7MMyUK0OTfg1ZxBc8aSEkYaZ/u5G8BKJvhhySgiQvf+j4oAuPibIvZQZ3NF90Bso9hYL8HsvPB2CiYrNzTBuIafLJ6GfHT0dxamSSzP6rW+x+LnbUersORYhx65WekmTQM1Nh8+rFRTgKLQZAS9nVnc9GZ/aZ0SIN5+wWCAFwmLcpReuEcfFBKfdnItS8426wuRKIxzC9YkrQnTQkVuOpc/IUAFoVxApqMIWZYmFFpFGm5MWUiUYlq/Pb2rEgRyYhlASYxjL4QqERC2Aq1Fi8LOQ/TfTbkqyWZQqpWVWurlnMYCf5q8B1k21JwsCYbk/waosnRvbysiCJxzk4XbQ6vBrWiDurLh1KCGeFz8XFmhoudbdAjPWyB6TgY3K9OEHmVeHRbpCosy0gCuac5N6HGAqK9H1UpqgVGOqiSFC/EyRDUSXg14d8w7CZvZEsuMgPz29LGgGx0u2pLsWTsC5XHzgqT8vfJqFHm8w+0+rf9CO70eNcrkzVqn0ubtYDPHcTzdw8=", 
                     //3 = Unknown
                     "BwIAAACkAABSU0EyAAgAAAEAAQA5WQn9lTT4Ci679UcfZW6y8GkbeGTN9bKbgjnigtWmb7pPkifbr3ihmmtJ1ZWJmZCyDyeRNHwHDieOiM8zfgRJr575RKQI8yWi6wNAZVhUZDzKlch4BgABut2lcjZRT5o/Iyotd0tKW7Np1ur8D/HawdmHXdhN42hjg7PKNfvbgXICNNK+uschVzA39HWejEowO5ppaXBObLpN28Ipun3+s0xPNePHNVKD/4azFGd11ZZWmoh3NpnZXBGW3Jk2fn6hmrQ434Mrw4qdpIfTqh/d0aWGE7CseZPYR0F9Gd6DWyXn6JzkvPBPRNtdU7SK5Xeh+pDmTnme5av3c1XNBka2hScgqAT/BOAwaIvufA6QZXccHkeHnOVO/XHEi339OT0FJLNWearerYzfHtHh6D8+d7fIdHBsgMCMd/O2suhNVBWsipzA8UPnhy4+4uPAhoV7fqaYjPbE0fUTXT82SUG11W4tjs8+kTflzwX1qoNezfLdG6++h7LJSGJNPe2QfsQlB8NxLTReIHsyW5Fv5Q0LZH/Z5tJsOeu0P39z9k/oW30TGHIVnipOkdfA1PREFFwDWJ7MKsTQkW2ikSo9Y1HbUhIAb2xI9M28GAxGxdaPa69vAepfqiPOfEFOiZcUhVkLs6vv8GVOsLRMHFalKhwNi6bWX32R76OKmRHLPPl47dkHCBy/nBVSLaVyUo25gEX3pVgGDpoiHOTzeq1qvPdguBMXHtgvpvEMTBEMDFpp1hMqWkNcapPA25oGQmJr5LouRsfaHXe52LoJpniCA/Lf7cFSCbx+Wkh1bl/4uepz45bZGpjde4WvPnKPBOsi+EZ30lYi0mfKGBQ7HS6RE9iQSbOJYZ2djnY+ok8VkGrXU28l1kQParu3mnXOcQdviIJhtH6nor3GjXYbMml40/b3lGPn6qPjf0UW9glD2apdQMyTTxO2YzLlpiW96d5SwsPTDfP83YTZUZd6Er4cvmlb7G4qidlF7xIdVzzmGx5PPAuv6oLzMf3qFHKgo8nGC3ZcHfTsHz62eTvDFfCxuqTSbZYby+SraGvez3gZSKnbmvkfaBumgMPULGjsPC0FGMf1PXzxHQ3Y5chnpxYXF86h9NRRf9efeByhj3cS1AQGNidgIfo1l0CdNDtWegcZC/0U8+0O/lMGUnemt8a+Zl6jb+XHB9czxWjfetE3KcLXlfXrIBMM7Ve3JNEU1dL01vZ7THJXYWS6mIvGnOK+nW4GxsgReW8an5HlE1qF3O0r0vmpttZ6tK0NjxZFrUIVJwE+X/rJrRIS7eJJsgLoI4HD37AMcQ3rGY4/mnR7JitqNj4TNq+P/XNNl7wkjmRLOruLrOdShKON1ZvmaZ9BKUYI02FjxRntO8MPOrR2ImdRpTp+1rGtLlWWe0MxmPOkIQIsPKocIeitjWXIgNErcdzulagizd+cmcf2PPOyNkOd7yVv1xxxLy2ePYsHdGaYxIgM0xJ+NNrNpLz9/3W2quhEt4JL6jIhnIuvIUd67SQLwf7qy2jS3lLwbkBqPJpalAE="
                    };
    
                try
                {
                    //Check file validity
                    XmlDocument doc = new XmlDocument();
                    XmlNodeList nl;
                    ESDfile = esdfile;
    
                    //Create a new instance of the Decryption class 
                    Decryption clsDecrypt = new Decryption();
    
                    //Get WIM data from file
                    Progress.Msg = "Checking the ESD for validity...";
                    string WIMXML = clsDecrypt.GetXMLdata("<WIM>");
                    if (!WIMXML.Contains("<WIM>"))
                    {
                        Progress.Msg += Environment.NewLine + DateTime.Now.ToString("HH:mm:ss") + " ESD does not contain valid WIM data";
                        return false;
                    }
                    else if (!WIMXML.Contains("<ESD>"))
                    {
                        Progress.Msg += Environment.NewLine + DateTime.Now.ToString("HH:mm:ss") + " ESD is not encrypted";
                       return true;
                    }
                     
                    //Create an XML document to hold XML data from ESD
                    doc.LoadXml(WIMXML);
    
                    // Get the private key..
                    string xmlKey = doc.GetElementsByTagName("KEY").Item(0).InnerText;
    
                    //Get the offsets and byte range combination into array (makes it easier to iterate)
                    nl = doc.GetElementsByTagName("RANGE");
                    int arraylength = Convert.ToInt32(nl.Item(0).ParentNode.Attributes.Item(0).InnerText);
                    Int64[] OffsetBytes = new Int64[arraylength * 2];
                    int i = 0;
                    foreach (XmlNode nd in nl)
                    {
                        OffsetBytes = Convert.ToInt64(nd.Attributes.Item(0).InnerText);
                        OffsetBytes[i + 1] = Convert.ToInt64(nd.Attributes.Item(1).InnerText);
                        i += 2;
                    }
    
                    //Create byte arrays to hold original encrypted and decrypted data.
                    byte[] encryptedData;
                    byte[] decryptedData;
    
                    //Create a new instance of the RSACryptoServiceProvider class 
                    RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();
    
                    // get version and associate cryptokey
                    string getEdition = doc.GetElementsByTagName("DISPLAYNAME").Item(0).InnerText;
                    string build = doc.GetElementsByTagName("BUILD").Item(0).InnerText;
                    byte[] CryptoKey = new byte[Cryptokeys[0].Length];
                    if (getEdition.Contains("Windows 10"))
                    {
                        if (Convert.ToInt32(build) > 10150)
                        {
                            CryptoKey = Convert.FromBase64String(Cryptokeys[0]);
                        }
                        else
                        {
                            CryptoKey = Convert.FromBase64String(Cryptokeys[1]);
                        }
                    }
                    else if (getEdition.Contains("Windows 8"))
                    {
                        CryptoKey = Convert.FromBase64String(Cryptokeys[2]);
                    }
                    else
                    {
                        MessageBox.Show("Invalid cryptokey");
                    }
    
                    //Decrypt private key to get session key...
                    byte[] PrivateKey = Convert.FromBase64String(xmlKey);
                    RSAalg.ImportCspBlob(CryptoKey);
                    byte[] AESkey = RSAalg.Decrypt(PrivateKey, true);
                    RSAalg.Dispose();
    
                    //Loop through each block of encrypted data and write decrypted data back to file
                    Progress.Msg += "Decryption in progress...";
                    for (int j = 0; j < OffsetBytes.Length; j += 2)
                    {
                        encryptedData = clsDecrypt.GetEncryptedData(OffsetBytes[j], OffsetBytes[j + 1]);
                        decryptedData = clsDecrypt.DecryptIt(encryptedData, AESkey);
                        clsDecrypt.WriteDecryptedData(OffsetBytes[j], decryptedData);
                    }
                    //Update WIM header,XML and integrity table data for validation
                    FixWim fixwim = new FixWim();
                    fixwim.UpdateWIM();
                    Progress.Msg = "Decryption completed...";
                    return true;
                }
                catch (CryptographicException e)
                {
                    //To Do: some exception handling in case the decryption did not succeed.
                    Progress.Msg = "Error(s) during decryption: " + Environment.NewLine + e.Message;
                    //MessageBox.Show(e.Message);
                    return false;
                }
                finally
                {
                    //do something innocuous;
                }
            }
            sealed class Decryption
            {
                internal byte[] DecryptIt(byte[] encryptchunk, byte[] AESkey)
                {
                    try
                    {
                        int OriginalSize = encryptchunk.Length;
                        // Chunk needs to be in equal blocksizes of 16 bytes(determined by IV) 
                        // round up original size to nearest multiple of 16 bytes and add another +1  for IV
                        int NewBlockSize = ((encryptchunk.Length - 1) | 15) + 17;
    
                        Array.Resize(ref encryptchunk, NewBlockSize);
                        byte[] result = new byte[encryptchunk.Length];
    
                        //Get unencrypted remainder bytes outside the last 16-byte block
                        double size = (double)(OriginalSize) / 16;
                        size = (size - Math.Truncate(size)) * 16;
    
                        if (size < 0) size = 0;
                        byte[] finalBytes = new byte[(int)size];
                        Buffer.BlockCopy(encryptchunk, OriginalSize - finalBytes.Length, finalBytes, 0, finalBytes.Length);
    
                        //Create a new instance of the AesCryptoServiceProvider managed class 
                        AesManaged AES = new AesManaged();
                        AES.Mode = CipherMode.CBC;
                        AES.Padding = PaddingMode.Zeros;
                        AES.Key = AESkey;
                        AES.BlockSize = 128;
    
                        using (MemoryStream msDecrypt = new MemoryStream(encryptchunk))
                        {
                            using (ICryptoTransform decryptor = AES.CreateDecryptor(AESkey, AES.IV))
                            {
                                int transed = 0;
                                for (int i = 0; i < encryptchunk.Length; i += transed)
                                {
                                    transed = decryptor.TransformBlock(encryptchunk, i, 16, result, i);
                                }
                                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
                                {
                                    csDecrypt.Write(encryptchunk, 0, encryptchunk.Length);
                                    csDecrypt.FlushFinalBlock();
                                    csDecrypt.Close();
                                }
                            }
                            result = msDecrypt.ToArray();
                            Array.Resize(ref result, OriginalSize);
    
                            //Write back excess bytes if original chunk size not a complete array of 16-byte blocksizes
                            if ((OriginalSize % 16) > 0)
                                Buffer.BlockCopy(finalBytes, 0, result, result.Length - finalBytes.Length, finalBytes.Length);
    
                            //Cleanup
                            msDecrypt.Close();
                        }
                        AES.Clear();
                        AES.Dispose();
                        return result;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    return null;
                }
                internal byte[] GetEncryptedData(long startoffset, long encryptedbytes)
                {
                    byte[] ret = new byte[encryptedbytes];
                    try
                    {
                        using (BinaryReader BinRead = new BinaryReader(File.Open(ESDfile, FileMode.Open), Encoding.Default))
                        {
                            // Seek the required index.
                            BinRead.BaseStream.Seek(startoffset, SeekOrigin.Begin);
                            ret = BinRead.ReadBytes((int)encryptedbytes);
                            BinRead.Dispose();
                            return ret;
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    return ret;
                }
                internal void WriteDecryptedData(long startoffset, byte[] decryptedbytes)
                {
                    try
                    {
                        using (BinaryWriter BinWrite = new BinaryWriter(File.Open(ESDfile, FileMode.Open, FileAccess.Write), Encoding.Unicode))
                        {
                            // Seek the required index.
                            BinWrite.BaseStream.Seek(startoffset, SeekOrigin.Begin);
                            BinWrite.Write(decryptedbytes);
                            BinWrite.Dispose();
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
                internal string GetXMLdata(string strXML)
                {
                    try
                    {
                        byte[] StringBytes = Encoding.Unicode.GetBytes(strXML);
                        FixWim clsFixWim = new FixWim();
    
                        Int64[] xmloffset = clsFixWim.WimHeader();
    
                        using (BinaryReader BinRead = new BinaryReader(File.Open(ESDfile, FileMode.Open, FileAccess.Read)))
                        {
                            int i = 0;
                            int j = 0;
                            int bytesRead;
                            string str = "";
    
                            byte[] ByteBuffer = new byte[Convert.ToInt32(xmloffset[1])];
    
                            BinRead.BaseStream.Seek(xmloffset[0], SeekOrigin.Begin);
    
                            Int64 WIMoffset = xmloffset[2] - Encoding.Unicode.GetBytes("</WIM>").Length;
                            Int64 WimEOF = BinRead.BaseStream.Length;
                            Int64 StartESDoffset = 0;
                            Int64 EndESDoffset = 0;
                            if (!strXML.Contains("WIM"))
    
                                while ((bytesRead = BinRead.Read(ByteBuffer, 0, ByteBuffer.Length)) > 0)
                                {
                                    for (i = 0; i <= (ByteBuffer.Length - StringBytes.Length); i++)
                                    {
                                        if (ByteBuffer == StringBytes[0])
                                        {
                                            for (j = 1; j < StringBytes.Length && ByteBuffer[i + j] == StringBytes[j]; j++) ;
                                            if (j == StringBytes.Length)
                                            {
                                                //Return the start ESD tag offset and send WIM tag offset
                                                if (!strXML.Contains("/"))
                                                {
                                                    if (StartESDoffset == 0)
                                                        StartESDoffset = (xmloffset[0] + i + j) - StringBytes.Length;
                                                }
                                                else
                                                {
                                                    EndESDoffset = (xmloffset[0] + i + j);
                                                }
                                                str = StartESDoffset.ToString() + "," + EndESDoffset.ToString() + "," + WIMoffset.ToString() + "," + WimEOF.ToString();
                                            }
                                        }
                                    }
                                }
                            else if (strXML.Contains("WIM"))
                            {
                                ByteBuffer = BinRead.ReadBytes((int)xmloffset[1]).Skip(2).ToArray();
                                str = ASCIIEncoding.Unicode.GetString(ByteBuffer);
                            }
                            BinRead.Dispose();
                            return str;
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    return "XML data not found";
                }
            }
            sealed class FixWim
            {
               public Int64[]  WimHeader()
                {
                   //Retrieves wim header
                    try
                    {
                        BinaryReader BinRead = new BinaryReader(File.Open(ESDfile, FileMode.Open, FileAccess.Read));
                        byte[] HdrBuffer = new byte[208];
                        BinRead.Read(HdrBuffer, 0, 208);
                        var WimHdr = new Utils.Wim.FileHeader();
                        WimHdr.Read(HdrBuffer, 0);
                        BinRead.Close();
    
                        //Return an array with only the data we need -> NB: Compressed size = Original size so only need one
                        Int64[] HdrArray = new Int64[6];
    
                        if (WimHdr.IsValid())
                        {
                            //Get XML header data buffer
                            HdrArray[0] = WimHdr.XmlDataHeader.FileOffset;
                            HdrArray[1] = WimHdr.XmlDataHeader.CompressedSize;
                            //Get Integrity table header data buffer
                            HdrArray[2] = WimHdr.IntegrityHeader.FileOffset;
                            HdrArray[3] = WimHdr.IntegrityHeader.CompressedSize;
                        }
                        return HdrArray;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    return null;
                }
    
               internal void UpdateWIM()
               {
                   try
                   {
                       Decryption clsDecrypt = new Decryption();
                       Int64[] WimHdr = WimHeader();
                       Int64 xmloffset = WimHdr[0];
                       Int64 xmlsize = WimHdr[1];
                       Int64 integrityoffset = WimHdr[2];
                       Int64 integritysize = WimHdr[3];
    
                       string[] temp = clsDecrypt.GetXMLdata("<ESD>").Split(',');
    
                       //Get <ESD> tag offset
                       Int64 ESDoffset = Convert.ToInt64(temp[0]);
    
                       //Get </WIM> tag offset
                       Int64 WimEndoffset = Convert.ToInt64(temp[1]);
    
                       //Get <TOTALBYTES> tag offset
                       temp = clsDecrypt.GetXMLdata("<TOTALBYTES>").Split(',');
                       Int64 FirstTotalbytesoffset = Convert.ToInt64(temp[0]);
    
                       //Get </ESD> tag offset
                       temp = clsDecrypt.GetXMLdata("</ESD>").Split(',');
                       Int64 ESDoffset2 = Convert.ToInt64(temp[1]);
                       Int64 oldEOF = Convert.ToInt64(temp[3]);
    
                       //Delete ESD table from XML
                       Int64 newXMLsize = xmlsize - (ESDoffset2 - ESDoffset);
                       Int64 newEOF = ESDoffset;
    
                       //Calculate the new WIM size
                       Int64 TotalBytes = xmloffset + newXMLsize + integritysize;
    
                       //Set new </WIM> position
                       Int64 newIntegrityoffset = integrityoffset - (ESDoffset2 - ESDoffset);
    
                       //Create streams for new header and new XML data
                       byte[] newHeaderData = new byte[208];
                       BinaryReader BinRead = new BinaryReader(File.Open(ESDfile, FileMode.Open, FileAccess.Read));
                       BinRead.Read(newHeaderData, 0, 208);
                       var fh = new Utils.Wim.FileHeader();
                       UInt64[] val = { Convert.ToUInt64(newXMLsize), Convert.ToUInt64(newIntegrityoffset) };
                       fh.Write(val, newHeaderData);
                       BinRead.Close();
    
                       byte[] Totalbytes = Encoding.Unicode.GetBytes(TotalBytes.ToString());
    
                       byte[] newAppendData = clsDecrypt.GetEncryptedData(ESDoffset2, oldEOF - ESDoffset2);
    
                       using (BinaryWriter BinWrite = new BinaryWriter(File.Open(ESDfile, FileMode.Open, FileAccess.Write)))
                       {
                           //Write new header data
                           BinWrite.Seek(0, SeekOrigin.Begin);
                           BinWrite.Write(newHeaderData);
                           BinWrite.Flush();
    
                           //Write new <TOTALBYTES> data
                           BinWrite.BaseStream.Seek(FirstTotalbytesoffset + Encoding.Unicode.GetBytes("<TOTALBYTES>").Length, SeekOrigin.Begin);
                           BinWrite.Write(Totalbytes);
                           BinWrite.Flush();
    
                           //Write new append data
                           BinWrite.BaseStream.SetLength(newEOF);
                           BinWrite.BaseStream.Seek(newEOF, SeekOrigin.Begin);
                           BinWrite.Write(newAppendData);
                           BinWrite.Flush();
                           BinWrite.Dispose();
                       }
                   }
                   catch (Exception ex)
                   {
                       MessageBox.Show(ex.Message);
                   }
               }
            }
    
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  7. Superfly

    Superfly MDL Expert

    Jan 12, 2010
    1,143
    543
    60
    #7 Superfly, Jul 19, 2015
    Last edited by a moderator: Apr 20, 2017
    (OP)
    Calling MasterDisaster...

    I'm using DiscUtils to create the iso but can't get it to boot in VM (bootmngr missing)... UltraISO sees it as bootable and creating a USB with Rufus is fine. Should I change the boot image?
    This is the code I'm using:
    Code:
                public static void BuildISO()
                {
                    string isoFile = WorkingDir + ".iso";
                    CDBuilder builder = new CDBuilder();
                    string[] VolId = isoFile.Split('_');
                    builder.VolumeIdentifier = "J_CCSA_" + VolId[3] + "FRE_" + VolId[4].ToUpper() + "_DV5";
                   
                   // Combine the boot images
                    byte[] bootMBR = File.ReadAllBytes(WorkingDir + @"\boot\etfsboot.com");
                    byte[] bootEFI = File.ReadAllBytes(WorkingDir + @"\efi\Microsoft\boot\efisys.bin");
                    byte[] bootBoth = Combine(bootMBR, bootEFI);
    
                // Create a memory stream for the boot image
                    MemoryStream bootImage = new MemoryStream(bootBoth);
                    builder.SetBootImage(bootImage, BootDeviceEmulation.NoEmulation,0);
    
                    DirectoryInfo di = new DirectoryInfo(WorkingDir);
                    PopulateFromFolder(builder, di, di.FullName);
                    builder.Build(isoFile);
                    bootImage.Dispose();
                    Progress.Msg = isoFile + " created";
            }
    
                public static byte[] Combine(byte[] MBR, byte[] EFI)
               {
                   byte[] ret = new byte[MBR.Length + EFI.Length];
                   Buffer.BlockCopy(MBR, 0, ret, 0, MBR.Length);
                   Buffer.BlockCopy(EFI, 0, ret, MBR.Length, EFI.Length);
                   return ret;
               }
    
                private static void PopulateFromFolder(CDBuilder builder, DirectoryInfo di, string basePath)
                {
                    foreach (FileInfo file in di.GetFiles())
                    {
                        builder.AddFile(file.FullName.Substring(basePath.Length), file.FullName);
                    }
                    foreach (DirectoryInfo dir in di.GetDirectories())
                    {
                        PopulateFromFolder(builder, dir, basePath);
                    }
                }
    FYI: Appears MBR boot needs a UDF system - the efi boot image works on plain data ISO's with the above - no way I found to get a managed solution (i.e without IMAPI2 or similar)
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  8. Superfly

    Superfly MDL Expert

    Jan 12, 2010
    1,143
    543
    60
    #8 Superfly, Nov 12, 2015
    Last edited by a moderator: Apr 20, 2017
    (OP)
    This is how to combine MBR and EFI boot images

    Code:
    using System;
    using System.Runtime.InteropServices;
    using ComTypes = System.Runtime.InteropServices.ComTypes;
    using IMAPI2FS;
    using System.IO;
    
    namespace ISOBuilder
    {
        public class BuildISO
        {
            [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_DISPATCH)] Array psaBoot;
    
            [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
            static internal extern uint SHCreateStreamOnFile(string pszFile, uint grfMode, out FsiStream ppstm);
            public void MakeISO(string bootFile, string bootFile2,string path, string VolID)
            {
                MsftFileSystemImage iso = new MsftFileSystemImage();
                psaBoot = Array.CreateInstance(typeof(Object), 2);
                FsiStream bootStream;
                FsiStream bootStream2;
    
                iso.ChooseImageDefaultsForMediaType(IMAPI_MEDIA_PHYSICAL_TYPE.IMAPI_MEDIA_TYPE_DISK);
                iso.FileSystemsToCreate = FsiFileSystems.FsiFileSystemUDF;
                iso.VolumeName = VolID;
                
                // Need  streams for the boot image file
                SHCreateStreamOnFile(bootFile, 0x00, out bootStream);
                SHCreateStreamOnFile(bootFile2, 0x00, out bootStream2);
    
                // Create MBR boot
                BootOptions bootOptions = new BootOptions();
                bootOptions.Manufacturer = "Microsoft";
                bootOptions.PlatformId = PlatformId.PlatformX86;
                bootOptions.Emulation = EmulationType.EmulationNone;
                bootOptions.AssignBootImage(bootStream);
    
                ///<!-- EFI boot is architecture specific -->
                // Create EFI boot
                BootOptions bootOptions2 = new BootOptions();
                bootOptions2.Manufacturer = "Microsoft";
                bootOptions2.PlatformId = PlatformId.PlatformEFI;
                bootOptions2.Emulation = EmulationType.EmulationNone;
                bootOptions2.AssignBootImage(bootStream2);
    
                psaBoot.SetValue(bootOptions, 0);
                psaBoot.SetValue(bootOptions2, 1);
                iso.BootImageOptionsArray = psaBoot;
    
                iso.Root.AddTree(path, false);
    
                IFileSystemImageResult resultImage = iso.CreateResultImage();
                IStream imageStream =  resultImage.ImageStream;
                FsiStream newStream = null;
    
                if (imageStream != null)
                {
                    tagSTATSTG stat;
                    imageStream.Stat(out stat, 0x1);
    
                    uint res = SHCreateStreamOnFile(path + ".iso", 0x1001, out newStream);
                    if (res == 0 && newStream != null)
                    {
                        _ULARGE_INTEGER inBytes;
                        _ULARGE_INTEGER outBytes;
    
                        try
                        {
                            imageStream.RemoteCopyTo(newStream, stat.cbSize, out inBytes, out outBytes);
                        }
                        finally
                        {
                            Marshal.FinalReleaseComObject(imageStream);
                            newStream.Commit(0);
                            Marshal.FinalReleaseComObject(newStream);
                            Marshal.FinalReleaseComObject(resultImage);
                            Marshal.FinalReleaseComObject(iso);
                           // if (System.IO.Directory.Exists(path)) System.IO.Directory.Delete(path, true);
    
                        }
                    }
                    else
                    {
                        Marshal.FinalReleaseComObject(imageStream);
                        Marshal.FinalReleaseComObject(resultImage);
                        Marshal.FinalReleaseComObject(iso);
                        //TODO: Throw exception or do whatever to signal failure here
                    }
                }
                else
                {
                    Marshal.FinalReleaseComObject(resultImage);
                    Marshal.FinalReleaseComObject(iso);
                    //TODO: Throw exception or do whatever to signal failure here
                }
            }
        }
    Took me a while to figure out how to convert C++ safearrays to C# even if it was just a few lines.
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...