对付DNF硬件断点的NtGetContextThread的写法

合集下载

OllyDbg常用断点

OllyDbg常用断点

OllyDbg常用断点查找子健bp RegSetValue(A) 设置子健bp RegSetValueEx(A) 设置子健程序专用断点:BP __vbaObjSet (功能限制----灰色按钮中断)bp __vbaFreeObjListbp __vbaVarDupbp MessageBoxA 窗口断点bp __vbaStrMoveBP __vbaFreeVarListbpx hmemcpybp ShellExecuteA (弹出网页窗口断点)bp rtcMsgBox (杀窗专用)bp __vbaStrCmpbp __vbaVarMovebp VarBstrCmp(字符串比较真码!!)bp __vbaStrCmp 字符串比较文件长度:RtcFileLenbp __vbaFreeStr 对付VB程序重启验证bp __vbaStrCmp 比较字符串是否相等bp __vbaStrComp 比较字符串是否相等bp __vbaVarTstNe 比较变量是否不相等bp __vbaVarTstEq 比较变量是否相等bp __vbaStrCopy 复制字符串bp __vbaStrMove 移动字符串bp MultiByteToWideChar ANSI字符串转换成Unicode字符串bp WideCharToMultiByte Unicode字符串转换成ANSI字符串bp __vbaStrCompbp __vbaStrCompVarbp __vbaStrTextCmpbp __vbaFileOpenbp __vbaInputFilebp __vbaFileSeekbp __vbaWriteFilebp __vbaFileClosebp rtcFileAttributesbp rtcFileDateTimebp rtcFileLenbp rtcFileLengthbp __vbaVarIntbp __vbaVarCmpGebp __vbaVarCmpGtbp __vbaVarCmpLebp __vbaVarCmpLtbp __vbaVarCmpNebp __vbaVarTextCmpEqbp __vbaVarTextCmpGebp __vbaVarTextCmpGtbp __vbaVarTextCmpLebp __vbaVarTextCmpLtbp __vbaVarTextCmpNebp __vbaVarTextTstEqbp __vbaVarTextTstGebp __vbaVarTextTstGtbp __vbaVarTextTstLebp __vbaVarTextTstLtbp __vbaVarTextTstNebp __vbaVarTstEq (字符串比较)bp __vbaVarTstGebp __vbaVarTstGtbp __vbaVarTstLebp __vbaVarTstLtbp __vbaVarTstNe注意:VB程序仍然可以使用普通API函数,只要函数“最终”CALL了这个函数上面的断点对应VB6程序,如果是VB5程序则将msvbvm60改成msvbvm50即可bpx hmemcpy 破解万能断点,拦截内存拷贝动作 (注意:Win9x专用断点,XP无效) bpx Lockmytask 当你用其它断点都无效时可以试一下,这个断点拦截按键的动作实在找不到断点可以试下面的方法:bmsg handle wm_gettext 拦截注册码(handle为对应窗口的句柄)bmsg handle wm_command 拦截OK按钮(handle为对应窗口的句柄)拦截窗口:bpx CreateWindow 创建窗口bpx CreateWindowEx(A/W) 创建窗口bpx ShowWindow 显示窗口bpx UpdateWindow 更新窗口bpx GetWindowText(A/W) 获取窗口文本拦截消息框:bpx MessageBox(A) 创建消息框bpx MessageBoxExA 创建消息框bpx MessageBoxIndirect(A) 创建定制消息框拦截警告声:bpx MessageBeep 发出系统警告声(如果没有声卡就直接驱动系统喇叭发声)vbaStrMove 移动字符串__vbaVarCat 连接字符串rtcMidCharVar 在字符串中取字符或者字符串!__vbaLenBstr 取字符串的长度vbaVarTstNe 变量比较vbaVarTstEq 变量比较rtcMsgBox 显示对话框VarBstrCmp 比较字符串VarCyCmp 比较字符串用OD载入脱壳后的程序,在命令行输入:bpx hmemcpy,然后回车,会弹出程序运行调用的所有的函数,在每个函数上设置好断点!说明:我破VB程序喜欢用这个断点设置方法,通过一步步跟踪,基本可以把握程序保护的思路,所以我破VB程序基本用这个断点,当然你可以用其它的断点,只要能找到关键,任何断点都是用意义的。

OllyDBG分析报告系列(3)---硬件断点

OllyDBG分析报告系列(3)---硬件断点

方的韩国Ollydbg(以下均简称为OD)中的硬件断点的主要原理是:将要下断点的内存地址放入调试寄存器对应的选项中,由调试寄存器将其断下,并报异常给OD,等待调试人员操作。

硬件断点的长度有3种情况:1个字节(1)、2个字节(2)、4个字节(4)硬件标识有8种情况:未知(0)、执行断点(1)、访问断点(2)、写入断点(3)、未知(4)、临时断点(5)、未知(6)、未知(7)临时断点主要用于单步跳过OD在以下结构体中存放了以下硬件断点的信息:第一个4字节:硬件断点的首地址第二个4字节:硬件断点的长度第三个4字节:硬件断点的标识下面三个4字节:未知004D8D70 7A 06 40 00 01 00 00 00 02 00 00 00 00 00 00 00 z @. ... .......004D8D80 00 00 00 00 00 00 00 00 00 00 00 00 ............通过分析,硬件断点表的设置、断点表的添加以及断点表的删除都是由不同的函数来完成的,一共有三个函数。

这里硬件断点表的添加和删除要特别说明一下,函数中会在添加断点表时检查调试线程是否是运行状态,如果是运行状态就会进入一个判断函数,并查看是否需要断下。

写完断点表后,断点的处理就不需要由这两个函数来完成了。

这里先概括的介绍其流程,下面再详细分析代码:添加硬件断点表(Sethardwarebreakpoint):该函数有三个参数:断点首地址、断点长度、断点标识(访问、写入、执行断点等等)1、判断是何种类型的断点,若是可执行断点的话,下断的内存长度只能是1,而且会强制设为1;2、若为断点类型不为4(这个还没有逆向出来)的话,要判断下断的内存长度是否是4的倍数,如果不是则退出;3、判断下断的内存长度是否为1、2、4,如果都不符合,则退出;4、读取硬件断点表数据,用于下面的比较;5、循环判断当前断点是否已经存在在硬件断点表中,判断的方法如下:a) 判断断点类型是否相同,不同则判断表中的下一个元素;b) 断点地址是否相同,相同则继续,不同则判断原先的断点是否命中在当前断点地址之中,若在其中,则修改原先的断点地址和长度,若不在其范围内,则判断下一个元素;c) 断点长度是否相同,相同则继续,不同则如同b的处理;d) 判断4个硬件调试寄存器是否已经用完,若用完了,则弹出硬件断点对话框,传入参数为1,要求用户必须删掉一个断点,若不删除,则退出;e) 若为类型为5、6、7的话,直接退出;f) 若有空余的寄存器元素,则把当前的断点信息赋值;6、检查线程是否运行,线程信息结构体是否存在,若没有运行则跳过下面的处理,直接退出;7、暂停所有活动线程;8、遍历所有线程,查询硬件断点表,EIP的地址是否等于断点表中的地址,判断方法如下:a) 设置调试寄存器属性为CONTEXT_DEBUG_REGISTERS,并得到线程环境,若得到线程环境失败则查询下一个线程;b) 根据硬件断点表中的数据修改线程环境结构体数据;c) 遍历整个硬件断点表,判断表中是否有值,若无则继续检查下一个;d) 根据硬件断点的不同做相应的处理,主要是设置调试寄存器的dr7;e) 遍历完硬件断点表后,使用SetThreadContext函数将线程环境设置回去;f) 继续遍历线程9、重启线程并退出函数00451CE3 . 6A 03 push 3 ; BreakPoint_Flag00451CE5 . 6A 01 push 1 ; BreakPoint_Len00451CE7 . 8B4D B0 mov ecx, dword ptr [ebp-50] ; |00451CEA . 51 push ecx ; | BreakPoint_Addr00451CEB . E8 A069FBFF call _Sethardwarebreakpoint ; \_Sethardwarebreakpoint该函数主要有三个参数:断点首地址、断点长度、断点标识(访问、写入、执行断点)00408690 >/$ 55 push ebp00408691 |. 8BEC mov ebp, esp00408693 |. 81C4 24FDFFFF add esp, -2DC00408699 |. 53 push ebx0040869A |. 56 push esi0040869B |. 57 push edi0040869C |. 8B75 10 mov esi, dword ptr [ebp+10] ;断点标识0040869F |. 8B7D 08 mov edi, dword ptr [ebp+8] ;断点首地址004086A2 |. 833D 5C374D00>cmp dword ptr [4D375C], 0004086A9 |. 75 08 jnz short 004086B3004086AB |. 83C8 FF or eax, FFFFFFFF004086AE |. E9 2F030000 jmp 004089E2一个switch…case循环体,用来判断要设置什么类型的硬件断点:004086B3 |> 83FE 01 cmp esi, 1 ;比较是否是执行断点004086B6 |. 74 0F je short 004086C7 ;跳转到处理函数004086B8 |. 83FE 05 cmp esi, 5004086BB |. 74 0A je short 004086C7004086BD |. 83FE 06 cmp esi, 6004086C0 |. 74 05 je short 004086C7004086C2 |. 83FE 07 cmp esi, 7004086C5 |. 75 09 jnz short 004086D0 ;如果都不是,跳到下面处理处理执行断点:004086C7 |> C745 0C 01000>mov dword ptr [ebp+C], 1 ;设置断点长度为1 004086CE |. EB 21 jmp short 004086F1 ;跳转到长度处理比较该断点标识是不是4004086D0 |> 83FE 04 cmp esi, 4004086D3 |. 75 08 jnz short 004086DD004086D5 |. 81E7 FFFF0000 and edi, 0FFFF ; Case 4004086DB |. EB 14 jmp short 004086F1 ;跳转到长度处理比较该断点标识是不是0004086DD |> 85F6 test esi, esi004086DF |. 74 10 je short 004086F1 ;跳转到长度处理断点标识为1、2、3时检查断点的长度及地址是否按内存对齐:004086E1 |. 8B55 0C mov edx, dword ptr [ebp+C] ; Default004086E4 |. 4A dec edx004086E5 |. 85FA test edx, edi004086E7 |. 74 08 je short 004086F1 ;跳转到长度处理004086E9 |. 83C8 FF or eax, FFFFFFFF ;内存不对齐则返回错误004086EC |. E9 F1020000 jmp 004089E2断点长度检查处理:004086F1 |> 837D 0C 01 cmp dword ptr [ebp+C], 1 ; Case 0004086F5 |. 74 14 je short 0040870B ;长度为一跳转004086F7 |. 837D 0C 02 cmp dword ptr [ebp+C], 2004086FB |. 74 0E je short 0040870B ;长度为二跳转004086FD |. 837D 0C 04 cmp dword ptr [ebp+C], 400408701 |. 74 08 je short 0040870B ;长度为四跳转00408703 |. 83C8 FF or eax, FFFFFFFF ;长度不为1 / 2 / 4时,返回错误00408706 |. E9 D7020000 jmp 004089E2查询断点表,要下的断点是否在表中,如果是则直接返回:0040870B |> B8 708D4D00 mov eax, 004D8D70 ;004D8070是断点表的首地址00408710 |. 33D2 xor edx, edx00408712 |. 8955 F8 mov dword ptr [ebp-8], edx00408715 |. 33DB xor ebx, ebx00408717 |> 8B50 08 /mov edx, dword ptr [eax+8]0040871A |. 85D2 |test edx, edx ;查询表是否有记录0040871C |. 74 3E |je short 0040875C ;没有则跳转到下一个记录结构体0040871E |. 3BF2 |cmp esi, edx ;比较断点类型是否相同00408720 |. 75 3A |jnz short 0040875C ;不同则跳转到下一个记录结构体如果要下的断点在断点表某个断点的范围内,则直接返回:00408722 |. 3B38 |cmp edi, dword ptr [eax] ;比较断点首地址与断点表地址00408724 |. 72 15 |jb short 0040873B ;断点首地址小则跳转00408726 |. 8B08 |mov ecx, dword ptr [eax]00408728 |. 8B55 0C |mov edx, dword ptr [ebp+C]0040872B |. 0348 04 |add ecx, dword ptr [eax+4]0040872E |. 03D7 |add edx, edi00408730 |. 3BCA |cmp ecx, edx ;比较断点尾地址与断点表尾地址00408732 |. 72 07 |jb short 0040873B ;断点尾地址大则跳转00408734 |. 33C0 |xor eax, eax00408736 |. E9 A7020000 |jmp 004089E2 ;跳转到结束处如果要下的断点在断点表中存在,则直接返回:0040873B |> 3B38 |cmp edi, dword ptr [eax] ;比较断点首地址与断点表地址0040873D |. 77 1D |ja short 0040875C ;断点首地址大则跳转0040873F |. 8B08 |mov ecx, dword ptr [eax]00408741 |. 8B55 0C |mov edx, dword ptr [ebp+C]00408744 |. 0348 04 |add ecx, dword ptr [eax+4]00408747 |. 03D7 |add edx, edi00408749 |. 3BCA |cmp ecx, edx ;比较断点尾地址与断点表尾地址0040874B |. 77 0F |ja short 0040875C ;断点尾地址小则跳转0040874D |. 8938 |mov dword ptr [eax], edi0040874F |. 8B4D 0C |mov ecx, dword ptr [ebp+C]00408752 |. 8948 04 |mov dword ptr [eax+4], ecx00408755 |. C745 F8 01000>|mov dword ptr [ebp-8], 1跳转到下一个结构体中:0040875C |> 43 |inc ebx0040875D |. 83C0 1C |add eax, 1C00408760 |. 83FB 04 |cmp ebx, 400408763 |.^ 7C B2 \jl short 00408717 如果断点表没访问完,继续比较查询断点是否包含在断点表中,包含则跳转到标识检查:00408765 |. 837D F8 00 cmp dword ptr [ebp-8], 000408769 |. 0F85 91000000 jnz 00408800通过检查断点表中的标识,判断断点表是否已满:0040876F |. 33DB xor ebx, ebx00408771 |. B8 788D4D00 mov eax, 004D8D7800408776 |> 8338 00 /cmp dword ptr [eax], 000408779 |. 74 09 |je short 00408784 ;如果有空位,跳转到下面处理0040877B |. 43 |inc ebx0040877C |. 83C0 1C |add eax, 1C0040877F |. 83FB 04 |cmp ebx, 400408782 |.^ 7C F2 \jl short 00408776 ;若断点表没访问完,继续比较如果断点表未满,则跳转到设置断点表代码中去:00408784 |> 83FB 04 cmp ebx, 400408787 |. 7C 40 jl short 004087C9如果断点表已满,比较断点标识,如果小于5则跳转到处理函数:00408789 |. 83FE 05 cmp esi, 5 ;标识为5,返回-10040878C |. 74 0A je short 004087980040878E |. 83FE 06 cmp esi, 6 ;标识为6,返回-100408791 |. 74 05 je short 0040879800408793 |. 83FE 07 cmp esi, 7 ;标识为7,返回-100408796 |. 75 08 jnz short 004087A000408798 |> 83C8 FF or eax, FFFFFFFF0040879B |. E9 42020000 jmp 004089E2 ;跳转到函数结束处断点表已满处理函数(弹出对话框选择在断点表中删除一个断点来放置现在的断点):004087A0 |> 6A 01 push 1 ; /Arg1 = 00000001004087A2 |. E8 AD070000 call _Hardbreakpoints ; \_Hardbreakpoints004087A7 |. 59 pop ecx004087A8 |. 85C0 test eax, eax ;查看是否有删除断点表中的值004087AA |. 74 08 je short 004087B4 ;如果有删除则跳转到下面检查空位004087AC |. 83C8 FF or eax, FFFFFFFF004087AF |. E9 2E020000 jmp 004089E2 ;如果选择取消,则返回-1这里检查断点表中是否有空位,没有则报错,并返回-1:004087B4 |> 33DB xor ebx, ebx004087B6 |. B8 788D4D00 mov eax, 004D8D78004087BB |> 8338 00 /cmp dword ptr [eax], 0 ;比较断点表的标识变量004087BE |. 74 09 |je short 004087C9 ;如果为0则跳转004087C0 |. 43 |inc ebx ;比较下一个表中的值004087C1 |. 83C0 1C |add eax, 1C004087C4 |. 83FB 04 |cmp ebx, 4004087C7 |.^ 7C F2 \jl short 004087BB ;如果没有比较完,继续比较004087C9 |> 83FB 04 cmp ebx, 4 ;查看断点表中有多少个值004087CC |. 7C 13 jl short 004087E1 ;如果断点表不满则跳转到下面004087CE |. 68 040D4B00 push 004B0D04; /当前没有空闲的位置进行新的硬件中断。

调试技巧(断点调试的各种技巧,让你调试程序更得心应手)

调试技巧(断点调试的各种技巧,让你调试程序更得心应手)

调试技巧(断点调试的各种技巧,让你调试程序更得⼼应⼿)断点的源由:INT 是Intel系列CPU的⼀个指令,可以让程序产⽣⼀个中断或者异常。

程序中如果有中断或者异常发⽣了以后,CPU会中断程序的执⾏,去⼀个叫做IDT的部件查找处理这个中断(或者异常)的例程(Handler)。

IDT是操作系统在启动的时候初始化的,⾄于IDT的细节问题,例如什么是IDT,怎样编写⼀个IDT的例程,怎样初始化IDT,可以去⽹上搜索⼀些资料。

总之,这⾥我们只要知道,CPU在执⾏程序指令过程中,碰到INT 3中断程序的执⾏,CPU然后去IDT表⾥⾯找到处理断点的例程⼊⼝。

这个例程要做的事情就是:1. 先看看机器⾥⾯是不是安装了⼀个调试器—记住,这⼀步很重要,之所以重要以后的⽂章⾥⾯会介绍。

2. 如果机器⾥⾯没有安装调试器,那么操作系统就会终⽌程序的执⾏。

3. 否则操作系统启动调试器,并将调试器附到进程上。

4. 这样,我们才能在调试器⾥⾯检查程序内部变量的值。

INT 3 (或者DebugBreak(),或者Debugger.Break())指令是我们⾃⼰在代码⾥⾯硬编码进去的,因此我们在Visual Studio⾥,在相应的代码⾏⾥⾯点⼀下,出现⼀个⼩红球,也就是说Visual Studio在程序指令集某个地⽅动态地添加了⼀个INT 3指令。

现在的问题来了,Visual Studio是如何在程序中正确找到插⼊INT 3指令的位置的?或者更具体⼀些,我们在源代码(⽂本⽂件)⾥⾯设置断点的,Visual Studio需要把代码⾏翻译成在程序指令集中的位置。

Visual Studio之所以需要做翻译,是因为通常⼀⾏C++或者 C#代码都会对应好⼏⾏汇编指令。

因此,Visual Studio需要⼀个额外的⽂件来执⾏这个翻译过程,这个额外的⽂件叫做调试符号⽂件(Symbols),是由编译器⽣成的。

Visual Studio系列的编译器,不论是C#、还是C++编译器都会⽣成这个调试符号⽂件,.pdb ⽂件。

最新TX过保护-DebugPort清0

最新TX过保护-DebugPort清0

最新TX过保护-DebugPort清0.txt21春暖花会开!如果你曾经历过冬天,那么你就会有春色!如果你有着信念,那么春天一定会遥远;如果你正在付出,那么总有一天你会拥有花开满圆。

最新过TX驱动保护,恢复debugport相关函数我过TX驱动是为了能用windbg调试DNF,我把他分成几个部分来做:1.恢复OpenProcess, OpenThread,ReadVirtualMemory,WriteVirtualMemory2.修改读写DebugPort的相关API3.修复AttachProcess步骤应该和以前是一样,但是方法变了.我做一个TX驱动保护恢复工具(由于要时不时的看看ssdt和对比反汇编索性做在一起了,后面有下载地址),在工具启动的时候(打开游戏之前)做一些数据初始化和收集工作,并在进入游戏之后在点恢复键做真正的恢复工作.[attach]190083[/attach]1. ReadVirtualMemory,WriteVirtualMemory这两个函数现在没有保护,在工具启动的时候复制前16个字节保存:ULONG AddrRead = (ULONG)KeServiceDescriptorTable->pSSDTBase + 0xBA * 4;ULONG AddrWrite = (ULONG)KeServiceDescriptorTable->pSSDTBase + 0x115 * 4;//记录NtReadVirtualMemory/NtWriteVirtualMemory 前16 字节OrgRead[0] = *(PULONG)(*(PULONG)AddrRead);OrgRead[1] = *(PULONG)(*(PULONG)AddrRead + 4);OrgRead[2] = *(PULONG)(*(PULONG)AddrRead + 8);OrgRead[3] = *(PULONG)(*(PULONG)AddrRead + 12);OrgWrite[0] = *(PULONG)(*(PULONG)AddrWrite);OrgWrite[1] = *(PULONG)(*(PULONG)AddrWrite + 4);OrgWrite[2] = *(PULONG)(*(PULONG)AddrWrite + 8);OrgWrite[3] = *(PULONG)(*(PULONG)AddrWrite + 12);恢复OpenProcess(OpenThread是一样的,只是跳转的地址需要重新计算):OpenProcess只修改了一处call ObOpenObjectByPointer, 直接用原始的地址去恢复直接蓝屏,修改call ObOpenObjectByPointer前的push代码跳转到自制代码也是蓝屏,甚至原本想修改e9的跳转地址再跳回来也是蓝屏,后来我把心一横,直接修改了OpenProcess的前两个push指令改成一个一个jmp,跳到我的自制代码,自制代码的结构是前16个字节做好堆栈直接jmp到一个写好的C函数,C函数的作用的是比较是否DNF.exe进程在调用OpenProcess,这里要先说一下在工具初始化的时候我分配了整个OpenProcess两倍加16个字节的代码数组也就是0x285*2+16,初始化的时候我已经复制了一份原始的OpenProcess到数组里面,然后在游戏运行的时候又复制了一份已经被HOOK了的OpenProcess代码在里面,所以C函数的作用是如果是DNF.exe的进程则进第二份被HOOK了的代码,否则进原始的代码:UCHAR MyThreadRoot[ThreadLength*2+16], MyProcessRoot[ProcessLength*2+16];// 游戏加载前,保存一次原始的函数代码BufferCode(MyThreadRoot+16, (ULONG)OldThread, ThreadLength);BufferCode(MyProcessRoot+16, (ULONG)OldProcess, ProcessLength);// 游戏加载后,保存一次被HOOK了的函数代码BufferCode(MyThreadRoot + ThreadLength + 16, (ULONG)OldThread, ThreadLength); BufferCode(MyProcessRoot + ProcessLength + 16, (ULONG)OldProcess, ProcessLength); // 修改OpenProcess前几个字节跳到自己的MyOpenProcessProcessCode[0] = *((BYTE*)OldProcess+0);ProcessCode[1] = *((BYTE*)OldProcess+1);ProcessCode[2] = *((BYTE*)OldProcess+2);ProcessCode[3] = *((BYTE*)OldProcess+3);ProcessCode[4] = *((BYTE*)OldProcess+4);ProcessCode[5] = *((BYTE*)OldProcess+5);addr1 = (ULONG)(UCHAR*)(MyProcessRoot) - (ULONG)OldProcess - 5;*(BYTE*)((ULONG)OldProcess) = 0xe9;*((BYTE*)((ULONG)OldProcess)+1) = *(BYTE*)(&addr1);*((BYTE*)((ULONG)OldProcess)+2) = *((BYTE*)(&addr1)+1);*((BYTE*)((ULONG)OldProcess)+3) = *((BYTE*)(&addr1)+2);*((BYTE*)((ULONG)OldProcess)+4) = *((BYTE*)(&addr1)+3);*((BYTE*)((ULONG)OldProcess)+5) = 0x90;// 下面是上面跳转到的自制代码// 这里相当于前面提到的代码数组的前16个字节,需要再跳到C函数进行上面提到的那个判断然后在选// 择跳到原始代码还是被HOOK了的代码addr1 = (ULONG)IsDNFprocess - (ULONG)MyProcessRoot - 5;*(BYTE*)((ULONG)MyProcessRoot) = 0xe8;*((BYTE*)((ULONG)MyProcessRoot)+1) = *(BYTE*)(&addr1);*((BYTE*)((ULONG)MyProcessRoot)+2) = *((BYTE*)(&addr1)+1);*((BYTE*)((ULONG)MyProcessRoot)+3) = *((BYTE*)(&addr1)+2);*((BYTE*)((ULONG)MyProcessRoot)+4) = *((BYTE*)(&addr1)+3);addr1 = (ULONG)(MyProcessRoot + ProcessLength + 16) - (ULONG)(UCHAR*)(MyProcessRoot + 7) - 6;*((BYTE*)((ULONG)MyProcessRoot)+5) = 0x85;*((BYTE*)((ULONG)MyProcessRoot)+6) = 0xc0;*((BYTE*)((ULONG)MyProcessRoot)+7) = 0x0f;*((BYTE*)((ULONG)MyProcessRoot)+8) = 0x84;*((BYTE*)((ULONG)MyProcessRoot)+9) = *(BYTE*)(&addr1);*((BYTE*)((ULONG)MyProcessRoot)+10) = *((BYTE*)(&addr1)+1);*((BYTE*)((ULONG)MyProcessRoot)+11) = *((BYTE*)(&addr1)+2);*((BYTE*)((ULONG)MyProcessRoot)+12) = *((BYTE*)(&addr1)+3);// 下面是那个判断是否是DNF.exe进程的C函数int IsDNFprocess() {char Name[16];if(GetProcessName(Name)) {if (strcmp(Name,"DNF.exe")) {dprintf("不是指定进程在调用!\n");return 1;}else {dprintf("是指定进程在调用!\n");return 0;}}else {dprintf("未获取到进程名!\n");return 2;}}// 下面是上面IsDNFprocess函数调用到的几个函数ULONG GetProcessNameOffset() {int i=0;PEPROCESS curproc;DWORD procNameOffset;curproc = PsGetCurrentProcess();for(; i< 4096; i++) {if( !strncmp( "System", (PCHAR) curproc + i, strlen("System") )) {procNameOffset = i;return procNameOffset;}}return 0;}BOOL GetProcessName( PCHAR theName ) {PEPROCESS curproc;char *nameptr;ULONG i;KIRQL oldirql;if( g_ProcessNameOffset ) {curproc = PsGetCurrentProcess();nameptr = (PCHAR) curproc + g_ProcessNameOffset;strncpy( theName, nameptr, 16 );theName[15] = '\0'; /**//* NULL at end */return TRUE;}return FALSE;}还有一个重要的处理是将被HOOK了OpenProcess中call ObOpenObjectByPointer地址提取出来重新计算代码数组第二段的call ObOpenObjectByPointer(因为e8是相对地址所以要再计算一次..)接下来是恢复DebugPort:还是老办法将nt!_eprocess+0xbc转移到其他地址,我尝试了0x70,0x74,我发现经常被修改,如果将DebugPort对象地址保存到里面被修改之后再由nt!PsGetProcessDebugPort返回出来直接蓝屏,我用的0x78这个地址好象没怎么被修改.找DebugPort相关是函数我是直接KD调试虚拟机,然后先设置硬件写断点,然后在虚拟机里面随便调试一个进程,ba w4 nt!_eprocess+0xdc,找出所有修改了这个地址的API,然后再找读的,读和写是一个方法.找到之后我整理了一下有如下几个(我看到有人找的和我找的很多不一样,我百思不得其解,这也是我最后要请教的问题):// 自己跟踪出来的地址(下面用的0x74我已经换成了0x78)写1 nt!DbgkpSetProcessDebugObject+0x6a 8063a9308063a98e 8b450c mov eax,dword ptr [ebp+0Ch]8063a991 8b4d14 mov ecx,dword ptr [ebp+14h]8063a994 8987bc000000 mov dword ptr [edi+0BCh],eaxChange: 898774000000 {0x89,0x87,0x74,0x00,0x00,0x00}2 nt!DbgkCopyProcessDebugPort+0xf80639993 8b4508 mov eax,dword ptr [ebp+8]80639996 83a0bc00000000 and dword ptr [eax+0BCh],0读1 nt!DbgkpSetProcessDebugObject+0x5c 8063a9308063a980 c645ff01 mov byte ptr [ebp-1],18063a984 ffd6 call esi8063a986 399fbc000000 cmp dword ptr [edi+0BCh],ebxChange: 399f74000000 {0x39,0x9f,0x74,0x00,0x00,0x00}2 nt!DbgkpMarkProcessPeb+0x48 806398fa80639937 897dfc mov dword ptr [ebp-4],edi8063993a 33c0 xor eax,eax8063993c 39bebc000000 cmp dword ptr [esi+0BCh],ediChange: 39be74000000 {0x39,0xbe,0x74,0x00,0x00,0x00}3 nt!DbgkCreateThread+0x12b 8063b08c8063b1b1 399ebc000000 cmp dword ptr [esi+0BCh],ebxChange: 399e74000000 {0x39,0x9e,0x74,0x00,0x00,0x00}4 nt!DbgkpQueueMessage+0x81: 80639bec80639c64 8b4508 mov eax,dword ptr [ebp+8]80639c67 8b80bc000000 mov eax,dword ptr [eax+0BCh]Change: 8b8074000000 {0x8b,0x80,0x74,0x00,0x00,0x00}5 nt!PsGetProcessDebugPort+0xe 8052874c8052874f 8bec mov ebp,esp80528751 8b4508 mov eax,dword ptr [ebp+8]80528754 8b80bc000000 mov eax,dword ptr [eax+0BCh]Change: 8b8074000000 {0x8b,0x80,0x74,0x00,0x00,0x00}6 nt!DbgkForwardException+0x44 8063aee08063af1e 8b81bc000000 mov eax,dword ptr [ecx+0BCh]Change: 8b8174000000 {0x8b,0x81,0x74,0x00,0x00,0x00}7 nt!PspExitThread+0x28c 805c938a805c9606 7408 je nt!PspExitThread+0x286 (805c9610)805c9608 8b4de0 mov ecx,dword ptr [ebp-20h]805c960b e862a5f5ff call nt!ObfDereferenceObject (80523b72)805c9610 399fbc000000 cmp dword ptr [edi+0BCh],ebxChange: 399f74000000 {0x39,0x9f,0x74,0x00,0x00,0x00}8 nt!DbgkExitThread+0x26 8063b42a8063b441 f6804802000004 test byte ptr [eax+248h],48063b448 7551 jne nt!DbgkExitThread+0x71 (8063b49b)8063b44a 8b89bc000000 mov ecx,dword ptr [ecx+0BCh]Change: 8b8974000000 {0x8b,0x89,0x74,0x00,0x00,0x00}9 nt!KiDispatchException+0x18d 804fd94e804fdacc 64a124010000 mov eax,dword ptr fs:[00000124h]804fdad2 8b4044 mov eax,dword ptr [eax+44h]804fdad5 39b8bc000000 cmp dword ptr [eax+0BCh],ediChange: 39b874000000 {0x39,0xb8,0x74,0x00,0x00,0x00}10 nt!DbgkpCloseObject+0x3e:8063a7bd 8b5d08 mov ebx,dword ptr [ebp+8]8063a7c0 81c3bc000000 add ebx,0BChChange: 81c374000000 {0x81,0xc3,0x74,0x00,0x00,0x00}然后是修改相关API,我没有一个一个找特征码我怕漏了,我直接计算了KernelBase和KernelSize比如0x804d8000, 0x1f000000,我就在这区间里面直接替换。

轻松过掉DNF游戏保护

轻松过掉DNF游戏保护
invoke ModifyFuncAboutDbg, Dspdo_1, 90784789h, 0fde89090h invoke ModifyFuncAboutDbg, Dmpp_1, 90787e39h, 950f9090h invoke ModifyFuncAboutDbg, Dct_1, 90785e39h, 840f9090h invoke ModifyFuncAboutDbg, Dqm_1, 9078408bh, 45899090h invoke ModifyFuncAboutDbg, Kde_1, 90787839h, 13749090h invoke ModifyFuncAboutDbg, Dfe_1, 9078418bh, 0d2329090h invoke ModifyFuncAboutDbg, Pcp_1, 90784389h, 45f69090h
.code ;还原自己的 Hook DriverUnload proc pDriverObject:PDRIVER_OBJECT
ret
DriverUnload endp
ModifyFuncAboutDbg proc addrOdFunc, cmd_1, cmd_2 pushad mov ebx, addrOdFunc mov eax, cmd_1 mov DWORD ptr [ebx], eax mov eax, cmd_2 mov DWORD ptr [ebx + 4], eax popad ret
and eax,not 10000h mov cr0,eax }
*((ULONG*)Address) = (ULONG)MyNtReadVirtualMemory;//HOOK SSDT *((UriteVirtualMemory;

使用OllyDbg从零开始Cracking 第十一章-硬件断点与条件断点

使用OllyDbg从零开始Cracking 第十一章-硬件断点与条件断点

第十一章:硬件断点与条件断点下面我们将把剩下的类型的断点介绍完,本章先介绍硬件断点和条件断点。

硬件断点硬件断点(简称:HBP)是处理器的特性之一,它的工作原理我不是很了解,但是我们会用就行了,我们可以设置硬件断点使程序中断下来。

在OD中我们最多可以设置4个硬件断点,如果想设置第5个的话,你需要删除已经设置了的4个中的其中一个。

跟之前一样,我们还是拿CrueHead'a的CrackMe来做实验。

硬件断点分为:硬件执行断点(ON EXECUTION),硬件写入断点(ON WRITE),硬件访问断点(ON ACCESS)3种。

硬件执行断点与普通的CC断点作用一样,但硬件执行断点并不会将指令首字节修改为CC,所以更难检测。

但是有些程序会使用一些技巧来清除硬件断点,应对方法我们会在后面的章节介绍。

如果你想在401013处设置硬件执行断点的话,请在401013这一行单击鼠标右键选择-Breakpoint-Hardware,on execution。

也可以在命令栏中输入:这样可以设置硬件执行断点。

OD中有个特殊的窗口,通过它我们可以查看和管理硬件断点。

我们选择菜单栏中的Debug-Hardware breakpoints就可以打开这个窗口。

在硬件断点窗口中,如果我们单击Follow按钮,反汇编窗口中该硬件断点所对应的那一行指令就会灰色高亮显示。

如果我们单击Delete按钮,那么相应的硬件断点就会被清除。

现在按F9键运行程序。

中断在401013处。

正如你所看到的,起到的效果跟普通的CC断点有点像,如果你像对CC断点做的测试-MOV EAX,DWORD PTR DS:[401013]一样的话,你会发现机器码并没有改变。

在401000这一行单击鼠标右键选择-New origin here将EIP修改为401000,接着按F7键单步。

可以看到EAX的值为0004A6E8,内存的形式为E8 A60400,机器码并没有发生变化。

OllyDBG断点

OllyDBG断点

OllyDBG断点INT3 断点INT3 断点是在汇编指中向下断地址写⼊0xCC指令,当被调试进程执⾏INT3指令时产⽣异常,调试器就会捕获这个异常,从⽽停在断点处。

在OllyDBG中使⽤快捷键F2来设置或取消断点。

硬件断点硬件断点和DRx调试寄存器有关。

DRx调试寄存器共有8个(DR0-DR7),硬件断点的原理是使⽤DR0-DR7设置地址,并使⽤DR7设置状态,所以最多设置4个断点。

设置硬件断点的快捷键是F4内存断点OD可以设置内存访问或写⼊断点,原理是对所设置的地址赋予不可访问/不可写属性,这样当访问/写⼊的时候就会产⽣异常。

OD捕获异常后,⽐较异常地址是不是断点地址,如果是中断。

OllyDBG设置内存断点的⽅式:点击View -> Memory调出内存窗⼝,在需要下断点的地⽅右击选择set memory breakpoint on write内存访问⼀次性断点windows对内存使⽤段页式的管理⽅式。

在OD⾥按“Alt+M”快捷键显⽰内存,可以看到许多个段,每个段都有不可访问、读、写、执⾏属性。

在相应的段上点击右键,会在快捷菜单中发现⼀个命令“set memory breakpoint on access”,⽤于对整个内存块设置断点。

这个断点是⼀次性的,当所在段被读取或执⾏时就会中断。

如果想捕获调⽤或返回某个模块,该类断点就⾮常有⽤。

消息断点Windows本⾝是由消息驱动的,如果调试时没有合适的断点,可以尝试使⽤消息断点,当某个特定窗⼝函数接受到某个指定消息时,消息断点将使程序中断。

消息断点与INT 3断点的区别在于:INT 3断点可以在程序启动之前设置,消息断点只有在窗⼝被创建之后才能被设置并拦截消息的断点设置⽅法:View -> Windows列出窗⼝中相关参数OD⽆法反汇编代码逆向脱ASPack壳找OEP时发现程序在跳转到OEP后OD⽆法分析出代码,如下图。

按Ctrl+A或者右键删除分析即可。

浅谈ASPROTECT脱壳

浅谈ASPROTECT脱壳

1. 一般的壳,没有Stolen Code的情况ASProtect 1.2 / 1.2c-> Alexey SolodovnikovASProtect 1.23 RC1 -> Alexey SolodovnikovASProtect 2.3 SKE build 06.26 Beta [Extract]对于这些壳一般脱壳方法:忽略除了内存访问之外的所有异常,直接Shift+F9运行。

运行到最后一次异常后,打开内存镜像,来到00401000处,F2断点,F9中断,到达OEP注意:判断最后一次异常的方法:注意堆栈,从硬盘指纹出现,直到没有了硬盘指纹后,那么就是最后一次异常保存注册名:一般的话,当出现硬盘指纹第二次后,打开内存,00401000处,F2断点,此时中断下来的地方,对应的move语句里面的就是保存的注册名的地方2. 有Stolen Code的情况下ASProtect 1.23 RC4 - 1.3.08.24 [1]方法一:忽略除了内存访问的所有异常,开始Shift+F9运行。

当出现硬盘指纹的第二次的时候,打开内存,00401000处,F2断点,F9中断下来!那么此时的mov语句里面的值对应的就是保存“注册名”的地方!此时继续,来到最后一次异常!在下面的第一个retn处,F2断点,F9中断下来!此时,注意堆栈:ASCII码的第二行所对应的地址,形如:0012FF60 00400000 crysb.004000000012FF64 574F42C80012FF68 0012FFA4 //这里的地址 0012FF68此时命令行下:hr 0012FF68 F9运行,中断下来后!取消硬件断点,F7跟进一下此时F8单步一下,这个对应的内存地址就是以壳解壳的区域,此时我们可以做的1.以壳解壳:到达上面的一步,此时Lord—PE脱壳,首先是完整脱壳,接着是区域脱壳区域脱壳的地址要包含我们此时到达对应的内存地址接着就是利用PE编辑器载入完整脱壳的程序,选择最后一个区段,从磁盘载入刚才区域脱壳的文件,载入完成后,修改VA和区段名VA=区域脱壳的地址减去基址接着就是重建PE上述完成后,此时就是修复的工作此时用AsprDBGr.exe 载入加壳程序,找到OEP地址,REC修复的时候选择最上面一个进程,此时填入OEP,IAT自动搜索后,修复了IAT后,此时不要抓取修复把OEP地址改成区域脱壳到达的地址,此时抓取修复!此时OD打开现在抓取修复好了的文件!刚才记录的保存注册名的地方,命令行下DD 注册名地址,在下面找一个全0的区域,二进制编辑写入自己的注册名,记下这个内存地址。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档