• 反调试


    反调试

    1. IsDebuggerPresent()   该函数读取当前进程的PEBBeingDebugged的值用于判断自己是否处于调试状态

    BOOL

    APIENTRY

    IsDebuggerPresent(VOID)

    {

        return NtCurrentPeb()->BeingDebugged;

    }

     

    x86下windbg查看PEB结构

    可知在PEB偏移0x002处获得BeingDebugged    

    kd>  dt _PEB

    nt!_PEB

       +0x000 InheritedAddressSpace : UChar

       +0x001 ReadImageFileExecOptions : UChar

       +0x002 BeingDebugged    : UChar

       +0x003 BitField         : UChar

       +0x003 ImageUsesLargePages : Pos 0, 1 Bit

       +0x003 IsProtectedProcess : Pos 1, 1 Bit

       +0x003 IsLegacyProcess  : Pos 2, 1 Bit

       +0x003 IsImageDynamicallyRelocated : Pos 3, 1 Bit

       +0x003 SkipPatchingUser32Forwarders : Pos 4, 1 Bit

       +0x003 SpareBits        : Pos 5, 3 Bits

       +0x004 Mutant           : Ptr32 Void

       +0x008 ImageBaseAddress : Ptr32 Void

       +0x00c Ldr              : Ptr32 _PEB_LDR_DATA

       +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS

       +0x014 SubSystemData    : Ptr32 Void

       +0x018 ProcessHeap      : Ptr32 Void

       ......

    PEB(进程环境块)结构体存储在TEB(线程环境块)中,

    TEB结构如下

    kd> dt _teb

    nt!_TEB

       +0x000 NtTib            : _NT_TIB

       +0x01c EnvironmentPointer : Ptr32 Void

       +0x020 ClientId         : _CLIENT_ID

       +0x028 ActiveRpcHandle  : Ptr32 Void

       +0x02c ThreadLocalStoragePointer : Ptr32 Void

       +0x030 ProcessEnvironmentBlock : Ptr32 _PEB

       +0x034 LastErrorValue   : Uint4B

       +0x038 CountOfOwnedCriticalSections : Uint4B

       +0x03c CsrClientThread  : Ptr32 Void

       +0x040 Win32ThreadInfo  : Ptr32 Void

       +0x044 User32Reserved   : [26] Uint4B

       +0x0ac UserReserved     : [5] Uint4B

       +0x0c0 WOW32Reserved    : Ptr32 Void

       ......

    其中_NT_TIB结构如下

    kd> dt _NT_TIB

    nt!_NT_TIB

       +0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD

       +0x004 StackBase        : Ptr32 Void

       +0x008 StackLimit       : Ptr32 Void

       +0x00c SubSystemTib     : Ptr32 Void

       +0x010 FiberData        : Ptr32 Void

       +0x010 Version          : Uint4B

       +0x014 ArbitraryUserPointer : Ptr32 Void

       +0x018 Self             : Ptr32 _NT_TIB

    ......

      其中+0x018 Self 是一个指向TIB的指针.同时也是TEB结构体的首地址

    FS段寄存器中 地址FS:0指向当前线程TEB。

    当我们需要TEB地址时,可以利用 mov eax, fs:[0x18]得到。且从上文可知在TEB偏移0x30处得到PEB地址。

    固可以通过fs:[30h}获得当前进程的PEB。

    BOOL IsDebuggerPresentPEB()

    {

    #if defined (ENV64BIT)

    PPEB pPeb = (PPEB)__readgsqword(0x60);

     

    #elif defined(ENV32BIT)

    PPEB pPeb = (PPEB)__readfsdword(0x30);

     

    #endif

     

    if (pPeb->BeingDebugged == 1)

    return TRUE;

    else

    return FALSE;

    }

    内联汇编版本

    BOOL MYIsDebuggerPresent()

          __asm{

                mov eax, fs:[0x30]

                  movz eax, byte ptr [eax+]

    }

     

     

       

    2. __readgsqword(0x60)得到指向PEB64的指针,__readfsdword(0x30)得到指向PEB32的指针,pPeb->BeingDebugged .

    3. CheckRemoteDebuggerPresent(GetCurrentProcess(), &bIsDbgPresent)

    4. BOOL HeapFlags()64位下,得到指向PEB的地址加上0x30的偏移得到pProcessHeap,由于pHeapFlags在不同版本的操作系统中位置不一,需要IsWindowsVistaOrGreater()判断大概版本,高于VISTA的版本pProcessHeap解星号加上0x70的偏移得到pHeapFlags,低于高于VISTA的版本pProcessHeap解星号加上0x14的偏移得到pHeapFlags
    32位下,得到指向PEB的地址加上0x18的偏移得到pProcessHeap,由于pHeapFlags在不同版本的操作系统中位置不一,需要IsWindowsVistaOrGreater()判断大概版本,高于VISTA的版本pProcessHeap解星号加上0x40的偏移得到pHeapFlags,低于VISTA的版本pProcessHeap解星号加上0x0C的偏移得到pHeapFlags。判断*pHeapFlags > 2 是否为真

    5. __readgsqword(0x30)得到TEB64指针.*(DWORD64*)(_teb64 + 0x60)得到PEB64结构体,PEB64取偏移0xBC得到NTGlobalFlag
    __readfsdword(0x18)得到TEB32指针.*(DWORD64*)(_teb32 + 0x30)得到PEB32结构体,PEB32取偏移0x68得到NTGlobalFlag
    假如是wow64下的__readfsdword(0x18)得到TEB64指针.*(DWORD64*)(_teb64 + 0x60)得到PEB64结构体,PEB64取偏移0xBC得到NTGlobalFlag当进程被调试时,NTGlobalFlag会被置为FLG_HEAP_ENABLE_TAIL_CHECK (0x10), FLG_HEAP_ENABLE_FREE_CHECK(0x20), FLG_HEAP_VALIDATE_PARAMETERS(0x40)0x70

    6. BOOL HeapForceFlags()64位下,得到指向PEB的地址加上0x30的偏移得到pProcessHeap,由于pHeapForceFlags在不同版本的操作系统中位置不一,需要IsWindowsVistaOrGreater()判断大概版本,高于VISTA的版本pProcessHeap解星号加上0x74的偏移得到pHeapFlags,低于高于VISTA的版本pProcessHeap解星号加上0x18的偏移得到pHeapFlags
    32位下,得到指向PEB的地址加上0x18的偏移得到pProcessHeap,由于pHeapForceFlags在不同版本的操作系统中位置不一,需要IsWindowsVistaOrGreater()判断大概版本,高于VISTA的版本pProcessHeap解星号加上0x44的偏移得到pHeapForceFlags,低于VISTA的版本pProcessHeap解星号加上0x10的偏移得到pHeapFlags。判断*pHeapFlags > 2 是否为真

    7. 通过LoadLibrary  得到ntdll的句柄hNtdll,通过GetProcAddressntdll模块中得到NtQueryInformationProcess  const int ProcessDbgPort = 7;
    NtQueryInfoProcess(GetCurrentProcess(),
     ProcessDbgPort, 
    &IsRemotePresent, 
    dProcessInformationLength, 
    NULL) IsRemotePresent不等于0时 进程被调试

    8. 通过LoadLibrary  得到ntdll的句柄hNtdll,通过GetProcAddressntdll模块中得到NtQueryInformationProcess  const int ProcessDebugFlags =  0x1f;
    NtQueryInfoProcess(GetCurrentProcess(),
     ProcessDebugFlags,
     &NoDebugInherit, 
    sizeof(DWORD), 
    NULL);NoDebugInherit精确等于0时,被调试

    9. 通过LoadLibrary  得到ntdll的句柄hNtdll,通过GetProcAddressntdll模块中得到NtQueryInformationProcess  const int ProcessDebugObjectHandle =  0x1e;NtQueryInfoProcess(GetCurrentProcess(), ProcessDebugObjectHandle, &hDebugObject, dProcessInformationLength, NULL);hDebugObject不为空

    10. 通过GetProcAddressntdll模块中得到NtSetInformationThreadThreadInformationClass设置为0x11(ThreadHideFromDebugger),用于隐藏调试器中的线程,调用之后调试器与该线程不再关联  NtSetInformationThread(GetCurrentThread(), ThreadHideFromDebugger, NULL, 0);当函数成功时,被调试

    11. CloseHandle_InvalideHandle()当进程被调试时,调用CloseHandle并传入无效句柄,会得到一个STATUS_INVALID_HANDLE的异常,函数返回TRUE__try NtClose_((HANDLE)0x99999999);}__except (EXCEPTION_EXECUTE_HANDLER) {return TRUE;}

    12. UnhandledExcepFilterTest () 设置一个SetUnhandledExceptionFilter。然后利用RaiseException提出一个异常交给异常处理机制 由于没有设置相应的异常处理程序 当进程被调试时,会通知进程的调试器,而不会调用UnhandledExceptionFilter

    13. OutputDebugStringAPI(),只在XP2000中适用。OutputDebugString()用于输出字符串给调试器显示。若GetLastError被置为Val,说明调试器与进程关联。

    14. HardwareBreakpoints(),初始化PCONTEXT ctx,将ctx->ContextFlags = CONTEXT_DEBUG_REGISTERS。通过GetThreadContext(GetCurrentThread(), ctx)得到寄存器信息,硬件断点,用Dr0-Dr7七个寄存器控制。Dr1-Dr3存放了断点地址,若有一个寄存器存放了断点地址说明 被调试

    15. SoftwareBreakpoints(),NOTE this check might not work on x64 because of alignment 0xCC bytes.软件断点 INT 332位下被编译成0xCC建立两个函数A B,在B中调用A。计算A B地址之间的偏移,将A强制类型转换成PUCHAR型放置在变量v1中, 两个函数地址之间的偏移为长度 以字节为单位查询是否存在0xCC  

    16. Interrupt_0x2d()AddVectoredExceptionHandler()注册一个定向的情况处理__int2d()是一个用asm写的函数,利用指令 int 2dh测试进程是否被调试,当进程没有关联调试器,会返回一个异常进入我们设置的定向情况处理。无需手动Rip或Eip++

    17. Interrupt_3()AddVectoredExceptionHandler()注册一个定向的情况处理__debugbreak() Microsoft专用将在代码中引起断点,并在其中提示用户运行调试程序。当进程没有关联调试器,会返回一个异常,当情况为异常断点时需要我们手动将RipEip++

    18. MemoryBreakpoints_PageGuard(),动态分配大小为SystemInfo.dwPageSize的一块内存,并将0xC3ret写入内存中,最后将这块内存VirtualProtect属性置为PAGE_EXECUTE_READWRITE | PAGE_GUARD可读写,页面保护)。以函数的形式调用这块内存的首地址,观察是否抛出异常。线程试图访问具备PAGE_GUARD属性的内存。该内存可以被访问,但同时EXCEPTION_GUARD_PAGE异常会被抛出 此时进程没有被调试。

    19. CanOpenCsrss()当进程被调试且被提权到administrator时,该进程可以打开Csrss进程

    20. NtYieldExecutionAPI()

    21. NtQueryObject_ObjectTypeInformation()

    22. NtQueryObject_ObjectAllTypesInformation()

    23. SetHandleInformatiom_ProtectedHandle(),创建了一个互斥体对象,利用SetHandleInformation将我们互斥体对象句柄标志改为HANDLE_FLAG_PROTECT_FROM_CLOSE,最后关闭句柄会抛出异常HANDLE_FLAG_PROTECT_FROM_CLOSE

  • 相关阅读:
    03-字典
    02-列表
    01-字符串操作
    Django中的跨域问题
    Codeforces Round #617 (Div. 3) A
    Codeforces Round #717 (Div. 2) A
    如何在Vuespa中使用less
    excle导出
    ajaxFileUpload上传文件
    图片插入word
  • 原文地址:https://www.cnblogs.com/Crisczy/p/7575521.html
Copyright © 2020-2023  润新知