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

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




}




你可能感兴趣的:(技术,C语言,指针,函数劫持,函数拦截)