马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 匿名 于 2016-12-12 20:32 编辑
参考:
书籍C++反汇编与逆向技术
任老师http://bbs.pediy.com/showthread.php?t=114479
首先代码并无实际意义
先看代码VS2013写的,当switch小于3
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
switch (argc)
{
case 1: printf("argc=%d", argc); //故意写的别喷,天书夜谈第二章课后习题反汇编就有这个陷阱
case 2: printf("argc=%d", argc); break;
case 3: printf("argc=%d", argc); break;
}
return 0;
}
反汇编后
switch (argc)
00A813DE mov eax,dword ptr [argc]
00A813E1 mov dword ptr [ebp-0C4h],eax //switch语句很明显的特征,判断语句全部放在前面
00A813E7 cmp dword ptr [ebp-0C4h],1
00A813EE je wmain+44h (0A81404h)
00A813F0 cmp dword ptr [ebp-0C4h],2
00A813F7 je wmain+5Fh (0A8141Fh)
00A813F9 cmp dword ptr [ebp-0C4h],3
00A81400 je wmain+7Ch (0A8143Ch)
00A81402 jmp wmain+97h (0A81457h)
{
case 1: printf("argc=%d", argc);
00A81404 mov esi,esp
00A81406 mov eax,dword ptr [argc]
00A81409 push eax
00A8140A push 0A85858h
00A8140F call dword ptr ds:[0A89114h]
00A81415 add esp,8
00A81418 cmp esi,esp
00A8141A call __RTC_CheckEsp (0A81140h) //假设你不加break就继续执行下面的。
case 2: printf("argc=%d", argc); break;
00A8141F mov esi,esp
00A81421 mov eax,dword ptr [argc]
00A81424 push eax
00A81425 push 0A85858h
00A8142A call dword ptr ds:[0A89114h]
00A81430 add esp,8
00A81433 cmp esi,esp
00A81435 call __RTC_CheckEsp (0A81140h)
00A8143A jmp wmain+97h (0A81457h) //加了break就等于多了个jmp 执行跳出switch-case外面
题外话:
各位有没看过天书夜谈,第二章节课后习题,就故意写少了个break。不知道有没有迷惑到你们
那么问题来了,如果有一百个case程序是否就有一百个判读语句在前面?
当switch大于3,他的优化就体现出来了
switch把case做成地址数组,这个数组保存每个case的首地址,因为地址都是0开始算,所以ecx-1
提示下:case做地址数组上限至255(8位)
switch (argc)
008E13DE mov eax,dword ptr [argc]
008E13E1 mov dword ptr [ebp-0C4h],eax
008E13E7 mov ecx,dword ptr [ebp-0C4h]
008E13ED sub ecx,1 //下标是从0开始的哦
008E13F0 mov dword ptr [ebp-0C4h],ecx
008E13F6 cmp dword ptr [ebp-0C4h],3 //当argc-1还大于switch里面最大值那就跳出
008E13FD ja $LN4+72h (08E147Eh) //跳出去
008E13FF mov edx,dword ptr [ebp-0C4h] //edx得到下标
008E1405 jmp dword ptr [edx*4+8E1494h] //地址是从0开始,8E1494h存放的是每个case的地址
//我只复制关键代码其他省略了
然而事情并没有那么简单,如果这个数大于255又该如何优化呢,那么数据结构二叉树就登场了
代码如下:
switch (argc)
{
case 25: printf("argc=%d", argc); break;
case 255: printf("argc=%d", argc); break;
case 98: printf("argc=%d", argc); break;
case 500: printf("argc=%d", argc); break;
case 800: printf("argc=%d", argc); break;
case 1111: printf("argc=%d", argc); break;
case 1531: printf("argc=%d", argc); break;
}
平均值
500
/ \
25 800
/ \
98 1111
/ \
255 1531
switch (argc)
01063C7E mov eax,dword ptr [argc]
01063C81 mov dword ptr [ebp-0C4h],eax
01063C87 cmp dword ptr [ebp-0C4h],1F4h //很明显取个中间值做比较走哪边
01063C91 jg wmain+6Ah (01063CCAh) //大于跳到另一条路
01063C93 cmp dword ptr [ebp-0C4h],1F4h //判断==500
01063C9D je wmain+0FCh (01063D5Ch)
01063CA3 cmp dword ptr [ebp-0C4h],19h //判断==25
01063CAA je wmain+9Fh (01063CFFh)
01063CAC cmp dword ptr [ebp-0C4h],62h //判断==98
01063CB3 je wmain+0DFh (01063D3Fh)
01063CB9 cmp dword ptr [ebp-0C4h],0FFh //判断==255
01063CC3 je wmain+0BFh (01063D1Fh)
01063CC5 jmp wmain+16Eh (01063DCEh) //都不是跳出switch外
01063CCA cmp dword ptr [ebp-0C4h],320h //判断==800
01063CD4 je wmain+119h (01063D79h)
01063CDA cmp dword ptr [ebp-0C4h],457h //判断==1111
01063CE4 je wmain+136h (01063D96h)
01063CEA cmp dword ptr [ebp-0C4h],5FBh //判断==1531
01063CF4 je wmain+153h (01063DB3h)
01063CFA jmp wmain+16Eh (01063DCEh) //都不是跳出switch外
return 0;
01063DCE xor eax,eax |