将字符串动态加载到局部变量中

Loading a string into a local variable dynamically

假设,我在堆栈中创建了一个局部变量,或者更确切地说,为一个字符串分配了内存,现在我想在其中放入一个值。

push ebp
mov ebp, esp
sub esp, 0xff ; 255 bytes

并将字符串存储在 C:

的堆栈中
strcat(my_str1, "something1");
strcat(my_str1, get_var2());
strcat(my_str1, "something3");
strcat(my_str1, get_var4());

我想了解在 FASM 或 NASM 中没有 "strcat" 时如何做到这一点:

;1
mov byte ptr [esp - 1], 's'
mov byte ptr [esp - 2], 'o'
mov byte ptr [esp - 3], 'm'
mov byte ptr [esp - 4], 'e'
; and so on

这是怎么做到的?关于 "get_var2()" 和 "get_var4()" 的部分?

;2
call get_var2
mov ??byte?? ptr [esp - 11], eax
; or lea?

1) sub esp, 0xff 保持 esp 对齐,至少每 4 个对齐。如果 C 字符串只需要 255 个字节(254 个字符 + 零终止符),则分配 256 个。

2) mov [esp-1],'s' 您已经递减了 esp,因此局部变量位于某个 [esp+X] 地址(多少取决于您压入堆栈的其他值的数量)。或者更确切地说,将 [ebp-Y] 与类似 C 的函数序言一起使用,首先在 ebp 中初始化堆栈帧指针(push ebp mov ebp,esp sub esp,local_vars_size .. 然后是尾声 mov esp,ebp pop ebp ret).

但永远不要触及 esp 以下的值,除非你确切地知道你在做什么以及为什么(比如在 64b 模式下写入红色区域),因为如果你不确定,那么在 99% 情况下它会以错误结束,并且通常是难以发现的错误之一,很少影响代码。

3) 在 NASM 中,这 4 个 movs 可以用单个双字常量 mov [esp-4],dword 'emos' 完成(顺便说一句,你可能确实想设置 'some'?)

是的,这是编译器在本地分配的堆栈 space 中设置较短常量的常见方式,对于更大的数据,他们可能会使用来自常量模板数据的 memcpy

4)关于get_var2(),所以get_var2()returns稳定(char *)指针?然后你将不得不重新实现完整的 strcat,除非你能知道字符串中已经有多少个字符,以及将添加多少个。如果 get_var2() returns 一些值,你必须先将它转换成一些字符并决定有多少等。然后你可以直接写它们,或者在一些循环中等。太宽泛了。

此外,当在本地堆栈上操作时,我会在您的变量周围分配一些安全 space 以防您超出边界并覆盖几个字节。你甚至可以先将这些额外的字节设置为某个金丝雀值,然后在函数结束时检查它,看看是否发生了一些堆栈覆盖(至少在调试版本中)。而不是 strcat 然后你需要 strncat 或类似的东西,以避免堆栈被恶意数据溢出。

否则,正如 Jester 所建议的,也许首先尝试在固定内存缓冲区上实现 strcat,这样您就可以专注于代码本身,而不是解决本地内存的分配问题。然后您可以在此基础上进行构建,甚至将其用作函数调用。