从人造DLL返回值


6

有点背景;我试图将自己的代码注入旧游戏SimTower中,最终目标是以与创建OpenRCT2相同的方式对其进行逆向工程。

由于SimTower是作为16位NE可执行文件分发的,我在注入我自己的DLL并将主方法更改为我自己的过程中遇到了一些问题(如本文的https://bwrsandman.wordpress.com/2014/12/27/first-steps-to-reverse-engineering-an-executable/),但我认为我已经找到另一种方式。

SimTower的第一件事之一是从WAVMIX16.DLL运行WAVEMIXINIT。据我所知,如果返回值是0它显示一个对话框并禁用声音。

我现在的计划是简单地创建一个虚假的wavmix16 DLL会(现在)总是从该函数返回0。这应该让我得到一个入口点来运行我自己的代码,并开始游戏。

typedef void *HANDLE; 

HANDLE __far __pascal WAVEMIXINIT() { 
    // while (1) {;}; 
    return 0; 
} 

void __far __pascal STUB4() {} 
void __far __pascal STUB5() {} 
void __far __pascal STUB6() {} 
void __far __pascal STUB7() {} 
void __far __pascal STUB9() {} 
void __far __pascal STUB10() {} 
void __far __pascal STUB11() {} 
void __far __pascal STUB12() {} 

这个编译成一个DLL,并将其命名wavmix16.dll似乎工作,我可以看到来电时我的功能,因为如果我去掉while循环的程序将被卡住里面。

由于某种原因,尽快我的程序崩溃,当我到我的return语句。

(酒)

上的地址0x148f读取访问0x0000fa30

未处理的页面错误:0x0000000c(线程002B)

(Windows XP中)

这是我调用的DDL函数的程序集。我有点不确定为什么有更多的东西,而不仅仅是一个movretf(如nop?),但我是新手,所以也许这是正常的。

这是原来的DLL功能的装配:

非常感谢所有帮助,谢谢!

  0

您是否检查过使用正确的参数和调用约定?这看起来像是一个清理错误。 07 11月. 172017-11-07 05:52:25

  0

据我可以告诉我是。查看wavemix库的头文件,我可以看到该函数被定义为'HANDLE WINAPI WaveMixInit(void);'。 'HANDLE'被定义为一个空指针,我在我的代码中以相同的方式定义。 'WINAPI',如果我理解[这篇文章](https://msdn.microsoft.com/en-us/library/wda6h6df.aspx)正确与我的'__far __pascal'一样......我将添加反编译函数从原始的DLL,看看我能否发现任何差异... 07 11月. 172017-11-07 07:26:20

  0

对我来说,似乎我的函数在返回之前将2个值推入堆栈,并且原始DLL正在推送6并弹出4个值(将2个值再次)在返回之前,这对我来说表明调用约定应该是相同的... 07 11月. 172017-11-07 07:41:25

  0

WINAPI应该解析为__stdcall(在现代系统上)。在另一个节点上,你的函数不能恢复原始的bp和sp。真奇怪的约定 07 11月. 172017-11-07 08:21:36

  0

所以,我正在编译一个带有古代编译器的16位DLL,因为我还没有找到任何可以输出16位代码的现代系统:)我正在关注[本指南来自DigitalMars](http:///www.digitalmars.com/ctg/win16-dll-programming.html)并且正在使用它们的编译器 07 11月. 172017-11-07 08:36:01

  0

哪条指令位于DLL中的偏移量0C处? 07 11月. 172017-11-07 09:29:16

  0

0C似乎指向对齐的中间:'0001 align 10h','0010 push bp' ...如果你的意思是原始DLL? 07 11月. 172017-11-07 09:55:02

  0

你可以尝试将你的函数实现减少到最后两条指令吗? 'xor ax,ax'和'retf'就足够了。我的猜测仍然是打破 07 11月. 172017-11-07 10:42:48

  0

我也建议尝试OpenWatcom编译器。或者甚至可能是Borland C++。 08 11月. 172017-11-08 12:43:49

  0

坐了几个小时试图让OpenWatcom建立一个DLL :(关于'inc bp'的https://stackoverflow.com/questions/47184876/compile-a-16-bit-windows-dll-with-open-watcom 08 11月. 172017-11-08 16:30:05

6

您的人造函数并未在函数的结尾处修复堆栈。它应该有

pop ds 
pop bp 
dec bp 

最后的调用约定。

如果您查看原始函数,它会正确地修正堆栈。

比方说,堆栈指针有1000h的值进入函数(CS:IP已经在远程调用堆栈上被压入)。这样,你会在原有的功能

; sp = 1000h 
mox ax, ds  
... 
push bp  ; sp = 0ffeh 
mov bp, sp  ; bp = 0ffeh 
... 
lea sp, [bp-2] ; sp = 0ffch 
pop ds   ; sp = 0ffeh 
pop bp   ; sp = 1000h 
retf 

要在这个问题,the Digital Mars compiler dmc.exe使用的编译器,生成这些指令来自一个遥远的函数返回时,通过标志-Wm将“生成INC BP/DEC BP来标记远端堆栈帧“。

+1

) /'dec bp':https://blogs.msdn.microsoft.com/oldnewthing/20110316-00/?p=11203 08 11月. 172017-11-08 12:44:29

  0

谢谢!我添加了'xor ax,ax','pop ds','pop bp' ,'dec bp','retf' as inline assembly in the function and it solve it! 08 11月. 172017-11-08 16:55:31

  0

这就是说,如果有人能指出我在正确的方向得到[DigitalMars编译器dmc.exe](http:// www .digitalmars.com/ctg/win16-dll-programming.html)输出正确的指令我会非常高兴:) 08 11月. 172017-11-08 17:03:07

  0

我发现它!标志'-Wm'将使dmc“生成INC BP/DEC BP来标记远端堆栈帧”。将此添加到完整性的答案中。在其他编译器中添加如何执行它可能是很好的:) 08 11月. 172017-11-08 19:56:22