做浙大PTA的7-105 寻找250时候,对scanf的的机制不太熟悉,于是想到联系之前学过的汇编来理解。
这里可以看出,scanf接受一个指针和一个变量地址。注意这里的OFFSET操作符,相当于C++中的&。
读%d
也就是缓冲区里的内容,放到_tmp$[ebp]里面。但是这里汇编看不到_scanf的细节,这里先不讨论。
为了学习逆向,我选择先巩固逆向所需要的汇编知识,利用pta的编程题,多对比学习c和assembly language。
main函数的汇编
在 x86 汇编语言中,EBP 寄存器通常在函数的开头被初始化为栈帧的基地址。然后,它被用作基址指针和帧指针,以访问函数的局部数据和返回地址。
main函数实质上也是一个函数,每个函数调用之前,需要保存调用之前的状态,即使main函数也不例外。
为了做到这件事情,需要有一个地方保存函数调用前堆栈的状态,ebp就是这个地方。
函数头为新函数的调用做好准备,很容易想到,它需要完成两件事情。分别是辞旧、迎新。
- ebp入栈,这是为了保存原函数的状态地址。也就是辞旧
- ebp指向当前栈顶esp,这是初始化调用函数空间,将其指向栈空间的顶部,为使用“专属”的栈空间做好准备。也就是迎新
函数尾为新函数的调用做好收尾工作,先看其中最重要的一件事:
- 恢复函数头存储的ebp的地址,即回到原函数的地址空间。
另外两件事情:
- eax寄存器清零,格式化通用寄存器。
ret 0
,该指令的作用是返回到调用函数,并以 0 作为返回值。实际上这里是__stdcall调用方式,参数使用栈传递,被调用者即main函数负责释放参数空间。
scanf操作符的汇编
相当于
lea指令相当于对后者取地址,放到前者里面。类比于C++中的取地址符&
这里是__stdcall的函数调用约定,使用栈空间进行传递参数,最后esp+8出栈。