当前位置: 首页 > 科技 > 人工智能 > 极其方便的多极指针读取封装_腾讯新闻

极其方便的多极指针读取封装_腾讯新闻

天乐
2020-06-12 05:17:18 第一视角

我想你或许写过这样的代码:

a = *(DWORD*)(a+0xXX);

a = *(DWORD*)(a+0xXX);

a = *(DWORD*)(a+0xXX);

或者这样的:

DWORD a = NULL;

ReadProcessMemory(hProcess, (DWORD*)(a), &a, sizeof(DWORD), 0);

ReadProcessMemory(hProcess, (DWORD*)(a+0xXX), &a, sizeof(DWORD), 0);

ReadProcessMemory(hProcess, (DWORD*)(a+0xXX), &a, sizeof(DWORD), 0);

ReadProcessMemory(hProcess, (DWORD*)(a+0xXX), &a, sizeof(DWORD), 0);

ReadProcessMemory(hProcess, (DWORD*)(a+0xXX), &a, sizeof(DWORD), 0);

如果你为这玩意烦恼过,下面的代码或者思路或许可以帮到你。

后面写出的代码可以如这样般简洁:

让我们来看看代码:

XyGet.h

#include

void F输出调试信息(char *pszFormat, ...);

DWORD xyGet(char*szpCHAR,int index,DWORD nd基质,DWORD nd中间值);

template

DWORD xyGet(char*szpCHAR,int index,DWORD nd基质,DWORD nd中间值,int ndIndex,const Types&...args)

{

__try

{

return xyGet(szpCHAR,index,nd基质, *(DWORD*)(nd中间值 +ndIndex),args...);

}

__except (1)

{

F输出调试信息("%sxyGet,基址:%4X 第%d层偏移:%X 读取异常\r\n",szpCHAR,nd基质,index -sizeof...(args) + 1,ndIndex);

return 0;

}

}

template

DWORD xyGet(char*szpCHAR,DWORD nd基质,const Types&...args)

{

__try

{

//int ndIndex =

return xyGet(szpCHAR, (int)sizeof...(args),nd基质, *(DWORD*)nd基质,args...);

}

__except (1)

{

F输出调试信息("%sxyGet,基址:%4X 异常!请传入有效基地址\r\n",szpCHAR,nd基质);

return 0;

}

}

template

DWORD xyGet(DWORD nd基质,const Types&...args)

{

return xyGet("调试头",nd基质,args...);

}

xyGet.cpp

#include "xyGet.h"

void F输出调试信息(char *pszFormat, ...)

{

#ifdef _DEBUG

char szbufFormat[0x1000];

char szbufFormat_Game[0x1100] ="";

va_list argList;

va_start(argList,pszFormat);

vsprintf_s(szbufFormat,pszFormat, argList);

strcat_s(szbufFormat_Game, szbufFormat);

OutputDebugStringA(szbufFormat_Game);

va_end(argList);

#endif

}

DWORD xyGet(char*szpCHAR,int index,DWORD nd基质,DWORD nd中间值)

{

return nd中间值;

}

使用方法第一个参数传入基地址,后面跟任意多个偏移

使用了C++ 11的新特性,任意类型任意个数的函数模板,如果你的编译器无法通过编译,或许需要手动开启C++ 11,如下。

PS:需要一些C++理论知识。

首先4个重载函数和我们的例子匹配度最高的肯定是:

第一步:

template

DWORD xyGet(DWORD nd基质,const Types&...args)

{

return xyGet("调试头",nd基质,args...);

}

我们看它接受什么参数,一个DWORD 和const Types&...args(一包东西)

然后调用了另外一个重载函数,第一个参数传入了一个字符串,然后把剩下2个参数原封不动的传入。为什么?主要我是担心我的程序出异常,指针读取非常危险的动作,我们必须时刻小心,所以传入一个调试头 ,以便出异常方便使用Dbgview捕捉异常所打印的信息,以此知道我们的程序 在读取那一个基地址 那一级偏移 产生了错误。如

接下来显而易见的程序走到了这,

第二步:

template

DWORD xyGet(char*szpCHAR,DWORD nd基质,const Types&...args)

{

__try

{

//int ndIndex =

return xyGet(szpCHAR, (int)sizeof...(args),nd基质, *(DWORD*)nd基质,args...);

}

__except (1)

{

F输出调试信息("%sxyGet,基址:%4X 异常!请传入有效基地址\r\n",szpCHAR,nd基质);

return 0;

}

}

接收一个字符串,一个DWORD,还有一包东西,嗯100%匹配,看看它做了什么处理。

调用了重载函数,传入一个字符串原封不动,计算一包东西还有多少个,DWORD基地址,把基地址里面的值读取出来传入,还有一包东西。

有什么参数?Char* int DWORD DWORD加args...(一包东西)

好像现在没有完美匹配的重载函数了,是的。但是编译器非常聪明,它把那一包东西拆解一下,变成char* int DWORD DWORD int加args...(一包东西) 显而易见的:

第三步:

DWORD xyGet(char*szpCHAR,int index,DWORD nd基质,DWORD nd中间值,int ndIndex,const Types&...args)

{

__try

{

return xyGet(szpCHAR,index,nd基质, *(DWORD*)(nd中间值 +ndIndex),args...);

}

__except (1)

{

F输出调试信息("%sxyGet,基址:%4X 第%d层偏移:%4X 读取异常\r\n",szpCHAR,nd基质,index -sizeof...(args) + 1,ndIndex);

return 0;

}

}

看它干了什么,再次调用了重载函数。前3个参数原封不动的传入,但是传入的第4个参数是什么?

nd中间值 是什么?没记住的去看第二步,它基地址里面读取出来的值把,ndIndex又是什么?它是那一包东西中的第一个数值,那一包东西是什么?可以去看第一步 一包东西 是那一堆偏移,显然我们读取了一层偏移。

看看我们现在传入调用函数什么东西:char* int DWORD DOWRD加 一包东西。很熟悉把,和第三步一样 编译器有会从一包东西里面取一样东西出来 变成char* int DWORD DWORD int加args...(一包东西)

那么很明显又会调用第三步的那货:

DWORD xyGet(char*szpCHAR,int index,DWORD nd基质,DWORD nd中间值,int ndIndex,const Types&...args)

程序陷入了递归循环,什么时候结束呢?一包东西一个一个的取出来,总有一次递归会取干净。那么传入重载函数的参数会变成:szpCHAR,index,nd基质, *(DWORD*)(nd中间值 +ndIndex)

也就是char* int DWORD DWORD ,这一堆参数有完美匹配的重载函数:

DWORD xyGet(char*szpCHAR,int index,DWORD nd基质,DWORD nd中间值)

{

return nd中间值;

}

看看他内部做了什么:

哦,直接返回了nd中间值,如果一包东西被消耗干净了,那么说明所有的偏移都被读取完毕,没错 这里返回了我们要的东西。

总结

本文章所提到的思路以及代码,是我在学习C++ 11新特性时 无意想到的,相对于C++ 98的半成品产品,C++ 11新标准明显更现代更经典更好用。

提示:支持键盘“← →”键翻页
为你推荐
加载更多
意见反馈
返回顶部