hook api 反OD调试的一种思路
作者:admin 日期:2009-12-02
标 题: 【原创】hook api 反OD调试的一种思路
作 者: 蓝云
时 间: 2007-07-23,15:32
链 接: http://bbs.pediy.com/showthread.php?t=48413
hook api 反OD调试的一种思路
by胡华
本程序在backer的耐心指导下完成,非常感谢backer的帮助!!!
关于OD怎样在程序中下断点相信大家都知道,就是用WriteProcessMemory函数在要下断点的地方写入0xCC,也就是int 3的中断,
如果我们挂钩OD的WriteProcessMemory函数不让它下断点是不是就可以让OD不能正常跟踪了呢?有了这个思路,下面就是实践了。
首先得解决几个问题:
1.我们的目标是最好在OD正常加载本程序后就已经被hook,怎么解决?
这个问题其实很简单,我们知道全局类的初始化工作在main函数之前,OD正常加载后会停在WinMain函数处,如果把hook api 代
码放在一个全局类的构造函数中就可以了,呵呵,就这么简单。
2.要得到OD的输入表中的WriteProcessMemory函数的跳转地址
呵呵,用OD来调试OD不就很容易得到了么?
用OD调试OD后我们得到WriteProcessMemory函数的跳转地址放在0x0050D450这个地方。
3.如果前面的两个问题解决,现在剩下的就是程序在运行期间要判断自己的父进程是否是OD,如果是OD那么就可以肯定被OD加载,
问题是怎么方便的取得父进程?如果用列取进程列表的方式来获的父进程,这比较麻烦,但是的确是一种思路。我们不采取这种
思路,其实在ntdll.dll中有一个函数可以得到父进程,下面用代码来说话吧:
NTDLL.DLL中有一个函数叫NtQueryInformationProcess,用它可以将指定类型的进程信息拷贝到某个缓冲。其原型如下:
NTSYSAPI
NTSTATUS
NTAPI
NtQueryInformationProcess (
IN HANDLE ProcessHandle, // 进程句柄
IN PROCESSINFOCLASS InformationClass, // 信息类型
OUT PVOID ProcessInformation, // 缓冲指针
IN ULONG ProcessInformationLength, // 以字节为单位的缓冲大小
OUT PULONG ReturnLength OPTIONAL // 写入缓冲的字节数
);
第一个参数是希望操作的进程句柄,这个句柄必须以PROCESS_QUERY_INFORMATION模式存取。为了取得一个句柄,我们必须用
OpenProcess函数:
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,dwProcessID);
第二个参数是请求信息的类型,这个参数可以有许多个值,本文例子中将用ProcessBasicInformation (值为0)。
因此,如果第二个参数是ProcessBasicInformation的话,则第三个参数必须为一个指针指向结构PROCESS_BASIC_INFORMATION:
typedef struct
{
DWORD ExitStatus; // 接收进程终止状态
DWORD PebBaseAddress; // 接收进程环境块地址
DWORD AffinityMask; // 接收进程关联掩码
DWORD BasePriority; // 接收进程的优先级类
ULONG UniqueProcessId; // 接收进程ID
ULONG InheritedFromUniqueProcessId; //接收父进程ID
} PROCESS_BASIC_INFORMATION;
这个结构的最后一个参数是InheritedFromUniqueProcessId,它就是我们所要的东西。
得到了父进程id之后,呵呵,现在开始打开进程了
DWORD dwId=GetCurrentProcessId();
DWORD dwParentId;
dwParentId=GetParentProcessID(dwId); //获取父进程id
hParentProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwParentId);
又有一个问题怎么判断是否是OD呢?
我们可以用读取内存的方式查看某一段代码是不是OD的就行了,要检查哪段代码那就随你了,
我这里是读取OD的0x00401000开始的几个字节。
更简单的方法是读取0x0050D450这个地址判断是不是WriteProcessMemory这个函数的真实跳转地址,如果是那就基本可以断定是OD了,呵呵,不会那么巧其它的有的程序也会是这个地址吧!
判断是OD后,现在要做的就是在OD中申请一段空间把要执行的代码写在这个地址了
BYTE bRet=0xC3; //这是hook api后转到这要执行的代码
LPVOID lpWriteFunAddress=(void*)0x0050D450;
LPVOID lpNewWriteFunAddress=NULL;
lpNewWriteFunAddress=VirtualAllocEx(hParentProcess,NULL,sizeof(bRet),MEM_COMMIT,PAGE_READWRITE);
//插入函数返回代码
if(lpNewWriteFunAddress==NULL)
{
MessageBox(NULL,"virtualalloc err","error",MB_OK);
}
if(WriteProcessMemory(hParentProcess, lpNewWriteFunAddress, &bRet, sizeof(bRet), NULL)==0)
{
MessageBox(NULL,"insert retn err","error",MB_OK);
}
写入后现在就是把0x0050D450这个地址的WriteProcessMemory函数的真实跳转地址改为我们上面申请的地址了:
//改变api地址
DWORD flOldProtect;
VirtualProtect(lpWriteFunAddress,sizeof (lpWriteFunAddress),PAGE_READWRITE,&flOldProtect);
if(WriteProcessMemory(hParentProcess, lpWriteFunAddress, &lpNewWriteFunAddress, sizeof(lpNewWriteFunAddress), NULL)==0)
{
MessageBox(NULL,"insert fun addr err","error",MB_OK);
}
不知道大家注意没,我插入的要执行的代码只有一个字节BYTE bRet=0xC3,
其实就是ret,呵呵,知道了吧,只要在OD中按F2下断点就会执行WriteProcessMemory这个函数,而这个函数现在是什么都不做就直接返回了,也不用考虑堆栈平衡,我们要的就是OD悄无声息的挂掉!如果想忽悠一下而不让OD挂掉,那就用ret14了,大家尽情的发挥吧!!!
好了,到这里已经结束了,再次感谢backer的指导!!!
作 者: 蓝云
时 间: 2007-07-23,15:32
链 接: http://bbs.pediy.com/showthread.php?t=48413
hook api 反OD调试的一种思路
by胡华
本程序在backer的耐心指导下完成,非常感谢backer的帮助!!!
关于OD怎样在程序中下断点相信大家都知道,就是用WriteProcessMemory函数在要下断点的地方写入0xCC,也就是int 3的中断,
如果我们挂钩OD的WriteProcessMemory函数不让它下断点是不是就可以让OD不能正常跟踪了呢?有了这个思路,下面就是实践了。
首先得解决几个问题:
1.我们的目标是最好在OD正常加载本程序后就已经被hook,怎么解决?
这个问题其实很简单,我们知道全局类的初始化工作在main函数之前,OD正常加载后会停在WinMain函数处,如果把hook api 代
码放在一个全局类的构造函数中就可以了,呵呵,就这么简单。
2.要得到OD的输入表中的WriteProcessMemory函数的跳转地址
呵呵,用OD来调试OD不就很容易得到了么?
用OD调试OD后我们得到WriteProcessMemory函数的跳转地址放在0x0050D450这个地方。
3.如果前面的两个问题解决,现在剩下的就是程序在运行期间要判断自己的父进程是否是OD,如果是OD那么就可以肯定被OD加载,
问题是怎么方便的取得父进程?如果用列取进程列表的方式来获的父进程,这比较麻烦,但是的确是一种思路。我们不采取这种
思路,其实在ntdll.dll中有一个函数可以得到父进程,下面用代码来说话吧:
NTDLL.DLL中有一个函数叫NtQueryInformationProcess,用它可以将指定类型的进程信息拷贝到某个缓冲。其原型如下:
NTSYSAPI
NTSTATUS
NTAPI
NtQueryInformationProcess (
IN HANDLE ProcessHandle, // 进程句柄
IN PROCESSINFOCLASS InformationClass, // 信息类型
OUT PVOID ProcessInformation, // 缓冲指针
IN ULONG ProcessInformationLength, // 以字节为单位的缓冲大小
OUT PULONG ReturnLength OPTIONAL // 写入缓冲的字节数
);
第一个参数是希望操作的进程句柄,这个句柄必须以PROCESS_QUERY_INFORMATION模式存取。为了取得一个句柄,我们必须用
OpenProcess函数:
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,dwProcessID);
第二个参数是请求信息的类型,这个参数可以有许多个值,本文例子中将用ProcessBasicInformation (值为0)。
因此,如果第二个参数是ProcessBasicInformation的话,则第三个参数必须为一个指针指向结构PROCESS_BASIC_INFORMATION:
typedef struct
{
DWORD ExitStatus; // 接收进程终止状态
DWORD PebBaseAddress; // 接收进程环境块地址
DWORD AffinityMask; // 接收进程关联掩码
DWORD BasePriority; // 接收进程的优先级类
ULONG UniqueProcessId; // 接收进程ID
ULONG InheritedFromUniqueProcessId; //接收父进程ID
} PROCESS_BASIC_INFORMATION;
这个结构的最后一个参数是InheritedFromUniqueProcessId,它就是我们所要的东西。
得到了父进程id之后,呵呵,现在开始打开进程了
DWORD dwId=GetCurrentProcessId();
DWORD dwParentId;
dwParentId=GetParentProcessID(dwId); //获取父进程id
hParentProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwParentId);
又有一个问题怎么判断是否是OD呢?
我们可以用读取内存的方式查看某一段代码是不是OD的就行了,要检查哪段代码那就随你了,
我这里是读取OD的0x00401000开始的几个字节。
更简单的方法是读取0x0050D450这个地址判断是不是WriteProcessMemory这个函数的真实跳转地址,如果是那就基本可以断定是OD了,呵呵,不会那么巧其它的有的程序也会是这个地址吧!
判断是OD后,现在要做的就是在OD中申请一段空间把要执行的代码写在这个地址了
BYTE bRet=0xC3; //这是hook api后转到这要执行的代码
LPVOID lpWriteFunAddress=(void*)0x0050D450;
LPVOID lpNewWriteFunAddress=NULL;
lpNewWriteFunAddress=VirtualAllocEx(hParentProcess,NULL,sizeof(bRet),MEM_COMMIT,PAGE_READWRITE);
//插入函数返回代码
if(lpNewWriteFunAddress==NULL)
{
MessageBox(NULL,"virtualalloc err","error",MB_OK);
}
if(WriteProcessMemory(hParentProcess, lpNewWriteFunAddress, &bRet, sizeof(bRet), NULL)==0)
{
MessageBox(NULL,"insert retn err","error",MB_OK);
}
写入后现在就是把0x0050D450这个地址的WriteProcessMemory函数的真实跳转地址改为我们上面申请的地址了:
//改变api地址
DWORD flOldProtect;
VirtualProtect(lpWriteFunAddress,sizeof (lpWriteFunAddress),PAGE_READWRITE,&flOldProtect);
if(WriteProcessMemory(hParentProcess, lpWriteFunAddress, &lpNewWriteFunAddress, sizeof(lpNewWriteFunAddress), NULL)==0)
{
MessageBox(NULL,"insert fun addr err","error",MB_OK);
}
不知道大家注意没,我插入的要执行的代码只有一个字节BYTE bRet=0xC3,
其实就是ret,呵呵,知道了吧,只要在OD中按F2下断点就会执行WriteProcessMemory这个函数,而这个函数现在是什么都不做就直接返回了,也不用考虑堆栈平衡,我们要的就是OD悄无声息的挂掉!如果想忽悠一下而不让OD挂掉,那就用ret14了,大家尽情的发挥吧!!!
好了,到这里已经结束了,再次感谢backer的指导!!!
评论: 1 | 查看次数: 9007