首页 > 其他分享 >C语言逆向——switch语句中的大表和小表,本质上是内在存储空间降低

C语言逆向——switch语句中的大表和小表,本质上是内在存储空间降低

时间:2023-04-03 16:00:09浏览次数:35  
标签:小表 default 跳转 esp C语言 switch ebp printf mov

连续值中抹去多项

CPP代码:

#include "stdafx.h"
void Fun(int x) {
	switch (x) {
		case 100:
			printf("100");
			break;
		case 101:
			printf("101");
			break;
		case 102:
			printf("102");
			break;
		case 106:
			printf("106");
			break;
		case 108:
			printf("108");
			break;
		case 112:
			printf("112");
			break;
		case 115:
			printf("115");
			break;
		default:
			printf("None");
			break;
	}
}

int main(int argc, char* argv[]) {
	Fun(110);
	return 0;
}

反汇编:

Fun:
0040D7E0   push        ebp
0040D7E1   mov         ebp,esp
0040D7E3   sub         esp,44h
0040D7E6   push        ebx
0040D7E7   push        esi
0040D7E8   push        edi
0040D7E9   lea         edi,[ebp-44h]
0040D7EC   mov         ecx,11h
0040D7F1   mov         eax,0CCCCCCCCh
0040D7F6   rep stos    dword ptr [edi]
0040D7F8   mov         eax,dword ptr [ebp+8]
0040D7FB   mov         dword ptr [ebp-4],eax
0040D7FE   mov         ecx,dword ptr [ebp-4]
0040D801   sub         ecx,64h
0040D804   mov         dword ptr [ebp-4],ecx
0040D807   cmp         dword ptr [ebp-4],0Fh
0040D80B   ja          $L545+0Fh (0040d888)
0040D80D   mov         eax,dword ptr [ebp-4]
0040D810   xor         edx,edx				;edx清零
0040D812   mov         dl,byte ptr  (0040d8c6)[eax]	;dl=[小表地址+eax] ==>没有看懂。。。todo
0040D818   jmp         dword ptr [edx*4+40D8A6h]
$L533:
0040D81F   push        offset string "102" (00422fb4)
0040D824   call        printf (0040d760)
0040D829   add         esp,4
0040D82C   jmp         $L545+1Ch (0040d895)
$L535:
0040D82E   push        offset string "1003\n" (00422fd8)
0040D833   call        printf (0040d760)
0040D838   add         esp,4
0040D83B   jmp         $L545+1Ch (0040d895)
$L537:
0040D83D   push        offset string "109" (00422fac)
0040D842   call        printf (0040d760)
0040D847   add         esp,4
0040D84A   jmp         $L545+1Ch (0040d895)
$L539:
0040D84C   push        offset string "1009\n" (00422fd0)
0040D851   call        printf (0040d760)
0040D856   add         esp,4
0040D859   jmp         $L545+1Ch (0040d895)
$L541:
0040D85B   push        offset string "108" (00422fa4)
0040D860   call        printf (0040d760)
0040D865   add         esp,4
0040D868   jmp         $L545+1Ch (0040d895)
$L543:
0040D86A   push        offset string "109" (00422fc8)
0040D86F   call        printf (0040d760)
0040D874   add         esp,4
0040D877   jmp         $L545+1Ch (0040d895)
$L545:
0040D879   push        offset string "115" (00422fc0)
0040D87E   call        printf (0040d760)
0040D883   add         esp,4
0040D886   jmp         $L545+1Ch (0040d895)
0040D888   push        offset string "error\n" (00422f6c)
0040D88D   call        printf (0040d760)
0040D892   add         esp,4
0040D895   pop         edi
0040D896   pop         esi
0040D897   pop         ebx
0040D898   add         esp,44h
0040D89B   cmp         ebp,esp
0040D89D   call        __chkesp (004010a0)
0040D8A2   mov         esp,ebp
0040D8A4   pop         ebp
0040D8A5   ret

Memory:

;大表
0040D8A6  1F D8 40 00  .谸.
0040D8AA  2E D8 40 00  .谸.
0040D8AE  3D D8 40 00  =谸.
0040D8B2  4C D8 40 00  L谸.
0040D8B6  5B D8 40 00  [谸.
0040D8BA  6A D8 40 00  j谸.
0040D8BE  79 D8 40 00  y谸.
0040D8C2  88 D8 40 00  堌@.
;小表
0040D8C6  00 01 02 07  ....
0040D8CA  07 07 03 07  ....
0040D8CE  04 07 07 07  ....
0040D8D2  05 07 07 06  ....

小表的解释:

  • 当空缺值太多时内存的浪费也会变多,编译器当然知道这样不是办法,所以利用小表来解决这个问题。小表可以看作是一个智能蹦床,对于不同的玩家会给出不同的力,遇到没有付费的玩家(空缺值)直接将他抛出场外(给出参数,使其跳转到default的语句块),遇到付费玩家(存在的值)则按照他的等级给出不同的力(给出参数,使其跳转到其对应的语句块)

  • 可以看出,在小表中所有的空缺值都是07(因为在这个样例中,当edx=7[edx*4+40D8A6h]的地址为default语句块的地址),而存在的值的对应值从0递增。

 

断开一定程度的选择

在这里插入图片描述

在这里插入图片描述
关键点

mov dl,byte ptr (004010d0)[eax]

jmp dword ptr [edx4+4010BCh]
(004010d0)[eax] = [004010d0 + eax
4] 在这个地址中得到一个偏移 作为查询大表的edx值。==》内在原理是啥???再度深入思考了下,其实很简单!上面switch case 302~307缺失,如果使用大表查询的话,则需要在大表里填充6个default地址,如果缺失的量比较大,则造成地址空间的浪费,假如100个,则这100个都是default都浪费啊。

如何降低这些浪费的空间呢?很直观的思路就是大表里只需要存一个default,编译器的做法是使用用小表去记录跳转。也就是上面dl(0-255)mov语句,记录了跳转的case清单,小表里可以记录0-255内的跳转,这样就节省了一些空间。

也就是说,小表里记录:

case1 跳转小偏移1

case2 跳转小偏移2

case3 跳转小偏移3

...

对于上面那种6个default的跳转场景:

 

case302 default跳转小偏移

 

case302 default跳转小偏移

 

case303 default跳转小偏移

case304 default跳转小偏移

case305 default跳转小偏移

case306 default跳转小偏移

 

...

 

这样最后跳转的时候,就直接先通过小表查询到跳转的小偏移(2个字节),然后大表里就只需要一个default地址(4个字节)即可了。而不再像原来那样,需要大表里6个default地址了。

 

我们计算下节省的空间,

仅大表的方式存储空间:6x4=24 字节

小表+大表结合的方式:6x2+4=16字节

还是节省了8个字节。

 

标签:小表,default,跳转,esp,C语言,switch,ebp,printf,mov
From: https://www.cnblogs.com/bonelee/p/17283322.html

相关文章

  • 汉源高科INDGS2280-WEB千兆2光8电工业级环网交换机Web Smart Switch
     INDGS2280-WEB是汉源高科(北京)科技有限公司自主研发的一款专门针对工业控制领域的工业级环网交换机产品,该产品支持国际标准IEEE802.3D/W/S标准的STP/RSTP/MSTP协议,以及丰富的网管功能,可以提供的稳定可靠的以太网传输,具有高质量的设计和可靠性。可为用户提供并实现高效带宽、可靠......
  • C语言itoa函数
    一、atoi()函数atoi()是C语言中的字符串转换成整型数的一个函数(1)【头文件】#include<stdlib.h>(2)【函数原型】intatoi(constchar*str);(3)【函数说明】atoi()函数会扫描参数str字符串,跳过前面的空白字符(例如空格,tab缩进等),直到遇上数字或正负符号才开始做转换,而再遇到非......
  • C语言-变量的存储类型
    0存储类型是指变量占用内存空间的方式,也称为存储方式。从内存分配的时间上,可分为“静态存储”和“动态存储”类。  0.1静态存储:在程序前,系统(编译器)自动分配内,程序结束后,系统(编译器)自动释放。  0.2动态存储:在程序执行时;根据需要手动分配内存,使用完成后再手动释放。1C......
  • C语言,str系列函数
     1、strcat()此函数原型为char*strcat(char*dest,constchar*src).功能为连接两个字符串,把src连接到dest后面;返回dest地址//函数实现char*strcat(char*dest,constchar*src){char*addr=dest;while(*dest)//找到'\0'{dest++;};......
  • 逍遥自在学C语言 | 变量、常量与数据类型
    前言一、人物简介第一位闪亮登场,有请今后会一直教我们C语言的老师——自在。第二位上场的是和我们一起学习的小白程序猿——逍遥。二、基本数据类型1、整型C语言中的整型数据如下表所示:数据类型含义长度(字节)取值范围(有符号)取值范围(无符号)shor......
  • C语言逆向——数组和结构体,数组多维只是一个编译构造的假象,本质会转成一维数组,结构体
    数组数组是C语言中非常重要的一个概念,学习C语言主要就是两个知识点:数组、指针,学好这两个,那么你的C语言一定也会很好。什么是数组?或者说什么情况下我们需要使用数组,比如说我们需要定义一个人的年龄,我们可以定义一个变量来表示,但是如果我们需要定义三个人的年龄呢?那就需要三个变......
  • C语言逆向——循环语句
    循环语句循环语句的反汇编如下图是各个循环语句的反汇编代码:但从汇编来看我们可以看得出do...while循环语句效率是最高的,但是在日常使用来说大部分会选择使用for与while,do...while出现的较少,还是跟之前我们说的一样,这一点空间可以忽视不管,for语句是最方便书写的,也就是我们可......
  • C语言逆向分析——Switch语句,为何大多数情况较if语句更高效?就是因为查找表
    Switch语句Switch语句也是分支语句的一种,其语法如下:switch(表达式){case常量表达式1:语句;break;case常量表达式:语句;break;case常量表达式:语句;break;......default:语句;break;}需要注意如下几点:表达式结束不能是浮点数case后的......
  • 学习C语言的第四天
    继续进行上一次的数组。一,数组1.1数组作为函数的参数  #include<stdio.h>voidprintArr(intarry[3])//形参中不存在数组的概念,即便中括号约定了数组的大小,也无效//传递是一个地址,是数组的首地址{inti;for(i=0;i<3;i++){......
  • 逆向——C语言的汇编表示之堆栈图 手把手示例 可以考虑在函数内部加一个局部变量来综
    课程概要来自:https://gh0st.cn/Binary-Learning/C%E8%AF%AD%E8%A8%80.html写得非常详细本章课程需要具备汇编语言基础,若无汇编语言基础是无法去理解课程中所讲的一些知识点和技术细节的;同时也表示本课程是以汇编语言来理解C语言,透过本质理解高级语言。关于本节课的环境:VC6,VC6......