您的位置:首页 > 编程语言 > C语言/C++

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

2016-04-18 21:28 615 查看

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);
}
运行结果:
FileFunc
EditFunc


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];//批量改变指针

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: