反调试技术 - 阻止我设置内存和硬件断点。我怎样才能绕过它?

逆向工程 视窗 部件 ollydbg 反调试 登录
2021-07-02 05:11:49

我正在调试这个过程,其中有很多反调试技术,我遇到了一些我不知道如何绕过的新事物。

动态更改代码会导致发生异常并导致进程崩溃。所以设置INT 3断点不是一个选项。我调试过程的方式只是使用Hardware Breakpoints.

现在我找到了读取部分内存并在该内存上使用一些 CheckSum 函数的函数(至少其中之一......),然后它检查内存 CheckSum 是否符合预期。如果我更改了内存中的一个字节,CheckSum 将不会像预期的那样,因此进程会崩溃。这实际上非常简单,在代码中是这样完成的:

CMP EAX,EDX                  ; Compare CheckSum
JE __GoodCode                  ; jmp must be taken
CALL <CrashProgram>
__GoodCode: 
XOR EAX,EAX
...

JE shortis的十六进制值,0x74 0x0B我想将其更改为JMP shortis 0xEB 0x0B当我这样做时,程序会崩溃。Memory breakpoints在代码的不同位置找到了程序崩溃的地方,然后我找到了执行 CheckSum 的函数(它读取所有内存)。但是现在我发现还有另一个现有的功能可能会做类似的事情!导致程序崩溃。

但是这一次,当我将Memory breakpoint“已更改”的 JE 设置为 JMP 时,它永远不会在断点处停止。

所以这是我的第一个问题,我遇到的另一个问题是我怀疑有一个函数与更改代码时的崩溃有关,但是当我Hardware breakpoint在它上面设置 a时,它没有中断。我确信正在调用此函数并且代码肯定会运行。所以我对自己想,可能有某种东西可以确保我Memory & Hardware breakpoints无法工作,某种反调试机制。

我读了一点关于它并发现大约GetThreadContext,在我的情况下它调用Wow64GetThreadContext. 它接收一个包含大多数寄存器的上下文结构。下面是 Context 结构的样子:

CONTEXT _X86_

typedef struct _CONTEXT {
DWORD ContextFlags;
/* ContextFlags contians CONTEXT_DEBUG_REGISTERS. */
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
/* ContextFlags contians CONTEXT_FLOATING_POINT. */
FLOATING_SAVE_AREA FloatSave;
/* ContextFlags contians CONTEXT_SEGMENTS. */
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
/* ContextFlags contians CONTEXT_INTEGER.*/
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
/* ContextFlags contians CONTEXT_CONTROL */
DWORD Ebp;
DWORD Eip;
DWORD SegCs; // MUST BE SANITIZED
DWORD EFlags; // MUST BE SANITIZED
DWORD Esp;
DWORD SegSs;
/* ContextFlags word contains CONTEXT_EXTENDED_REGISTERS */
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;

第一个参数是我的Hardware breakpoints,我可以清楚地看到它们,但它似乎对它们的值没有任何作用。所以我不认为是这个函数导致了崩溃。每当它被调用时,它看起来更像是一个调试代码。此外,这个函数永远不会被定期调用——只有在程序崩溃之后。

现在还有ReadProcessMemory我读过的,它可能Memory breakpoints出于某种原因绕过我的。我在该函数上设置了日志断点,但它似乎从未读取过Page接近我更改的函数(大小 0x1000),是的,我也检查了它正在读取的大小。虽然这个函数被定期调用,但它似乎仍然不是这样。

我还听说过ZwProtectVirtualMemory更改内存区域属性的函数,以便Memory breakpoint不会发生“异常”,并且调试器不会收到它们。这个函数正在被调用,但我不确定它的用途是什么,或者内存中哪些参数与我相关。

还有什么我可能会遗漏的吗?

我正在阅读的文章对我有很大帮助,但没有帮助我找出导致崩溃的原因:http : //waleedassar.blogspot.in/2012/11/defeating-memory-breakpoints.html


我已经改变了我对这个问题的措辞。我希望现在更清楚了。

1个回答

一些可能性(很多):

1. 程序可以调用SetThreadContext, 或者ZwContinue使用新的上下文设置所有寄存器。如果 DRx 寄存器复位,则硬件断点将被删除。

2. 程序调用ZwSetInformationThread带有0x11( ThreadHideFromDebugger) 参数。如果线程对调试器隐藏,则调试器不会捕获断点异常,但将传递给程序,如果未处理 - 它将崩溃。