c语言强化训练笔记2010/5/9
函数指针
下面是关于函数指针的一些资料
函数指针是指向函数的指针变量。
因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上是一致的。函数指针有两个用途:调用函数和做函数的参数。函数指针的声明方法为:
数据类型标志符 (指针变量名) (形参列表);
我们通过(*(int far *)+地址)这样的代码实现了访问任意一段内存的数据,那么可以通过函数指针实现执行任意一段代码
首先在debug下用a命令在一段安全的空间中写入一段程序,然后用u命令反汇编得到这段程序的机器码
C:\minic>debug
-a 0:200
0000:0200 mov ax,b800
0000:0203 mov es,ax
0000:0205 es:
0000:0206 mov byte ptr [0690],61
0000:020B retf
0000:020C
-u 0:200
0000:0200 B800B8 MOV AX,B800
0000:0203 8EC0 MOV ES,AX
0000:0205 26 ES:
0000:0206 C606900661 MOV BYTE PTR [0690],61
0000:020B CB RETF
在c语言编写程序,将这段机器码写入到一个数组中,然后在main函数中将数组拷贝到0:200这段安全的空间中,再定义一个指向0:200的函数指针,通过调用函数指针来执行数组中的这一段程序
void (far *p)(); char a[20]={0xb8,0x00,0xb8,0x8e,0xc0,0x26, 0xc6,0x06,0x90,0x06,0x61,0xcb}; main() { int n; for(n=0;n<20;n++) ((char far *)0x200)[n]=a[n]; p=(void (far *)())0x200; p(); }
上面这个程序并没有定义函数,而是通过函数指针调用了一段空间中的程序
可以改进这个程序,不需要将数组中的机器码拷贝到安全空间中,只要直接调用数组的首地址就可以
char a[20]={0xb8,0x00,0xb8,0x8e,0xc0,0x26, 0xc6,0x06,0x90,0x06,0x61,0xcb}; main() { void (far * p)(); p = (long)a; p(); }
既然变量本质是某块内存空间的名称,那么可以省略函数指针变量p,直接使用地址来调用数组中的程序
char a[20]={0xb8,0x00,0xb8,0x8e,0xc0,0x26, 0xc6,0x06,0x90,0x06,0x61,0xcb}; main() { ((void (far *)())(long) a)(); }
还可以做的更简单
char main[20]={0xb8,0x00,0xb8,0x8e,0xc0,0x26, 0xc6,0x06,0x90,0x06,0x61,0xc3};