你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

C语言逆向之循环结构分析

[复制链接]
埃斯提爱慕 提问时间:2021-5-17 19:50 /
C语言的循环结构有for循环、while循环、do循环和goto循环。本文介绍前3种循环方式。

1. for循环结构

for循环也可以称为步进循环,它的特点是常用于已经明确了循环的范围。看一个简单的C语言代码,具体如下:
#include <stdio.h>
int main()
{
  int nNum = 0, nSum = 0;
  for ( nNum = 1; nNum <= 100; nNum ++ )
  {
    nSum += nNum;
  }
  printf("nSum = %d \r\n", nSum);
  return 0;
}
这是很典型的求1~100的累加和的程序。通过这个程序来认识关于for循环结构的反汇编代码。
.text:00401028 mov [ebp+nNum], 0
.text:0040102F mov [ebp+nSum], 0
.text:00401036 mov [ebp+nNum], 1
.text:0040103D jmp short LOC_CMP
.text:0040103F ; ---------------------------------------------------------
.text:0040103F
.text:0040103F LOC_STEP: ; CODE XREF: _main+47j
.text:0040103F mov eax, [ebp+nNum]
.text:00401042 add eax, 1
.text:00401045 mov [ebp+nNum], eax
.text:00401048
.text:00401048 LOC_CMP: ; CODE XREF: _main+2Dj
.text:00401048 cmp [ebp+nNum], 64h
.text:0040104C jg short LOC_ENDFOR
.text:0040104E mov ecx, [ebp+nSum]
.text:00401051 add ecx, [ebp+nNum]
.text:00401054 mov [ebp+nSum], ecx
.text:00401057 jmp short LOC_STEP
.text:00401059 ; ---------------------------------------------------------
.text:00401059
.text:00401059 LOC_ENDFOR: ; CODE XREF: _main+3Cj
.text:00401059 mov edx, [ebp+nSum]
.text:0040105C push edx
.text:0040105D push offset Format ; "nSum = %d \r\n"
.text:00401062 call _printf
.text:00401067 add esp, 8
.text:0040106A xor eax, eax
这次的反汇编代码,修改了其中的变量、标号,看起来更加直观。从修改的标号来看,for结构可以分为3部分,在LOC_STEP上面的部分是初始化部分,在LOC_STEP下面的部分是修改循环变量的部分,在LOC_CMP下面和LOC_ENDFOR上面部分是比较循环条件和循环体的部分。

for循环的反汇编结构如下:
; 初始化循环变量
  jmp LOC_CMP
LOC_STEP:
  ; 修改循环变量
LOC_CMP:
  ; 循环变量的判断
  jxx LOC_ENDFOR
  ; 循环体
  jmp LOC_STEP
LOC_ENDOF:
再用IDA来看一下生成的流程结构图,如图1所示。
图片
图1  for结构的流程图

2. do…while循环结构

do循环的循环体总是会被执行一次,这是do循环与while循环的区别。这里还是1~100的累加和代码,来看一下它的反汇编结构。先看C语言代码,具体如下:
#include <stdio.h>
int main()
{
  int nNum = 1, nSum = 0;
  do
  {
    nSum += nNum;
    nNum ++;
  } while ( nNum <= 100 );
  printf("nSum = %d \r\n", nSum);
  return 0;
}
do循环的结构要比for循环的结构简单很多,反汇编代码也少很多。先来看一下IDA生成的流程图,如图2所示。
图片
图2  do循环流程图

反汇编代码如下:
.text:00401028 mov [ebp+nNum], 1
.text:0040102F mov [ebp+nSum], 0
.text:00401036
.text:00401036 LOC_DO: ; CODE XREF: _main+3Cj
.text:00401036 mov eax, [ebp+nSum]
.text:00401039 add eax, [ebp+nNum]
.text:0040103C mov [ebp+nSum], eax
.text:0040103F mov ecx, [ebp+nNum]
.text:00401042 add ecx, 1
.text:00401045 mov [ebp+nNum], ecx
.text:00401048 cmp [ebp+nNum], 64h
.text:0040104C jle short LOC_DO
.text:0040104E mov edx, [ebp+nSum]
.text:00401051 push edx
.text:00401052 push offset Format ; "nSum = %d \r\n"
.text:00401057 call _printf
.text:0040105C add esp, 8
.text:0040105F xor eax, eax
do循环的主体就在LOC_DO和0040104C的jle之间。其结构整理如下:
  ; 初始化循环变量
LOC_DO:
  ; 执行循环体
  ; 修改循环变量
  ; 循环变量的比较
  Jxx LOC_DO
3. while循环结构

while循环与do循环的区别在于,在进入循环体之前需要先进行一次条件判断,循环体有可能因为循环条件的不成立而一次也不执行。看1~100累加和的while循环代码:
#include <stdio.h>
int main()
{
  int nNum = 1, nSum = 0;
  while ( nNum <= 100 )
  {
    nSum += nNum;
    nNum ++;
  }
  printf("nSum = %d \r\n", nSum);
  return 0;
}
再来看一下它的反汇编代码,while循环比do循环多了一个条件的判断,因此会多一条分支。反汇编代码如下:
.text:00401028 mov [ebp+nNum], 1
.text:0040102F mov [ebp+nSum], 0
.text:00401036
.text:00401036 LOC_WHILE: ; CODE XREF: _main+3Ej
.text:00401036 cmp [ebp+nNum], 64h
.text:0040103A jg short LOC_WHILEEND
.text:0040103C mov eax, [ebp+nSum]
.text:0040103F add eax, [ebp+nNum]
.text:00401042 mov [ebp+nSum], eax
.text:00401045 mov ecx, [ebp+nNum]
.text:00401048 add ecx, 1
.text:0040104B mov [ebp+nNum], ecx
.text:0040104E jmp short LOC_WHILE
.text:00401050 ; -----------------------------------------------------------
.text:00401050
.text:00401050 LOC_WHILEEND: ; CODE XREF: _main+2Aj
.text:00401050 mov edx, [ebp+nSum]
.text:00401053 push edx
.text:00401054 push offset Format ; "nSum = %d \r\n"
.text:00401059 call _printf
.text:0040105E add esp, 8
.text:00401061 xor eax, eax
while循环的主要部分全部在LOC_WHILE和LOC_WHILEEND之间。在LOC_WHILE下面的两句是cmp和jxx指令,在LOC_WHILEEND上面是jmp指令。这两部分是固定的格式,其结构整理如下:
  ; 初始化循环变量等
LOC_WHILE:
  cmp xxx, xxx
  jxx LOC_WHILEEND
  ; 循环体
  jmp LOC_WHILE
LOC_WHILEEND:
再来看一下IDA生成的流程图,如图3所示。
图片
图3  while循环流程图

对于for循环、do循环和while循环这3种循环而言,do循环的效率显然高些,而while循环相对来说比for循环效率又高些。

参考文献:C++ 黑客编程揭秘与防范(第3版)
收藏 评论1 发布时间:2021-5-17 19:50

举报

1个回答
xmshao 回答时间:2021-7-15 17:00:08
谢谢分享!

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版