OD Anti Debug 研究笔记

V盾网络验证 Anti Debug

 
1.V盾debug.exe
 
 
0044B77C . FF15 D0F24700 call dword ptr ds:[<&KERNEL32.CreateThre>; CreateThread
 
创建线程api CreateThread (OD附加程序后 按T可以看到程序调用的线程地址)
 
0012FC8C 00000000 |pSecurity = NULL
0012FC90 00000000 |StackSize = 0x0
0012FC94 004011CE |ThreadFunction = V盾debug.004011CE xc较对call
0012FC98 00000000 |pThreadParm = NULL
0012FC9C 00000000 |CreationFlags = 0
0012FCA0 0012FCB4 pThreadId = 0012FCB4
 
V盾创建线程用了这个api CreateRemoteThreadEx
 
 
xc防附加Anti方法 xc较对和防附加内容是一样的
 
防破.取线程状态()
 
首先它取下退出线程这个api的返回值
 
返回259为正在运行 16进制为103
 
 
GetExitCodeThread (结果返回在ecx)
 
 
这个函数是获得线程的退出码, 第二个参数是一个 DWORD的指针,用户应该使用一个 DWORD 类型的变量去接收数据,返回的数据是线程的退出
 
码,第一个参数是线程句柄,用 CreateThread 创建线程时获得到。
 
通过线程退出码可以判断线程是否正在运行,还是已经退出。
 
或者可以判断线程是否是正常退出还是异常退出。
 
 
 
如果上面不等于103的话就会触发脱离调试器
 
 
 
防破.脱离调试器 ()
 
 
1.获取这个函数(ZwSetInformationThread)的地址
 
调用api GetProcAddress
 
 
2.GetCurrentThread 获取当前线程的一个伪句柄
 
 
3.跳向ZwSetInformationThread (JMP Handle)
 
 
4.调用api KiFastSystemCall(进入内核 )
 
Windows API的系统调用过程通过KiFastSystemCall或int 2e进入内核
 
自己的理解是进入系统内核,ring3调试器没有权限调试,但是最后ret 8返回到错误地址。
 
 
进入到这个脱离调试器的函数里,只能在头部retn
 
 
 
 
防破.防下断_附加 ()
 
1.调用api(GetTickCount) 获取毫秒数
 
GetTickcount函数:它返回从操作系统启动到当前所经过的毫秒数,常常用来判断某个方法执行的时间,特别注意:这个函数并非实时发送,而是由
 
系统每18ms发送一次,因此其最小精度为18ms。
 
 
2.计算得出一个数值来进行对比
 
 
004018F8 |. 837D F8 35 cmp [local.2],0x35
004018FC |. 0F84 2C000000 je V盾debug.0040192E
00401902 |. 837D F8 21 cmp [local.2],0x21
00401906 |. 0F84 22000000 je V盾debug.0040192E
0040190C |. 837D F8 32 cmp [local.2],0x32
00401910 |. 0F84 18000000 je V盾debug.0040192E
00401916 |. 837D F8 2B cmp [local.2],0x2B
0040191A |. 0F84 0E000000 je V盾debug.0040192E
00401920 |. 837D F8 28 cmp [local.2],0x28
00401924 |. 0F84 04000000 je V盾debug.0040192E
 
如果等于以上指定的数值,就赋值 mov eax,1。
 
jmp part1
 
否则 jmp part2
 
part1:
 
1.调用api(GetTickCount) 获取毫秒数
 
获取到的数据和0x1E对比,如果少于0x1E 赋值mov eax,1
 
接着和0x37对比,如果大于0x37 mov eax,1
 
所以得出的数据必须满足 0x1E<X<0x37
 
 
part2:
 
1.延时
 
2.调用api(GetTickCount) 获取毫秒数
 
3.计算得出一个数据
 
test ah,0x41 对比高位是否等于41,不等于的话就mov eax,1
 
 
经研究调试,把你要调试的软件运行起来,然后下GetTickCount这个断点,如果能断下,返回的地址是40开头的,即返回到程序领空的,
可以初步判断出改软件用了防附加的暗桩。解决方法是,直接hook住这个api,然后在正常运行的时候会得出一组不会被检测的数据,
每当调用到检测断就返回该数据即可解决。(或者附加你要破解的软件,然后下GetTickCount这个断点也会断在触发暗桩处)
 
demo 下载地址 :http://www.vdisk.cn/down/index/19536923 解压密码:123
 
 
2.不哭暗桩demo
 
经调试发现以下特征
V盾的暗桩也是这样的特征,来到call dword ptr ds:[eax+0x1C] 这段代码,然后数据窗口中跟随地址,会看到所有关于anti的数据
 
00401019 |. 68 80825100 push 不哭暗桩.00518280 ; puah 检测参数
0040101E |. 8B0424 mov eax,dword ptr ss:[esp] ; 不哭暗桩.00518280
00401021 |. 8B00 mov eax,dword ptr ds:[eax] ; 不哭暗桩.00489FB1
00401023 |. 8B00 mov eax,dword ptr ds:[eax] ; 不哭暗桩.00489FB1
00401025 |. FF50 1C call dword ptr ds:[eax+0x1C] ; 不哭暗桩.00489EA1
 
fp.验证安全密钥 (“作者QQ_7539235”)
 
 
1.调用api(GetTickCount) 获取毫秒数
 
2.获取“>”和"="字符串进行对比
 
3.然后将作者的key逐个进行对比
 
 
0040109C |. FF50 18 call dword ptr ds:[eax+0x18] ; 不哭暗桩.004893EC
 
0040109C这个call进行一系列获取OD菜单进行检测
 
 
GetDesktopWindow 这个api获取到10010 以我自己的理解是获取到了当前调试器的窗口句柄的意思
 
然后调用 GetWindow 10010 来进行获取菜单
 
GetMenu
 
GetMenuItemCount
 
GetMenuStringA 获取当前调试器的菜单
 
GetSubMenu
 
0GetMenuItemCount
 
防止检测OD菜单,直接hook GetDesktopWindow 这个api 当返回的值为10010,就修改为000000 或者直接改为mov eax,0
 
 
不哭暗桩就在GetDesktopWindow修改为mov eax,0 即可秒杀暗桩检测
 
 
3.空虚OD检测.exe
 
空虚OD检测中的驱动检测
 
这个检测主要是检测OD的StrongOD插件是否存在
 
分别调用了以下api函数
 
ZwQuerySystemInformation 枚举内核模块
 
这个函数可以用来查询进程信息、内核信息、硬件信息(例如CPU数目)、句柄信息、时间信息等54个系统信息。
 
RtlMoveMemory 从指定内存中复制内存至另一内存里 这个不能直接下该api函数 只能定位jmp eax来进行跳到该函数
 
LocalAlloc 从堆中分配指定大小的字节数
 
破解方法直接下ZwQuerySystemInformation这个函数断点,修改为retn 10 即可,要找准时机修改,不然会出错。
 
最直接的方法是设置sod,不要使用sod即可!
3.E盾AntiDebug
 
E盾检测分为3个部分
 
辅助_检测OD调试器
 
 
第一部分:
 
调用了GetStartupInfoA 来获取 获取启动信息,直接调用IsDebuggerPresent 这个从字面上理解就是检测是否被调试,但是因为我调试的时候加
 
了sod,所以这个函数可以直接无视,sod已经帮我们过了这个检测。
 
 
第二部分:
 
主要是检测OD菜单并且获取机器码,获取机器码应该是检测到调试就封正版账号,因为我目前还没有研究E盾,所以这里就不验证是否封号。
 
过检测OD菜单最简单,直接下GetDesktopWindow 如果返回值是10010 就直接修改为0即可。
 
 
第三部分:
 
检测sod,和空虚的驱动检测是一样的,所以可以总结出暗桩的特性都是差不多的,因为他们检测的项目都是一样的,不是检测菜单就是检测sod,
所以这里也是下 ZwQuerySystemInformation这个函数断点,修改为retn 10 即可。
 
 
OD结束调用了以下api
 
TerminateProcess //函数终止指定进程及其所有线程
 
ZwSetContextThread//修改目标进程线程执行位置
 
易语言退出
 
 
4.锦年OD检测.exe
和E盾的检测一模一样,自己可以参考锦年的检测模块源码,更加一目了然的知道哪里是关键检测。
 
 
 
5.防OD附加.exe
 
看易语言代码就只有简单几句,所以分析起来也是比较简单。
 
1、调用IsDebuggerPresent 检测是不是在调试状态,但是这个api已经被sod干掉了
 
2、0012FCD4 004010DE /CALL 到 GetModuleHandleA 来自 防OD附加.004010D9
0012FCD8 00468AA2 pModule = "ntdll.dll"
 
GetModuleHandleA 获取 ntdll.dll的句柄
 
3、0012FCD0 00401108 /CALL 到 GetProcAddress 来自 防OD附加.00401103
0012FCD4 77CF0000 |hModule = 77CF0000 (ntdll)
0012FCD8 00468AAC ProcNameOrOrdinal = "DbgBreakPoint"
 
获取DbgBreakPoint的地址
 
4、0012FCC8 00401145 /CALL 到 VirtualProtect 来自 防OD附加.00401140
0012FCCC 77D240E0 |Address = ntdll.DbgBreakPoint
0012FCD0 00000001 |Size = 0x1
0012FCD4 00000040 |NewProtect = PAGE_EXECUTE_READWRITE
0012FCD8 0012FCEC pOldProtect = 0012FCEC
 
当做对应之 Win32 函数的逻辑包装函数。VirtualProtect 的 Win32 实作会在呼叫处理序的虚拟位址空间里,变更认可页面区域上的保护。
 
BOOL VirtualProtect(
 
LPVOID lpAddress, // 目标地址起始位置
 
DWORD dwSize, // 大小
 
DWORD flNewProtect, // 请求的保护方式
 
PDWORD lpflOldProtect // 保存老的保护方式
 
我的理解是改写指定地址的内存属性
 
 
5、0012FCCC 00401179 /CALL 到 RtlMoveMemory 来自 防OD附加.00401174
0012FCD0 77D240E0 |Destination = ntdll.DbgBreakPoint
0012FCD4 00468AC2 |Source = 防OD附加.00468AC2
0012FCD8 00000001 Length = 0x1
 
拷贝内存
 
6、0012FCC8 004011AF /CALL 到 VirtualProtect 来自 防OD附加.004011AA
0012FCCC 77D240E0 |Address = ntdll.DbgBreakPoint
0012FCD0 00000001 |Size = 0x1
0012FCD4 00000020 |NewProtect = PAGE_EXECUTE_READ
0012FCD8 0012FCE4 pOldProtect = 0012FCE4
 
破解方法很简单,可以在GetModuleHandleA那里retn就可以了,附加的话,附加后单步走几下,然后直接运行就不会出现内存地址读取不了。
 
6.桃花仙人暗桩检测,看下源码就知道和不哭暗桩一样,下GetDesktopWindow 直接可以ko
 
先更新到这里,暂时就写那么多。
 
by 星空 之上
19:58 2016/6/20
原文地址:https://www.cnblogs.com/Sendige/p/9600791.html