从假 DLL 返回值

逆向工程 dll 调用约定
2021-06-13 10:43:45

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

由于 SimTower 是作为 16 位 NE 可执行文件分发的,因此我在注入我自己的 DLL 并将主要方法更改为我自己的方法时遇到了一些麻烦(如本文中所示https://bwrsandman.wordpress.com/2014/12 /27/first-steps-to-reverse-engineering-an-executable/),但我想我找到了另一种方法。

SimTower 做的第一件事就是WAVEMIXINITWAVMIX16.DLL. 据我所知,如果返回值是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 循环的注释,程序将被卡在其中。

但出于某种原因,一旦我到达我的返回语句,程序就会崩溃。

(葡萄酒)

读取访问地址 0x148f:0x0000000c(线程 002b)处的 0x0000fa30 时出现未处理的页面错误

(Windows XP)

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

这是原始 DLL 函数的程序集:

真的很感谢任何帮助,谢谢!

1个回答

您的仿函数没有修复函数结尾处的堆栈。它应该有

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

为了使问题中使用的编译器Digital Mars 编译器 dmc.exe在从远函数返回时生成这些指令,传递-Wm将“生成 INC BP / DEC BP 以标记远堆栈帧”的标志。