• 32位汇编逆向分析基础


    数字表示

    无符号数

    32位的无符号数表示形式如下图所示:
    在这里插入图片描述

    有符号数

    32位有符号数以补码形式表示,表示形式如下图所示:
    在这里插入图片描述
    由于取反是关于 -1 和 0 对称,因此负数转补码需要将数字位取反后加一。
    在这里插入图片描述

    浮点数

    浮点数的表示遵循 IEEE754 标准。

    一个浮点数为:
    S ⋅ 2 E ⋅ M   ( S ∈ { − 1 , 1 } , 0 ≤ M < 2 ) S\cdot2^{E}\cdot M\ (S\in \{-1,1\},0\le M<2) S2EM (S{1,1},0M<2)

    • float的存储方式如下图所示:
      在这里插入图片描述
    • double的存储方式如下图所示:
      在这里插入图片描述

    其中阶码需要在补码的基础上加上 2 e − 1 − 1 2^{e-1}-1 2e11,这里 e e e 为阶码 E 的位数。

    通过拆分浮点数进行验证:

    #include 
    
    int main() {
        float x = 1;
        auto b = std::bitset<32>(*(unsigned int *) &x);
        std::cout << b[31] << " ";
        for (int i = 30; i >= 23; i--) {
            std::cout << b[i];
        }
        std::cout << " ";
        for (int i = 22; i >= 0; i--) {
            std::cout << b[i];
        }
        std::cout << std::endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    通用寄存器

    类型

    在这里插入图片描述

    主要用途

    在这里插入图片描述

    MOV 指令

    在这里插入图片描述
    在这里插入图片描述

    ADD 指令

    在这里插入图片描述

    SUB 指令

    在这里插入图片描述

    AND 指令

    在这里插入图片描述

    OR 指令

    在这里插入图片描述

    XOR 指令

    在这里插入图片描述

    NOT 指令

    在这里插入图片描述

    XCHG 指令

    在这里插入图片描述

    内存

    从指定内存中写入/读取数据

    在这里插入图片描述

    寻址公式

    在这里插入图片描述

    堆栈

    在这里插入图片描述

    EFLAGS 寄存器

    在这里插入图片描述

    进位标志CF(Carry Flag)

    如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。(无符号数溢出)
    在这里插入图片描述

    以下两类指令在运算时需要将 CF 标志位加上:
    在这里插入图片描述

    奇偶标志PF(Parity Flag)

    奇偶标志PF用于反映运算结果中最低字节中“1”的个数的奇偶性。
    如果“1”的个数为偶数,则PF的值为1,否则其值为0。

    辅助进位标志AF(Auxiliary Carry Flag)

    在发生下列情况时,辅助进位标志AF的值被置为1,否则其值为0

    • 在字操作时,发生低字节向高字节进位或借位时
    • 在字节操作时,发生低4位向高4位进位或借位时。

    零标志ZF(Zero Flag)

    如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。

    符号标志SF(Sign Flag)

    符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。

    溢出标志OF(Overflow Flag)

    溢出标志OF用于反映有符号数加减运算所得结果是否溢出。(有符号数溢出)
    在这里插入图片描述
    在这里插入图片描述

    追踪标志TF(Trap Flag)

    当追踪标志TF被置为1时,CPU进入单步执行方式,即每执行一条指令,产生一个单步中断请求。这种方式主要用于程序的调试。

    中断允许标志IF(Interrupt-enable Flag)

    中断允许标志IF是用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。但不管该标志为何值,CPU都必须响应CPU外部的不可屏蔽中断所发出的中断请求,以及CPU内部产生的中断请求。具体规定如下:

    • 当IF=1时,CPU可以响应CPU外部的可屏蔽中断发出的中断请求;

    • 当IF=0时,CPU不响应CPU外部的可屏蔽中断发出的中断请求。

    CPU的指令系统中也有专门的指令来改变标志位IF的值。

    方向标志DF(Direction Flag)

    方向标志DF用来决定在串操作指令执行时有关指针寄存器发生调整的方向。

    • DF = 1:EDI 减
    • DF = 0:EDI 加

    在这里插入图片描述

    JCC

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    函数

    汇编结构

    在这里插入图片描述
    在这里插入图片描述

    调用约定

    在这里插入图片描述

    参数分析

    在这里插入图片描述
    在这里插入图片描述

    特殊语句

    条件分枝语句

    IF

    在这里插入图片描述
    在这里插入图片描述

    IF-ELSE

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    IF-ELSE IF-ELSE

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    循环语句

    do…while

    在这里插入图片描述

    在这里插入图片描述

    while

    在这里插入图片描述
    在这里插入图片描述

    for

    在这里插入图片描述
    在这里插入图片描述

    switch

    分支较少

    当条件分支较少时与 if-else 结构类似。
    在这里插入图片描述

    分支较多但比较连续

    分支较多且条件比较连续时会通过查表的方式找到要执行的分支语句。
    在这里插入图片描述

    分支较多但比较不连续

    此时会再生成一个以字节为单位的小表来减少存储过多 default 分支地址造成的空间浪费。
    在这里插入图片描述

    分支较多但比较特别不连续

    此时会形成类似二叉树的 if-else 分支嵌套,还会在其中嵌套查表的方法,较为复杂。

    结构体

    在这里插入图片描述
    因此假设一个结构体中有 n n n 个元素,每个元素大小为 a i ( 1 ≤ i ≤ n ) a_i(1\le i\le n) ai(1in) 并且按照 k k k 字节对齐,则结构体大小计算方式如下:

    #include 
    
    int main() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
    
        int n, k;
        std::cin >> n >> k;
        assert(__builtin_popcount(k) == 1);
    
        std::vector<int> a(n);
        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
            assert(__builtin_popcount(a[i]) == 1);
        }
    
        k = std::min(k, *std::max_element(a.begin(), a.end()));
    
        int ans = 0;
        for (int i = 0; i < n; i++) {
            if ((ans + a[i] - 1) / a[i] * a[i] + a[i] <= (ans + k - 1) / k * k) {
                ans = (ans + a[i] - 1) / a[i] * a[i] + a[i];
            } else {
                ans = (ans + k - 1) / k * k + a[i];
            }
        }
    
        ans = (ans + k - 1) / k * k;
    
        std::cout << ans << std::endl;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    移位

    在这里插入图片描述

  • 相关阅读:
    【Mysql】 blob 转text
    首1标准型和尾1标准型
    [CG] 用 Docker 配置 Ubuntu OpenGL 环境
    为什么说使用领英的人一定要用领英精灵
    Java密码库Password4j
    动态库和静态库,混合使用下的单例bug
    SQLite导出数据库至sql文件
    在Mysql中一条查询SQL的执行过程是怎样的
    Windows 下安装 Bun:像 Node 或 Deno 一样的现代 JavaScript 运行时
    Python基于Flask的招聘信息爬取、招聘信息可视化系统
  • 原文地址:https://blog.csdn.net/qq_45323960/article/details/127835707