assembly 在Win API调用中使用字符串值

2ledvvac  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(92)

我正在尝试使用MessageBoxA Windows API,如下所示https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messageboxa
当执行以下代码时,r15是MessageBoxA,我成功执行了API,但没有值。

xor rcx, rcx
xor rdx, rdx
xor r8, r8
xor r9, r9
call r15

当我尝试在文本字段中分配字符串值时,它无法执行,我不知道为什么。

xor rcx, rcx
mov rdx, 0x0041414141
xor r8, r8
xor r9, r9
call r15

我可以使用在.data部分中定义的变量,它工作得很好,但我想弄清楚如何在没有.data部分的情况下实现它。
例如

section .data
    aaaa db 'AAAA',0
...
mov rdx, aaaa
7bsow1i6

7bsow1i61#

MessageBoxA函数要求其字符串参数位于内存中,而不是寄存器中。既然你不想把它放在.data部分,我们可以使用堆栈:

mov  edx, 'AAAA' ; zeroes the upper half of rdx so it is null-terminated
push rdx
mov  rdx, rsp

sub  rsp, 32 ;  Reserve shadow space: the callee can overwrite these bytes

xor ecx, ecx
xor r8d, r8d
xor r9d, r9d
call r15
add rsp, 40    ; free the shadow space and the string

字符串需要在函数调用的整个持续时间内都在堆栈上,它不能在更早的时候弹出。
它不能在影子空间中,被调用者在阅读指向的内存之前可能会覆盖它,这就是为什么我们在保留影子空间之前要push *。
请记住,在call之前将RSP对齐16,因为Windows x64调用约定要求这样做。这意味着从函数入口开始,执行奇数个8字节调整,计算推压和sub rsp, constant。如果你已经做了奇数次的push,然后你想push一些ASCII字节,你可以sub rsp, 40而不是sub rsp, 32,并调整add rsp, 40相同的数量来撤消它。
在这种情况下,push 'AAAA'将具有与mov edx, 'AAAA'/push rdx相同的效果。push只支持16位和64位的操作数大小,NASM默认为64位,除非另有说明。push imm32将立即数符号扩展为64位,而'A'将其符号位置零,因此我们将从符号扩展中获得一个以零结尾的字符串,就像零扩展一样。

yacmzcpb

yacmzcpb2#

如果使用x86,你可以在self代码中使用下一个片段:

call @@0
    DB 'some demo string',0
@@0:
    pop ecx ; or another register, in which you need get address of string

(or只是将其留在堆栈中,以便传递给API调用)
或者你可以使用这样的宏

createAstring macro name, string
@CatStr(_,name) proc
  call @@1
  DB string,0
@@1:
  pop eax
  ret
@CatStr(_,name) endp
endm

和create函数,返回字符串的地址

createAstring some_string, 'some demo string'

并在代码中使用它:

call _some_string
mov edx,eax ; or push eax, etc

这段代码也可以在x64中使用,但这里也可以简单地使用莱亚,因为它是独立的

createAstring macro name, string
name proc
    lea rax,@@1
    ret
@@1:
    DB string,0
name endp
endm

或者直接用代码

lea r8,@@1
    ...
@@1:
    DB 'aaa bbb ccc...',0

相关问题