滴水逆向 03-06 指针8
指针的本质是什么?指针指向什么跟它本身是什么没有任何关系,比如结构体指针并不是非得指向一个结构体,数组指针也不是非得指向指定长度或者类型的数组,指针就是指针,我们想让它指啥就指啥,指针只是一个用来操作数据的工具。
指针的本质海哥概括为以下六条:
1、它是一个类型,是前面带 * 的,带几个都行
2、它的宽度都是 4
3、它可以做 ++\-- 的运算,到底加几减几看砍掉一个 * 后的宽度
4、与一个整数相加或相减
5、可以比较大小
6、两个指针可以相减,相减后的结果也要除以砍掉一个 * 后的宽度
是曰:除了以上以外,其余全是扯。
数组指针
一维、二维、三维数组指针:
1 |
|
n 维数组指针访问 m 维数组:
1 | //一维数组指针访问一维数组 |
函数指针
-
函数指针的声明
返回类型(*函数名)(参数表),如int (*pFun)(int,int) -
函数指针的属性探测
1
2
3
4
5
6
7
8
9
10int main(int argc, char* argv[]) {
int (*pFunc)(int, int);
//宽度探测
printf("%d\n", sizeof(pFunc)); //4
pFunc = (int (__cdecl *)(int,int))10; //默认__cdecl,删掉这么写也可以(int (*)(int,int))
//++-- +-整数 相减
pFunc++;
printf("%d\n", pFunc); //函数的宽度是不确定的(多写几句内存大小也会跟着变),所以这些都是编译不过去的
//大小比较可以做,就不演示了
} -
函数指针的赋值
pFun = (int (*)(int,int))10或者pFun = 函数名。
虽然编译的时候可以通过强制转型编译通过,但是运行的时候就会挂了,因此如果想要让这个函数指针有意义,那么就必须给它赋值一个格式跟它一样的函数,包括返回值和参数的个数与类型,比如函数指针声明的返回值是 void,那赋值的函数也得是 void,如果包含两个 int 参数,那么赋值的函数也得是有俩 int 参数的 -
函数指针的使用
1
2
3
4
5
6
7
8
9
10int Function(int x,int y) {
return x + y;
}
int main(int argc,char* argv[]) {
int (*pFun)(int,int);
pFun = Function;
int sum = pFun(1,2);
printf("%d",sum); //1+2=3
return 0;
}与函数的使用方式是相同的。那既然都一样这东西还有啥用呢?课上简单提了一嘴,调用dll时要用到,以我薄弱的功底此前没有接触过此方面,等后面学到再说吧,还有就是隐藏函数代码到数据区时也会用,下面会讲到。
-
隐藏代码到数据区
代码和数据本质上是没有区别的,都是一堆存储在内存中的二进制数,使用硬编码展示,所以如果知道了硬编码,也就可以还原出来函数,VC 就是这么做的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28//Function的硬编码
unsigned char code[] = {
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 main(int argc, char* argv[]) {
int (*Fun)(int,int);
Fun = (int (*)(int,int))&code;
int x = p(2,3);
printf("%d\n",x); //5
return 0;
}这东西有啥用?如果你想写一个壳来保护你的程序,你去把你自己写的所有的函数都抠出来,放到一个你自己定义的数组里(数据区),然后再对这个数组做做手脚,再把原来存储这些函数的地方全部变成 0,就可以给想要逆你程序的人上难度!
课后作业
-
下列说法是否正确?为什么?
1
2
3
4指针的指针:就是指向指针的指针
结构指针:就是指向结构的指针
数组指针:就是指向数组的指针
函数指针:就是指向函数的指针错!指针就是指针,想让它是啥就是啥,想让它指啥就指啥
-
将一个函数存储到数据区,通过指针进行访问
写一个x*y的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37// 222.cpp : Defines the entry point for the console application.
//
/*int Function(int x, int y) {
return x*y;
}*/
unsigned char code[] = {
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,
0x0F, 0xAF, 0x45, 0x0C,
0x5F,
0x5E,
0x5B,
0x8B, 0xE5,
0x5D,
0xC3
};
int main(int argc, char* argv[]) {
int (*pFun)(int,int);
pFun = (int (*)(int,int))&code;
int sum = pFun(2,3);
printf("%d",sum);
return 0;
}运行后输出是 6
-
char 数组内容如下:
1
2
3
4
5
6
7
8
9
100x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x07,0x09,
0x00,0x20,0x10,0x03,0x03,0x0C,0x00,0x00,0x44,0x00,
0x00,0x33,0x00,0x47,0x0C,0x0E,0x00,0x0D,0x00,0x11,
0x00,0x00,0x00,0x02,0x64,0x00,0x00,0x00,0xAA,0x00,
0x00,0x00,0x64,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x02,0x00,0x74,0x0F,0x41,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0A,0x00,
0x00,0x02,0x74,0x0F,0x41,0x00,0x06,0x08,0x00,0x00,
0x00,0x00,0x00,0x64,0x00,0x0F,0x00,0x00,0x0D,0x00,
0x00,0x00,0x23,0x00,0x00,0x64,0x00,0x00,0x64,0x00指针定义如下:
1
2
3
4int (*px)[2];
int (*py)[2][3];
char (*pz)[2];
char (*pk)[2][3];不运行说出下面结果:
*(*(px+0)+0):0x00*(*(px+1)+0):1*(2*4)+0=8往后数 8 个,int 取 4 字节0x07 0x09 0x00 0x20,小端序0x20000907*(*(px+2)+3):2*(2*4)+3*4=28往后数 28 个,int 取 4 字节0x00 0x11 0x00 0x00,小端序0x1100*(*(*(py+1)+2)+3):1*(2*3*4)+2*(3*4)+3*4=60往后数 60 个,int 取 4 字节0x01 0x00 0x00 0x00,小端序0x01*(*(pz+2)+3):2*(2*1)+3*1=7往后数 7 个0x07*(*(*(pk+2)+3)+4):2*(2*3*1)+3*(3*1)+4*1=25往后数 25 个0x0E