这可能是微不足道的,但由于某些原因我无法工作。它应该是一个简单的函数,它将dword的最后一个字节更改为'AA'(10101010),但是当我调用该函数时没有任何反应。它只是返回我原来的dword。
__declspec(naked) long
function(unsigned long inputDWord, unsigned long *outputDWord)
{
_asm{
mov ebx, dword ptr[esp+4]
push ebx
call SET_AA
pop ebx
mov eax, dword ptr[esp+8]
mov dword ptr[eax], ebx
}
}
__declspec(naked) unsigned long
SET_AA( unsigned long inputDWord )
{
__asm{
mov eax, [esp+4]
mov al, 0xAA //10101010 didn't work either
ret
}
}
答案 0 :(得分:4)
你似乎很难回复一个值而且有一个out变量。
下面:
push ebx
call SET_AA
pop ebx
你表现得像ebx
是一个变量。
在这里:
mov eax, [esp+4]
mov al, 0xAA //10101010 didn't work either
ret
您只是将内容写入eax
两次(一次使用参数,然后用您的0xAA覆盖)。 eax
传统上是返回值寄存器。你需要选择你想要使用的那个。
如果您希望它成为变量,您需要执行以下操作:
__declspec(naked) long function(unsigned long inputDWord, unsigned long *outputDWord) {
_asm{
mov ebx, dword ptr[esp+4]
push ebx
call SET_AA
pop ebx
mov eax, dword ptr[esp+8]
mov dword ptr[eax], ebx
}
}
__declspec(naked) void SET_AA( unsigned long inputDWord ) {
__asm{
mov [esp+4], 0xAA // put 0xAA into the variable passed on the stack
ret
}
}
如果您想要返回值,可以执行以下操作:
__declspec(naked) long function(unsigned long inputDWord, unsigned long *outputDWord) {
_asm{
mov ebx, dword ptr[esp+4]
call SET_AA
mov ebx, eax
mov eax, dword ptr[esp+8]
mov dword ptr[eax], ebx
}
}
__declspec(naked) unsigned long SET_AA(/* input param not needed, we are just returning a value */) {
__asm{
mov eax, 0xAA // return 0xAA via the eax register
ret
}
}
答案 1 :(得分:2)
我认为这更像是你的意思。一件重要的事情:正如MSDN所说,
裸体功能必须提供自己的功能 prolog ...和epilog
您的SET_AA()
没问题。它将结果保留在eax
中。 (你可以在没有prolog / epilog的情况下离开,因为你是从_asm
而不是C来调用它。)
__declspec(naked) unsigned long
SET_AA(unsigned long inputDWord )
{
__asm
{
mov eax, [esp+4]
mov al, 0xAA
ret // final value is in eax
}
}
function()
应返回void
,因为您希望将结果放在*outputDWord
中。另外,您也可以使用inputDWord
代替[esp + 4]:
__declspec(naked) void
function(unsigned long inputDWord, unsigned long *outputDWord)
{
_asm
{
// you need a prolog/epilog to make C happy
// here's the prolog:
push ebp
mov ebp, esp
mov ebx, inputDWord // the value you're going to change
mov ecx, outputDWord // address of where to put the result
push ebx
call SET_AA // puts the result in eax
pop ebx
// copy the result to the thing ecx points to (*outputDWord)
mov [ecx], eax
// epilog to keep C happy
pop ebp
ret
}
}
答案 2 :(得分:0)
您的函数SET_AA
修改了EAX
(仅限寄存器)中的值,但在call SET_AA
之后,您在第一个函数中将另一个值移到EAX
,从而覆盖SET_AA
电话的结果。因此,以不覆盖EAX
(如答案中所示)的方式更改寄存器的使用可以解决您的问题。
答案 3 :(得分:0)
我同意其他用户所说的话。
SET_AA
将返回值存储在EAX
寄存器中。但是,不是返回它,而是返回传递它的参数(EBX
)。function
最后没有RET
条指令。你没有手动实现返回调用者的代码。此外,我还要注意,在function
中,您覆盖EBX
寄存器的值而不保存(在堆栈中)并在最后恢复。
您没有指定为function
指定的呼叫约定。 (由于您甚至不使用RET
或RET(8)
指令,我无法猜测它必须是什么。
但是根据我所知道的大多数调用约定,覆盖EBX
寄存器是非法而不是在最后恢复它。
可供函数使用的寄存器(在大多数约定中)是EAX
,ECX
,EDX
。所有其他寄存器也可以随意使用,但必须恢复它们。
答案 4 :(得分:0)
除非你使用__cdecl作为你的调用对话,否则你的两个函数都缺少堆栈清理,这会在返回展开堆栈帧时引起问题,以及寄存器未正确保存的事实。
使用更结构化,清晰简洁的东西:
__declspec(naked) unsigned long __stdcall SET_AA(unsigned long inputDWord )
{
__asm
{
mov eax, [esp+4]
mov al, 0xAA
retn 4
}
}
__declspec(naked) void __fastcall function(unsigned long inputDWord, unsigned long *outputDWord)
{
_asm
{
push ecx //push inputDWord
call SET_AA // puts the result in eax
// copy the result to the thing ecx points to (*outputDWord)
mov [edx], eax
retn//fastcall has no cleaup for the first 2 args
}
}
答案 5 :(得分:0)
为什么不用C ++编写函数呢?它很乐意提供位操作。