Windows 32位-调试与反调试

1.加载调试符号链接文件并放入d:/symbols目录下.

0:000> .sympath srv*d:\symbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: srv*d:\symbols*http://msdl.microsoft.com/download/symbols
Expanded Symbol search path is: srv*d:\symbols*http://msdl.microsoft.com/download/symbols

0:000> .reload
Reloading current modules

2.位于fs:[0x30]的位置就是PEB结构的指针,接着我们分析如何得到的该指针,并通过通配符找到TEB结构的名称.

0:000> dt ntdll!*teb*
          ntdll!_TEB
          ntdll!_GDI_TEB_BATCH
          ntdll!_TEB_ACTIVE_FRAME
          ntdll!_TEB_ACTIVE_FRAME_CONTEXT
          ntdll!_TEB_ACTIVE_FRAME_CONTEXT

3.接着可通过dt命令,查询下ntdll!_TEB结构,如下可看到0x30ProcessEnvironmentBlock存放的正是PEB结构.

0:000> dt -rv ntdll!_TEB
struct _TEB, 66 elements, 0xfb8 bytes
   +0x000 NtTib            : struct _NT_TIB, 8 elements, 0x1c bytes                  # NT_TIB结构
   +0x018 Self             : Ptr32 to struct _NT_TIB, 8 elements, 0x1c bytes         # NT_TIB结构
   +0x020 ClientId         : struct _CLIENT_ID, 2 elements, 0x8 bytes                # 保存进程与线程ID
   +0x02c ThreadLocalStoragePointer : Ptr32 to Void
   +0x030 ProcessEnvironmentBlock : Ptr32 to struct _PEB, 65 elements, 0x210 bytes   # PEB结构

偏移地址0x18_NT_TIB结构,也就是指向自身偏移0x0的位置.

0:000> r $teb
$teb=7ffdf000

0:000> dd $teb+0x18
7ffdf018  7ffdf000 00000000 00001320 00000c10
7ffdf028  00000000 00000000 7ffd9000 00000000

!teb地址加0x30正是PEB的位置,可以使用如下命令验证.

0:000> dd $teb+0x30
7ffdf030  7ffd9000 00000000 00000000 00000000
7ffdf040  00000000 00000000 00000000 00000000

0:000> !teb
TEB at 7ffdf000
    ExceptionList:        0012fd0c
    StackBase:            00130000
    StackLimit:           0012e000
    SubSystemTib:         00000000
    FiberData:            00001e00
    ArbitraryUserPointer: 00000000
    Self:                 7ffdf000
    EnvironmentPointer:   00000000
    ClientId:             00001320 . 00000c10
    RpcHandle:            00000000
    Tls Storage:          00000000
    PEB Address:          7ffd9000               # 此处teb地址

上方的查询结果可得知偏移位置fs:[0x18]正是TEB的基址TEB:7ffdf000

0:000> dd fs:[0x18]
003b:00000018  7ffdf000 00000000 000010f4 00000f6c
003b:00000028  00000000 00000000 7ffda000 00000000

0:000> dt _teb 0x7ffdf000
ntdll!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x01c EnvironmentPointer : (null) 
   +0x020 ClientId         : _CLIENT_ID         # 这里保存进程与线程信息

0:000> dt _CLIENT_ID 0x7ffdf000                 # 查看进程详细结构
ntdll!_CLIENT_ID
   +0x000 UniqueProcess    : 0x0012fd0c Void    # 获取进程PID
   +0x004 UniqueThread     : 0x00130000 Void    # 获取线程PID

上方TEB首地址我们知道是fs:[0x18],接着我们通过以下公式计算得出本进程的进程ID.

在Windows系统中如果想要获取到PID进程号,可以使用NtCurrentTeb()这个系统API来实现,但这里我们手动实现该API的获取过程.

获取进程PID:

#include "stdafx.h"
#include <Windows.h>

DWORD GetPid(){
    DWORD dwPid=0;
    __asm
    {
        mov eax,fs:[0x18]    // 获取PEB地址
        add eax,0x20         // 加0x20得到进程PID
        mov eax,[eax]
        mov dwPid,eax
    }
    return dwPid;
}

int main()
{
    printf("%d\n",GetPid());
    return 0;
}

获取线程PID:

#include "stdafx.h"
#include <Windows.h>

DWORD GetPid(){
    DWORD dwPid=0;
    __asm
    {
        mov eax,fs:[0x18]    // 获取PEB地址
        add eax,0x20         // 加0x20得到进程PID
        add eax,0x04         // 加0x04得到线程PID
        mov eax,[eax]
        mov dwPid,eax
    }
    return dwPid;
}

int main()
{
    printf("%d\n",GetPid());
    return 0;
}

通过标志反调试: 下方的调试标志BeingDebugged是Char类型,为1表示调试状态.为0表示没有调试.可以用于反调试.

0:000> dt _peb
ntdll!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar
   +0x003 SpareBool        : UChar
   +0x004 Mutant           : Ptr32 Void
#include "stdafx.h"
#include <Windows.h>

int main()
{
    DWORD dwIsDebug = 0;
    __asm
    {
        mov eax, fs:[0x18];      // 获取TEB  
        mov eax, [eax + 0x30];   // 获取PEB
        movzx eax, [eax + 2];    // 获取调试标志
        mov dwIsDebug,eax
    }

    if (1 == dwIsDebug)
    {
        printf("正在被调试");
    }
    else
    {
        printf("没有被调试");
    }
    return 0;
}

通过API反调试:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

int main()
{
    STARTUPINFO temp;
    temp.cb = sizeof(temp);
    GetStartupInfo(&temp);

    if (temp.dwFlags != 1)
    {
        ExitProcess(0);
    }
    printf("程序没有被反调试");
    return 0;
}

Windows 32位-调试与反调试

上一篇:Acwing-284-金字塔(区间DP)


下一篇:wpf 当DataGrid列模版是ComboBox时,显示信息