-
-
[分享]自己制作了一个下函数钩子的程序,可以用于单元测试中的替身制作也可以用于逆向分析
-
发表于: 2018-5-16 20:19 2536
-
最近看了java单元测试书,知道有一章说替身问题,测试里使用替身可解决很多不需要的初始化和环境构建降低复杂度,和实现自动化测试有不小意义.随后我翻了下vs2013(我现在使用的环境)有vc++支持的原生单元测试但是没有提供这个接口只有托管代码可以类似的功能.没有查到相关功能.在百度上也搜不到相关知识.
在windows下没有不可能,那么就造一个轮子吧:
/***********************************************************************************************************************
*结构名:JMPBYTE
*功能:换掉需要替身函数用自己便于的函数去实现通过写入目标地址实现跳转
*变量;jmpcode就是跳转指令
*变量:jmptag就是跳转地址
*构造函数:无参数的直接将跳转头设置E9(jmp指令)地址设置0
*有构造函数:通过给定地址直接计算出需要的函数地址可以直接通过复制指令将指令复制到目标地址
***********************************************************************************************************************/
#include <map>
#include "memoryapi.h"
using std::map;
#pragma pack(1)//1个字节对齐下钩子的数据结构,这边我jmp指令有经验的同学可以自行修改
typedef struct JMPBYTE
{
JMPBYTE(){ jmpcode = 0xe9; jmptag = 0; }
JMPBYTE(void * fromaddress, void * toaddress)
{
jmpcode = 0xe9;
jmptag = (void *)((char *)toaddress - (char *)fromaddress - sizeof(JMPBYTE));
}
unsigned char jmpcode;
void * jmptag;
}JMPTAG;
#pragma pack()
/***********************************************************************************************************************
*函数名:ChangeThisCallFun
*类名:ChangeFun
*功能:换掉需要替身函数用自己便于的函数去实现
*参数:t就是我们自己写的替身
*参数:f就是我们需要替换掉函数的地址
***********************************************************************************************************************/
class ChangeFun
{
public:
map<void *, JMPBYTE> m_oldcode;//保存原来的地址信息用来恢复
template<typename ToType, typename FromType>BOOL ChangeThisCallFun(ToType t, FromType f)
{
BOOL ret = FALSE;
union funaddress
{
FromType _f;//原始函数的地址
ToType _t;//需要转换成目标函数的地址
void * address;
};
SIZE_T siz = 0;
DWORD oldprt;
funaddress formadd, toaddr;
toaddr._t = t;
formadd._f = f;
JMPBYTE bk, tag(formadd.address,toaddr.address);
VirtualProtectEx((HANDLE)-1, formadd.address,5, PAGE_EXECUTE_READWRITE, &oldprt);
ReadProcessMemory((HANDLE)-1, formadd.address, &bk, 5, &siz);
WriteProcessMemory((HANDLE)-1, formadd.address, &tag, 5, &siz);
VirtualProtectEx((HANDLE)-1, formadd.address, 5, oldprt, &oldprt);
return ret;
}
};
以上轮子就造好了,那么我们如何替换呢?
我现在以CTreeCtrl 类为例替换它的成员函数DeleteAllItems
首先先建立自己的类和成员函数:
class TestTree
{
BOOL DeleteAllItems();
}
BOOL TestTree::DeleteAllItems()
{return TRUE;
}
接着我们就去完成更换和调用吧:
void testfunadd()
{ChangeFun testtree;
testtree.ChangeThisCallFun(&TestTree::DeleteAllItems, &CTreeCtrl::DeleteAllItems);
CTreeCtrl test;
test.DeleteAllItems();
}
为了说明原理删减检测和其他还原机制,需要的同学自己加上代码就可以了.
本文方法属于通过自己下钩子实现替身测试功能,这个工程可以用于逆向工程和测试工程.
以上代码在vs2013中的c++工程中编译测试成功.有不对的地方肯定指正.
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)