从零开始的反反调试日志
程序员文章站
2022-07-05 22:46:17
作 者: tongyongmc
我也不知道取个什么名字合适,主要是给那些准备调试内核人的参考资料
============= ...
作 者: tongyongmc
我也不知道取个什么名字合适,主要是给那些准备调试内核人的参考资料
============= 编程环境 =====================
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
基本实现OD 的附加调试,但是0x00cc0654 线程是从哪里来的,如何被创建,如何检查OD? (一直未解决,太多的代码变异)
总结:
大部分的反调试还是在驱动层面,并且是已知的几个技术点
1、 反Debug系统 debug 系统与 正常版本切换
2、 DebugPort 清零 nop 掉相关代码段
3、 主线程HidePort 置1 重置HidePort
4、 内核函数钩子,采用白名单方式放行。 找到白名单,手动添加
5、 0x00cc0654 线程检测 直接将线程入口修改为retn
我想很多在内核之外的人,跟我一样在门外徘徊,其实,只要做,并没有那么难。
我也不知道取个什么名字合适,主要是给那些准备调试内核人的参考资料
============= 编程环境 =====================
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
基本实现OD 的附加调试,但是0x00cc0654 线程是从哪里来的,如何被创建,如何检查OD? (一直未解决,太多的代码变异)
总结:
大部分的反调试还是在驱动层面,并且是已知的几个技术点
1、 反Debug系统 debug 系统与 正常版本切换
2、 DebugPort 清零 nop 掉相关代码段
3、 主线程HidePort 置1 重置HidePort
4、 内核函数钩子,采用白名单方式放行。 找到白名单,手动添加
5、 0x00cc0654 线程检测 直接将线程入口修改为retn
我想很多在内核之外的人,跟我一样在门外徘徊,其实,只要做,并没有那么难。
推荐阅读
-
Node.js利用debug模块打印出调试日志的方法
-
从零开始的反反调试日志
-
从零开始的Python学习Episode 14——日志操作
-
如何提高后台服务应用问题的排查效率?日志 VS 远程调试 nodejsVisual Studio Code调试debug
-
Node.js利用debug模块打印出调试日志的方法
-
从零开始的Nginx [ 6 ] --- Nginx的日志配置,log_format 、error_log指令,日志轮转,错误页面配置
-
如何提高后台服务应用问题的排查效率?日志 VS 远程调试 nodejsVisual Studio Code调试debug
-
php yii 调试sql的日志 yii2.0视频教程 yii2.0 yii官
-
php yii 调试sql的日志 yii2.0视频教程 yii2.0 yii官
-
从零开始的反反调试日志