Assembly 为什么在lstrlen之后EDX中的地址增加了1字节?

Assembly 为什么在lstrlen之后EDX中的地址增加了1字节?,assembly,Assembly,我目前正在学习汇编,因此正在尝试一些简单的crackmes,或者只是看看汇编中的不同程序。但现在我偶然发现了一个非常奇怪的案例,我无法理解。 代码如下所示: LEA, EDX, [406349] PUSH EDX CALL <JMP.&kernel32.lstrlenA> LEA,EDX[406349] 推式EDX 呼叫 没什么可怕的。据我所知,字符串的地址被加载到EDX寄存器中,然后作为strlen的参数推送到堆栈上。我可以在OllyDbg中跟踪这个过程。 奇怪的事情发

我目前正在学习汇编,因此正在尝试一些简单的crackmes,或者只是看看汇编中的不同程序。但现在我偶然发现了一个非常奇怪的案例,我无法理解。 代码如下所示:

LEA, EDX, [406349]
PUSH EDX
CALL <JMP.&kernel32.lstrlenA>
LEA,EDX[406349]
推式EDX
呼叫
没什么可怕的。据我所知,字符串的地址被加载到EDX寄存器中,然后作为
strlen
的参数推送到堆栈上。我可以在OllyDbg中跟踪这个过程。 奇怪的事情发生在函数调用之后。EDX中的地址突然增加了1个字节,因此指向字符串的第二个字符。
为什么会发生这种情况?

该应用程序是针对Windows/x86的32位应用程序,因此它使用stdcall调用约定来调用系统函数。从:

stdcall

stdcall调用约定是Pascal调用的变体 被叫方负责清理系统的约定 堆栈,但参数按从右到左的顺序推送到堆栈上 顺序,如_cdecl调用约定中的顺序寄存器EAX、ECX和 EDX指定用于函数。返回值为 存储在EAX寄存器中

stdcall是Microsoft Win32 API的标准调用约定 对于开放的WATCOM C++,

很可能,
EDX
在函数内部似乎是递增的,因为函数将参数从堆栈读入
EDX
,然后递增以对齐它,以便一次读取32位字符


但是,由于什么原因修改它并不重要:允许该函数修改
EDX
(和
ECX
)。它还可能在返回时包含一个与原始值无关的任意值,并且函数仍将遵守ABI。

Hmm…这可能是允许的,因为EDX是ABI中与您使用的平台相关的暂存器,而您没有告诉我们它是什么,所以没什么好说的。我正在使用32位OllyDbg版本的x64平台上工作。我相信这个应用程序也是为32位系统设计的。你用的是什么操作系统?哦,ups。也打算把它放在那里。Windows 7 x64感谢您的回答。这表明开发人员确实自己编写了部分asm代码,不是吗?或者编译器在任何情况下都会这样做吗?@puelo完全可以编写关心对齐的低级C代码。无论如何,您可以使用调试器进入函数并查看它的功能。我的回答是否给人的印象是,
EDX
只是增加了?它很可能最终包含地址+1,因为地址已从堆栈中读取,并且在递增之前已存在。函数中没有必要直接操作
EDX
,因为ABI没有说明参数是如何传递的。谢谢您的解释!这很清楚。EDX稍后在用于逐字节读取每个字符的函数中。我只是想知道编译器是否会这样构造它,或者是否必须由开发人员有目的地完成?我的意思是在函数调用之前使用EDX寄存器存储地址,之后仍然使用它,即使函数使用stdcall调用约定?@puelo这听起来像是一件非常危险的事情,无论是由编译器还是由人来做。事实上,编译器可能不会犯这个错误。也许是有人编写了您正在查看的代码,但从未注意到它有问题,因为它碰巧在Windows的strlen实现中用于预期目的。Raymond Chen的博客包含了很多关于让有缺陷的应用程序在新版本Windows中运行的恐怖故事,这可能是其中之一。