windows二进制安全零底子(二)

[复制链接]
发表于 2024-11-21 23:06:46 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

在x86架构中,栈(Stack)是一个非常重要的内存区域,它用于支持线程的短期数据需求,如函数调用、局部变量存储和程序控制信息。下面是对栈和调用约定的详细介绍:
栈(The Stack)

栈是一种后进先出(LIFO)的数据布局,CPU通过专用的PUSH和POP汇编指令来操纵栈。当线程实行时,它会从程序映像或动态链接库(DLLs)中实行代码。每个运行中的线程都有自己的栈,以支持多线程的独立实行。


  • PUSH:将数据压入栈顶。
  • POP:从栈顶弹出数据。
栈的重要用途包罗:


  • 函数调用:存储函数的返回地址,以便函数实行完毕后能够返回到正确的代码位置。
  • 局部变量:存储函数内部声明的局部变量。
  • 程序控制信息:存储函数调用时的上下文信息,如寄存器的值。
调用约定(Calling Conventions)

调用约定定义了函数如何接收参数以及如何返回效果。x86架构支持多种调用约定,它们在实现上的差异包罗参数和返回值的传递方式(使用CPU寄存器、压入栈中或两者联合)、传递次序、调用前后栈的准备和清理方式,以及被调用函数需要为调用者保留哪些CPU寄存器。
常见的x86调用约定包罗:


  • cdecl:由调用者清理栈。通常用于C语言函数,允许函数有可变数目的参数。
  • stdcall:由被调用者清理栈。通常用于Windows API函数。
  • fastcall:前两个参数(如果有的话)通过寄存器传递,其余参数通过栈传递。用于快速函数调用。
  • thiscall:通常用于C++成员函数。第一个参数(this指针)通过ECX寄存器传递,其余参数通过栈传递。
调用约定的选择通常由编译器决定,但在某些情况下,程序员可以在函数级别指定特定的调用约定。这可以通过函数声明时的调用约定关键字来实现。
调用约定的选择对程序的性能和兼容性有重要影响。比方,使用寄存器传递参数可以淘汰栈操纵,从而进步函数调用的速度。而差别的调用约定也可能影响函数之间的接口兼容性,因此在跨模块调用时需要特别留意调用约定的一致性。

在x86架构中,函数返回机制和CPU寄存器是理解程序实行流程的关键。下面是对这些概念的详细表明:
函数返回机制

当线程中的代码调用一个函数时,它必须知道函数完成后返回到哪个地址。这个“返回地址”(连同函数的参数和局部变量)存储在栈上。这些数据的聚集与一个函数调用相关联,并存储在栈内存的一个部分,称为栈帧(stack frame)。栈帧是函数调用期间用于存储全部须要信息的数据布局。
一个典型的栈帧可能包罗以下内容:


  • 返回地址:函数实行完毕后,控制权返回到此地址。
  • 参数:调用函数时传递的参数。
  • 局部变量:函数内部声明的变量。
  • 旧的基指针(EBP):用于指向当前栈帧的开始位置。
当函数结束时,返回地址从栈中取出,用于将实行流恢复到调用函数。
为了实行高效的代码,CPU维护并使用一系列寄存器。在32位架构中,这些寄存器通常是32位的。寄存器是CPU内部的小型、极高速的存储位置,数据可以在这里高效地读取或操纵。
在x86架构中,有九个重要的32位寄存器,包罗:


  • EAX:累加器,用于存储函数返回值。
  • EBX:基址寄存器,通常用于存储数据段的地址。
  • ECX:计数器,用于循环和字符串操纵。
  • EDX:数据寄存器,用于I/O操纵和与EAX一起存储大数值。
  • ESI:源索引寄存器,用于字符串和数组操纵。
  • EDI:目标索引寄存器,用于字符串和数组操纵。
  • ESP:栈指针,指向栈顶。
  • EBP:基指针,用于访问栈帧中的变量。
  • EIP:指令指针,存储下一条要实行的指令的地址。
这些寄存器的名称源自16位架构,并在32位(x86)平台出现时举行了扩展,这就是寄存器缩写中字母“E”的泉源(表示“扩展”)。每个寄存器可以包罗一个32位值(允许值在0到0xFFFFFFFF之间),或者在相应的子寄存器中包罗16位或8位值,如EAX寄存器的AX、AH和AL子寄存器所示。
在CPU级别,函数调用和返回涉及到以下几个步调:

  • 函数调用:

    • 使用CALL指令调用函数时,CPU自动将下一条指令的地址(返回地址)推入栈中。
    • 控制权转移到函数的起始地址。

  • 函数实行:

    • 函数可能使用PUSH和POP指令来保存和恢复寄存器的值。
    • 局部变量和参数可以通过修改ESP(栈指针)来在栈上分配空间。

  • 函数返回:

    • 使用RET指令从栈中弹出返回地址,并将其赋值给EIP(指令指针)。
    • 控制权返回到调用函数,继续实行。

理解这些机制对于深入理解程序如安在底层工作至关重要,尤其是在调试和性能优化时。
ESP - 栈指针
正如之前提到的,栈用于存储数据、指针和参数。由于栈是动态的,而且在程序实行过程中不断变化,栈指针ESP通过存储一个指向栈上最近引用位置(栈顶)的指针来“跟踪”它。
指针是对内存中地址(或位置)的引用。当我们说一个寄存器“存储一个指针”或“指向”一个地址时,这基本上意味着该寄存器正在存储那个目标地址。
EBP - 基指针
由于在实行线程期间栈不断变化,函数定位其栈帧可能变得困难,栈帧存储了所需的参数、局部变量和返回地址。基指针EBP通过存储一个指向函数被调用时栈顶的指针来解决这个问题。通过访问EBP,函数在实行期间可以轻松引用其栈帧中的信息(通过偏移量)。
EIP - 指令指针
EIP,指令指针,是我们目标中最重要的寄存器之一,由于它总是指向下一个要实行的代码指令。由于EIP基本上指导了程序的流程,因此在使用任何内存破坏漏洞(如缓冲区溢出)时,它是攻击者的重要目标。
2.2 Windows调试器简介
现在我们已司理解了x86架构的基本概念,是时间探索调试工具了。
在Windows上有几个可用的调试程序。OllyDbg和Immunity Debugger因其用户友好的界面而在逆向工程和漏洞开发领域广为人知。Immunity Debugger最初是OllyDbg的一个分支,但现在已经超越了OllyDbg的功能。
尽管这些程序使用方便,固然存在一个针对64位的OllyDbg的开源实现,但它并不提供与WinDbg相同的功能或支持。
WinDbg也是我们首选的调试器,由于它可以在用户模式和内核模式下举行调试,这使其成为开发在Windows上使用的任何范例漏洞的最佳选择。WinDbg作为软件开发工具包(SDK)、Windows驱动程序开发工具包(WDK)和Windows调试工具的一部分,免费提供。
微软发布了一个名为WinDbg Preview的WinDbg版本。它具有更直观的界面以及额外的功能,如时间旅行调试和用于脚本支持的JavaScript API。然而,WinDbg Preview仅在Windows 10周年纪念版(1607/RS1)及更高版本上工作。
调试器是一个盘算机程序,它被插入到目标应用程序和CPU之间,原则上,它就像一个代理。调试器允许开发者暂停程序的实行、单步实行代码、检查和修改程序的状态,以及实行其他各种诊断任务,从而资助开发者理解和修复程序中的错误或非常行为。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表