当前位置: 首页 > 科技观察

说说一个C#商业程序的反反调试

时间:2023-03-20 19:39:14 科技观察

一、背景1、讲故事前段时间有朋友在微信上找到我,说用WinDbg无法附加一个商业C#程序。之后C#程序就自动退出了,这是怎么回事呢?有什么不对?有经验的朋友应该知道,这其实是商业程序的反调试机制造成的。人们为了保护程序的隐私,一般不希望别人对自己进行逆向分析。你能破解它的反调试机制吗?羊毛布?当然可以,难易程度就看对方的诚意了。摆弄了一下朋友的技术,发现还可以。对方刚刚用的是KERNELBASE!IsDebuggerPresent进行反调试判断,老规矩,在WinDbg上讲。二、WinDbg分析1、案例演示为了便于描述,我们先来举个例子。内部类程序{[DllImport("kernelbase.dll",SetLastError=true)]staticexternboolIsDebuggerPresent();staticvoidMain(string[]args){Console.ReadLine();varisAttached=IsDebuggerPresent();if(isAttached){Console.WriteLine("/(ㄒoㄒ)/~~小心,我附加了一个调试器!");}else{Console.WriteLine("O(∩_∩)O程序是安全的!");}控制台.ReadLine();}}这是没有WinDbg时的输出方式。这是WinDbg的输出。肯定有小伙伴生气了,为什么C#里面有个Debugger.IsAttached属性,为什么不用呢,我试过了,这东西很烂,WinDbg等非托管调试器的attachment检测不到。2.IsDebuggerPresent方法简单说明IsDebuggerPresent方法其实就是提取PEB中的BeingDebugged字段。这个字段是在KernelBase.dll中定义的,那么如何验证呢?可以用!peb查看进程环境块的地址,然后用dt观察。0:001>!pebPEBat000000000035b000InheritedAddressSpace:NoReadImageFileExecOptions:NoBeingDebugged:YesImageBaseAddress:00007ff719030000NtGlobalFlag:4000NtGlobalFlag2:0Ldr00007ffb1259b4c0...0:001>dtntdll!_PEB000000000035b000+0x000InheritedAddressSpace:0''+0x001ReadImageFileExecOptions:0''+0x002bueDebugged:0x1'+0x003比特菲尔德:0x4''+0x003ImageSuseslargePages:0y0+0x003isprotectedProcess:0y0+0x003Isimagedysimagedysimagedynymagedyallyallyallyallicallysallycalialicallialcalialityandy1+0y1+0x003Skippippatchinguser32foring的,当前程序附有调试器。3.反反调试思路找到IsDebuggerPresent()方法的阅读源。这个问题很容易处理。通常有两种方法。修改IsDebuggerPresent()方法的反汇编代码。只要IsDebuggerPresent()方法一直返回false,那么我们就可以成功破解反调试。首先用x命令找到IsDebuggerPresent()的汇编代码,输出如下:0:007>xKernelBase!IsDebuggerPresent00007ffb`0fe468a0KERNELBASE!IsDebuggerPresent(IsDebuggerPresent)0:007>u00007ffb`0fe468a0KERNELBASE!PresentDebug:00007ffb`0fe468a065488b042560000000movrax,qwordptrgs:[60h]00007ffb`0fe468a90fb64002movzxeax,byteptr[rax+2]00007ffb`0fe468adc3ret00007ffb`0fe468aeccint300007ffb`0fe468afccint300007ffb`0fe468b0ccint300007ffb`0fe468b1ccint300007ffb`0fe468b2ccint3根据stdcall协议,eax会作为方法的返回值,然后用WinDbg的a命令修改00007ffb0fe468a0处的汇编代码,输入汇编代码,按回车即可,输出如下:0:007>a00007ffb`0fe468a000007ffb`0fe468a0moveax,000007ffb`0fe468a5ret00007ffb`0fe468a60:007>u00007ffb`0fe468a0KERNELBASE!IsDebuggerPresent:00007ffb`0fe468a0b800000000moveax,000007ffb`0fe468a5c3ret00007ffb`0fe468a60000addbyteptr[rax],al00007ffb`0fe468a8000faddbyteptr[rdi],cl00007ffb`0fe468aab640movdh,40h00007ffb`0fe468ac02c3addal,bl00007ffb`0fe468aeccint300007ffb`0fe468afccint3可以看到WinDbg已经成功修改了KERNELBASE!IsDebuggerPresent方法的代码,哈哈,继续走,截图如下:可以看到反反调试成功,看到程序很开心,我也很happytousebpbreakpointstointerceptsuch方法是用bp+script来拦截,大概是用脚本自动修改KERNELBASEret处的eax值吧!IsDebuggerPresent。这也是可以的,当然也是最安全的。先看ufKERNELBASE!IsDebuggerPresent函数的汇编代码。0:004>ufKERNELBASE!IsDebuggerPresentKERNELBASE!IsDebuggerPresent:00007ffb`0fe468a065488b042560000000movrax,qwordptrgs:[60h]00007ffb`0fe468a90fb64002movzxeax,byteptr[rax+2]00007ffb`0fe468adc3ret接下来在00007ffb0fe468ad处下下一个断点,也就是位置KERNELBASE!IsDebuggerPresent+0xd,然后用寄存器修改命令r修改eax的值,然后让程序gc,脚本代码如下:0:004>bpKERNELBASE!IsDebuggerPresent+0xd"reax=0;gc"0:004>g可以看到此时的程序又在笑了。3.小结本文无意对抗,只是一个难题的探索,大家要合理使用。