巩固C语言(十)----指针数组 & 函数指针和指针函数

来源:互联网 发布:php 网盘 程序 编辑:程序博客网 时间:2024/05/20 13:37

1 利用指针数组实现多个函数劫持技术

#include<stdio.h>#include<stdlib.h>#include<windows.h>#include"detours.h"#pragma comment(lib, "detours.lib")int newAdd(int a, int b)//static文件只能限制在本文件使用{printf("+++++++\n");return a + b;}int newMinis(int a, int b){printf("-----------\n");return a - b;}int newMulti(int a, int b)//函数名是一个常量地址{printf("***********\n");return a*b;}int newDel(int a, int b){printf("///////////");return a / b;}int add(int a, int b)//static文件只能限制在本文件使用{return a + b;}int minis(int a, int b){return a - b;}int multi(int a, int b)//函数名是一个常量地址{return a*b;}int del(int a, int b){return a / b;}static int(*OldFunction[4])(int, int) = { add, minis, multi, del };//被劫持函数数组int(*NewFunction[4])(int, int) = { newAdd, newMinis, newMulti, newDel };//劫持函数数组//开始拦截void Hook(){DetourRestoreAfterWith();//恢复原来的状态DetourTransactionBegin();//拦截开始DetourUpdateThread(GetCurrentThread());//刷新当前线程//这里可以连续多次调用DetourAttach,表明Hook多个函数for (int i = 0; i < 4; i++)DetourAttach((void**)&OldFunction[i], NewFunction[i]);//实现函数拦截, 如果想拦截多个指令,只需添加多个拦截函数即可DetourTransactionCommit();//拦截生效}void main()//函数名实际上保存着这个函数的地址{int(*p)(int a, int b) = add;//函数指针printf("1 + 2 = %d\n", add(1, 2));p = minis;printf("1 - 2 = %d\n", minis(1, 2));Hook();//开始劫持int(*pp[4])(int a, int b) = { add, minis, multi, del };//函数指针数组,注意函数的返货类型要一致for (int i = 0; i < 4; i++){printf("%d\n", pp[i](10, 2));}system("pause");}
运行结果:主函数中的函数被替换为自己定义的函数。

2 函数指针和指针函数

以下内容引自<http://blog.csdn.net/htyurencaotang/article/details/11490081>

辨别指针函数与函数指针最简单的方式就是看函数名前面的指针*号有没有被括号包含,如果被包含就是函数指针,反之则是指针函数。

2.1 指针函数

指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针
类型标识符 *函数名(参数表)int *f(x,y); 
首先它是一个函数,只不过这个函数的返回值是一个地址值。指针函数一定有函数返回值,而且在主调函数中,函数返回值必须赋给同类型的指针变量。例如
float *fun();float *p;p = fun(a);

当一个函数声明其返回值为一个指针时,实际上就是返回一个地址给调用函数,以用于需要指针或地址的表达式中。
由于返回的是一个地址,所以类型说明符一般都是int。例如:
int *GetDate();int * aaa(int,int);

2.2 函数指针

函数指针是指向函数的指针变量,即本质是一个指针变量。
int (*f)(int x); /*声明一个函数指针 */f=func; /*将func函数的首地址赋给指针f */
指向函数的指针包含了函数的地址,可以通过它来调用函数。声明格式如下:
类型说明符 (*函数名)(参数)
例如:
void (*fptr)();
把函数的地址赋值给函数指针,可以采用下面两种形式:
(1)fptr = &Function;(2)fptr = Function;
取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址。
如果是函数调用,还必须包含一个圆括号括起来的参数表。
通过指针调用函数,可以采用如下两种方式:
(1)x=(*fptr)();(2)x=fptr();

第二种格式看上去和函数调用无异,但是有些程序员倾向于使用第一种格式,因为它明确指出是通过指针而非函数名来调用函数的。下面举一个例子:
void (*funcp)();void FileFunc(),EditFunc();main(){  funcp = FileFunc;  (*funcp)();  funcp = EditFunc;  (*funcp)();}void FileFunc(){  printf(FileFunc\n);}void EditFunc(){  printf(EditFunc\n);}
运行结果:
FileFuncEditFunc


3 劫持函数

#include<stdio.h>#include<stdlib.h>#include<Windows.h>void printf1(){printf("11111");}void printf2(){printf("22222");}void printf3(){printf("33333");}void newprintf1(){MessageBoxA(0, "11111", "11111", 0);}void newprintf2(){MessageBoxA(0, "22222", "22222", 0);}void newprintf3(){MessageBoxA(0, "33333", "33333", 0);}void  main(){void(*p[3])() = { printf1, printf2, printf3 };//函数指针数组printf("%p", p);//数组的地址void(*px[3])() = { newprintf1, newprintf2, newprintf3 };for (int i = 0; i < 3; i++){printf("\n%p", px[i]);//打印三个函数的地址}while (1){for (int i = 0; i < 3; i++){printf("\n");p[i]();//挨个调用函数printf("\n");}Sleep(3000);}}void main1(){void(*p)() = printf1;printf("\n%p", &p);printf("\n%p,%p", printf1, newprintf1);//打印地址while (1){printf("\n");p();Sleep(3000);}}

劫持模块
#include<stdlib.h>#include<stdio.h>//导出函数,可以加载的时候调用_declspec(dllexport)  void go(){//改变一个变量,需要变量的地址//改变一个指针,需要指针的地址void(**p)() = (void(**)())0x2af8ac;*p =(void(*)()) 0x2d1010;}_declspec(dllexport)  void go1(){void(*p[3])(); //指针数组,批量管理函数地址p[0] = 0x291030;p[1] = 0x291050;p[2] = 0x291070;void(**pp)() = 0x22fa54;//for (int i = 0; i < 3; i++){*(pp+i) = p[i];//批量改变指针}}




0 0