Quantcast

Jump to content

» «
Photo

Using Detours/EasyHook in an .ASI?

10 replies to this topic
lpgunit
  • lpgunit

    It's L, as in Lpgunit, not I.

  • Feroci
  • Joined: 24 May 2008
  • Philippines

#1

Posted 11 August 2016 - 01:58 PM

Yeah, I know I am not that well versed with C++ or programming as of now, but I'm trying to cobble this up as a simple fix of sorts. Sure, ASIs are most commonly associated with GTA, but this has little to do with the series so I'll leave this here.

See, I have this 1990s era game which ran off Win9x properly, but not on 2000 and later due to changes in the API, specifically on how CreateWindowEx is used. Running the game through both Wine and an API debugger reveals it's calling an invalid menu handle, which I assume is either an oversight on the developer's part, or Microsoft moving goalposts. There aren't any drop down menus or menu bars in the game, so I assume hMenu should be NULL, yet the programmers used 1 or 0x1 as a value.

I am trying to experiment on this by using an ASI mod to hook into the game process and alter the API function so it runs properly, but I'm at a loss as to how to use either Detours or EasyHook to alter things.

Here's one thread on Stackoverflow regarding CreateWindowEx, though it doesn't appear to pertain to DLLs/ASIs: http://stackoverflow...called-after-it

K^2
  • K^2

    Vidi Vici Veni

  • Moderator
  • Joined: 14 Apr 2004
  • United-States
  • Best Poster [Technology / Programming] 2016
    Best Poster [Programming] 2015
    Most Knowledgeable [Web Development/Programming] 2013
    Most Knowledgeable [GTA Series] 2011
    Best Debater 2010

#2

Posted 13 August 2016 - 05:33 AM

ASI worked with early 3D GTA games because they read additional libraries at startup. Later games in the series relied on a DirectX injector introducing code to load ASI files. The format was kept simply because people who wrote them were used to ASIs.

If you are hooking into a Win98 game, none of these loaders are going to work. On the other hand, you seem to have already found the function you are trying to hook, so writing your own injector is a piece of cake. You have two routes. You can either modify the CreateWindowEx function itself, by clobbering function prologue with a jump to a new prologue, or you can modify the calling function. In that case, you can either find the place where it passes a bad argument and change it (if it's a constant), or call your own wrapper for CreateWindowEx that will fix the parameters.

The function you will be mostly using is WriteProcessMemory. You can pass to it any valid process handle. You can get the process handle by either calling OpenProcess or by starting the process yourself. Basically, it depends on whether you want your program to run side-by-side or work as a launcher. Either way, once you have process handle, you need to find the virtual address of the function you are trying to modify. This will be a constant offset from the module base.

Now, there are effectively two ways of going about this. You can do all your surgery from remote process (launcher, w/e.). That makes work easy, but you first need to get the base address of the image of the target process. You do that with a call to EnumProcessModules and grabbing module whose name matches that of the image. In other words, name of the executable. The hModule pointer is actually the base address you want, but you can get additional info with GetModuleInformation.

Second option is injecting payload into target process. You can use CreateRemoteThread to force target to run your code. You usually want to make it a DLL, so that all of its linking is dynamic. This is how most basic DLL/ASI injectors actually work under the hood. Since your code now runs inside the target process, you just call GetModuleHandle(NULL) to get the base address for the image.

From there, it's easy. You know location of your functions relative to module base, so just add the hModule to the offset and use the WriteProcessMemory to change whatever you need. If you need to add a jump instruction anywhere see the x86 JMP reference. If you need to write a wrapper function with no prologue of its own, __declspec(naked) should do the trick in MSVC.
  • lpgunit and thehambone like this

lpgunit
  • lpgunit

    It's L, as in Lpgunit, not I.

  • Feroci
  • Joined: 24 May 2008
  • Philippines

#3

Posted 13 August 2016 - 05:51 AM

The game used Ddraw and since ThirteenAG's loader seemed to work with it I thought of giving it a try.

K^2
  • K^2

    Vidi Vici Veni

  • Moderator
  • Joined: 14 Apr 2004
  • United-States
  • Best Poster [Technology / Programming] 2016
    Best Poster [Programming] 2015
    Most Knowledgeable [Web Development/Programming] 2013
    Most Knowledgeable [GTA Series] 2011
    Best Debater 2010

#4

Posted 13 August 2016 - 06:16 AM

Well, see if it works. Make a DLL that pops up a MessageBox on load. If it does, saves you a little bit of work in writing your own injector.

Either way, though, you'll have to write your own hooks and place them with WriteProcessMemory.
  • lpgunit likes this

lpgunit
  • lpgunit

    It's L, as in Lpgunit, not I.

  • Feroci
  • Joined: 24 May 2008
  • Philippines

#5

Posted 13 August 2016 - 06:34 AM Edited by lpgunit, 13 August 2016 - 06:54 AM.

Well, see if it works. Make a DLL that pops up a MessageBox on load. If it does, saves you a little bit of work in writing your own injector.

Either way, though, you'll have to write your own hooks and place them with WriteProcessMemory.


As a matter of fact, I did use this code snippet LINK2012 made for the lulz:
http://gtaforums.com...entry1061507590

It displays a message box as I expected:
RSUgWbw.jpg

What I'm wondering is how to inject the game just for a single function. EasyHook seemed fit for my needs as I don't feel like going Rube Goldbergian for just one show-stopper, but the problem is I couldn't get it to hook properly yet:
https://github.com/E...Hook/issues/134

Hope you don't mind, but I also sent you a Skype request so I can further expound my problem to you. :)

K^2
  • K^2

    Vidi Vici Veni

  • Moderator
  • Joined: 14 Apr 2004
  • United-States
  • Best Poster [Technology / Programming] 2016
    Best Poster [Programming] 2015
    Most Knowledgeable [Web Development/Programming] 2013
    Most Knowledgeable [GTA Series] 2011
    Best Debater 2010

#6

Posted 13 August 2016 - 07:15 AM

Well, there you go then. Now see if you can hook the function you are trying to modify. Simplest thing you can do for testing is write a single byte 0xCC to the function's address. This is an INT 3 instruction which causes a software breakpoint. If you have debugger attached to the process you've hooked, it will stop execution on that function. This will make it easy to see where the function is being called from and what are the parameters that are being passed.

Edit: Didn't see the text at the bottom. Ok, first of all, test to see what the returns are for GetModuleHandle. Make sure you are actually getting a module. Then see if you are also getting a valid address with GetProcAddress. You can keep using the MessageBox to print debug info.

Edit2: By the way, that 0x01 passed as hMenu, is it a constant, or does it come from one of the registers? I'm wondering if you aren't just stepping on a debugger trap.
  • lpgunit likes this

lpgunit
  • lpgunit

    It's L, as in Lpgunit, not I.

  • Feroci
  • Joined: 24 May 2008
  • Philippines

#7

Posted 13 August 2016 - 08:12 AM Edited by lpgunit, 13 August 2016 - 08:15 AM.

Well, there you go then. Now see if you can hook the function you are trying to modify. Simplest thing you can do for testing is write a single byte 0xCC to the function's address. This is an INT 3 instruction which causes a software breakpoint. If you have debugger attached to the process you've hooked, it will stop execution on that function. This will make it easy to see where the function is being called from and what are the parameters that are being passed.

Edit: Didn't see the text at the bottom. Ok, first of all, test to see what the returns are for GetModuleHandle. Make sure you are actually getting a module. Then see if you are also getting a valid address with GetProcAddress. You can keep using the MessageBox to print debug info.

Edit2: By the way, that 0x01 passed as hMenu, is it a constant, or does it come from one of the registers? I'm wondering if you aren't just stepping on a debugger trap.


I'm not sure on why the game uses 0x01 tbh, except it seems to call for a nonexistent menu as no context or menu bars exist within the game. Maybe the programmers just used it out of random, not caring about potential NT compatibility as the NT/2000 series wasn't marketed towards average end users back then.

K^2
  • K^2

    Vidi Vici Veni

  • Moderator
  • Joined: 14 Apr 2004
  • United-States
  • Best Poster [Technology / Programming] 2016
    Best Poster [Programming] 2015
    Most Knowledgeable [Web Development/Programming] 2013
    Most Knowledgeable [GTA Series] 2011
    Best Debater 2010

#8

Posted 13 August 2016 - 01:17 PM

I sent you a PM, because I don't want to drop a ton of code in here. Let me know how that works out or if you have any problems with it.
  • lpgunit likes this

lpgunit
  • lpgunit

    It's L, as in Lpgunit, not I.

  • Feroci
  • Joined: 24 May 2008
  • Philippines

#9

Posted 13 August 2016 - 01:46 PM

Didn't mean to make you go through all the trouble and all, but thanks anyway. I'll see what I can do from here.

lpgunit
  • lpgunit

    It's L, as in Lpgunit, not I.

  • Feroci
  • Joined: 24 May 2008
  • Philippines

#10

Posted 14 August 2016 - 03:19 AM Edited by lpgunit, 28 August 2016 - 05:13 AM.

And yeah, turns out I was right all along, and the game's fixed.

The American Girls Dress Designer used to be like this whenever I click print, load a saved outfit, quit or basically anything that invokes a new popup window:
UZfnn7V.gif

And with the .ASI, it now works as it should:
U2D4EMn.jpg

lpgunit
  • lpgunit

    It's L, as in Lpgunit, not I.

  • Feroci
  • Joined: 24 May 2008
  • Philippines

#11

Posted 29 August 2016 - 03:01 AM Edited by lpgunit, 29 August 2016 - 03:03 AM.

Sorry for the triple-post, but I'd like to share this as it's something of an epic/funny fail on part of the programmers: The game doesn't work on Windows NT 4.0 either! To think that NT4 was released a few years before this game was even developed.

So that more or less confirms it: from what it seems, the developers never intended to make Dress Designer compatible with NT at all. It figures as few if any families would even bother having a workstation OS installed on their rigs anyway, but when the NT line came to home systems through XP, lulz ensued. :p




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users