C/C++逆向:循环语句逆向分析

在逆向分析中,循环语句通常会以特定的汇编模式或结构体现出来。常见的循环语句包括 for 循环、while 循环和 do-while 循环。由于不同的编译器会根据代码优化的级别生成不同的汇编代码,分析循环的模式也可能会有所不同。以下是三种常见循环语句的汇编分析要点:

1. for循环的逆向分析

典型的 C 代码:

for (int i = 0; i < n; i++) {
    // 循环体
}
汇编特征:
初始化:i = 0 通常表现为一个寄存器赋初始值。
条件检查:比较寄存器与终止条件(如 n),可能使用跳转指令如 JLE、JGE。
循环体:位于条件检查后的指令块。
递增:通过 ADD 或 INC 操作来递增寄存器的值。
汇编示例:
mov     eax, 0          ; 初始化 i = 0
cmp     eax, n          ; 比较 i 和 n
jge     end_loop        ; 如果 i >= n,跳转到 end_loop
loop_body:              ; 循环体开始
; (循环体指令)
add     eax, 1          ; 递增 i
cmp     eax, n          ; 再次比较 i 和 n
jl      loop_body       ; 如果 i < n,跳回到 loop_body
end_loop:               ; 结束
逆向分析技巧:

找到初始化的代码片段,如给寄存器赋值的操作;寻找条件比较部分,通常使用 CMP 或 TEST,接着跟踪跳转指令(如 JLE, JL),确定循环的边界。递增操作(ADD, INC)通常位于循环体的末尾或条件检查前。

2.while 循环的逆向分析

典型的 C 代码:

while (i < n) {
    // 循环体
}

汇编特征:

条件检查:在进入循环体之前,首先比较寄存器的值,若不满足条件则直接跳出循环。
循环体:条件检查通过后,执行循环体代码。
递增:递增通常在循环体内完成,然后再次检查条件。
汇编示例:
cmp     eax, n          ; 比较 i 和 n
jge     end_while       ; 如果 i >= n,跳转到 end_while
while_body:             ; 循环体开始
; (循环体指令)
add     eax, 1          ; 递增 i
cmp     eax, n          ; 比较 i 和 n
jl      while_body      ; 如果 i < n,跳回到 while_body
end_while:              ; 结束

当条件和索引的初始值都确定的情况下,编译器可以判断第一次会不会执行

逆向分析技巧:

条件检查通常位于循环体之前,通过 CMP 和跳转指令控制,循环体代码位于条件检查之后,跟踪跳转位置可以定位循环体的结束。确定计数器或条件变量的更新位置,并检查跳转逻辑。

3.do-while 循环的逆向分析

典型的 C 代码:

do {
    // 循环体
} while (i < n);
汇编特征:
循环体:无条件执行一次循环体。
条件检查:循环体执行后检查条件,决定是否跳回循环。
跳转:条件满足时跳回到循环体的起始处。
汇编示例:
do_while_body:          ; 循环体开始
; (循环体指令)
add     eax, 1          ; 递增 i
cmp     eax, n          ; 比较 i 和 n
jl      do_while_body   ; 如果 i < n,跳回到 do_while_body
逆向分析技巧:

do-while 循环的特点是循环体在条件检查之前执行,因此逆向时首先识别无条件执行的代码块,条件检查位于循环体之后,查看 CMPTEST 等操作判断是否跳回;循环体通常使用跳转指令(如 JL, JG)回到循环体开头。

逆向分析示例

下面是一个包含 for 循环、while 循环 和 do-while 循环的 C 代码示例,我们可以将它编译成可执行文件,使用IDAx64dbg进行逆向分析,观察它们对应的汇编代码差异。

#include <stdio.h>
​
int main() {
    int sum_for = 0;
    int sum_while = 0;
    int sum_do_while = 0;
​
    // for 循环
    for (int i = 0; i < 5; i++) {
        sum_for += i;
    }
​
    // while 循环
    int j = 0;
    while (j < 5) {
        sum_while += j;
        j++;
    }
​
    // do-while 循环
    int k = 0;
    do {
        sum_do_while += k;
        k++;
    } while (k < 5);
​
    printf("sum_for: %d\n", sum_for);
    printf("sum_while: %d\n", sum_while);
    printf("sum_do_while: %d\n", sum_do_while);
    system("pause");
    return 0;
}

此时使用Visual Studio对该代码进行编译,生成exe文件,对应的编译配置为Debug-x86;本文只针对Debug-x86程序进行分析,其他编译配置分析方式也大同小异。

静态分析:

将生成的程序载入IDA中进行静态分析

在为了不模糊重点,我们直接在Functon Window中定位main函数(关于定位main函数的各种方法有兴趣请查看前面的文章)。

接下去开始逐步对进行代码分析,正文代码从后线以下开始:

首先代码先初始化了四个局部变量var_8var_14var_20var_2C,并将其值全部设置为0。

mov     [ebp+var_8], 0
mov     [ebp+var_14], 0
mov     [ebp+var_20], 0
mov     [ebp+var_2C], 0
jmp     short loc_41185F

在初始化变量后进行了跳转,跳转的目标地址为loc_41185F

①for循环

可以看到在跳转到loc_41185F时,中间跳过了三条指令,这三条指令做的就是自增的操作,我们就可以通过这个特征就判断出这段代码就是for循环结构(该特征是for循环和while循环最明显的区别),接着我们来解析以下这个代码:

loc_411856:                             ; CODE XREF: _main+5E↓j
                mov     eax, [ebp+var_2C]
                add     eax, 1
                mov     [ebp+var_2C], eax
loc_41185F:                             ; CODE XREF: _main+44↑j
                cmp     [ebp+var_2C], 5
                jge     short loc_411870
                mov     eax, [ebp+var_8]
                add     eax, [ebp+var_2C]
                mov     [ebp+var_8], eax
                jmp     short loc_411856

跳转至loc_41185F后:cmp [ebp+var_2C], 5局部变量var_2C先于5进行比较(可以看出来5就是这个循环的边界值),jge short loc_411870若局部变量var_2C大于等于5则跳转到loc_411870地址(也就是跳出循环),若不大于则继续往下执行。 mov eax, [ebp+var_8]var_8的值存入寄存器eaxadd eax, [ebp+var_2C]将局部变量的var_2C的值于eax中的值相加,mov [ebp+var_8], eax再将eax中存储的两数之和存储至var_8中。jmp short loc_411856最后跳转至loc_411856地址处执行局部变量var_2C自增代码。自增完成后再执行loc_41185F处指令。

总结:
初始化:var_2C 初始化为 0。
条件检查:每次循环开始时,比较 var_2C 是否小于 5。
递增计数器:在每次循环结束时,var_2C 增加 1。
累加操作:每次循环中,将 var_2C 的值加到 var_8 中。
循环终止:当 var_2C >= 5 时,跳出循环。

伪代码如下:

for(int var_2C = 0;var_2C < 5;var_2C++);
{
    var_8 += var_2C;
}
②while循环

根据上述代码可知第一个循环结束后跳出循环,来到地址loc_411870进行执行,代码如下:

loc_411870:                             ; CODE XREF: _main+53↑j
                mov     [ebp+var_38], 0
loc_411877:                             ; CODE XREF: _main+7F↓j
                cmp     [ebp+var_38], 5
                jge     short loc_411891
                mov     eax, [ebp+var_14]
                add     eax, [ebp+var_38]
                mov     [ebp+var_14], eax
                mov     eax, [ebp+var_38]
                add     eax, 1
                mov     [ebp+var_38], eax
                jmp     short loc_411877

mov [ebp+var_38], 0将局部变量 var_38 初始化为 0,这个变量可能是用作循环计数器。

cmp [ebp+var_38], 5比较 var_38 的值和 5,var_38 是循环计数器。

jge short loc_411891如果 var_38 的值大于或等于 5,则跳转到 loc_411891,这意味着循环结束(跳出循环)。

mov eax, [ebp+var_14]将局部变量 var_14 的值加载到 eax 寄存器中。var_14 可能是一个用于累加的变量。

add eax, [ebp+var_38]var_38(循环计数器)的值加到 eax 中。

mov [ebp+var_14], eax将累加后的结果存回 var_14,即更新了累加器。

mov     eax, [ebp+var_38]
add     eax, 1
mov     [ebp+var_38], eax

后面三条指令就是对var_38局部变量进行自增的操作。

最后jmp short loc_411877无条件跳转到 loc_411877,重新执行循环体,继续下一次迭代。

这段代码是一个典型的 while循环,其中 var_38 是一个循环计数器,从 0 开始,直到计数器达到 5 时结束循环。循环中,var_38 的值不断累加到 var_14 中。

伪代码表示如下:

int var_38 = 0;  // 计数器初始化
while (var_38 < 5) {
    var_14 += var_38;  // 累加操作
    var_38++;  // 计数器递增
}
③do-while循环

第二个循环结束后,根据上述代码可知跳入第三个循环loc_411891(红线以上部分):

loc_411891:                             ; CODE XREF: _main+6B↑j
                mov     [ebp+var_44], 0
loc_411898:                             ; CODE XREF: _main+9E↓j
                mov     eax, [ebp+var_20]
                add     eax, [ebp+var_44]
                mov     [ebp+var_20], eax
                mov     eax, [ebp+var_44]
                add     eax, 1
                mov     [ebp+var_44], eax
                cmp     [ebp+var_44], 5
                jl      short loc_411898

mov [ebp+var_44], 0始化局部变量 var_44 为 0。var_44 作为循环计数器,用来控制循环执行的次数。

mov eax, [ebp+var_20]将局部变量 var_20 的值加载到 eax 寄存器中。var_20 可能是一个用于累加操作的变量。

add eax, [ebp+var_44]var_44(计数器)的值加到 eax 中,累加操作。

mov [ebp+var_20], eax将累加后的结果存回 var_20,更新累加器。

mov eax, [ebp+var_44]将计数器 var_44 的值加载到 eax 寄存器中。

add     eax, 1
mov     [ebp+var_44], eax
cmp     [ebp+var_44], 5

后面三条指令则是局部变量var_44(循环计数器)自增。

cmp [ebp+var_44], 5比较 var_44 和 5,判断计数器是否小于 5。

jl short loc_411898如果 var_44 小于 5,则跳转回 loc_411898,继续循环。这是一个 "jump if less" 指令,意味着只要 var_44 小于 5,循环继续。

总结

这段代码实现了一个 do-while 循环,其中 var_44 作为循环计数器,从 0 开始,每次循环中都会将计数器的值累加到 var_20,直到计数器达到 5 后,循环结束。

伪代码表示如下:

int var_44 = 0;
do {
    var_20 += var_44;  // 累加操作
    var_44++;  // 计数器递增
} while (var_44 < 5);

最后一部分代码则是分别打印第一个循环到第三个循环获得的值,并执行system(pause)代码。

分析起来比较简单且并不是本文重点,所以就不再赘述了。

动态分析

动态分析代码与静态分析基本一致,在这我们将特征代码进行标注:

①for循环

②while循环

③do-while循环

动态分析代码与静态分析基本一致,这边就不再过多赘述了。

在逆向分析循环语句的过程中,通过仔细观察循环的初始化、条件判断和循环体的逻辑,我们能够准确识别出不同类型的循环结构,如 forwhiledo-while。这些循环的识别不仅帮助我们理解程序的控制流,还为进一步的分析和优化提供了线索。无论是通过静态分析还是动态调试,掌握循环的逆向分析方法将大大提高我们对程序行为的洞察力,并为复杂程序的深入解析奠定基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/883203.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++ Primer Plus习题】17.7

问题: 解答: #include <iostream> #include <vector> #include <string> #include <fstream> #include <algorithm>using namespace std;const int LIMIT 50;void ShowStr(const string& str); void GetStrs(ifstream& fin, vector<…

ShardingSphere 分库分表

中间件 常用中间件 MyCat 是基于 Proxy&#xff0c;它复写了 MySQL 协议&#xff0c;将 Mycat Server 伪装成⼀个 MySQL 数据库客户端所有的jdbc请求都必须要先交给MyCat&#xff0c;再有 MyCat转发到具体的真实服务器缺点是效率偏低&#xff0c;中间包装了⼀层代码⽆侵⼊性…

【刷题3】找到字符串中所有字母异位词、串联所有单词的子串

目录 一、找到字符串中所有字母异位词二、串联所有单词的子串 一、找到字符串中所有字母异位词 题目&#xff1a; 思路&#xff1a; 用一个变量count来统计有效字符的个数。哈希表2统计字符串p的每个字符出现的个数&#xff0c;然后遍历字符串s&#xff0c;先进窗口&#xf…

Unity-物理系统-碰撞检测-物理材质

物理材质的作用&#xff1a;改变碰撞效果 因为碰撞的过程是相互的&#xff0c;所以在碰撞双方都要加相同的物理材质才能实现效果 物理材质创建 参数

微软宣布弃用WSUS,企业用户尽早准备替换方案

微软最近宣布将逐步弃用Windows Server Update Services (WSUS)&#xff0c;不再为其开发新功能&#xff0c;但会继续支持现有的更新和功能。这一决定对企业客户来说影响深远&#xff0c;尤其是那些依赖WSUS来管理大规模Windows设备更新的组织。 对企业客户的影响 安全性与合规…

模型Alignment之RLHF与DPO

1. RLHF (Reinforcement Learning from Human Feedback) RLHF 是一种通过人类反馈来强化学习的训练方法&#xff0c;它能够让语言模型更好地理解和执行人类指令。 RLHF 的三个阶段 RLHF 的训练过程一般分为三个阶段&#xff1a; 监督微调&#xff08;Supervised Fine-Tuning,…

Apache ZooKeeper 及 Curator 使用总结

1. 下载 官网地址&#xff1a;Apache ZooKeeper 点击下载按钮 选择对应的版本进行下载 2. 使用 1、解压 tar -zxf apache-zookeeper-3.9.2-bin.tar.gz2、复制配置文件&#xff0c;有一个示例配置文件 conf/zoo_sample.cfg&#xff0c;此文件不能生效&#xff0c;需要名称为…

Docker Registry API best practice 【Docker Registry API 最佳实践】

文章目录 1. 安装 docker2. 配置 docker4. 配置域名解析5. 部署 registry6. Registry API 管理7. 批量清理镜像8. 其他 &#x1f44b; 这篇文章内容&#xff1a;实现shell 脚本批量清理docker registry的镜像。 &#x1f514;&#xff1a;你可以在这里阅读&#xff1a;https:/…

安卓13设置动态显示隐藏第一页的某一项 动态显示隐藏无障碍 android13设置动态显示隐藏第一页的某一项

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改4.1修改方法14.2修改方法25.编译6.彩蛋1.前言 有时候,我们的设置里面显示的信息,需要根据不同的情况显示不同的信息,例如,动态的显示或者隐藏 “无障碍” 这一项。 2.问题分析 像这个问题…

基于 K8S kubernetes 搭建 安装 EFK日志收集平台

目录 1、在k8s中安装EFK组件 1.1 安装elasticsearch组件 1.2 安装kibana组件 1.3 安装fluentd组件 文档中的YAML文件配置直接复制粘贴可能存在格式错误&#xff0c;故实验中所需要的YAML文件以及本地包均打包至网盘 链接&#xff1a;https://pan.baidu.com/s/15Ryaoa0_…

Leetcode面试经典150题-39.组合总数进阶:40.组合总和II

本题是扩展题&#xff0c;真实考过&#xff0c;看这个题之前先看一下39题 Leetcode面试经典150题-39.组合总数-CSDN博客 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数…

Java查找算法——(四)分块查找(完整详解,附有代码+案例)

文章目录 分块查找1.1普通分块查找 分块查找 1.1普通分块查找 分块原则&#xff1a; 块内无序&#xff0c;块间有序:前一块中的最大数据&#xff0c;小于后一块中所有的数据&#xff0c;块与块之间不能有数据重复的交集。块的数量一般等于数字个数开根号 核心思路&#xff…

CentOS Linux教程(6)--CentOS目录

文章目录 1. 根目录2. cd目录切换命令3. CentOS目录介绍4. pwd命令介绍5. ls命令介绍5.1 ls5.2 ls -a5.3 ls -l 1. 根目录 Windows电脑的根目录是计算机(我的电脑)&#xff0c;然后C盘、D盘。 Linux系统的根目录是/&#xff0c;我们可以使用cd /进入根目录&#xff0c;然后使…

VUE条件树查询

看如下图所示的功能&#xff0c;是不是可高级了&#xff1f;什么&#xff0c;你没看懂&#xff1f;拜托双击放大看&#xff01; 是的&#xff0c;我最近消失了一段时间就是在研究这个玩意的实现&#xff0c;通过不懈努力与钻研并参考其他人员实现并加以改造&#xff0c;很好&am…

南开大学联合同济大学发布最新SOTA Occ OPUS:使用稀疏集进行占据预测,最快实现8帧22FPS

Abstract 占据预测任务旨在预测体素化的 3D 环境中的占据状态&#xff0c;在自动驾驶社区中迅速获得了关注。主流的占据预测工作首先将 3D 环境离散化为体素网格&#xff0c;然后在这些密集网格上执行分类。然而&#xff0c;对样本数据的检查显示&#xff0c;大多数体素是未占…

Windows内核编程基础(3)

内存分配 在应用层编程时&#xff0c;系统提供了GlobalAlloc/HeapAlloc/LocalAlloc等函数。C/C库提供了malloc函数&#xff0c;以及new操作符在堆上分配内存。 在我前面一个关于Windows页交换文件的博客中&#xff0c;介绍了虚拟内存&#xff0c; 虚拟内存是计算机系统内存管…

Unity开发绘画板——03.简单的实现绘制功能

从本篇文章开始&#xff0c;将带着大家一起写代码&#xff0c;我不会直接贴出成品代码&#xff0c;而是会把写代码的历程以及遇到的问题、如何解决这些问题都记录在文章里面&#xff0c;当然&#xff0c;同一个问题的解决方案可能会有很多&#xff0c;甚至有更好更高效的方式是…

Go容器化微服务系统实战

1-1 本课的go微服务有什么不同&#xff1f; 聚焦于容器化可观测的购物微服务系统实战&#xff0c;通过介绍Go语言的应用趋势、容器化优势及微服务适用性&#xff0c;旨在解决学习微服务过程中遇到的难点。课程内容涵盖微服务整体架构、技术工具框架及容器平台等关键技术&#…

Java之路--瓦解逻辑控制与方法使用已是瓮中捉鳖

嗨嗨大家&#xff01;今天我们来学习逻辑运算和方法的使用~ 目录 一 逻辑控制 1 分支结构 1.1 if语句 1.2 switch 语句 2 循环结构 2.1 while 循环 2.2 for 循环 2.3 do while 循环 2.4 break 2.5 continue 3. 输出输入 二、方法的使用 1 方法定义语法 2 实参和…

苹果macOS 15.0 Sequoia正式版发布:iPhone应用镜像玩、手机消息电脑知

9月17日苹果向 Mac 电脑用户推送了 macOS 15 更新&#xff08;内部版本号&#xff1a;24A335&#xff09;&#xff0c;除了引入数个 iOS 18 的新功能外&#xff0c;macOS 15 Sequoia 还带来了全新的 Continuity 功能 ——iPhone 镜像。 iPhone 镜像功能可以让用户直接在 Mac 上…