IDA简单Switch-Case结构的汇编代码分析

    使用IDA进行静态逆向分析,很重要的一点是对高级语言程序结构的解析,比如Switch-Case结构。偏偏IDA的F5功能很多时候会无法生成C语言代码,此时就需要我们自己分析汇编代码,理解switch-case结构等。

   从简单入手, 测试使用的C++代码如下:

    

int switch_case(char a,int b,int *c,int d,int e)
{
	switch(a)
	{
	case 'a':
		*c = d + 3;
		break;
	case 'b':
		*c = d + 4;
		break;
	case 'c':
		*c = d - 8;
		break;
	case 'd':
		*c = d + e;
		break;
	default:
		e -= 10;
		break;
	}

	switch(b)
	{
	case 1235:
		b += d;
		break;
	case 1236:
		b += e;
		break;
	case 1237:
		b += *c;
		break;
	case 1238:
		b -= 100;
		break;
	default:
		e += 100;
		break;
	}

	printf("a=%d\r\n,b=%d\r\n,*c=%d",a,b,*c);

	return e;
}

int main(int argc,char *argv[])
{
	int number = 0;
	int i = 0;
	int j = 0;
	int k = 0;
	scanf("%d",&number);
	scanf("%d",&i);
	scanf("%d",&j);
	scanf("%d",&k);

	char c = '\0';
	scanf("%c",&c);
	int m = switch_case(c,i,&number,j,k);

	printf("m = %d\r\n",m);

	return 0;
}
       编译生成release版本的EXE执行文件,删除pdb文件后,使用IDA加载EXE进行静态分析。首先看main函数调用swcitch_case函数处如何传递参数:

.text:004010A0 var_14          = dword ptr -14h
.text:004010A0 var_10          = dword ptr -10h
.text:004010A0 var_C           = dword ptr -0Ch
.text:004010A0 var_8           = dword ptr -8
.text:004010A0 var_4           = dword ptr -4
.text:004010A0 argc            = dword ptr  4
.text:004010A0 argv            = dword ptr  8
.text:004010A0 envp            = dword ptr  0Ch
.text:004010A0
.text:004010A0                 sub     esp, 14h
.text:004010A3                 push    ebx
.text:004010A4                 push    esi
.text:004010A5                 mov     esi, ds:scanf
.text:004010AB                 push    edi
.text:004010AC                 lea     eax, [esp+20h+var_8]
.text:004010B0                 xor     ebx, ebx
.text:004010B2                 push    eax
.text:004010B3                 push    offset aD       ; "%d"
.text:004010B8                 mov     [esp+28h+var_8], ebx
.text:004010BC                 mov     [esp+28h+var_4], ebx
.text:004010C0                 mov     [esp+28h+var_C], ebx
.text:004010C4                 mov     [esp+28h+var_10], ebx
.text:004010C8                 call    esi ; scanf
.text:004010CA                 lea     ecx, [esp+28h+var_4]
.text:004010CE                 push    ecx
.text:004010CF                 push    offset aD       ; "%d"
.text:004010D4                 call    esi ; scanf
.text:004010D6                 lea     edx, [esp+30h+var_C]
.text:004010DA                 push    edx
.text:004010DB                 push    offset aD       ; "%d"
.text:004010E0                 call    esi ; scanf
.text:004010E2                 lea     eax, [esp+38h+var_10]
.text:004010E6                 push    eax
.text:004010E7                 push    offset aD       ; "%d"
.text:004010EC                 call    esi ; scanf
.text:004010EE                 lea     ecx, [esp+40h+var_14]
.text:004010F2                 push    ecx
.text:004010F3                 push    offset aC       ; "%c"
.text:004010F8                 mov     byte ptr [esp+48h+var_14], bl
.text:004010FC                 call    esi ; scanf
.text:004010FE                 mov     edx, [esp+48h+var_14]  ; char c 
.text:00401102                 mov     eax, [esp+48h+var_10]  ; int k 传入值
.text:00401106                 mov     edi, [esp+48h+var_C]   ; int j 传入值
.text:0040110A                 mov     ecx, [esp+48h+var_4]   ; int i 传入值
.text:0040110E                 push    edx                    ; char c 通过入栈传递参数
.text:0040110F                 lea     edx, [esp+4Ch+var_8]   ; int number 传入指针
.text:00401113                 call    sub_401000

      如上,sub_401000函数即为switch_case函数,该函数的起始地址为401000。

      Go on。再看看switch_case函数的汇编解析:

      

.text:00401000 sub_401000      proc near               ; CODE XREF: _main+73p
.text:00401000
.text:00401000 arg_0           = byte ptr  4   ; char c 通过入栈传递参数
.text:00401000
.text:00401000                 push    ebx
.text:00401001                 push    esi
.text:00401002                 movsx   esi, [esp+8+arg_0] ; arg_0 即为 char c
.text:00401007                 mov     ebx, eax        ; eax 为 int k 传入值
.text:00401009                 lea     eax, [esi-61h]  ; switch 4 cases  61h = 'a'
.text:0040100C                 cmp     eax, 3
.text:0040100F                 ja      short loc_401034 ; default
.text:00401011                 jmp     ds:off_401078[eax*4] ; switch jump  off_401078 为第一个switch case的跳转表首地址
.text:00401018
.text:00401018 loc_401018:                             ; DATA XREF: .text:off_401078o
.text:00401018                 lea     eax, [edi+3]    ; jumptable 00401011 case 97  edi 为 int j 传入值
.text:0040101B                 mov     [edx], eax
.text:0040101D                 jmp     short loc_401037
.text:0040101F ; ---------------------------------------------------------------------------
.text:0040101F
.text:0040101F loc_40101F:                             ; CODE XREF: sub_401000+11j
.text:0040101F                                         ; DATA XREF: .text:off_401078o
.text:0040101F                 lea     eax, [edi+4]    ; jumptable 00401011 case 98
.text:00401022                 mov     [edx], eax
.text:00401024                 jmp     short loc_401037
.text:00401026 ; ---------------------------------------------------------------------------
.text:00401026
.text:00401026 loc_401026:                             ; CODE XREF: sub_401000+11j
.text:00401026                                         ; DATA XREF: .text:off_401078o
.text:00401026                 lea     eax, [edi-8]    ; jumptable 00401011 case 99
.text:00401029                 mov     [edx], eax
.text:0040102B                 jmp     short loc_401037
.text:0040102D ; ---------------------------------------------------------------------------
.text:0040102D
.text:0040102D loc_40102D:                             ; CODE XREF: sub_401000+11j
.text:0040102D                                         ; DATA XREF: .text:off_401078o
.text:0040102D                 lea     eax, [edi+ebx]  ; jumptable 00401011 case 100
.text:00401030                 mov     [edx], eax
.text:00401032                 jmp     short loc_401037
.text:00401034 ; ---------------------------------------------------------------------------
.text:00401034
.text:00401034 loc_401034:                             ; CODE XREF: sub_401000+Fj
.text:00401034                 sub     ebx, 0Ah        ; default
.text:00401037
.text:00401037 loc_401037:                             ; CODE XREF: sub_401000+1Dj
.text:00401037                                         ; sub_401000+24j ...
.text:00401037                 lea     eax, [ecx-4D3h] ; switch 4 cases  ; ecx 为 int i 传入值
.text:0040103D                 cmp     eax, 3
.text:00401040                 ja      short loc_40105A ; default
.text:00401042                 jmp     ds:off_401088[eax*4] ; switch jump off_401088 为第二个switch case的跳转表首地址
.text:00401049
.text:00401049 loc_401049:                             ; DATA XREF: .text:off_401088o
.text:00401049                 add     ecx, edi        ; jumptable 00401042 case 1235
.text:0040104B                 jmp     short loc_40105D
.text:0040104D ; ---------------------------------------------------------------------------
.text:0040104D
.text:0040104D loc_40104D:                             ; CODE XREF: sub_401000+42j
.text:0040104D                                         ; DATA XREF: .text:off_401088o
.text:0040104D                 add     ecx, ebx        ; jumptable 00401042 case 1236
.text:0040104F                 jmp     short loc_40105D
.text:00401051 ; ---------------------------------------------------------------------------
.text:00401051
.text:00401051 loc_401051:                             ; CODE XREF: sub_401000+42j
.text:00401051                                         ; DATA XREF: .text:off_401088o
.text:00401051                 add     ecx, [edx]      ; jumptable 00401042 case 1237
.text:00401053                 jmp     short loc_40105D
.text:00401055 ; ---------------------------------------------------------------------------
.text:00401055
.text:00401055 loc_401055:                             ; CODE XREF: sub_401000+42j
.text:00401055                                         ; DATA XREF: .text:off_401088o
.text:00401055                 sub     ecx, 64h        ; jumptable 00401042 case 1238
.text:00401058                 jmp     short loc_40105D
.text:0040105A ; ---------------------------------------------------------------------------
.text:0040105A
.text:0040105A loc_40105A:                             ; CODE XREF: sub_401000+40j
.text:0040105A                 add     ebx, 64h        ; default
.text:0040105D
.text:0040105D loc_40105D:                             ; CODE XREF: sub_401000+4Bj
.text:0040105D                                         ; sub_401000+4Fj ...
.text:0040105D                 mov     edx, [edx]
.text:0040105F                 push    edx
.text:00401060                 push    ecx
.text:00401061                 push    esi
.text:00401062                 push    offset Format   ; "a=%d\r\n,b=%d\r\n,*c=%d"
.text:00401067                 call    ds:printf
.text:0040106D                 add     esp, 10h
.text:00401070                 pop     esi
.text:00401071                 mov     eax, ebx
.text:00401073                 pop     ebx
.text:00401074                 retn
.text:00401074 sub_401000      endp
.text:00401074
.text:00401074 ; ---------------------------------------------------------------------------
.text:00401075                 align 4
.text:00401078 off_401078      dd offset loc_401018    ; DATA XREF: sub_401000+11r
.text:00401078                 dd offset loc_40101F    ; jump table for switch statement
.text:00401078                 dd offset loc_401026
.text:00401078                 dd offset loc_40102D
.text:00401088 off_401088      dd offset loc_401049    ; DATA XREF: sub_401000+42r
.text:00401088                 dd offset loc_40104D    ; jump table for switch statement
.text:00401088                 dd offset loc_401051
.text:00401088                 dd offset loc_401055
.text:00401098                 align 10h
.text:004010A0
       如上,2个switch_case函数里面包括2个Switch-Case结构,汇编代码中就包含有2个跳转表,每个跳转表都包括4个case的跳转地址,可以理解为跳转数组,然后程序根据跳转数组的索引值,通过jmp指令跳转到各个分支即可。

      

你可能感兴趣的:(汇编语言基础)