首页 > 其他分享 >[3] 以逆向的角度来看循环语句——do、while、for的比较

[3] 以逆向的角度来看循环语句——do、while、for的比较

时间:2023-02-03 02:33:51浏览次数:35  
标签:语句 do 逆向 代码 mov while ebp 跳转

[3] 以逆向的角度来看循环语句——do、while、for的比较

1. do循环

​ 先执行循环体,后比较判断

#include <stdio.h>
int main(int argc, char* argv[]) {
  int sum = 0;
  int i = 0; 
  do {
    sum += i; 
    i++;
  }
  while(i <= argc); 
  return sum;
}

汇编标识:

;x86_vs
00401000  push    ebp
00401001  mov     ebp, esp
00401003  sub     esp, 8
00401006  mov     dword ptr [ebp-8], 0         ;sum=0
0040100D  mov     dword ptr [ebp-4], 0         ;i=0 
{
00401014  mov     eax, [ebp-8]                 ;do_while语句块代码
00401017  add     eax, [ebp-4]
0040101A  mov     [ebp-8], eax                 ;sum+=i
0040101D  mov     ecx, [ebp-4]
00401020  add     ecx, 1
00401023  mov     [ebp-4], ecx                 ;i+=1 
}00401026  mov     edx, [ebp-4]
00401029  cmp     edx, [ebp+8]
0040102C  jle     short loc_401014             ;如果i<=argc,跳转到do_while语句块代码
0040102E  mov     eax, [ebp-8]                 ;do_while结束代码块
00401031  mov     esp, ebp
00401033  pop     ebp
00401034  retn

;x86_gcc
00401510  push    ebp
00401511  mov     ebp, esp
00401513  and     esp, 0FFFFFFF0h
00401516  sub     esp, 10h
00401519  call    ___main
0040151E  mov     dword ptr [esp+0Ch], 0       ;sum=0
00401526  mov     dword ptr [esp+8], 0         ;i=0 
{
0040152E  mov     eax, [esp+8]                 ;do_while语句块代码
00401532  add     [esp+0Ch], eax               ;sum+=i
00401536  add     dword ptr [esp+8], 1         ;i+=1
0040153B  mov     eax, [esp+8]
0040153F  cmp     eax, [ebp+8]
00401542  jg      short loc_401546             ;如果i>argc,跳转到do_while结束代码块
}
00401544  jmp     short loc_40152E             ;跳转到do_while语句块代码
00401546  mov     eax, [esp+0Ch]               ;do_while结束代码块

逆向总结:

​ x86_vs:while语句的比较数是相同的

{
DO_WHILE语句代码块
...
}
执行影响标志位指令
JXX跳转到DO_WHILE语句代码块

​ x86_gcc:while语句的比较数是相反的

{
DO_WHILE语句代码块
执行影响标志位指令
JXX跳转到DO_WHILE结束代码块
...
}
跳转到DO_WHILE语句代码块
DO_WHILE结束代码块

2. while循环:先比较判断,后执行循环体

#include <stdio.h>
int main(int argc, char* argv[]) {
  int sum = 0;
  int i = 0;
  while(i <= argc)  { 
    sum += i;
    i++; 
  }
  return sum; 
}

汇编标识:

00401000  push    ebp
00401001  mov     ebp, esp
00401003  sub     esp, 8
00401006  mov     dword ptr [ebp-8], 0        ;sum=0
0040100D  mov     dword ptr [ebp-4], 0        ;i=0 
{
00401014  mov     eax, [ebp-4]                ;while语句代码块
00401017  cmp     eax, [ebp+8]
0040101A  jg      short loc_401030            ;如果i>argc,则跳转到while结束代码块
0040101C  mov     ecx, [ebp-8]
0040101F  add     ecx, [ebp-4]
00401022  mov     [ebp-8], ecx                ;sum+=i
00401025  mov     edx, [ebp-4]
00401028  add     edx, 1
0040102B  mov     [ebp-4], edx                ;i+=1 
}
0040102E  jmp     short loc_401014            ;跳转到while语句代码块
00401030  mov     eax, [ebp-8]                ;while结束代码块

注意:

​ while循环结构中使用了两次跳转指令完成循环,因为多使用了一次跳转指令,所以while循环比do循环效率低一些

​ while循环结构很可能被优化成do循环结构,被转换后的while结构需要检查是否可以被成功执行一次,通常会被嵌套在if单分支结构中

逆向总结:

{
while语句代码块
执行影响标志位指令
JXX跳转到while结束代码块
...
}
JMP跳转到while语句代码块
while结束代码块

3. for循环:先初始化,再比较判断,最后执行循环体

#include <stdio.h>
int main(int argc, char* argv[]) { 
  int sum = 0;
  for (int i = 0; i <= argc ; i++) { 
    sum += i;
  }
  return sum; 
}

汇编标识:

00401006  mov     dword ptr [ebp-8], 0         ;sum=0 
{
0040100D  mov     dword ptr [ebp-4], 0         ;赋初值语句代码块,i=0
}
00401014  jmp     short loc_40101F             ;跳转到for语句代码块
{
00401016  mov     eax, [ebp-4]                 ;步长语句代码块
00401019  add     eax, 1
0040101C  mov     [ebp-4], eax                 ;i+=1 
}
{
0040101F  mov     ecx, [ebp-4]                 ;for语句代码块
00401022  cmp     ecx, [ebp+8]
00401025  jg      short loc_401032             ;如果i>argc,则跳转到for结束语句块
00401027  mov     edx, [ebp-8]
0040102A  add     edx, [ebp-4]
0040102D  mov     [ebp-8], edx                 ;sum+=i}
00401030  jmp     short loc_401016             ;跳转到步长语句代码块
00401032  mov     eax, [ebp-8]                 ;for结束语句块

逆向总结:

赋初值语句代码块
JMP跳转到for语句代码块
{
步长语句代码块
...
}
{
for语句代码块
执行影响标志位的指令
JXX跳转到for结束语句块
...
}
JMP跳转到步长语句代码块
for结束语句块

​ 计数器变量被赋初值后,利用jmp跳过第一次步长计算。然后,通过3个跳转指令还原for循环的各个组成部分:

​ 1)第一个jmp指令之前的代码为初始化部分;

​ 2)从第一个jmp指令到循环条件比较处之间的代码为步长计算部分;

​ 3)在条件跳转指令jxx之后寻找向上跳转的jmp指令,且其目标是到步长计算的位置,在jxx和这个jmp指令之间的代码即为循环语句块

4. 三种循环结构的效率比较

Release优化

​ 1)do循环效率最高

​ 2)while循环执行两次JMP跳转,效率低于do循环,可将其优化为if嵌套的do循环提高效率

int LoopWhile(int count){
  int sum = 0;
  int i = 0;  if(count >= 0){ 
    do {
      sum += i; 
      i++; 
    }
    while(i <= count) 
  }
  return sum; 
}

​ 3)for循环执行三次JMP跳转,效率最低,可将其优化为if嵌套的do循环提高效率

标签:语句,do,逆向,代码,mov,while,ebp,跳转
From: https://www.cnblogs.com/XiuzhuKirakira/p/17087897.html

相关文章

  • [1] 以逆向的角度来看流程控制语句——if
    [1]以逆向的角度来看流程控制语句——if1.if语句(单分支)​ if语句转换的条件跳转指令与if语句的判断结果是相反的,因为C语言是根据代码行的位置决定编译后二进制代码地......
  • [2] 以逆向的角度来看流程控制语句——switch
    [2]以逆向的角度来看流程控制语句——switch1.switch分支数小于4汇编标识:00401021mov[ebp-4],ecx00401024cmpdwordptr[ebp-4],100401028jz......
  • CMD 基本的Dos命令
    CMD基本的Dos命令打开CMD的方式开始+系统+命令提示符Win键+R输入cmd打开控制台(推荐使用)在桌面任意位置按住shift键+鼠标右键,点击打开powershell窗口在资源......
  • 使用Docusaurus搭建个人网站
    第一次使用Docusaurus搭建我的个人网站第一步安装node环境安装Node.js16.14或更高版本(可以通过执行node-v命令来查看当前所用的Node。js版本)下载并安......
  • 「SDOI2016」征途 TJ
    「SDOI2016」征途TJ题目传送门题目大意:有\(n\)个块,给出其块长,将其分为\(m\)组,使得每组内长度之和的方差最小。输出\(v\timesm^2\),其中\(v\)是方差。思路:......
  • 在腾讯云上创建一个玩具docker-mysql数据服务
    有时候开发需求会自己做一下测试数据,在自己电脑本地安装的服务多了电脑环境会搞的很乱,这时使用云服务器安装个docker服务是一个不错的寻找。下面步骤是在腾讯云上安装dock......
  • 震惊!大多数 Windows 用户并不关心安全问题
    微软一直研发新技术让Windows系统更加安全。而最近一项调查表明,大多数的Windows用户并不关心安全问题。DuoSecurity公司通过现有的Windows使用数据分析有多少用户......
  • Docker部署XXL-Job
    Docker部署XXL-Job前置条件必须保证Client与Server互通Linux上已经安装好了Docker地址:分布式任务调度平台XXL-JOB(xuxueli.com)1.创建数据库脚本从官网中......
  • JavaScript学习笔记—DOM:元素的添加、修改、删除
    appendChild(node):向节点添加最后一个子节点insertAdjacentHTML(position,text):把元素插入到指定位置position:beforebegin-插入到当前元素的前面,即开始标签之前a......
  • fedora 53端口占用
    其实是systemd-resolve占用的。这个服务也不能停。echo"DNS=8.8.8.8">>/etc/systemd/resolved.confecho"DNSStubListener=no">>/etc/systemd/resolved.confsystemct......