据说该leave指令与以下内容相同:
mov esp,ebp
pop ebp
Run Code Online (Sandbox Code Playgroud)
但这是mov esp,ebp为了什么?这对我来说似乎没有用......
那些熟悉x86汇编编程的人非常习惯于典型的函数序言/结语:
push ebp ; Save old frame pointer.
mov ebp, esp ; Point frame pointer to top-of-stack.
sub esp, [size of local variables]
...
mov esp, ebp ; Restore frame pointer and remove stack space for locals.
pop ebp
ret
Run Code Online (Sandbox Code Playgroud)
也可以使用ENTER和LEAVE指令实现相同的代码序列:
enter [size of local variables], 0
...
leave
ret
Run Code Online (Sandbox Code Playgroud)
所述ENTER指令的第二操作数是嵌套级别,它允许从被调用函数访问的多个父帧.
这不在C中使用,因为没有嵌套函数; 局部变量只有它们声明的函数的范围.这个构造不存在(虽然有时我希望它这样做):
void func_a(void)
{
int a1 = 7;
void func_b(void)
{
printf("a1 = %d\n", a1); /* a1 inherited from func_a() …Run Code Online (Sandbox Code Playgroud) 我想用英特尔I64汇编程序做一些长整数数学运算(128位),需要创建一个2的补码.让我们说我的正面价值在于RDX:RAX.
2的补码是通过"翻转位并加1"来完成的.所以最天真的实现是(4条指令和14个字节的代码):
NOT RAX
NOT RDX
ADD RAX,1 ; Can't use INC, it doesn't set Carry
ADC RDX,0
Run Code Online (Sandbox Code Playgroud)
当我在RAX而不是NOT上使用NEG指令时,它对我来说是"+1"但是Carry是错误的,当RAX为零时NEG RAX清除了Carry,但是我需要携带JUST IN THIS CASE.所以下一个最好的方法可能是(4条指令和11个字节的代码):
NOT RDX
NEG RAX
CMC
ADC RDX,0 ; fixed, thanks lurker
Run Code Online (Sandbox Code Playgroud)
还有4条说明.但是不是加+1,我可以减去-1,因为SBB将Carry-Bit加到减数上,当Carry清零时我会加+1.所以我的下一个最好的尝试是这个,有3个指令和10个字节的代码:
NOT RDX
NEG RAX
SBB RDX,-1
Run Code Online (Sandbox Code Playgroud)
从我冗长的文字中可以看出,这一点并不明显.是否有一种更好,更易理解的方法来在汇编程序中进行级联2的补码?
有人可以解释为什么这个代码:
#include <stdio.h>
int main()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当使用tcc使用tcc编译时,生成这个asm:
00401000 |. 55 PUSH EBP
00401001 |. 89E5 MOV EBP,ESP
00401003 |. 81EC 00000000 SUB ESP,0
00401009 |. 90 NOP
0040100A |. B8 00000000 MOV EAX,0
0040100F |. E9 00000000 JMP fmt_vuln1.00401014
00401014 |. C9 LEAVE
00401015 |. C3 RETN
Run Code Online (Sandbox Code Playgroud)
我猜可能是
00401009 |. 90 NOP
Run Code Online (Sandbox Code Playgroud)
也许有一些内存对齐,但是怎么样
0040100F |. E9 00000000 JMP fmt_vuln1.00401014
00401014 |. C9 LEAVE
Run Code Online (Sandbox Code Playgroud)
我的意思是为什么编译器会插入跳转到下一条指令的近跳转,LEAVE会执行呢?
我在64位Windows上使用TCC 0.9.26生成32位可执行文件.
我正在尝试反汇编一个包含简单函数的简单程序。该程序是使用 gcc 为 32 位 x86 目标编译的。该函数通过call指令调用。在函数的末尾,我看到一条ret指令,这是正常的,但还有一条leave指令。程序中任何地方都没有输入指令。我想知道这个离开的功能是什么......
在Xeno Kovah在OpenSecurityTraining 上主持的x86 程序集介绍的第一天作业中,他指定:
我们现在知道的说明(24)
NOP PUSH/POP CALL/RET MOV/LEA ADD/SUB JMP/Jcc CMP/TEST AND/OR/XOR/NOT SHR/SHL IMUL/DIV REP STOS,REP MOV LEAVE
编写一个程序来查找我们尚未涵盖的指令,并在明天报告该指令。
他进一步断言这个任务是,
SAL/SAR MUL/IDIV变体IMUL/DIV也不要指望是否可以找到 GCC 当前输出的 x86 汇编指令列表,而不是objdump随机执行并审核它们然后创建源代码?
这个问题的基础似乎是实际使用的指令的一个非常小的子集,人们需要知道逆向工程(这是课程的重点)。Xeno 似乎试图找到一种有趣的、有指导意义的方式来说明这一点,
我认为知道大约 20-30(不包括变化)就足够了,你很少会检查手册
虽然我欢迎大家加入我在 OpenSecurityTraining 的这个很棒的课程,但问题是我提出的从 GCC 中找出它的方法(如果可能的话)。不是,让人们真正完成 Xeno 的任务。;)
我没有清楚地理解LEAVE函数,它是这两条指令的缩写:
MOV ESP, EBP
POP EBP
Run Code Online (Sandbox Code Playgroud)
因此MOV ESP, EBP将ESP向下移动到EBP(堆栈的开始)的水平.
然后POP EBP,移动ESP指向的值并将其影响到EBP,并将ESP向下移动一步.
但我真的没有看到,这两个操作如何与离开函数的事实相关联(这是目的LEAVE).
你能帮我澄清一下吗?
为什么在 x86 上没有伴随指令离开?那样,
pushl %ebp
movl %esp,%ebp
pushl $3
popl %eax
leave
ret
Run Code Online (Sandbox Code Playgroud)
可以变成:
enter #or something
pushl $3
popl %eax
leave
ret
Run Code Online (Sandbox Code Playgroud)
一般来说,这不是更快吗?