引言
指针被称为C语言的灵魂,也是令许多初学者头疼的地方,在前一章节中我们讲解到了多级指针,从反汇编角度带大家了解了指针,如果对指针不是很熟悉的话,大家可以取看一看:http://t.csdn.cn/Qw5oi,这一章节来带大家了解函数指针,并且为大家介绍函数指针的一个利用:将代码隐藏到数据区。
我们在正向开发的过程中如果设计了一个功能函数,并且不想他人轻易地通过反汇编来得到我们功能函数的代码,那么我们可以通过将代码隐藏到数据区,这是一种简单的“加密”方式。
函数指针
在学习隐藏代码到数据区之前,我们首先来学习函数指针,因为我们如果要调用隐藏在数据区的函数的话,我们需要通过函数指针来完成。
1.简单了解函数指针
通过函数指针,我们可以做到为一个函数起别名:
例如:
#include<stdio.h> int add(int a,int b); int main(int argc, char* argv[]) { printf("%d",add(3,4)); return 0; } int add(int a,int b){ return a+b; }
在编译运行后我们观察到终端输出了7。我们再来通过函数指针来调用该函数(这里定义函数指针的方法接下来为大家介绍,这里看我操作就OK):
#include<stdio.h> int add(int a,int b); int main(int argc, char* argv[]) { int(*sub)(int,int); sub=&add; printf("%d",sub(3,4)); return 0; } int add(int a,int b){ return a+b; }
这里我们定义一个指针函数,并且把add函数的地址给到函数指针(注意指针类型,如果类型不同,可以通过强制转型进行赋值。
我们通过函数指针sub来调用add函数,发现终端还是输出7。
2. 函数指针的声明:
函数指针的声明方式为:
返回值类型(*函数名)(参数表)
在这里我们拿前面为函数起别名的代码举一个例子:
add函数返回值为int类型,参数表中有两个int类型的数据,那么我们在声明函数指针时,可以这样声明:
int(*sub)(int,int)
在前一张的学习中我们也了解到指针类型在内存中国都是占据4个字节。
隐藏代码到数据区的“骚”操作
在我们逆向学习的过程中,我们知道有些程序是被加了“壳”的,为逆向分析带来了许多困难,而这里的隐藏代码到数据区,如果代码较多,也能为逆向分析带来些许困难,实现对函数的“加密”。
接下我们就来了解一下将代码隐藏到数据区的“骚”操作:
首先来看看没有隐藏的源代码:
#include<stdio.h> int add(int a,int b); int main(int argc, char* argv[]) { printf("%d",add(3,4)); return 0; } int add(int a,int b){ return a+b; }
我们来到反汇编:
55 push ebp 8B EC mov ebp,esp 83 EC 40 sub esp,40h 53 push ebx 56 push esi 57 push edi 8D 7D C0 lea edi,[ebp-40h] B9 10 00 00 00 mov ecx,10h B8 CC CC CC CC mov eax,0CCCCCCCCh F3 AB rep stos dword ptr [edi] 8B 45 08 mov eax,dword ptr [ebp+8] 03 45 0C add eax,dword ptr [ebp+0Ch] 5F pop edi 5E pop esi 5B pop ebx 8B E5 mov esp,ebp 5D pop ebp C3 ret
这里是add函数的反汇编代码和硬编码,我们将这里的硬编码放入一个数组中:
#include <stdio.h> int main(int argc, char* argv[]) { char add[] = { 0X55,0X8B, 0XEC,0X83, 0XEC, 0X40, 0X53,0X56,0X57,0X8D, 0X7D, 0XC0,0XB9, 0X10, 0X00, 0X00, 0X00,0XB8, 0XCC, 0XCC, 0XCC, 0XCC,0XF3, 0XAB,0X8B, 0X45, 0X08,0X03, 0X45, 0X0C,0X5F,0X5E,0X5B,0X8B, 0XE5,0X5D,0XC3, }; int (*sub)(int,int); sub = (int (__cdecl *)(int,int))&add; printf("%d\n",sub(3,4)); return 0; } };
这样隐藏后,在反汇编窗口就无法直接找到add函数了,必须通过数组地址,找到硬编码,再将会硬编码转换至汇编进行分析,在非常庞大的数据量下寻找硬编码也是比较困难的,这样就能做到对代码的很好的隐藏(在计算机看来,代码和数据并无两样,计算机只负责存储)。
通过编译运行我们能够在程序终端看到仍然输出7,可以确定将代码隐藏进了数据区,这里实际上是将硬编码存储进了数据区。
OK今天的总结就到这里,在滴水逆向三期的视频中接下来的两节分别为位运算和内存分配,文件读写,我们就不在博客中介绍了,下一节我们就将进入逆向的入门学习:PE头解析。
最后,非常希望大家可以指出此篇笔记的不足或者错误之处,当然希望我们能够共同学习,共同进步!!!