将字符串动态加载到局部变量中
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
,这样您就可以专注于代码本身,而不是解决本地内存的分配问题。然后您可以在此基础上进行构建,甚至将其用作函数调用。
假设,我在堆栈中创建了一个局部变量,或者更确切地说,为一个字符串分配了内存,现在我想在其中放入一个值。
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
,这样您就可以专注于代码本身,而不是解决本地内存的分配问题。然后您可以在此基础上进行构建,甚至将其用作函数调用。