跳转至

X86汇编

这两天在看《老码识途》, 感觉x86汇编比较好玩, 随写一篇文章准备记录一下

寄存器

本质上就是存储数据的地方, 寄存器 - cache - 内存 - 硬盘 - 网络上的介质

不过寄存器存储的确实很少, 32位或者说是64位数,这里主要先考虑32位的

通用寄存器

在32位的寄存器下, 主要是由以下寄存器比较重要

  • EAX: 多数情况下是传入参数, 参数的第一个或者说直接是返回值放在EAX上
  • ECX: 传入参数
  • EDX: 传入参数
  • EBX: 传入参数
  • EBP: 函数寻址的情况下, EBP是保存栈的base的
  • ESP: 维护函数栈的情况下, ESP是栈顶
  • ESI
  • EDI:
  • EIP: PC寄存器, 是保存吓一条寄存器的地址的, 非常重要

其中, EIP这样的寄存器, 保存的是下一条指令的地址, 不过EIP寄存器是线性的, 是线性增长的

  • 传入参数按照规定的参数传入方式进行传入,比如说WINAPI的形式,或者说是fastcall的形式,这里比较重要的,因为传入参数的顺序决定了参数在栈里面的分布式怎么分布的,
    • C++规定了传入参数遵循WINAPI,fastcall这样的传入方式,但是没有规定怎么使用这个参数,
    • 使用参数的顺序式未定义的

如下图:

        High
        |   ...   |
        +---------+
     +24|  Arg 1  |
        +---------+
     +16|  Arg 2  |
        +---------+
     + 8| Return  |
        +---------+
EBP+--> |Saved EBP|
        +---------+
     - 8|  Var 1  |
        +---------+
ESP+--> |  Var 2  |
        +---------+
        |   ...   |
            Low
  • 先按照从右往左压栈传入参数,然后保存EBP这个指针,然后开始是局部变量,压栈的过程中,ESP这个指针式往下走的,所以可以大致分布是上图
  • 因为参数是固定的,那么就可以直接得到指针,然后+8+8这样的得到对应的参数,然后显示出来。
    • WinDbg调试得到参数比较常用这个信息

内存地址

下面是相关例子

# ds:[xxx]是段存储,因为内存就是一段一段的,这里直接就是0x12FFC4这个地址的数据, 
# mov 到eax这个寄存器上
# dword是双字,就是从这个0x13FFC4这个地方,四个字节,放到eax上
mov eax, dword ptr ds:[0x13FFC4]

# 同理,eax的数值存储到ds[0X13FFC4]上
// eax的数值往eax上写入数据,同样,dword是双字,也就是四字节
mov dword ptr ds:[0X13FFC4], eax
  • 程序中的内存地址很多都是按照基地址 + 偏移量存储的,比如说全局变量,数组,switch这样的关键字,都是base + offset这样存储的
  • Windows上按照0x40000这样base地址,但是offset不会变,base地址可能会发生偏移,但是大差不差,所以这里是用offset比较多