首页
社区
课程
招聘
[原创]hook api 反OD调试的一种思路
发表于: 2007-7-23 15:32 15928

[原创]hook api 反OD调试的一种思路

2007-7-23 15:32
15928

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的指导!!!


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (21)
雪    币: 200
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
2
futo隐藏od
2007-7-23 15:47
0
雪    币: 225
活跃值: (25)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
3
呵呵,你可以测试看下
2007-7-23 16:14
0
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
4
od可以选择停在system breakpoint或者entrypoint of program
bp OpenProcess你这个就挂了

btw: 只是修改writeprocessmemory可以绕开,参考themida
2007-7-23 16:17
0
雪    币: 325
活跃值: (97)
能力值: ( LV13,RANK:530 )
在线值:
发帖
回帖
粉丝
5
其次最简单的办法就是我以前写过的插件
OllgDbg为Admin权限
把被调试的程序的权限令牌弄成Users就行了。
操作系统会帮你返回Access Denied.
目前因为窗体没有权限表,所以说要判断还是从窗体判断最好。
2007-7-23 16:30
0
雪    币: 424
活跃值: (10)
能力值: ( LV9,RANK:850 )
在线值:
发帖
回帖
粉丝
6
留在第一页,
增长了一点经验值!
2007-7-23 17:10
0
雪    币: 7309
活跃值: (3788)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
7
思路不错
不过,如果你的父进程不是OD而是Explorer怎么办?---参考野猪力量
2007-7-23 18:21
0
雪    币: 494
活跃值: (629)
能力值: ( LV9,RANK:1210 )
在线值:
发帖
回帖
粉丝
8
作用有限,在ring0挂几个系统服务就不管用了
2007-7-24 10:36
0
雪    币: 184
活跃值: (65)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
9
anti类的,单独拆开来看是没什么用,假如综合起来用,还是很有效果的.
2007-7-24 10:50
0
雪    币: 424
活跃值: (10)
能力值: ( LV9,RANK:850 )
在线值:
发帖
回帖
粉丝
10
检测进程列表虽然麻烦,不过不失为一个好办法,楼主的方法还系有局限!
2007-7-24 10:54
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
增长了一点经验值
2007-7-24 12:39
0
雪    币: 156
活跃值: (48)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
12
有道理!!!!!
2007-7-24 17:08
0
雪    币: 264
活跃值: (30)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
13
大家多支持一下难得有好想法。
2007-7-24 17:35
0
雪    币: 1829
活跃值: (1377)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
14
有问题被指出是好事,新人很容易被小小的成果冲昏头脑,得感谢大家对他的指点才是。
2007-7-25 09:36
0
雪    币: 1919
活跃值: (901)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
15
收藏研究哈~~
2007-7-25 12:07
0
雪    币: 225
活跃值: (25)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
16
首先感谢两大版主提出的意见,也欢迎大家提出宝贵的意见,我很喜欢看雪这里的交流氛围.
在大家的指点下,我的加密思路更完善了一点.现在先放个CrackMe出来,给大家看看,整理一下后我会公布思路,还请多多指教
下载地址
http://dl2.csdn.net/down4/20070725/25102544267.rar
2007-7-25 14:54
0
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
17
上面不就是你的crackme源代码。。。
2007-7-25 19:05
0
雪    币: 1505
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
18
我记得外文翻译板块也有类似的文章,不只一篇噢
2007-7-25 22:06
0
雪    币: 846
活跃值: (221)
能力值: (RANK:570 )
在线值:
发帖
回帖
粉丝
19
能检查到父进程是OD,可用的方法就多了。。。前提是能检查到。。
2007-7-26 15:06
0
雪    币: 210
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
又学到一招,不失一个好办法
2007-7-27 11:06
0
雪    币: 334
活跃值: (22)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
21
如果OD以附加进程来加载就你的程序就HOOK不了OD了,
我有个思路:可以把SSDT的nt!NtOpenProcess挂接就不怕OD附加了
2007-7-27 11:50
0
雪    币: 280
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
大哥。我怎么随便找个OD都可以F2 F7 F8 F9?
2007-7-29 09:44
0
游客
登录 | 注册 方可回帖
返回
//