Obfuscating Install Guids



  • So I've been working with Windows Installer and I wanted to take a peek under the hood (or into the registry in this case) to figure out how to remove things by hand if push comes to shove.

     I open the MSI, grab the Upgrade Code and do a search through the registry, no hits.  As this MSI is installed, this seemed quite odd to me.  I mean would they be scanning all of the MSI files on demand to find the Upgrade Code?  That would be silly, even for Microsoft.  So I start looking for my Product Code and find it, but only as part of an uninstall/repair string.

     So I'm looking at the key in:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\1CF3AD8A00986884697F2F5B6B6380BE\InstallProperties

    where it says:

    MsiExec.exe /I{A8DA3FC1-8900-4886-96F7-F2B5B63608EB}

    and I think to my self, there's something fishy about the key name under products.  I mean looking at it side by side with the guid you get:

    A8DA3FC1-8900-4886-96-F7-F2-B5-B6-36-08-EB
    1CF3AD8A-0098-6884-69-7F-2F-5B-6B-63-80-BE

    So they are swaping the order of the bytes in the guid structure for no apparent reason, wonderful.  Same holds true for the Upgrade Code.  Obviously this highly developed obfuscation technique is aimed at keeping users from doing the wrong thing.  I mean, it's not like a user who is smart enough to extract the product and upgrade codes from an MSI would ever be able to crack this code (and possibly do something useful like removing an item that won't go away from the add/remove control panel).



  • Apparently, some parts of Windows are big-endian and some are little-endian. I have no idea how that could come about, but bear in mind it's Microsoft. Maybe .net has a different byte order from the rest of the system, as .net seems to be compiled to some kind of byte-code.

    Never ascribe to malice that which can be explained by incompetence.



  • @marinus said:

    Maybe .net has a different byte order from the rest of the system, as .net seems to be compiled to some kind of byte-code.
     

    ...Wow.



  • @marinus said:

    Apparently, some parts of Windows are big-endian and some are little-endian. I have no idea how that could come about, but bear in mind it's Microsoft. Maybe .net has a different byte order from the rest of the system, as .net seems to be compiled to some kind of byte-code.

     

    I think that explanation is a little off.  If it was a big/little endian issue, I wouldn't expect the 4 bits in the bytes on the end to be swapped.  A 4 bit endian would be an even bigger WTF (especially when you consider the first 4 bytes).  Finally, I may be wrong, but based on the APIs, I think Windows Installer was written in C without the .Net Framework.



  • Windows installer is TRWTF by itself.

     Besides from keeping the whole own database in registry, all records are obfuscated by something like ROT-13. Now, if anything breaks, your chances to fix it manually are zero.



  • @alegr said:

    all records are obfuscated by something like ROT-13. Now, if anything breaks, your chances to fix it manually are zero.
     

    It's more from the "hold next to a mirror to read" school of thought.

    Quite obviously* they are writing to the registry using a LIFO buffer.Characters go into the buffer A, then B, then C. The registry writer then works on the buffer pulling C out first, then B, then A.

     

     

    * May not actually be obvious or true.



  • @RayS said:

    @alegr said:

    all records are obfuscated by something like ROT-13. Now, if anything breaks, your chances to fix it manually are zero.
     

    It's more from the "hold next to a mirror to read" school of thought.

    Quite obviously* they are writing to the registry using a LIFO buffer.Characters go into the buffer A, then B, then C. The registry writer then works on the buffer pulling C out first, then B, then A.

     

     

    * May not actually be obvious or true.

    A LIFO for guids only?  Just a reminder, the code for this would have to be something like:

     

    byte Swap(byte b)
    {
        return ((b >> 4) | (b << 4));
    }

    void Swap(byte [] byteArray, int start, int stop)
    {
        byte temp;
        int swapPos = stop-1;
        for(int i = start; i < stop; i++)
        {
            temp = guidByteArray[i];
            guidByteArray[i] = guidByteArray[swapPos-i];
            guidByteArray[swapPos-i] = temp;
        }
    }


    Guid TransformGuid(Guid g)
    {
        byte [] guidByteArray = g.ToByteArray();
        byte temp;
        for(int i = 0; i < guidByteArray.Length; i++)
        {
            temp = Swap(guidByteArray[i]);
            guidByteArray[i] = temp;
        }
        Swap(guidByteArray, 0, 4);
        Swap(guidByteArray, 4, 6);
        Swap(guidByteArray, 6, 8);
        return new Guid(guidByteArray);
    }

     I have not tried compiling or running this code, but it should work.



  • @Guardian Bob said:

    A8DA3FC1-8900-4886-96-F7-F2-B5-B6-36-08-EB
    1CF3AD8A-0098-6884-69-7F-2F-5B-6B-63-80-BE

    So they are swaping the order of the bytes in the guid structure for no apparent reason, wonderful.  Same holds true for the Upgrade Code.  Obviously this highly developed obfuscation technique is aimed at keeping users from doing the wrong thing.  I mean, it's not like a user who is smart enough to extract the product and upgrade codes from an MSI would ever be able to crack this code (and possibly do something useful like removing an item that won't go away from the add/remove control panel).

     

    My guess would be that this is a cheap and easy mapping scheme.  They needed a second guid for some reason that will be associated with the source guid and that you can easily map between them.  Instead of generating a new guid and writing another register key that gives you the mapping (which would require work), they just flipped the bytes.

    It's lazy, but I can't find something specifically wrong with that approach.


  • @joe_bruin said:

    My guess would be that this is a cheap and easy mapping scheme.  They needed a second guid for some reason that will be associated with the source guid and that you can easily map between them. [...] It's lazy, but I can't find something specifically wrong with that approach.
    It would lead to a GUID collision as soon as you get one consisting only of palindromes. Granted, it only happens about once in every 2^64 times (for reference, GUIDs have 2^128 permutations).



  • @Faxmachinen said:

    @joe_bruin said:

    My guess would be that this is a cheap and easy mapping scheme.  They needed a second guid for some reason that will be associated with the source guid and that you can easily map between them. [...] It's lazy, but I can't find something specifically wrong with that approach.

    It would lead to a GUID collision as soon as you get one consisting only of palindromes. Granted, it only happens about once in every 2^64 times (for reference, GUIDs have 2^128 permutations).

     

    Actually, the first 4 bits of the 3rd field defines the version of the GUID.  Additionally, 1 to 3 bits in the second byte of data 4 determines the type of the GUID.   So if we assume we have a reasonable generator, those numbers drop slightly.  2^123-2^121 permutations with 2^59-2^57 palindromes.  This raises an interesting point, the "mapped" GUID may not match the standard format.

    Additionally, doesn't GUID stand for Globally Unique Identifier?  I guess I don't see any reason to map something that is statistically unique.  It's kind of like saying, "I have an array of a thousand items, and I want to access them by index quickly.  So I'm going to hash and store the index in a hash table for quick lookup."  The map explanation makes less sense to me than a lame attempt by Microsoft to hide information from the user.



  • @Guardian Bob said:

    So if we assume we have a reasonable generator

    Everything up to XP doesn't. Haven't checked Vista.

    @Guardian Bob said:

    Additionally, doesn't GUID stand for Globally Unique Identifier?

    I prefer to think of it as "Gratuitously different UID", since it's nothing more than a minor perversion of UUIDs with a stupid algorithm. There is no good reason for not just using UUIDs, it's pure NIH. The whole thing is silly.


Log in to reply