简单的反逆向工程指南(一)

本文由 @lonelyrains 出品,转载请注明出处。 
文章链接: http://blog.csdn.net/lonelyrains/article/details/9291093


原文在 这里,作者2008年发布这篇文章的时候还是高中生,自惭~

本文博客地址:http://blog.csdn.net/lonelyrains/article/details/9291093


简介

       在之前的文章里,曾经简要介绍过初级地使用Win32 API反调试/调试检测的方法。这篇文章里,我打算在逆向工程方面走得远一点,多探索一点中间级技术,消遣一下逆向工程师们。在上一篇文章里,有些评论说我提到的反调试技术很容易被中间级逆向工程玩家攻破。我想说,在开发人员和破解逆向工程师之间有一场正在上演的战役。每次防破解工程时发布一种新技术,逆向工程师们总有特殊的方法绕过这道障碍。这是破解和反逆向的角力。这里提到的大多数技术都可以被轻易破解,还有一些不那么容易。然而,它们都可以以某种手段破解。我在此把这些方法共享,希望有其他人能应用这些方法,并且延伸出新的路数,挑战当前的经典教义。


背景

       所有对逆向工程感兴趣的人需要对汇编有深刻的理解,所以如果你的汇编基础有点粗糙或者你只是个初学者,这里有些网站推荐:

内联函数

       我本觉得这部分不值得一提,但是当读到这篇文章或者附上的源码时,可能读者会注意到函数被标记为内联属性。虽然会导致执行文件变大,但它对反逆向工程是非常重要的。如果有非常详尽的函数入口和分区,逆向工程师可以更轻松完成它们的任务。他们将函数被调用时到底做了什么。如果是内联的,就不会这样,他们需要猜测函数的行为。


断点

       逆向工程中有三种类型的可用断点:硬件、内存和INT 3h的断点。断点是逆向工程的基础,没有它们,模块的现场分析无从谈起。在一个程序的任意位置设置断点,都可以让程序暂停执行。逆向工程师们可以在很多地方设置断点,例如Windows API,可以轻易找到‘坏男孩’消息(例如一个消息框,告诉你填了一个错误的序列号)从哪里来的。事实上,这可能是在破解时最有用的技术。唯一的挑战可能就是在程序中进行提示消息的字符串搜索。这就是为什么对例如MessageBox、VirtualAlloc、CreateDialog这样提示和保护用户消息流程的API来说,断点检测至关重要。下面第一个例子将描述使用最典型的INT 3h指令断点的场景。

INT 3

       INT 3h断点在IA-32指令集中有所描述,使用操作码CC(0xCC)。这是这种断点最常见的表达式;然而,它也可用导致一些麻烦的0xCD 0x03 字节序组合来表达。检测这种断点相对简单一些,示例代码如下。然不够,我们必须小心使用,因为使用这种扫描方法可能导致误判(false positives)。

bool CheckForCCBreakpoint(void* pMemory,  size_t SizeToCheck)
{
     unsigned char *pTmp = (unsigned char*)pMemory; 
    for (size_t i = 0; i < SizeToCheck; i++)
     {
         if(pTmp[i] == 0xCC)
             return true;
     } 

    return false;
}
       下面是另一种检测INT 3断点的混淆方法。要知道上面的代码即使对逆向新玩家来说都太傻叉了(stick out like a sore thumb)。通过引入间接方法,你,守卫者,将提高成功保护应用的概率。

bool CheckForCCBreakpointXor55(void* pMemory,  size_t SizeToCheck)
 {
     unsigned char *pTmp = (unsigned char*)pMemory;
    unsigned char tmpchar = 0;
        
    for (size_t i = 0; i < SizeToCheck; i++)
     {
        tmpchar = pTmp[i];
        if( 0x99 == (tmpchar ^ 0x55) ) // 0xCC xor 0x55 = 0x99
            return true;
     } 

    return false;
 }
内存断点

       内存断点通过调试器使用守卫内存页实现。守卫内存页就像内存页访问的一次性闹铃。简言之(in a nutshell),当内存页被标记为PAGE_GUARD并且被访问时,就会抛出一个STATUS_GUARD_PAGE_VIOLATION异常,然后通过当前程序的异常处理机制捕获和处理。此时,无法精确进行内存断点检测。然而,我们可以使用调试器实现内存断点的技术检测我们的程序当前是否在调试环境运行。大体上(in essense),就是我们先分配一块动态缓存,写一个RET到这个缓存中。然后标记这页为守卫页,并往栈上压入一个潜在的返回地址。这样一来,如果在调试环境下,就跳到我们的页内,特别是OllyDBG,然后出发RET指令,在跳到我们的页内之前,返回到我们往栈上放的地址。否则,抛出一个STATUS_GUARD_PAGE_VIOLATION异常,然后就知道不在被OllyDBG调试。下面是源码样例:

bool MemoryBreakpointDebuggerCheck()
{
     unsigned char *pMem = NULL;
     SYSTEM_INFO sysinfo = {0}; 
     DWORD OldProtect = 0;
     void *pAllocation = NULL; // Get the page size for the system 
 
    GetSystemInfo(&sysinfo); // Allocate memory 
 
    pAllocation = VirtualAlloc(NULL, sysinfo.dwPageSize, 
                        MEM_COMMIT | MEM_RESERVE, 
                         PAGE_EXECUTE_READWRITE); 
        
    if (pAllocation == NULL)
        return false; 
    
    // Write a ret to the buffer (opcode 0xc3)
    pMem = (unsigned char*)pAllocation;
    *pMem = 0xc3; 
    
    // Make the page a guard page         
    if (VirtualProtect(pAllocation, sysinfo.dwPageSize, 
                    PAGE_EXECUTE_READWRITE | PAGE_GUARD, 
                    &OldProtect) == 0)
    {
        return false;
    } 
    
    __try
    {
        __asm
        {
            mov eax, pAllocation
            // This is the address we'll return to if we're under a debugger
            push MemBpBeingDebugged
            jmp eax // Exception or execution, which shall it be :D?
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        // The exception occured and no debugger was detected
        VirtualFree(pAllocation, NULL, MEM_RELEASE);
        return false;
    }     
    
    __asm{MemBpBeingDebugged:}
    VirtualFree(pAllocation, NULL, MEM_RELEASE);
    return true;
}
硬件断点

       硬件断点是Intel在他们的处理器架构中实现的一种技术,通过利用特殊寄存器Dr0~Dr7控制。Dr0~Dr3是保存断点的32位寄存器。Dr4和Dr5是Intel保留用作调试其他寄存器的。Dr6和Dr7用作控制断点的行为(Intel1【注,不知道Intel1代表什么意思】)。Dr6和Dr7寄存器是如何影响断点的行为,这部分的内容有点太多。不过,如果有兴趣,可以参阅Intel® 64 和 IA-32 架构软件开发手册卷3B:系统编程向导:寄存器工作原理深度解释(System Programming Guide for an indepth explanation of how registers work)。

       现在,为了检测并且/或者移除硬件断点,有两种方法我们可以采用:Win32的GetThreadContext和SetThreadContext,或者使用结构化异常处理。在下面第一个例子中,将展示如何使用Win32的API:

// CheckHardwareBreakpoints returns the number of hardware 
// breakpoints detected and on failure it returns -1.
int CheckHardwareBreakpoints()
{
    unsigned int NumBps = 0;

    // This structure is key to the function and is the 
    // medium for detection and removal
    CONTEXT ctx;
    ZeroMemory(&ctx, sizeof(CONTEXT)); 
    
    // The CONTEXT structure is an in/out parameter therefore we have
    // to set the flags so Get/SetThreadContext knows what to set or get.
    ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; 
    
    // Get a handle to our thread
    HANDLE hThread = GetCurrentThread();

    // Get the registers
    if(GetThreadContext(hThread, &ctx) == 0)
        return -1;

    // Now we can check for hardware breakpoints, its not 
    // necessary to check Dr6 and Dr7, however feel free to
    if(ctx.Dr0 != 0)
        ++NumBps; 
    if(ctx.Dr1 != 0)
           ++NumBps; 
    if(ctx.Dr2 != 0)
           ++NumBps; 
    if(ctx.Dr3 != 0)
        ++NumBps;
        
    return NumBps;
}
       SEH方法来操作调试寄存器在反逆向工程的程序中更常见,并且通过汇编更容易实现,代码示例如下:

; One quick note about this little prelude; in Visual Studio 2008 
; release builds are compiled with the /SAFESEH flag which helps
; prevent exploitation of SEH by shellcode and the likes.
; What this little snippet does is add our SEH Handler to a
; special table containing a list of "safe" exceptions handlers , which
; if we didn't in release builds our handler would never be called,
; this problem plauged me for a long time, and im considering writing
; a short article on it

ClrHwBpHandler proto
 .safeseh ClrHwBpHandler

ClearHardwareBreakpoints proc
     assume fs:nothing
     push offset ClrHwBpHandler
    push fs:[0]
    mov dword ptr fs:[0], esp ; Setup SEH
     xor eax, eax
     div eax ; Cause an exception
     pop dword ptr fs:[0] ; Execution continues here
     add esp, 4
     ret
ClearHardwareBreakpoints endp

ClrHwBpHandler proc 
     xor eax, eax
    mov ecx, [esp + 0ch] ; This is a CONTEXT structure on the stack
     mov dword ptr [ecx + 04h], eax ; Dr0
     mov dword ptr [ecx + 08h], eax ; Dr1
     mov dword ptr [ecx + 0ch], eax ; Dr2
     mov dword ptr [ecx + 10h], eax ; Dr3
     mov dword ptr [ecx + 14h], eax ; Dr6
     mov dword ptr [ecx + 18h], eax ; Dr7
     add dword ptr [ecx + 0b8h], 2 ; We add 2 to EIP to skip the div eax
     ret
ClrHwBpHandler endp



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
逆向工程权威指南英文pdf》是一本关于逆向工程领域的权威指南,提供了全面而深入的介绍和指导。逆向工程是指通过分析和理解他人创建的产品或技术,以达到了解其工作原理、设计和功能的目的。这本指南的英文版本包含了许多重要的内容。 首先,指南介绍了逆向工程的基本概念和原理,包括逆向工程的定义、分类以及应用范围。它还介绍了逆向工程的基本步骤和常用工具,帮助读者了解逆向工程的工作过程和所需技能。 其次,指南提供了一些实用的技术和方法,帮助读者深入理解逆向工程的实践。这些包括代码分析、动态调试汇编和编译等技术,以及如何应对特定类型的加密、壳和保护机制的方法。 此外,指南还涵盖了逆向工程的伦理和法律问题,教读者如何合法而道德地进行逆向工程活动。它强调了尊重知识产权和保护他人创造的成果的重要性,警告读者不要滥用逆向工程技术。 最后,这本指南还提供了一些实际的案例和应用示例,帮助读者将理论知识应用于实际问题解决中。通过这些案例,读者可以深入了解逆向工程在不同领域的应用,提高自己的技能和实践能力。 总之,这本《逆向工程权威指南英文pdf》是一本全面而权威的指南,对于想要深入了解逆向工程并应用于实际工作的读者来说,是一本非常有价值的参考资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值