1、恶意软件逆向分析系列一恶意软件逆向分析系列(一):在汇编语言中识别重要的代码结构老王隔壁的白帽子2016-04-14+5共69620人围观,发现9个不明物体网络安全这一系列的文章都是与恶意软件相关的课程,因此我们首先从PE和ELF文件的完整结构讲起。另一个比较重要的概念就是这些恶意程序是通过可理解的汇编代码执行的,而这些不同的代码在二进制层面的架构如何呢?在这篇文章中,我们将在汇编层面认识代码结构。注意:这篇文章的受众人群默认是对汇编语言有一定的掌握。如果基础不好的好也不必担心,我会以最简单方式来解释这些东西。变量范围代码中声明的用于保存常量或者字符串的东西叫做变量。变量的范围可以是全局变量也
2、可以是局部变量。局部变量保存的是函数内部的值而全局变量可以在代码逻辑中的任何地方使用。当我们深入汇编代码的时候,全局变量表示的都是一些内存的地址,反之局部变量表示的是寄存器ebp的偏移值 。对于不熟悉汇编语言开始的人,汇编语言函数开头的指令类似这样:push ebpmov ebp,espebp设置新的函数的栈帧,第二条指令将ebp设置为基址。由于栈的生长方式是向上地址递减,这就意味着局部变量可以通过类似mov eax,ebp-4存取,即将ebp-4内的四个字节移动至eax中。局部变量由于不隶属于任意函数,所以如果通过ebp是无法引用这些变量的,而全局变量是指向的是内存地址,例如mov eax,
3、dword_50CF60,全局变量地址为0x50CF60。条件语句If条件语句经常在代码中使用到。一个基本的if条件语句如下:对应的汇编代码如下:mov ebp + var-4,1mov ebp+var_8,2mov eax,ebp+var_4cmp eax,ebp+var_8jnz short loc_50101Bpush offset aequalsb;”a & b are equaln”Push offset anotequalb;”a & b are not equal”注意cmp和jnz-compare、jump if no zerm指令对应于代码中的if(a=b)。Cmp指令表示减
4、去操作。因此,意思是比较两个变量,如果不相等则跳转至这个内存地址处,并且打印字符串”a&b are not equal”,否则的话,如果变量相等,jnz指令将会被跳过,接着打印字符串”a&b are equal”。如果内嵌多条if语句,你将会看到多个cmp,jnz/jz,接着在cmp后续会打印字符串或者其他的操作。循环代码逻辑中的循环语句是用来迭代一些操作,并且一直执行到某一个条件满足为止。For循环是经常被使用到的。对于For循环搞清楚这4件事:初始化,比较,执行,增加/减少。for(int i=0;i=(i=10)。如果不是则值被打印出来再递增。这整个过程再继续一遍。While循环语句在代
5、码中可以很轻易被追踪到。例如:int i=0;while(i10)printf(“current value of I is %dn”,i)i+;汇编语言Mov ebp+var_4, 0Jmp short loc_12345Loc_123456:mov eax, ebp+var_4add eax,1mov ebp_var_4,eaxLoc_102345:cmp ebp+var_4,Ahjge short loc_234567mov ecx,ebp+var_4push ecxpush offset iValue,” current value of I is %dn”add esp,8jmp l
6、oc_1023456可以看到While循环的汇编代码,和for循环类似。Switch 语句Switch case 经常被程序使用到,通过值来进行判定。例如:Switch(i)Case 1:Printf(“Current Value of I is %dn”,i+1);break;Case 2:Printf(“Current Value of I is %dn”,i+1);break;Case 3:Printf(“Current Value of I is %dn”,i+1);break;Case 4:Printf(“Current Value of I is %dn”,i+1);break;d
7、efault:break;汇编代码语言中看起来像是一系列的if语句,因为在刚开始的阶段可以看到很多cmp和jmp指令。当这些case没有按照顺序例如case 1 ,case12,case17等等,在这种情况下,汇编代码中就会出现很多if-else语句。变量会紧跟在case1,case2,case3等后面。编译器进行简单的优化如下:Mov ecx,ebp+var_4Sub ecx,1cmp ebp+var_8,3ja loc_12345mov edx,ebp+var_8jmp short loc_987650edx*4loc_234564:.Jmp loc_12345:loc_234565:.J
8、mp loc_12345:loc_234566:.Jmp loc_12345:loc_234567:.Jmp loc_12345:loc_12345:/ 清楚栈代码loc_987650offset loc_234564 /jump tableoffset loc_234565offset loc_234566offset loc_234567在这里都发生了些什么呢。首先我将相似内存地址的都进行了颜色标示(希望有所帮助!)。初始化case变量,例如“i”,保存在ecx,然后和1相减,为什么呢,这里用到一些跳转表的概念,编译器优化这些代码的时候采用这张跳转表,跳转表中存放的是这些不同case值的地址。因此ecx需要递减1,因为它是作为偏移指针指向这些开始位置为0的跳转表。最大的case最先比较是因为,这个case是默认的设置的case。对于其他变量,将会在跳转表中设置成偏移值。这篇只是描述一些代码中最基本的特征。在第二部分会讨论一些复杂的结构像数组、结构体和链表。*参考来源:infosecinstitute ,FB小编老王隔壁的白帽子翻译,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1