https://bugs.winehq.org/show_bug.cgi?id=40800
--- Comment #6 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Dmitry Timoshkov from comment #4)
The application contains a custom imports resolver which gets called at the start of the execution. Since the IAT (the imports table) has been already processed by the PE loader custom imports resolver tries to access the addresses calculated from the PE import thunks and that leads to an access violation because the relative virtual addresses there have been already replaced by real addresses of the imported APIs.
There is an interesting detail about the process: the application uses ReadProcessMemory() in order to read the IAT before resolving its contents (instead of a straight memcpy() or accessing the IAT directly in memory), perhaps win9x returns original mapped PE file contents in that case, making this technique work.
Probably it's possible to add a hack to ReadProcessMemory() to read the mapped file contents in order to emulate win9x behaviour, but I'd suggest to try writing a simple test app to confirm my theory first.
I've set up windows 98 in a virtualbox (a challenge these days) and ran there a test application that dumps the IAT that was read either directly or using ReadProcessMemory(). The test proved that my guess was wrong.
With the debugger and another test application I managed to figure out real differences between win9x and NT PE loaders: win9x modifies the TimeDateStamp and ForwarderChain in the IAT, while NT (and Wine) leave them intact. Simple patch that sets these fields to 0xffffffff (meaning there is no forwards) makes the application's custom PE imports resolver work. However now the app crashes after it fetches the IDT (using sidt instruction) and tries to patch it with its own data. I don't see how this could be solved.
Probably a WONTFIX.