switch 的简单情景(case 不超过 3 项)

首先,我们分析一下 switch 语句的一种简单情景,我们可以用 C 写出如下如下代码。

编译后用 OllyDBG 载入,它将显示出如下的反汇编代码。

首先,我们可以看到 ESP 减少了 8,除了定义变量 a 外,编译器还分配了一个临时变量(这里暂且叫它 t)用于比较。t 被赋值成 a 的值,然后与立即数 0x10,0x20,0x30 依次比较。如果有一项相等,那么就跳转到 case 里面,如果都不相等,就会无条件跳转到 default 里面。执行完 case 或 default 里面的代码之后,就会无条件跳转到 end 的位置。

switch 跳转表情景(case 超过 3 项)

上面是 switch 中比较简单的情景,但是当 case 项超过 3 项时,情景将发生很大的变化。我们可以先编写如下 C 语言代码,这里 switch 的 case 项已经超过 3 项。

编译后,用 OllyDBG 载入,可以得到如下的反汇编代码。与之前的简单情景类似,除了定义变量 a 外,编译器还分配了一个临时变量(这里暂且叫它 t)用于比较,t 被赋值成,接着我们可以观察到 t 减了 0x10,然后与 0x8A 做比较。实际上,我们不难看出 t 先减去了 case 项中的最小值,然后与 case 项中的最大值和最小值的差进行比较。这样做的目的是首先排除极端情况(如果 t 比最大值要大,或者比最小值小,那么肯定是 default),接下来的 JA 指令就能排除这类极端情况,提高程序执行效率。

说到这里,有些人可能不能理解为啥要先减去最小值,然后再与最大值和最小值的差进行比较。其实道理很简单,假设变量的值是 t,最小值是 min,最大值是 max,我们很容易建立一个比较关系,t – min 与 max – min 之间的比较。这里很容易化简成 t 与 max 的比较,如果 t 比 max 大,说明这是极端情况应该去 default。还有一种可能就是,t – min 的时候,t 比 min 小,这样寄存器就会溢出,t 会变得很大很大且大过 max,这也会变成极端情况。换言之,这样的一套操作下来,程序能保证 t 在 min 和 max 之间是能被 case 接受的,否则就是极端情况而进入 default。

我们往后看,假设变量的值不是极端情况,那么程序就会把 t 的值赋值给 EDX 寄存器,注意,这里的 t 已经减去了 case 项的最小值,换言之,如果把 case 项中的最小值看做起始点 0,最大值看做最大值与最小值的差,那么 t 就是介于最小值与最大值之间的某个点。

接下来,eax 被赋值成某个基址 + EDX 的值。我们跟进这个基址可以看到以下的内容:

我们仔细分析一下 EDX 的值(也是 t 的值)与基址起始的字节数据的内在联系。

  • 当 EDX == 0x0 时,取出数据 0x0 给 EAX。
  • 当 EDX == 0x22 时,取出数据 0x1 给 EAX。
  • 当 EDX == 0x34 时,取出数据 0x2 给 EAX。
  • 当 EDX == 0x8A 时,取出数据 0x3 给 EAX。
  • 当 EDX >= 0 且 EDX <= 0x8A 时,除去以上情况,将取出数据 0x4 给 EAX。

仔细观察可以发现,这里的内存数据从基址偏移 0x0 ~ 0x8A 的每个字节都是一个指示值,在此例中 EAX 可以被赋值成五个值 0,1,2,3,4,5。EDX 实际上也就是 a 减去 case 项最小值的结果,所以,最终我们能建立一个映射关系:

  • case 0x10 –> EAX = 0x0
  • case 0x32 –> EAX = 0x1
  • case 0x44 –> EAX = 0x2
  • case 0x9A –> EAX = 0x3
  • default –> EAX = 0x4

而 EAX 的值最终会被用于跳转表,跳转表里保存了每一个指示值所对应的内存地址,这些内存地址就是每个分支的入口。回到反汇编,接着程序将执行一个跳转,目的地址是某个基址 + EAX * 4,让我们在数据窗口跟随到这个基址:

我们很容易发现,这个基址就在之前指示器基址的上方。本例中它存储了 0x14 字节(20 字节)的数据,每个地址是 4 字节,那么就是五个地址,十六进制分别是 004095E6,004095E5,00409604,00409613,00409622。这刚好是程序中各个分支的入口地址。EAX(本例中 0x0 ~ 0x4)的值恰好是指示取这五个值中的哪一个值。

在本例中,EAX 会取到 0x4 这个值,最终会 JMP 到 00409622 这个地址,也就是 default 分支的入口点,这样 switch 就执行完毕了。

switch 语句的反汇编浅析的更多相关文章

  1. C++ 反汇编:关于Switch语句的优化措施

    流程控制语句是C语言中最基本的判断语句,通常我们可以使用IF来构建多分支结构,但同样可以使用Switch语句构建,Switch语句针对多分支的优化措施有4种形式,分别是,IF-ELSE优化,有序线性优 ...

  2. 逆向随笔 - switch 语句深入分析

    switch case 语句在c语言里还是比較简单的.可是被编译出来之后,优化结果往往让人非常疑惑.全然看不懂,以下我们一次次的尝试,看看编译器究竟把switch语句变成什么样了.   ① 先上个最简 ...

  3. switch语句分析

    1.关于switch语句 如果if语句中表达式是判断是否等于一个常量时,可以用switch语句来代替 if(表达式 == 常量1)                        {          ...

  4. switch语句的妙用

    switch语句的普通用法很简单,如下: var a = 3; switch (a) { case 1: console.log(a); break; case 2: case 3: console. ...

  5. 106运用SWITCH语句打印星期几的单词

    package com.chongrui.test;/*运用SWITCH语句打印星期几的单词 * */ public class TypeConvertion { public static void ...

  6. 通过goto语句学习if...else、switch语句并简单优化

    goto语句在C语言中实现的就是无条件跳转,第二章一上来就介绍goto语句就是要通过goto语句来更加清楚直观的了解控制结构. 我理解的goto语句其实跟switch语句有相似之处,都是进行跳转.不同 ...

  7. Java中简单的操作(if语句、常用操作符、switch语句、变量赋值等)

    ---------------------if语句介绍--------------------------------------------------- class IfDemo { public ...

  8. Switch语句的case穿透

    Switch语句的case穿透 一 switch语句几点说明: 1. case后面只能是常量,不能是变量,而且,多个case后面的值不能出现相同的. 2.case后面表达式可以接受: 基本数据类型,b ...

  9. ECMA中的switch语句

    switch借鉴自其他语言,但也有自己的特色. 1.可以在switch语句中使用任何数据类型(数值.字符串.对象等),很多其他语言中只能使用数值. 2.每个case的值不一定是常量,可以是变量或者表达 ...

随机推荐

  1. EXP/IMP version

    在imp数据的时候,有时候imp命令会不识别dump文件.这通常是因为dump是由高版本的exp 导出的而imp是低版本的. 这种情况下只能是用低版本的exp重新导出.

  2. CF #329 C

    C题我还以为是拉格朗日插值... 其实可以想象到,必须有这样一个函数,经过某一点时,其它圆相关的函数要为0. 于是,可以构造这样的一个函数,对于x有 (x/2)*(1-abs(t-i)+abs(1-a ...

  3. POJ 3233 Matrix Power Series 二分+矩阵乘法

    链接:http://poj.org/problem?id=3233 题意:给一个N*N的矩阵(N<=30),求S = A + A^2 + A^3 + - + A^k(k<=10^9). 思 ...

  4. 阻尼滑动--能够滑动过度的ScrollView(OverScrollView)

    贴上一个我自己用过的阻尼滑动的ScrollView,像QQ里面那种滑动效果,尽管不是我写的,可是我认为还能够,贴出来做个记录,实用到的时候免得到处去找. 代码例如以下: /* * Copyright ...

  5. CAS 4.0 配置开发手冊

    1    下载 地址http://downloads.jasig.org/ cas-server-4.0.0-release.tar.gz cas-client-3.3.3-release.tar.g ...

  6. 我在Suse 11 Sp3上使用anaconda安装TensorFlow的过程记录

    我在Suse 11 Sp3上使用anaconda安装TensorFlow的过程记录 准备安装包: gcc48 glibc--SP4-DVD-x86_64-GM-DVD1.iso tensorflow_ ...

  7. hdoj--5630--Rikka with Chess(规律题)

     Rikka with Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Othe ...

  8. git拉取远端改变,但是不覆盖本地的修改

    1.git stash 2.git  fetch weixin-old-remote 3.git rebase weixin-old-remote/main151028_wxpay_main15100 ...

  9. [Apple开发者帐户帮助]二、管理你的团队(3)删除团队成员

    如果您已加入Apple开发者计划,您将在App Store Connect中管理团队成员.有关详细信息,请转到App Store Connect帮助中的添加和编辑用户. 如果您已加入Apple Dev ...

  10. Oracle 批量插入值

    工作中常遇到将Excel文档数据转为SQL语句,然后再将SQL语句插入到数据库已完成数据转移保存到数据库中,下面介绍下如何一次性插入多条SQL语句,先抛个图: 由于真实数据不变给大家看,所以这里是做了 ...