asm inline vs 2015 with call RegCreateKeyEx

asm inline vs 2015 with call RegCreateKeyEx

本文关键字:call RegCreateKeyEx with 2015 inline vs asm      更新时间:2023-10-16

我尝试使用asm内联测试RegCreateKeyEx调用。 这是代码:

long regkey(HKEY lnKey, LPCTSTR lpsub, DWORD rise, LPTSTR lpc, DWORD dwopt, REGSAM sd, LPSECURITY_ATTRIBUTES lpas, HKEY * const &llkey, DWORD * const &dwDisposition)
{
__asm
{
lea eax, dwDisposition
push eax   // put eax at the top of the stack
lea eax, llkey
push eax
lea eax, lpas
push eax
lea eax, sd
push eax
lea eax, dwopt
push eax
lea eax, lpc
push eax
lea eax, rise
push eax
lea eax, lpsub
push eax
lea eax, lnKey
push eax
call DWORD ptr RegCreateKeyEx
}
return;
}
int main()
{
HKEY lnKey;
LPCTSTR lpsub;
DWORD rise;
LPTSTR lpc;
DWORD dwopt;
REGSAM sd;
LPSECURITY_ATTRIBUTES lpas;
HKEY llkey;
DWORD dwDisposition;
long ret0 = regkey(HKEY_CURRENT_USER, TEXT(linkey.c_str()), 0, NULL, 0, KEY_WRITE, NULL, &llkey, &dwDisposition);
printf("CREATE %dn", ret0);
return 0;
}

但是,它返回错误 87(无效参数)。

linkey.c_str () 变量包含字符串 "Software\\Microsoft\Windows\\CurrentVersion\\Run\\" 路径并正确传递它,因为我尝试通过直接调用 RegCreateKeyEx (HKEY_CURRENT_USER, 文本(linkey.c_str()), 0, 空, 0, KEY_WRITE、空、 &Llkey, & dwDisposition) 广告 一切都很好

我在内联使用 asm 时哪里有问题?

如果你用C++编写代码,如下所示:

LONG regkey(HKEY lnKey, LPCTSTR lpsub, DWORD rise, LPTSTR lpc, DWORD dwopt, REGSAM sd, LPSECURITY_ATTRIBUTES lpas, HKEY * const &llkey, DWORD * const &dwDisposition)
{
return RegCreateKeyEx(lnKey, lpsub, rise, lpc, dwopt, sd, lpas, llkey, dwDisposition);
}

然后,您可以使用/FA开关对其进行编译,如注释中所述,以使编译器生成它将生成的代码的程序集列表。或者,您可以编译它,然后中断,使用调试器显示实际二进制文件的反汇编。无论哪种方式,您都会看到编译器正在生成的以下程序集代码:

mov  eax, DWORD PTR [esp+36]    ; dwDisposition
push DWORD PTR [eax]
mov  eax, DWORD PTR [esp+36]    ; llkey
push DWORD PTR [eax]
push DWORD PTR [esp+36]         ; lpas
push DWORD PTR [esp+36]         ; sd
push DWORD PTR [esp+36]         ; dwopt
push DWORD PTR [esp+36]         ; lpc
push DWORD PTR [esp+36]         ; rise
push DWORD PTR [esp+36]         ; lpsub
push DWORD PTR [esp+36]         ; lnKey
call DWORD PTR RegCreateKeyEx
ret  0

因此,内联程序集应为:

LONG regkey(HKEY lnKey, LPCTSTR lpsub, DWORD rise, LPTSTR lpc, DWORD dwopt, REGSAM sd, LPSECURITY_ATTRIBUTES lpas, HKEY * const &llkey, DWORD * const &dwDisposition)
{
__asm
{
mov  eax, DWORD PTR [dwDisposition]
push DWORD PTR [eax]
mov  eax, DWORD PTR [llkey]
push DWORD PTR [eax]
push DWORD PTR [lpas]; 
push DWORD PTR [sd]; 
push DWORD PTR [dwopt]; 
push DWORD PTR [lpc]; 
push DWORD PTR [rise]; 
push DWORD PTR [lpsub]
push DWORD PTR [lnKey]
call DWORD PTR RegCreateKeyEx
}  // return value is left in EAX
}

这非常简单。您无需担心计算堆栈指针的偏移量,因为内联汇编器支持使用C++变量。永远不需要LEA指令。事实上,LEA指令是错误的,因为它导致您将指针作为参数传递给RegCreateKeyEx函数,而不是值本身,这就是您收到错误代码 87"无效参数"的原因。

唯一复杂的是处理dwDispositionllkey参数的方式。首先,地址必须加载到寄存器(EAX),然后该地址在被推送到堆栈时被取消引用。这种额外的间接寻址级别是必需的,因为您已将这些参数作为对指针的引用传递。我不知道你为什么选择这样做,但因为你这样做了,引用必须被取消引用。(在后台,C++编译器实现指针等引用。

但是,我不知道您为什么要在内联程序集中编写此代码。绝对没有理由这样做;它不会给你买任何东西,它只是让编写和维护变得更加复杂。这也在性能上花费了一些东西。上面,我展示了C++编译器将为函数调用生成的内容。下面是编译器在使用内联程序集时生成的内容:

push    ebp
mov     ebp, esp
mov     eax, DWORD PTR _dwDisposition$[ebp]
push    DWORD PTR [eax]
mov     eax, DWORD PTR _llkey$[ebp]
push    DWORD PTR [eax]
push    DWORD PTR _lpas$[ebp]
push    DWORD PTR _sd$[ebp]
push    DWORD PTR _dwopt$[ebp]
push    DWORD PTR _lpc$[ebp]
push    DWORD PTR _rise$[ebp]
push    DWORD PTR _lpsub$[ebp]
push    DWORD PTR _lnKey$[ebp]
call    DWORD PTR RegCreateKey
pop     ebp
ret     0

请注意使用内联程序集所必需的额外序言和尾声指令,因为编译器不知道您在内联程序集中实际在做什么,因此必须通过设置和拆除堆栈帧来补偿它。这不是巨大的性能成本或任何东西,但同样,它完全没有意义。

您的后续问题/问题(来自您发布的评论和答案)对我来说毫无意义。您不需要任何类型的异常处理程序,并且由于您没有引用您收到的确切错误消息,因此我不知道它可能想说什么。问题很可能与strtemp有关,您没有向我们展示其声明。既然你说你正在调用 ANSI 版本的RegCreateKeyExstrtemp应该是指向char缓冲区的指针,以 NUL 字符结尾。此外,您传递给RegSetValueEx的下一个参数是错误的:cbData必须包含终止 NUL 字符,因此应正确strlen(strtemp) + 1

代码的其他问题包括绝对没有错误检查的事实。如果尝试创建注册表项失败,则不应尝试写入该注册表项,也不应尝试将其关闭。

此外,在2017年,从来没有理由调用Windows API函数的ANSI版本。近二十年来,一切都在内部使用 Unicode,您的代码需要与程序一起使用。这意味着使用由wchar_t字符组成的字符串。