哦,近函数与远函数、近指针与远指针以及混合模型(远函数、近指针)的快乐
回到 16 位世界,程序可以
- 最多使用 64 KB 代码和 64 KB 数据,所有指针都使用 16 位,并忽略段寄存器。这被称为
near模型,因为所有偏移量都在同一段内
或者
- 选择能够拥有超过 64 KB 的代码,以及超过 64 KB 的数据;将指针设为 32 位(16 位段和 16 位偏移),并在使用指针时弄乱段寄存器。这被称为
far模型,因为指针可以指向不同的段,实际上,整个地址空间
或者
- 使用混合模型 - 代码的近指针和数据的远指针(更常用),反之亦然(我不知道使用它的单个程序)。
现在,问题是,strcpy您程序中的函数似乎是远代码近数据版本,而strcpy来自库的函数似乎是近代码远数据版本。
您会看到第一个函数如何确保es= ds( push ds; pop es) 但不会与段混淆。这将使它使用 16 位指针。将retf在年底提出它使用far代码约定。
第二个函数使用LES di, [bp+src], 同时加载es和di。这意味着它使用far堆栈上的数据指针,retn最后意味着它使用near代码模型。
发生的事情是,在您的反汇编程序中,IDA 看到了retf、扣除了far code,并且可能也假设far data了 - 这是错误的。如果数据确实是far,那么您将有 4 个字节用于src,另外还有 4 个字节用于dst,这就是 ida 在您的堆栈上显示的内容。但实际上,每个指针只有 2 个字节,因此dest在偏移量 6 处,但src在偏移量 8 处,而不是 0x0a (10)。这就是为什么访问src显示为dest+2,而 IDA 错误地假设为 的(错误的)偏移量 0x0asrc根本没有使用。
如图所示:
This is what IDA thinks: and this is the real stack layout:
+----------------------------+ +--------------------------------+
|000c src segment | | |
|000a src offset | | |
|0008 dest segment | |0008 src |
|0006 dest offset | |0006 dest |
|0004 saved bp | |0004 saved bp |
|0002 return address segment | |0002 return address segment |
|0000 return address offset | |0000 return address offset |
+----------------------------+ +--------------------------------+
要解决此问题,请打开函数原型对话框,并将指针定义更改为char near *。