GeistHaus
log in · sign up

Made Up Explorations

Part of wordpress.com

If I'd have thought ahead, I might have called this blog "Slorti Borks"

stories
Fix for Heroes of Might & Magic V: Hammers of Fate (Ubisoft Connect) [expansion pack] “Original game not found” Error on Windows.
Uncategorized
This is what to do, not how I did it. The problem is caused because Ubisoft altered the registry keys of the base game without correcting references to those keys in the expansion pack installer. It was sloppy work on their part and IMO unforgivable to take your money and offer you an unplayable game.Continue reading "Fix for Heroes of Might & Magic V: Hammers of Fate (Ubisoft Connect) [expansion pack] “Original game not found” Error on Windows."
Show full content
This image has an empty alt attribute; its file name is image.png
“Original game not found” error message window.
This is what to do, not how I did it.

The problem is caused because Ubisoft altered the registry keys of the base game without correcting references to those keys in the expansion pack installer. It was sloppy work on their part and IMO unforgivable to take your money and offer you an unplayable game. There have been complaints about this problem on forums going back years, with many open support tickets. Were I you, I’d just buy it on GOG, free of DRM and these problems. That said, if you’re here you probably have already bought the game and are looking to get what you have already bought working.

Darth Vader meme
“I have altered the deal. Pray I do not alter it again.”
I know, I know, that’s not the quote. I needed something that applied to the narrative so work with me here, ok?

If you’d like to see how I came to this fix or perhaps would like to replicate it yourself, please read my earlier blog post where I explain in detail how I fixed this. For just the fix, read on.

Caveats
  • I have shown this to work on my computer. I have a testing sample size of 1, so it may or may not work for you.
    • Specifically, I don’t know if the installer cache is always 146, I don’t know if the base game reg key is always Uplay Install 87, I don’t know if Ubisoft have updated either of the base game or the expansion, and I don’t know if the F127526C… key is ever going to change.
    • There may be other configurations of the game(s) and/or installer that mean that either the reg keys or hex edits won’t work. I don’t know about these configurations.
    • In fact, I don’t actually know anything about this beyond the problem on my own computer. I’d be interested to hear if there are any other configurations though.
  • I take no responsibility for what you do with this information and/or any damage it does to your computer. Messing with the registry and downloading dodgy files can be risky and I won’t be responsible if you wreck your own computer following these steps. Don’t come whinging to me if you wreck your registry and end up in a boot loop.
  • I expect this to work explicitly for the issue with Ubisoft Connect whereby this one game won’t install with the specific error “Original game not found.” Any other error, any other service, or any other game I do not expect this to work.
Fixes 1. Use my modified install script file
  1. In Ubisoft Connect, install the base game Hammers of Might & Magic V. This should work.
  2. In Ubisoft Connect, attempt to install the expansion pack Hammers of Might & Magic V: Hammers of Fate. Upon running the installer, this should fail with an “Original game not found.” error message in a window.
  3. Download the modified script file setup.inx from here.
  4. Navigate to the expansion pack installer directory. This is likely to be “C:\Program Files (x86)\Ubisoft Game Launcher\cache\installers\146” but it will be wherever you’ve told Ubisoft Connect to install itself. I have a sample size of 1 so I don’t know if the number ‘146’ is always the same.
  5. Copy the downloaded setup.inx file into this directory (overwriting the existing file).
  6. Click “Install” in Ubisoft Connect.
  7. The installation should succeed. Happy gaming!
My modified setup.inx checksum

Name: setup.inx
Size: 173379 bytes (169 KiB)
SHA256: F2CD012C512DC106138832475EB1BE376713987A1F2076B142EC4548D4B7AD9B

2. Copy the moved registry key and put it in the expected place
  1. In Ubisoft Connect, install the base game Hammers of Might & Magic V. This should work.
  2. Press Win+R and type “RegEdit” and press Enter to start the Registry Editor. (Note, you can mess up your system if you play about in the registry without knowing what you’re doing. If you’re unsure about any of these steps, just don’t do them.)
  3. Navigate to the path Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Uplay Install 87. This should have in it a string (in the right window) labelled “DisplayName” with the value “Heroes of Might and Magic V” and a string labelled “InstallLocation” with the install path of the base game.
  4. Export the key. Right click on the Uplay Install 87 key (the folder-looking thing in the left hand window) and select “Export”.
  5. Save the key in a safe place where you know where it is, with the filename “HoMMV.reg“. Ensure the “Export range” is “Selected branch” and not “All”.
  6. Navigate to “HoMMV.reg”. Right click it and select “Edit”.
  7. Notepad should open, showing some information. Line 3 should read “[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Uplay Install 87]
  8. Replace line 3 with “[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{F127526C-886E-44fa-BE7B-BB168D6D11F0}]
  9. Save and close Notepad.
  10. Double-click HoMMV.reg to add it to the registry.
  11. Install Hammers of Fate through Ubisoft Connect. It should work. Happy gaming!
3. Modify your own script file

If you’re cautious about downloading a random file off the internet and using it to install a game, the list of modifications I made to the setup.inx file to make it work is available at the bottom of my previous blog post and you’d be able to make the same modifications yourself. Once you’ve done this, you should be able to follow the instructions as in fix 1 above.

To do this, you’ll need to use a hex editor. One of my favourites is HxD.

4. Find the registry key yourself, and copy it into the correct place

If Ubisoft alters the base game registry key again without correcting the registry key, or indeed the expansion pack, the above won’t work verbatim. However, should this happen, you’d be able to fix this manually with a bit of digging.

Go into the Registry Editor and find a registry key with the “DisplayName” string value of “Heroes of Might and Magic V” and a string named “InstallLocation” which has the base game install path. Use this as per step 2 of fix 2 above and follow the rest of the steps.

If the reg key path in step 7 doesn’t work for you, the correct reg key path can be gotten in two ways. Either open the setup.inx file in a hex editor (or, tbh, notepad should work) and look around for a registry key path. I’d expect “SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall” and “F127526C-886E-44fa-BE7B-BB168D6D11F0” to be in plaintext in separate locations in the file (if yours is the same as mine). If this is different, these can be combined to make the correct reg key path.

If you’re not a fan of digging through binary, you can always download Process Monitor and set filters for a Process Name of IKernal.exe, an Operation of RegOpenKey and a Result of NAME NOT FOUND. Then run the installer and see what registry keys the installer is looking for. Then, copy the correct key into that path by putting that path into step 7 of fix 2 above.

Good Luck

Hopefully the above has fixed the issue for you. If so, I’d like to know. If not, let me know what you tried and what happened. I’ll help if I can. My original blog post may help you to fix the problem yourself.

richardstephenowens
This image has an empty alt attribute; its file name is image.png
Darth Vader meme
http://madeupexplorations.wordpress.com/?p=105
Extensions
Heroes of Might and Magic V – Hammers of Bait and Switch?
UncategorizedGameHackingHammers of FateHeroes of Might & Magic VInstallerReverse EngineeringTurn-based Strategy
This documents my process of finding a fix for the “Original game not found” problem when installing Heroes of Might and Magic V: Hammers of Fate from Ubisoft. For the actual fix, please visit the fix blog post. My partner came to me the other day, complaining that the game she bought from Ubisoft, HeroesContinue reading "Heroes of Might and Magic V – Hammers of Bait and Switch?"
Show full content

This documents my process of finding a fix for the “Original game not found” problem when installing Heroes of Might and Magic V: Hammers of Fate from Ubisoft. For the actual fix, please visit the fix blog post.

My partner came to me the other day, complaining that the game she bought from Ubisoft, Heroes of Might and Magic V: Hammers of Fate, wouldn’t install. This is an expansion pack of “Heroes of Might and Magic V” from 2006 and is now offered on Ubisoft’s service of some sort – I don’t know much about it. I don’t use it. It’s one of her favourite game series and she’s going to be taking a trip soon where she’ll need the moral support that gaming provides. I offered to take a look.

She showed me the attempted install and when the installer was run (through the Ubisoft service) it said “Original game not found” and gave up. The original game most certainly is there – it was installed also through Ubisoft’s service.

“Original game not found” error message window.

Now she’s no slouch in the tech department herself – she works in software just as I do, in devops, so she’d attempted to resolve this herself before mentioning this to me. She’d found a large number of forum posts complaining about this issue, with no resolution. Apparently people had complained to Ubisoft, they fixed it, then the service changed and it broke again. None of the many forum posts had a solution to this issue.

She had, open in front of her, the install directory. What the Ubisoft service did was copy what appeared to be (at least similar to) the original retail CD contents into the directory D:\Program Files (x86)\Ubisoft Game Launcher\cache\installers\146. In there, there was a “Setup.exe” which, when run, produced the same error message as above. Clearly, the Ubisoft “Install” button just ran this Setup.exe.

Plan: Force the install and sort the rest out manually

My plan at this point was this – since the original game was definitely there, if I tricked the installer into running and installing the expansion pack, despite it not finding the original game, then I’d be able to just clean it up afterwards so it points at the game. It wouldn’t know where the original game was (and it would need that to run) but I could fix that. I know that a lot of older games keep their configuration in a .ini file so I surmised that if I installed the game, I’d go into that .ini file, correct the installation directory and it would run.

I didn’t know how I was going to do this, but I was going to figure it out.

Where does it seem to think this crap is?

My first hope was that Ubisoft had changed the installation path compared to when the game was first released, that there would be an expected default install location within the expansion setup files that I could change to point to the correct location and it would all just work

I had no idea how the installer worked. There were a number of files – Setup.exe (165 kB in size – small, probably does very little), data1.cab (9 MB, clearly a bit more substantial), data2.cab (1.4 GB, clearly most of the game content), some image files, a unicode dll (unicows.dll – lol. What a name.), a setup.inx, various other bits and a setup.ini. Aha, thought I. Surely it’d be in there!

Sadly not. In all of the plaintext files in the installer, there was nothing that appeared to indicate a default path that I could correct.

Next up, I wanted to try to find that default path somewhere in the files. I wanted a minimum number of files to look through, so I deleted files in the install directory to see what the installer actually needed. So – delete a file, run the installer, does it give that error message? If so, that file is unnecessary so move onto the next file. If not, then that file is needed, restore it and move on.

I got rid of all of the subdirectories (which just appeared to be support and autorun shite), the autorun stuff, data2.cab (which was good – not searching through a 1GB+ file would make this easier), the images, and a load of other stuff.

This left me with the following minimum file roster required to get the “Orignal file not found” error message:

  • Setup.exe
  • Setup.inx
  • unicows.dll
  • ikernel.ex_
  • data1.cab
  • data1.hdr
Does it even have a default file path? Is this a wild goosechase?

So it was in here somewhere. I guess it’d probably look like plaintext, so it shouldn’t be too difficult to identify. It’s probably not actually in the Setup.exe, or the ikernal.ex_ (which appears to actually be a .exe renamed – it has that “This program cannot be run in dos mode” text near the start that’s a dead giveaway), or the dll. Still, let’s look through it all.

One of my favourite technical searching tricks, even when I’m dealing with binary data, is to just open the whole lot in Notepad++ and start from there. I opened it all and searched for “Heroes”, hoping that if the original path was here, it’d be nice and visible. Sadly not. Many references to this expansion pack but only one or two to the original game and none of them seemed to be a path. I tried a regex search for each of the characters of “Heroes” but with wildcards between, again no such luck.

This wasn’t going to be as easy as I thought.

Error messages come from somewhere…right?

Well what about the error message “Original game not found”. That had to come from somewhere and if I could find that somewhere, I could work backwards and jump over the thing that triggers it. Something somewhere has to be looking for the original game, and that something must have logic that I can tweak.

Searching in plaintext failed, but it had to be there. I assumed it wasn’t in the .exes or .dll, so this information had to be somewhere in the .cab, the .hdr or the .inx file. I had never heard of any of these files before, so off I went a’googling to try and figure out what I was looking at. Let’s start with “data1.cab” – it’s the most substantial so I’m guessing that the installer uses this to direct its behaviour.

I searched “data1.cab” and one of the previews said ““Data1.cab” seems to be a default used by the InstallShield Installer.” *Installshield Installer* At last, I now know at least what I’m looking at! It would appear that Installshield is a product used by a lot of old games to perform the installation process. Furthermore, .cab files are apparently compressed archive files of some sort which would have a lot more information in them if I decompress them. My trusty 7zip didn’t seem to know what to do with it so I went looking for some way to open them. Installshield is a current product that has a free trial version available, but I don’t know if I’d expect it to be able to open old installations, rather than just make new ones.

After some searching I found UniExtract, the universal extractor which claims to be able to extract InstallShield Cabinet archives. I install that and voila, I can extract the cab. It gives me some dlls, some bitmaps, some text files with EULAs in various languages and a few other files.

I think error messages are more intimidating in German.

Let’s find that-there error message. Using Notepad++ I search the extracted files for “Original” (to hopefully get “Original game not found” and… I get one hit! In a file named “value.shl”.

MESSAGE_GAME_NOT_INSTALLED=Cannot install Heroes of Might & Magic V: Hammers of Fate. Originalspiel nicht gefunden.

Wait. What? That’s definitely the error message I’m after…but in German? “Originalspiel nicht gefunden” is literally “Original game not found” but why the hell is it only in German? I could understand it maybe being in German and English (and the game might allow you to choose your language) but no, it’s only in German. The entire contents of value.shl were German, with very few English words scattered about.

At this point my partner piped up. She apparently explicitly asked Ubisoft for the German version of game. She does speak some German so that’s not that surprising, but where’s the English error message coming from?!

Is a “French Error Message” like a broken French Letter?

I start the installer again and it offers me multiple languages to choose from. Let’s try German then.

“Originalspiel nicht gefunden” error message window.

At this point I’m 100% convinced that I’m looking in the right direction. That’s exactly the error I’m trying to get past. Still. Something isn’t right about this because of the only German issue. So I try another language. How about French.

“Jeu de base non trouvé” error message window.

Time to go looking for “Jeu de base”. Nope. No jeu de base. So I have *only* the German error message. Clearly this isn’t the source of the error message so I need to change tactics. Searching further, I learn that data1.cab most likely only contains things that the installer will install, rather than the logic of the installer itself. Maybe this is the error message file for the uninstaller?

I do love it when I have to get to break out a decompiler

That German error message might have been a red herring, but it did at least give me another hint and another thread to pull.

MESSAGE_GAME_NOT_INSTALLED

This, if I’m lucky, might be the variable name for the message. I search… and it is! It’s in plaintext in the mostly-binary setup.inx. So what is this “setup.inx” anyway? I once more go a’googling and it’s apparently an installer script.

Aha! So this is the file that contains the logic used by the installer to install the file! How on earth am I going to get at it though? After some searching around, I come across an opensource “INX Decompiler” named “Sexy Installshield Decompiler”. It comes with some caveats, and I’m initially not hopeful, but I download and run it anyway. Even if it doesn’t work, I might be able to use the info in the opensource project to reverse-engineer what I’m looking at.

I get something called “sid.exe”, initially expect it to be a command line program, and open it in Powershell. Turns out I’m wrong and I’m presented with a GUI.

Blank “[sid] sexy installshield decompiler v1.0” window

Ok… Well, let’s give it a go. file > open, point it at setup.inx and….

[sid] decompiler window populated with the start of a decompilation and a completed progress-bar at the bottom

Look at it go!!! sn00pee, you’ve really pulled through for me here. Cheers, I owe you one. After about a minute I get a load of decompiled code that I can copy and paste into Notepad++. Time to start digging.

Time to sift through the chaff for the wheat

Ctrl-F “MESSAGE_GAME_NOT_INSTALLED” points me at one hit, in something called “function_44”, full of opaque function number references, “local_number666″s and magic numbers everywhere. Oh yeah – decompiled code is even harder to read than written code. Bugger. I’m really gonna have to work for my supper today.

Looking at the contents of the file near the “”MESSAGE_GAME_NOT_INSTALLED”, I see that it runs a function, checks something about it, then the aforementioned error message is part of an error message window displayed to the user. At the end of that error message is the instruction abort;. “Ooh,” thinks I, “That sounds good. Perhaps if I can just stop the installer from aborting and make it just continue when it finds an error, I’ll get an installation!”.

Function_44() decompiled source code. Largely opaque, with plaintext message names. I’ve highlighted the ‘abort’ command.

I break out my trusty hex editor, HxD, and I look at address 7C1A.

Hex editor data showing plaintext messages in the setup.inx file

So I take stock – I can see my NOT_INSTALLED error message in plaintext (the same one I saw before) around what appear to be instructions to present it to the screen. So if I change that 02 to a 00, would that change the abort into a no_operation and just step over it? I make the tweak and try it.

“An error occurred while launching the setup. (0x80040801)” error message window

Bugger.

Well. Maybe. Have I stepped over the problem and hit another one? Perhaps! So, let’s search for this 0x80040801. Nothing. No idea where it’s coming from.

Perhaps it’s a checksum problem? The decompiler handily provides checksums for every function so perhaps, the installer performs a checksum check before running?

A list of functions and 8-hex-digit checksums.

I search for 4060866E – function_44’s checksum – in setup.inx, but no hits. It doesn’t appear that there’s a checksum anywhere in the file. I try some others. Nope. It would appear that this isn’t it.

Googling “Installshield errors”, I come across this list of internal Installshield errors but sadly I think I’m barking up the wrong tree. No matter how long I spend calculating and recalculating my twos-complements, I can’t get that 0x80040801 to match up to any of these error messages. I’m like 2 pints of beer down at this point and our takeaway is waiting downstairs, so I have an enforced break and will come back to this with fresher eyes.

Sometimes you just need a bigger picture

A couple of days later, I come back to this problem and decide that I’m going to tackle it some other way. Rather than trying to step over the abort, let’s dig through the code and figure out how we get to this point and stop it getting there.

Function_44() source, with function_67() highlighted.

So clearly, it’s choosing whether or not to print that error message window on the basis of the output of function_67(), so let’s dig into that function.

function_67() code

@0000A56B:0022 function BOOL function_67()
@0000A56B NUMBER local_number1;
@0000A56B STRING local_string1;
@0000A56B
@0000A56B begin
@0000A574:0021 function_42(“F127526C-886E-44fa-BE7B-BB168D6D11F0”);
@0000A5A1:0006 local_string1 = LASTRESULT;
@0000A5AB:000D local_number1 = (local_string1 = “”);
@0000A5B8:0004 if(local_number1) then // ref index: 1
@0000A5C4:0021 function_42(“B860C21C-D6E0-46a2-9CE2-F4912A897EF0”);
@0000A5F1:0006 local_string1 = LASTRESULT;
@0000A5FB:0004 endif;
@0000A5FB:0004 label_a5fb:
@0000A5FD:000D local_number1 = (local_string1 = “”);
@0000A60A:0004 if(local_number1) then // ref index: 1
@0000A616:0021 function_42(“308F3DD5-7CC0-4fc2-9BDD-AF417479F920”);
@0000A643:0006 local_string1 = LASTRESULT;
@0000A64D:0004 endif;
@0000A64D:0004 label_a64d:
@0000A64F:000D local_number1 = (local_string1 = “”);
@0000A65C:0004 if(local_number1) then // ref index: 1
@0000A668:0021 function_42(“20071984-5EB1-4881-8EDB-082532ACEC6D”);
@0000A695:0006 local_string1 = LASTRESULT;
@0000A69F:0004 endif;
@0000A69F:0004 label_a69f:
@0000A6A1:000D local_number1 = (local_string1 = “”);
@0000A6AE:0004 if(local_number1) then // ref index: 1
@0000A6BA:0021 function_42(“DDB68A90-340C-42b9-B42B-D2CBED1B91DC”);
@0000A6E7:0006 local_string1 = LASTRESULT;
@0000A6F1:0004 endif;
@0000A6F1:0004 label_a6f1:
@0000A6F3:000D local_number1 = (local_string1 = “”);
@0000A700:0004 if(local_number1) then // ref index: 1
@0000A70C:0021 function_42(“BD0EB672-2417-437e-81EA-231F419C68BD”);
@0000A739:0006 local_string1 = LASTRESULT;
@0000A743:0004 endif;
@0000A743:0004 label_a743:
@0000A745:000D local_number1 = (local_string1 = “”);
@0000A752:0004 if(local_number1) then // ref index: 1
@0000A75E:0021 function_42(“28101984-0BA6-40fd-9ABE-72F62F80C06C”);
@0000A78B:0006 local_string1 = LASTRESULT;
@0000A795:0004 endif;
@0000A795:0004 label_a795:
@0000A797:000D local_number1 = (local_string1 = “”);
@0000A7A4:0004 if(local_number1) then // ref index: 1
@0000A7B0:0021 function_42(“28101984-0BA6-40fd-9ABE-72F62F80C06C”);
@0000A7DD:0006 local_string1 = LASTRESULT;
@0000A7E7:0004 endif;
@0000A7E7:0004 label_a7e7:
@0000A7E9:000D local_number1 = (local_string1 = “”);
@0000A7F6:0004 if(local_number1) then // ref index: 1
@0000A802:0021 function_42(“8829DAD4-8F07-4a96-B995-15498EBB8045”);
@0000A82F:0006 local_string1 = LASTRESULT;
@0000A839:0004 endif;
@0000A839:0004 label_a839:
@0000A83B:000D local_number1 = (local_string1 = “”);
@0000A848:0004 if(local_number1) then // ref index: 1
@0000A854:0021 function_42(“0DE075DB-4218-4b2c-A35E-48D80BA680BB”);
@0000A881:0006 local_string1 = LASTRESULT;
@0000A88B:0004 endif;
@0000A88B:0004 label_a88b:
@0000A88D:000D local_number1 = (local_string1 = “”);
@0000A89A:0004 if(local_number1) then // ref index: 1
@0000A8A6:0021 function_42(“F68563C0-2CCD-4799-A014-017A370D627B”);
@0000A8D3:0006 local_string1 = LASTRESULT;
@0000A8DD:0004 endif;
@0000A8DD:0004 label_a8dd:
@0000A8DF:000D local_number1 = (local_string1 = “”);
@0000A8EC:0004 if(local_number1) then // ref index: 1
@0000A8F8:0021 function_42(“EF19211B-DB8D-4ef6-B501-27329E455D2C”);
@0000A925:0006 local_string1 = LASTRESULT;
@0000A92F:0004 endif;
@0000A92F:0004 label_a92f:
@0000A931:000D local_number1 = (local_string1 = “”);
@0000A93E:0004 if(local_number1) then // ref index: 1
@0000A94A:0021 function_42(“1898B8E5-43E2-4BCA-AD6A-B9FBE0C93F84”);
@0000A977:0006 local_string1 = LASTRESULT;
@0000A981:0004 endif;
@0000A981:0004 label_a981:
@0000A983:000D local_number1 = (local_string1 = “”);
@0000A990:0004 if(local_number1) then // ref index: 1
@0000A99C:0021 function_42(“0387FAD3-A473-409e-973A-9DE599090714”);
@0000A9C9:0006 local_string1 = LASTRESULT;
@0000A9D3:0004 endif;
@0000A9D3:0004 label_a9d3:
@0000A9D5:000D local_number1 = (local_string1 = “”);
@0000A9E2:0004 if(local_number1) then // ref index: 1
@0000A9EE:0021 function_42(“A0E3BBC0-044D-4a0d-87CA-054937965720”);
@0000AA1B:0006 local_string1 = LASTRESULT;
@0000AA25:0004 endif;
@0000AA25:0004 label_aa25:
@0000AA27:000D local_number1 = (local_string1 = “”);
@0000AA34:0004 if(local_number1) then // ref index: 1
@0000AA40:0021 function_42(“0387FAD3-A473-409e-973A-9DE599090714”);
@0000AA6D:0006 local_string1 = LASTRESULT;
@0000AA77:0004 endif;
@0000AA77:0004 label_aa77:
@0000AA79:000D local_number1 = (local_string1 = “”);
@0000AA86:0004 if(local_number1) then // ref index: 1
@0000AA92:0021 function_42(“0387FAD3-A473-409e-973A-9DE599090714”);
@0000AABF:0006 local_string1 = LASTRESULT;
@0000AAC9:0004 endif;
@0000AAC9:0004 label_aac9:
@0000AACB:000D local_number1 = (local_string1 = “”);
@0000AAD8:0004 if(local_number1) then // ref index: 1
@0000AAE4:0027 // return coming
@0000AAE8:0023 return 0;
@0000AAF1:0004 endif;
@0000AAF1:0004 label_aaf1:
@0000AAF3:0006 global_string8 = local_string1;
@0000AAFD:0027 // return coming
@0000AB01:0023 return 1;
@0000AB0A:0026 end; // checksum: 7b0e912a

At a glance, it seems like the code is doing something with a series of strings, and if any one of the strings returns something, then it succeeds, otherwise it fails. It then returns either 0 or 1 depending on its success. Perhaps I can change that return 0 into a return 1 and it will install?

Taking a look at AAE4 in setup.inx, return 0 appears to be encoded with the hex value 27 00 00 00 23 00 01 00 07 00 00 00 and return 1 is encoded with 27 00 00 00 23 00 01 00 07 01 00 00 00. Searching around the file for other examples, that seems about right. On that basis, I can consider the 10th byte to be the actual return value (if it’s a constant). Since return 1 encodes success, let’s change the return 0 to return 1 and force it to succeed (at…whatever it’s doing) no matter what.

Fatal granny problems spoil my day

So value AAED becomes 01 instead of 00, test it aaaand….

An installer window. “Welcome to the InstallShield Wizard for Heroes of Might & Magic V: Hammers of Fate”…”[this] will install… on your computer. To continue, click Next.”

SUCCEEEEEEEEESSSSS! The installer is willing to run! So I go through the installation process and run the program.

An error message window titled “Fatal Granny Installation Error”. The message complains that ‘granny2.dll’ is in a system directory.

Wat. I’ll be honest, “Fatal Granny Installation Error” is one of the more out-there error messages I’ve received.

But wait. C:\Windows\bina1…? Ohkay, so it turns out this game has installed itself in my C:\Windows folder, just about the last place I want it. It didn’t actually ask for an installation directory and I’m guessing that C:\Windows is just the default. Bugger.

What’s worse is that the installed files have no .ini file where I can point it to the correct file path, so my original plan could never have been done. Still, I’m nearer my goal. It’s installed, just not where I want it to.

What’s even worse is that my modified setup.inx won’t uninstall what I’ve just done, giving the same 0x80040801 error as before. Thankfully, a completely-clean copy of the installer does uninstall it just fine.

So that stuff that I just forced into succeeding… what was it actually doing?

I feel like I’m speaking parseltongue whenever I can understand this shite

It’s just calling function_42() again and again, with different arguments that appear to be arbitrary text strings.

Function_67(), showing that it’s calling function_42() multiple times, with arbitrary-looking hex-number strings.

Guess I should probably look at what function_42() is actually doing.

Function_42, showing that it defines strings specifying a reg key path. It appears to be checking the value of “InstallLocation” in a key.

Alright, that looks relatively neat and self-contained. What’s more, I think it can be understood! It appears to be checking or setting registry keys. Even better, those two functions RegDBSetDefaultRoot and RegDBGetKeyValueEx/RegDBSetKeyValueEx have publicly available technical information! Awesome!

As for the value that RegDBSetDefaultRoot is specifying (-2147483646), it turns out that each of the base reg keys has an associated number, rather than a string. It wasn’t clear at first but googling around that number cleared it up. That number is for HKEY_LOCAL_MACHINE.

So it’s checking that path in the registry for one of the aforementioned arbitrary strings and getting the install location of the base game from a key in that directory. Awesome. Let’s rewrite this to be a bit more understandable.

Function check_reg_key, function_42() with named variables.
check_reg_key() code

@000079C7:0022 function STRING check_reg_key(key_name)
@000079C7 NUMBER data_type, original_game_install_path_string_length, local_number3;
@000079C7 STRING full_key_address, original_game_install_path, key_address;
@000079C7
@000079C7 begin
@000079D0:0014 key_address = (“SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall” ^ “{“);
@00007A11:0007 key_address = (key_address + key_name);
@00007A1E:0007 full_key_address = (key_address + “}”);//build the full reg path
@00007A2C:0021 RegDBSetDefaultRoot(-2147483646);//set the default reg path to HKEY_LOCAL_MACHINE
@00007A37:0021 RegDBGetKeyValueEx/RegDBSetKeyValueEx(full_key_address, “InstallLocation”, data_type, original_game_install_path, original_game_install_path_string_length);
//get the value of the original game InstallLocation reg key
@00007A5B:0006 local_number3 = LASTRESULT; //get the returnvalue. Was the key found?
@00007A65:0009 local_number3 = (local_number3 < 0);
@00007A74:0004 if(local_number3) then // the key wasn’t found here.
@00007A80:0027 // return coming
@00007A84:0023 return “”;
@00007A8B:0005 goto label_end;
@00007A94:0002 endif;
@00007A94:0002 label_success:
@00007A96:0027 // return coming
@00007A9A:0023 return original_game_install_path;
@0000end:0001 label_end:
@00007AA3:0026 end; // checksum: ddee655

So it’s looking in the registry at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, for each of the keys that are passed to it. It’s then looking in each of those keys for an InstallLocation string and returning it if it’s present. If it’s not finding those keys, then where is the installation reg key for the original game?

I look on my partner’s machine and it’s…

HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Uplay Install 87

Well there’s your problem. It’s in completely the wrong place. What’s more is the contents appear fine.

The contents of the “Uplay Install 87” reg key with a “DisplayName” of Heroes of Might and Magic V, and a sensible looking install string.

What happened was that Ubisoft modified the reg key location of the original game and couldn’t be arsed to fix the reg key location in the expansion. That’s just plain lazy. We *paid* for this game.

Problem found. How to solution?

At this point, I see that I have two realistic options. I can either copy and paste the contents of the existing reg key into one of the expected locations such as HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F127526C-886E-44fa-BE7B-BB168D6D11F0} and it should just work. The down side of this is that I’m making a hack to the registry and duplicating some information. I guess that isn’t that bad but…eh? I’d prefer a better solution.

Can I not fix the installer?

Actually, yeah, I probably can. All I need to do is modify the affected strings to point to the correct reg key location. I’ve got to be a bit careful here though. I can’t really modify the length of any of the strings or I’m going to change offsets within the setup.inx file, at which point it won’t work [I notice now after doing this that the sid.exe decompliler claims it can apply patches to the .inx file, which might be a better solution. That said, I don’t know if that will work or if it suffers from the same limitation]

As is obvious to see, the required path is longer (up to the Uninstall bit) than the original path, because of the addition of \WOW6432Node, but it’s shorter than the entire path overall. Because of this, I’ll be able to map the required path on to multiple strings and, without modifying the code, have the logic build the correct path itself.

Mapping shite onto other shite

In setup.inx, I’ve got the following ‘base’ key address to work with.

SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

which at 55 characters I can map, character for character, onto

SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersi

I’ve got

{

which maps to

o

and then I need to cannibalise one of the keys to fit the rest in. The 36 characters of

F127526C-886E-44fa-BE7B-BB168D6D11F0

maps to 28 characters of

n\Uninstall\Uplay Install 87

with 6 characters left over. Furthermore, there’s an additional } I need to get rid of.

I’m going to need to shrink these strings to get this to work. The strings don’t appear to be null terminated, but they appear to have the character count in the second preceding byte (so A57B has the value 0x24, which is 36). It would appear to be possible to shrink this string by modifying that value, but let’s try just padding the string with null characters first.

I decided against trying to get it to work with a zero-length string, so I put the last character in place of where the } would be.

So, back into HxD, in setup.inx, I enter

SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersi

at address 79DA. I enter ascii character

o

at address 7A10. I enter

n\Uninstall\Uplay Install 8ΔΔΔΔΔΔΔ

at address A57D (where Δ is a null character (0x00]).

I also enter the final 7 character at address 7A2B.

Well? Does it work?

No. And I don’t know why. It could be that it doesn’t like the null characters after the string. It once again provides me with an “Original game not found error.”

This gives me a thought – where does it try to install now, if I force it to run by patching the return value as I did above?

Nope. Back in C:\Windows\bina1. So it’s clearly not picking up the registry key. It must be asking for a registry key. So what is it actually looking for?

Down the rabbithole and hooked off

At this point, I had the thought “Using the registry must require Win32 API calls. Can I intercept Win32 API calls somehow?” and it turns out the answer is yes! …Apparently. There are two available projects which will intercept these calls – Detours by a project team at Microsoft and Mhook. Turns out that API intercepting is called API “hooking” and by all accounts these (mostly Detours) are the tools for the job.

So I look around, neither of them seem to be downloadable in an executable format. I need to download the C++ source and do it myself. I’ve got VS Code 2019 installed on my system, they come as .slns and I do this sort of stuff all the time in Linux land so this should be a doddle right?

Wrong.

I just kept getting compiler errors. Makefiles appeared to be missing bits(?), the resource compiler wouldn’t run (?!) and it appeared to be trying to declare a negative-size array(?!?). I spent a while trying this and that and adding all sorts of preprocessor directives but in the end I just got hacked off because none of it made sense. I’m *sure* it worked on an old SDK, but they aren’t working on mine now and installing an old SDK might be an easy thing to do, but I don’t actually know which one I want. There’s definitely some configuration crap going on in my machine, but sorting that out is opaque. I’m a software engineer by trade by I never use VS Code professionally. It seems to work fine for me when I want to potter around writing a bit of C or C++, so digging any deeper is going to take much more time than I really want to spend right now, especially considering that building either of these is an aside to my main problem.

Turns out there’s also a Microsoft package manager called vcpkg which would download and install it for me, so I get that running and tell it to get Detours, but still, the same problems arise for it. Right. Give up.

*sigh*. Sure, Linux tells you to “bake it yourself” but at least the Linux hands you the tools to do it and if you follow the instructions, the tools definitely do what you expect of them. I fear Windows just isn’t quite there.

Monitoring the Progress

Did you know that you don’t need an API hooker to see registry key operations? Well I didn’t. After searching around for alternatives, I learn that I even already had the bit of software I needed to do the job! Good old Process Monitor!

Opening it up, I see all sorts of events but the occasional registry event, so it’s clearly the right tool. I run the installer and look for registry events, but there’s so many I can’t see the wood for the trees.

I’ll need to use the filter to sort this out. In the first instance, I’ll look for a known key before I try to figure out what’s happening with a modified key. I run the unmodified installer and filter for “F127526C”, which is part of the default set of reg keys. …Nothing. Bugger. Oh, wait, turns out that you need to run plain old “ProcMon” and not “ProcMon64” if you want Win32 events! Makes sense.

Aha! I see the installer trying to open reg keys from the executable IKernal.exe, must be that iKernal.ex_ in the folder. So I filter for that and run my modified installer and I see it!

ProcessMonitor events showing the extra slash.

Hmm, that’s definitely the problem. It’s looking for the contents of string EY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersi\on\Uninstall\Uplay Install 87. It’s shoving an unexpected and unwanted slash in there. Why would it be doing that? I go back to the code.

Hiding in plaintext sight
A source snippet showing both a caret and plus used to “concatenate” a string.

You see that? There are two string operators in use there, ^ and +. I’d kind of noticed it but I didn’t think much about it. I kind of just assumed that both were string concatenation operators, but in retrospect that makes less sense than it should… Clearly, the ^ operator is “add to path” which is like a string concatenate, but with an unwanted \ in there.

The solution therefore is to convert the ^ to a +. I have two options – I can either dig through the binary data for examples of both operators to convert one to another but here’s something I can use that SID patching functionality for!

I load up SID and point it at my modified setup.inx. It appears I was right earlier when I said that SID might have the limitation that offsets might not be able to be modified – they can’t – but this is apparently exactly the sort of tweak it was designed for. I navigate to the offending line and when I right-click it, it offers me a little drop-down menu which includes “change to: + (plus)” as an option. The perfect option!

A [sid] decompiler window, showing “// changed to “+” at the end of line 79D0.

It annotates my line and I click “patch changes”. I compare the before and after in HxD and it changes the value of 79D0 from 0x14 to 0x07.

SUCCCEEEEEEEEEEEEEeeeeeeeeeee…..

I run setup.exe with the new setup.inx and wouldn’t you know it, it works. I give it to my partner, tell her to copy it into the cache\installer\146 directory and run it. Also success. Happy partner. All is well. And I now have a working installer for Heroes of Might and Magic V: Hammers of Fate when installing from Ubisoft.

But can I fix this for everybody else? I’m pretty comfortable handing a binary blob – that I’ve constructed – to my partner but that might not be ideal for everyone. Furthermore, if Ubisoft change anything about the installer of either the base game or the expansion, my installer script won’t work. People could go through this process to remake it, but there could be an easier way if one was to manually duplicate the base game registry key and make it fit what the expansion expects.

So I took the Uplay Install 87 registry key, exported it, changed the address to [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall{F127526C-886E-44fa-BE7B-BB168D6D11F0}], stuck that in my registry and tried it again.

A “Uplay Installer 87” key (as above), shown with its path changed to …F127526C…

And nah. It doesn’t work. Why the hell not? Is this not what you’re looking for? Is summat missing?

Are you not amused?

Since adding the supposedly correct reg key to my registry isn’t letting me install the game, why isn’t it working? Time to go back to my trusty ProcessMonitor and see what it’s actually looking for.

A block of ProcessMonitor events showing that the keys are “SOFTWARE\WOW6432Node\Microsoft…”

Wait. What? I’m asking that way too much. Where does that additional “WOW6432Node” pathname come from? That’s not in my source, or my binary!

At this point I’m assuming that in the 32-bit -> 64-bit conversion, Windows 10 puts legacy 32-bit Win32 API keys in their own WOW6432Node path. Therefore, my adding of keys has been putting them in the wrong place.

So the path should look like [HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{F127526C-886E-44fa-BE7B-BB168D6D11F0}] Let’s add that bit to the path and try again…

The same reg key, this time with “WOW6432Node” in its path

And it works. Just like that, I’ve found two solutions to the problem that will basically work for anyone. I think this project is now done.

Summary

The game expansion, Heroes of Might & Magic V: Hammers of Fate is looking for the wrong registry keys of the base game when it installs, meaning that it always has an “Original game not found” error. This can be fixed by modifying the InstallShield script file setup.inx to look at the correct location for the original game registry keys.

Checksum for the unmodified setup.inx that I worked on

Name: setup.inx
Size: 173379 bytes (169 KiB)
SHA256: 3F128BBB3B481F065F776080D9953B387FD68FE201FF79B3A0F6EC5A76B1C948

To correct this, I modified strings within the script file such that instead of searching for [one of] the default key[s] HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F127526C-886E-44fa-BE7B-BB168D6D11F0}, it searches for the (correct for Ubisoft Connect) reg key HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Uplay Install 87

I made the following modifications to setup.inx to fix this:

Address RangeValue FromValue ToPurpose79DA-7A0C[ASCII]SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall[ASCII]SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersiReplace the first bit of the constructed reg key string to point to the correct key.7A10[ASCII]{[ASCII]oTo overwrite the curly bracket, used to construct the default key.A57D-A597[ASCII]F127526C-886E-44fa-BE7B-BB168D[ASCII]n\Uninstall\Uplay Install 87To construct the second part of the reg key stringA598-A59D[ASCII]6D11F0[Binary] 00 00 00 00 00 00To shorten the original reg key string7A2B[ASCII]{[ASCII]7To end the reg key string79D0[Binary] 0x14[Binary] 0x07To change the “add to path” operator into a string concatenation operator.
List of modifications made to setup.inx to let the installer run.

Adding that modified setup.inx file to the installer directory (replacing the Ubisoft-supplied setup.inx) and running the installer will allow it to install.

richardstephenowens
http://madeupexplorations.wordpress.com/?p=18
Extensions
Techy Fiddlings
Uncategorized
I’m Richard, also known by Slortibort and a whole host of more-and-less kind names. I work in tech, mostly with ancient things at a low level. I’ve started this blog just to provide a place to document some techy things I do.
Show full content

I’m Richard, also known by Slortibort and a whole host of more-and-less kind names. I work in tech, mostly with ancient things at a low level. I’ve started this blog just to provide a place to document some techy things I do.

richardstephenowens
http://madeupexplorations.wordpress.com/?p=15
Extensions