IDA对case语句的处理

本文标题中的case语句是Ada语言中的一种控制结构,它与C语言的swich语句类似。

我正在阅读的一个exe文件是从Ada源程序编译生成的,其中有一类case语句的应用代码被IDA翻译为如下伪代码:

  if ( a2 > 0x1Au )
    __gnat_rcheck_06("page_s_arrival.adb", 1825);  result = (unsigned __int8)(a2 - 14);
  switch ( a2 )
  {
    case 0xEu:
      //略
      break;
    case 0xFu:
      //略
      break;
    case 0x10u:
      //略
      break;
    case 0x14u:
      //略
      break;
    case 0x15u:
      //略
      break;
    case 0x16u:
      //略
      break;
    case 0x1Au:
      //略
      break;
    default:
      return result;
  }

对应的汇编代码是:

..text:00AA5507 cmp    bl, 1Ah

.text:00AA550A jbe     short loc_AA551E

.text:00AA550C sub     esp, 8

.text:00AA550F push    721h

.text:00AA5514 push    0CDF9F4h

.text:00AA5519 call     ___gnat_rcheck_06

.text:00AA551E

.text:00AA551E loc_AA551E:

.text:00AA551E lea     eax, [ebx-0Eh]

.text:00AA5521 cmp     al, 0Ch         ; switch 1 cases

.text:00AA5523 ja      loc_AA5A22      ; jumptable 00A9DCD4 cases 68-70,74-76

.text:00AA5529 and     eax, 0FFh

.text:00AA552E jmp     ds:off_CDFA20[eax*4] ; switch jump

.text:00AA5535

.text:00AA5535 loc_AA5535:             ; jumptable 00A9DCD4 case 66

             ;略

.text:00AA558B jmp     loc_AA5A22      ; jumptable 00A9DCD4 cases 68-70,74-76

.text:00AA5590

.text:00AA5590 loc_AA5590:             ; jumptable 00A9DCD4 case 72

             ;略

.text:00AA5626 jmp     loc_AA5A22      ; jumptable 00A9DCD4 cases 68-70,74-76

.text:00AA562B

.text:00AA562B loc_AA562B:             ; jumptable 00A9DCD4 case 67

             ;略

.text:00AA57B8 jmp     loc_AA5A22      ; jumptable 00A9DCD4 cases 68-70,74-76

.text:00AA57BD

.text:00AA57BD loc_AA57BD:             ; jumptable 00A9DCD4 case 73

.             ;略

.text:00AA5973 jmp     loc_AA5A22      ; jumptable 00A9DCD4 cases 68-70,74-76

.text:00AA5978

.text:00AA5978 loc_AA5978:             ; jumptable 00A9DCD4 case 65

.             ;略

.text:00AA598B jmp     loc_AA5A22      ; jumptable 00A9DCD4 cases 68-70,74-76

.text:00AA5990

.text:00AA5990 loc_AA5990:             ; jumptable 00A9DCD4 case 77

.             ;略

.text:00AA59FB jmp     short loc_AA5A22 ; jumptable 00A9DCD4 cases 68-70,74-76

.text:00AA59FD

.text:00AA59FD loc_AA59FD:             ; jumptable 00A9DCD4 case 71

             ;略

.text:00AA5A22 loc_AA5A22:             ; jumptable 00A9DCD4 cases 68-70,74-76

ds:off_CDFA20中的内容是各种case处理代码的起始地址:

.rdata:00CDFA20 off_CDFA20 dd offset loc_AA5978 ; jump table for switch statement

.rdata:00CDFA24 dd offset loc_AA5535    ; jumptable 00A9DCD4 case 66

.rdata:00CDFA28 dd offset loc_AA562B    ; jumptable 00A9DCD4 case 67

.rdata:00CDFA2C dd offset loc_AA5A22    ; jumptable 00A9DCD4 cases 68-70,74-76

.rdata:00CDFA30 dd offset loc_AA5A22    ; jumptable 00A9DCD4 cases 68-70,74-76

.rdata:00CDFA34 dd offset loc_AA5A22    ; jumptable 00A9DCD4 cases 68-70,74-76

.rdata:00CDFA38 dd offset loc_AA59FD    ; jumptable 00A9DCD4 case 71

.rdata:00CDFA3C dd offset loc_AA5590    ; jumptable 00A9DCD4 case 72

.rdata:00CDFA40 dd offset loc_AA57BD    ; jumptable 00A9DCD4 case 73

.rdata:00CDFA44 dd offset loc_AA5A22    ; jumptable 00A9DCD4 cases 68-70,74-76

.rdata:00CDFA48 dd offset loc_AA5A22    ; jumptable 00A9DCD4 cases 68-70,74-76

.rdata:00CDFA4C dd offset loc_AA5A22    ; jumptable 00A9DCD4 cases 68-70,74-76

.rdata:00CDFA50 dd offset loc_AA5990    ; jumptable 00A9DCD4 case 77

与以上汇编代码更相近的伪代码应是:

If ((a1 – 14) <= 12)
{
  switch ( a2 )
  {
    case 0xFu:
      //略
      break;
    case 0x15u:
      //略
      break;
    case 0x10u:
      //略
      break;
    case 0x16u:
      //略
      break;
    case 0xEu:
      //略
      break;
    case 0x1Au:
      //略
      break;
    case 0x14u:
      //略
      break;
    default:
      return result;
  }
}

以上伪代码与IDA生成的伪代码之间的差别是:

  1. 恢复了最外层的if语句;
  2. 按各个case的处理代码的起始地址排序。

我用以下Ada程序来模拟上述代码的处理逻辑:

with Ada.Text_IO;
use Ada.Text_IO;

procedure try_case_main is
   case_number : Integer range 14 .. 26;
begin
   case_number := Integer'Value (Get_Line);
   case case_number is
      when 15 => Put ("case 15");
      when 21  => Put ("case 21");
      when 16  => Put ("case 16");
      when 22  => Put ("case 22");
      when 14  => Put ("case 14");
      when 26  => Put ("case 26");
      when 20  => Put ("case 20");
      when 17 | 18 | 19 | 23 | 24 | 25 => null;
   end case;
end try_case_main;

以上Ada程序中case处理的顺序与case值的大小顺序无关。

用GNAT GPL 2016编译后生成了exe文件,其中case处理的代码顺序与源程序的case处理的顺序相同。

再用IDA对GNAT GPL 2016编译生成的exe文件生成了以下伪代码:

  v4 = system__val_int__value_integer(line__4, v3);
  if ( v4 <= 13 || v4 > 26 )
    __gnat_rcheck_CE_Range_Check((const system__address)"try_case_main.adb", 7);
  v6[3] = v4;
  switch ( v4 )
  {
    case 14:
      ada__text_io__put__4("case 14case 26case 20", dword_4360A8);
      break;
    case 15:
      ada__text_io__put__4("case 15case 21case 16case 22case 14case 26case 20", dword_4360A8);
      break;
    case 16:
      ada__text_io__put__4("case 16case 22case 14case 26case 20", dword_4360A8);
      break;
    case 20:
      ada__text_io__put__4("case 20", dword_4360A8);
      break;
    case 21:
      ada__text_io__put__4("case 21case 16case 22case 14case 26case 20", dword_4360A8);
      break;
    case 22:
      ada__text_io__put__4("case 22case 14case 26case 20", dword_4360A8);
      break;
    case 26:
      ada__text_io__put__4("case 26case 20", dword_4360A8);
      break;
    default:
      break;
  }

以上伪代码中的case顺序与源程序中的顺序不同。

汇编中在case语句前面还有以下代码:

.text:004016AA loc_4016AA:

.text:004016AA mov     eax, [ebp+var_1C]

.text:004016AD sub     eax, 0Eh        ; switch 13 cases

.text:004016B0 cmp     eax, 0Ch

.text:004016B3 ja      def_4016C0      ; jumptable 004016C0 default case, cases 17-19,23-25

.text:004016B9 mov     eax, ds:jpt_4016C0[eax*4]

.text:004016C0 jmp     eax             ; switch jump

以上标红的汇编代码没有对应的源代码,可见这是Ada编译器生成的。

这段标红的汇编代码与前例中可翻译为If ((a1 – 14) <= 12)的标红的汇编代码相似,其作用都是检查case表达式的合法性。

但是,在这之前都已经有相同作用的检查代码。可见,IDA智能地省略了冗余的检查。

另外,源程序中的case处理代码不管按何种顺序排列,Ada编译器生成的exe文件都是按jumptable来选择执行某个case的。

因此,IDA按case表达式值的大小为序重新排列case的顺序是可以接受的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值