首页
社区
课程
招聘
[原创]从零开始的反反调试日志
发表于: 2011-1-14 21:45 49502

[原创]从零开始的反反调试日志

2011-1-14 21:45
49502
我也不知道取个什么名字合适,主要是给那些准备调试内核人的参考资料

=============    编程环境    =====================
VS2008+DDK+VA+DDKWIZARD
1、安装 VS2008,MSDN
2、安装 DDK
3、安装 ddkwizard_setup
4、安装 Visual Assist X
5、-> 错误 1 => 找到 ddkbuild.bat、ddkbuild.cmd(下载)放入 /windows/system32 目录下
6、-> 错误 2 => 计算机/.../环境变量 ,添加两个系统变量
    1、 W7BASE = D:\WinDDK\7600.16385.1
    2、WXPBASE = D:\WinDDK\7600.16385.1
7、-> 错误 3 => VS2008/Tools/Options/Projects and Solutions/VC++ Directories
    Win32/Include files =>
    添加 D:\WinDDK\7600.16385.1\inc\api 到末尾,否则编译普通win32应用程序会提示错误
    添加 D:\WinDDK\7600.16385.1\inc\ddk 到末尾
Other:如果安装顺序有错,导致VA无法支持DDK,则将 api、ddk 添加到 VA 的 /Options/Projects/C/C++ Directories
    => custom/Stable include files ,一样,添加到末尾
= done =

1 : error PRJ0019: A tool returned an error code from "Performing Makefile project actions"
=>'ddkbuild.cmd' 不是内部或外部命令,也不是可运行的程序
2 :1>DDKBLD: ERROR #3: To build using type W7 you need to set the %W7BASE% environment variable to point to the Windows 7/Windows 2008 Server R2 DDK base directory!
3 :VS2008 中 UNICODE_STRING 按 F12 无法追踪

=============    双机调试  =======================
Windbg+VMware
1、安装VMware
2、安装Windbg(DDK里面有这个东西)
3、安装IDA
4、VMware 设置(装有 xp 和 win7 两个系统)
xp版:
在 c:\boot.ini 文件中添加 debug 的启动项
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional - debug" /fastdetect /debug /debugport=com1 /baudrate=115200

win7版:
在 msconfig 中添加debug 启动项
msconfig -> 高级选项 -> 调试,调试端口 COM1,波特率 115200

在VMware 上修改两个系统的串口设置:
打开电源时连接
此终端是服务器
另一终端是一个应用程序
i/o 模式 轮询时主动放弃CPU占用
xp:使用命名管道 \\.\pipe\com_1
win7:使用命名管道 \\.\pipe\com_2

5、Windbg 设置
符号路径,xp 与 win7 的符号都可以放在同一个目录下,没有的话,windbg 会自动将文件下载到 E:\sysbols
E:\symbols;SRV*E:\symbols*http://msdl.microsoft.com/download/symbols

建立两个windbg 快捷方式的设置,修改其中参数,分别连接两个虚拟机
xp:
D:\tools\windbg\windbg.exe -b -k com:port=\\.\pipe\com_1,baud=115200,pipe
win7版:
D:\tools\windbg\windbg.exe -b -k com:port=\\.\pipe\com_2,baud=115200,pipe

6、在 windbg 下 dump 两个系统
  将整个win7系统内存dump下来( Full kernel dump),耗费了我40多个小时...其中一次机器休眠了...
  (Creating a full kernel dump over the COM port is a VERY VERY slow operation.)有除COM外其他的连接方式,但我不会。。
  .dump /f e:\win7_dump.dmp

=============   驱动加载工具 ====================
      后面附一个源码,喜欢的可以下

=============   准备工作完成 ====================
      至此,我们有了一个能随时能增加功能的驱动加载工具,一份 win7 dump 文件,双机调试,编程环境。

=============   从零开始分析驱动层的反调试 =========
      在这以前,只有应用层的逆向经验。没接触过驱动,也不知道反调试。
      下面是我过某个游戏驱动保护的过程,这个过程从11月14号左右开始,到12月1号结束。
         游戏一开始给人的表象有:
1、游戏进程、守护进程、驱动
2、OllyICE 附加列表中无法看到目标进程,任务管理栏则可正常显示目标进程名称。
3、Windows7:去除两个内核钩子Hook后,OD可看到目标进程,但是附加时提示附加失败!(用xuetr 看的到内核钩子)
4、Windows XP:去掉两个内核钩子,游戏直接退出。
5、采用虚拟机VMware+Windbg 调试,游戏进程 启动时报错!
6、VMware+Windows 7 [Debug]:游戏启动后Windows 7系统无响应,只能重新启动系统。
7、VMware+Windows 7:游戏可正常启动。
8、OD加载游戏主程,OD崩溃,模块时发生错误,错误代码:0xc0000005(最后发现是PE结构中一个模块名字超长导致,我的OD很老了)
9、OD正常加载游戏主程之后,有被检测到的信息,多次尝试找信息出处,无果

      以上是11月17日之前的各种尝试,也是最痛苦的时候——完全找不到任何方向。之后调整了思考方向,把重心放到第5、6、7条线索上。以下是当时调试日志的主要部分,有点小修改。

2010/11/17 对**的调试终于有点突破^_^
      之前一直不清楚**是如何区分系统处于Debug还是正常状态。经过对Windows的异常分发机制,了解了Debug与正常状态的流程不同,主要是KdpTrap与KdpStub两个函数对应于不同的系统。
      至此,与双机调试有关的地方有4处:KdpDebugRoutine(函数指针)、KdpBootedNodbug(bool)、KdPitchDebugger(bool)、DebuggerEnabled(bool)。
      通过修改KdpDebugRoutine 指向 KdpStub ,以及另外3个标志位,可将系统从Debug修改为正常状态,Windbg将处于等待状态。**可正常执行,待**加载完毕后,将上述4个值修改回来,Windbg可重新获取话语权!
      ******
      因此,我将要做另外一个任务,一个驱动程序,可以让系统在Debug与正常状态相互切换!这样,我就可以在游戏运行期间,随时进行调试。如果有可能,最好让驱动随时与OD进行通讯。

2010/11/18  完成驱动加载工具
      完成一个通用的驱动加载工具,测试,可将Debug系统在 Debug 与 正常状态间随意切换。但是对于正常系统,却无法切换成Debug。下一步要做的,就是将正常系统也能随意切换!
(这个到现在也没开始做...)

2010/11/19
    1、经过测试,被转换后的系统可以进行双机调试,下断 ws2_32!send 失败。
    2、使用XueTr恢复两个内核钩子后,OD能够看到 ** 进程,附加失败
    3、针对附加失败,使用双机调试查看原因!关键函数 kernel32!DebugActiveProcess。
         流程 kernel32!DebugActiveProcess -> ntdll!ZwDebugActiveProcess -> 功能号0x60 -> KeServiceDescriptorTable[0][0x60*4] -> nt!NtDebugActiveProcess
         上述步骤能够成功运行
         失败存在于 ntdll!NtCreateThreadEx -> nt!NtCreateThreadEx:
         经过跟踪发现,最终问题在上述线路中的 nt_RtlImageNtHeaderEx+0x45处,由于对象 ** 进程的PE头被抹去,导致此函数判断时,返回了一个失败值!
         进一步的,在不恢复内核钩子的情况下,** 的 Pe头不被改写,一旦恢复之后,**的某个线程会将此PE头抹去,导致OD无法附加
(有 win7 dump ,结合 ida 感觉真是好)

2010/11/??
         ** 在对比黑白名单后,判断是否放行目标进程。
         通过修改黑白名单的内容,OD 可以顺利附加,但是无法读出 ** 的模块信息!
(不知道具体日期了,主要是从 xuetr 上看到的2个内核钩子入手 nt!NtReadVirtualMemory,nt!NtWriteVirtualMemory,这期间,通过这条线索搞定了它的白名单)

2010/11/22   
         制作完相关工具后,经测试,OD 能够看见目标进程,附加,但附加之后便发生错误,无法看到对象的模块信息。应该是目标进程在不断的对 debugport 进行清零操作,目前发现有

         多个线程有此动作,其中有一个是在不断新建线程,新的线程就是不断对 debugport 做检查。如果绕过 debugport 检查?
         (这里可能会有些不准确,但确定是的某个线程在对 debugport 清零,查看了不少帖子,最后线索来自看雪)

2010/11/23   ** 对 debugport 清零的动作
         Windbg 对debugport 下写断点
kd> u **+0x41764
**+0x41764:
9b2fb764 8702            xchg    eax,dword ptr [edx]    //清零操作
9b2fb766 6685e9         test     cx,bp
9b2fb769 660fbae501   bt        bp,1
9b2fb76e 8b36            mov     esi,dword ptr [esi]
9b2fb770 83ecdc         sub      esp,0FFFFFFDCh
9b2fb773 0f886545ffff  js         **+0x35cde (9b2efcde)
9b2fb779 f5               cmc
9b2fb77a 3bf1            cmp     esi,ecx

         手动修改 edx 值,发现 od 附加后可正常存活。但是如果暂停该线程,则会导致od 附加后,很快游戏自动退出!

         使用工具对**驱动代码部分做修改(debugport清零),在多次测试中,很少的情况可以一直附加,但实体机状态下,OD很快就被检测到。在程序自退出时,有弹出守护进程被异常终止的对话框。程序自退出时,会有一个单独线程,冻结此线程,OD 会存活的比较久。
(到现在为止,还不能对游戏下断点)

2010/11/25
         OD 对游戏下断,游戏会异常退出,0x80000003

2010/11/29
         了解线程的HidePort后,制作工具可以下断点,但是OD 还会被检测到。主要的问题在于线程0x00cc0654中调用了RtlExitUserProcess 函数(该函数又调用了ZwTerminateProcess)。
         该线程会不停的创建,但未经过CreateThread API(功能号为 0x58)。
现在的问题是,创建该线程是否传递了参数进来?如果未有参数传递,是否该线程检测到OD运行?!
         补充:由于游戏主线程的HidePort被设置为1,导致内核将该线程上的异常屏蔽,不分发给用户层。因此OD修改的代码 int3 会引发一个异常,导致主线程退出。

2010/11/30
         在 nt!NtCreatethreadEx 下断,没有相关创建 0x00cc0654 线程的调用!因此,还是无法知道程序中哪里创建了线程 0x00cc0654 。比较奇怪的是,该线程应该是不断的被创建的、且线程 ID 总是相同,但是 retn 之后,该线程便不再被创建。。(之所以这么说,是因为在该线程的入口点,总是能断下)
  
2010/12/01
[LEFT]         基本实现 OD 的附加调试,但是 0x00cc0654 线程是从哪里来的,如何被创建,如何检查OD? (一直未解决,太多的代码变异)[/LEFT]

总结:
大部分的反调试还是在驱动层面,并且是已知的几个技术点
1、  反Debug系统                          debug 系统与 正常版本切换
2、  DebugPort 清零                       nop 掉相关代码段
3、  主线程 HidePort 置 1                          重置 HidePort
4、  内核函数钩子,采用白名单方式放行。     找到白名单,手动添加
5、  0x00cc0654 线程检测                  直接将线程入口修改为 retn

我想很多在内核之外的人,跟我一样在门外徘徊,其实,只要做,并没有那么难。

[课程]FART 脱壳王!加量不加价!FART作者讲授!

收藏
免费 7
支持
分享
最新回复 (40)
雪    币: 134
活跃值: (55)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
自制的驱动加载工具

驱动部分写的很简单,删除了针对游戏的代码,保留了3个win7 系统下的基本例子,检索eprocess、内核模块、win7下几个debug标志位的切换。

做这个工具的主要目的,是当我需要针对游戏的 debughide 什么的做恢复,希望能只真加一个写个 redebughide() 函数,然后直接在应用层去调用这么个函数。方便测试用。
最终效果是:
1、编写 redebughide() 函数
2、给它定义功能号  #define IOCTL_CODE_REDBUGHIDE  (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,0x906,METHOD_BUFFERED,FILE_ANY_ACCESS)
3、 在  InitIOServer 函数中,加入信息,通知用户程序
        myServer[3].dwEx = IOCTL_CODE_REDBUGHIDE ;
        wcscpy_s(myServer[3].strDescribe,L"枚举线程,恢复DEBUGHIDE");
4、在 DRVWIN7_DispatchDeviceControl  函数中添加回调
                  case IOCTL_CODE_REDBUGHIDE:
                {
                        KdPrint(("==== DRV_REDEBUGHIDE ====")) ;
                        Debughide () ;
                        Irp->IoStatus.Status = STATUS_SUCCESS ;
                }
                break ;
这样,我就能更多精力放在功能函数的实现上,而不管用户层的东西
上传的附件:
2011-1-14 22:51
0
雪    币: 6
活跃值: (1104)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
楼主是个有心人,代码能不能发下。
2011-1-14 22:57
0
雪    币: 1231
活跃值: (41)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
支持,进入内核,需要有面对蓝屏的勇气。等哪天有需要了,再研究研究。
2011-1-14 23:02
0
雪    币: 134
活跃值: (55)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
驱动加载的代码已发,游戏部分的几个反调试部分,根据日志里的信息,可以自己做针对性的编码。
2011-1-14 23:02
0
雪    币: 6051
活跃值: (1441)
能力值: ( LV15,RANK:1473 )
在线值:
发帖
回帖
粉丝
6
下载收藏了,感谢!
2011-1-14 23:11
0
雪    币: 53
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
不错,加油。
2011-1-15 00:01
0
雪    币: 239
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
mark~~
2011-1-15 00:33
0
雪    币: 585
活跃值: (568)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
9
标记........
2011-1-15 14:27
0
雪    币: 1683
活跃值: (674)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
mark~~
2011-1-15 16:00
0
雪    币: 57
活跃值: (55)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
11
嗯  
用得上……
2011-1-16 13:36
0
雪    币: 199
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
感觉LZ还是太暴露了,而且这些有些相关的信息其实可以从哪些做外挂的得到
2011-1-16 22:05
0
雪    币: 253
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
方法不错!学习。
2011-1-17 08:41
0
雪    币: 585
活跃值: (568)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
14
很不错,,,好帖
2011-1-17 12:59
0
雪    币: 276
活跃值: (34)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
好东东,收藏学习了.
2011-1-17 13:15
0
雪    币: 14
活跃值: (23)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
mark..
2011-1-18 11:45
0
雪    币: 322
活跃值: (113)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
留个脚印,方便查询
2011-1-18 12:58
0
雪    币: 33
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
真正从0开始的,佩服佩服
2011-1-18 18:06
0
雪    币: 2673
活跃值: (2947)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
19
mark..
2011-1-18 22:29
0
雪    币: 611
活跃值: (251)
能力值: ( LV12,RANK:390 )
在线值:
发帖
回帖
粉丝
20

学习了,感谢楼主分享
2011-1-19 15:36
0
雪    币: 611
活跃值: (251)
能力值: ( LV12,RANK:390 )
在线值:
发帖
回帖
粉丝
21
很好的帖子。
请教下,
1. OD附加调试失败,楼主是怎么确定是DebugActiveProcess这个API有问题,还是其他API有问题?
   是跟踪出来的,还是凭经验自己猜测DebugActiveProcess,然后在该API上下断点得到的?
2. 怎样得出OD附加失败的运行路径的?
   即:当楼主了解到是DebugActiveProcess问题时,在DebugActiveProcess上下断点。
   虚拟机中用OD附加调试游戏时,会命中该断点,怎样确定当前是哪个进程调用的DebugActiveProcess?还 是说,只有OD会调用DebugActiveProcess?
    若只有OD调DebugActiveProcess,接下来应该在本机Windbg中单步即可确定调用路径了。。。
3. 楼主是怎样利用IDA 分析dump文件的?

4. 想看一下楼主切换调试状态到非调试状态部分的代码。。。
2011-1-19 15:37
0
雪    币: 24
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
好,收藏了!
2011-1-19 16:07
0
雪    币: 134
活跃值: (55)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
23
1、
虚拟机中,OD 附加对象进程,有一个附加按钮可以追踪。

我实际中是取巧了,在网上搜索了一下附加进程所用的API,结果就是DebugActiveProcess

2、
OD 失败路径,就是从 DebugActiveProcess 开始。
我这里做了一个例子: OD 附加 测试程序 A
正常情况下OD附加成功的路径为 S
当 A 被其他进程用 Debug 权限打开后,OD 附加失败的路径为 B

对比 S 和 B ,就知道在 DebugActiveProcess 上下,哪里的返回值有错。

最终对比 OD 附加游戏时的路径,基本上就可以确定问题出在哪里。
至少 OD 知道附加失败了,它自己也会弹出一个对话框来。

我这里不是说 DebugActiveProcess 有问题,而是说从这条线索上去找 OD 附加进程这个动作为什么会失败的原因。
实际上好像也不是 DebugActiveProcess 失败,而是 它下面的其他 API 调用失败。

3、
我用 Windbg .dump 指令得到的是一个windows 完全的内存块,IDA 可以直接解开...

4、
这个给的代码中有,但要完全解释,没这个功力,可以翻一下论坛中关于 windows异常分发 的帖子
2011-1-19 17:33
0
雪    币: 81
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
24
看看…不敢试试…
2011-1-19 21:31
0
雪    币: 72
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
25
陋室空堂~当年笏满床~衰草枯杨~曾为歌舞场~
蛛丝儿结满雕梁~绿纱今又糊在蓬窗上~
说什么脂正浓~粉正香~如何两鬃又成霜~
昨日黄土垅头送白骨~今宵红绡帐底卧鸳鸯~
金满箱~银满箱~转眼乞丐人皆谤~
正叹他人命不长~哪知自己归来丧~
训有方~保不定日后做强梁~
择膏粱~谁承望流落在烟花巷~
因嫌纱帽小~致使锁枷扛~
昨怜破袄寒~今嫌紫蟒长~
乱烘烘你方唱罢我登场~反认他乡是故乡~
甚荒唐~到头来都是为他人做嫁衣裳~
2011-1-20 14:50
0
游客
登录 | 注册 方可回帖
返回
//