美文网首页
用ollydbg浅识TEB和PEB用来反跟踪 x86

用ollydbg浅识TEB和PEB用来反跟踪 x86

作者: 成员 | 来源:发表于2017-07-04 14:31 被阅读0次

    大部分内容引用于:
    http://bbs.pediy.com/thread-119827.htm

    以下内容基于x86系统,x64请查看 使用WinDbg验证PEB 基于x64

    首先,来了解下什么是TEB和PEB。

    TEB(Thread Environment Block,线程环境块):

    系统在此TEB中保存频繁使用的线程相关的数据。位于用户地址空间。进程中的每个线程都有自己的一个TEB。一个进程的所有TEB都以堆栈的方式,存放在从0x7FFDE000(WinXP SP1)开始的线性内存中,每4KB为一个完整的TEB,不过该内存区域是向下扩展的。
    在用户模式下,当前线程的TEB位于独立的4KB段,可通过CPU的FS寄存器来访问该段,存储在[FS:0]
    在用户态下WinDbg中可用命令!teb取得TEB地址。

    x64 下的TEB

    Windows x64中,TEB的寄存器换做了GS寄存器,使用[GS:0x30]访问
    Visual C++ 中可以使用函数

    NtCurrentTeb();
    // x86
    __readfsqword(0x18);
    // x64
    __readgsqword(0x30);
    

    为什么是0x18请看下文

    以下内容以x86为例,x64请使用WinDbg自行修正

    PEB(Process Environment Block,进程环境块)

    存放进程信息,每个进程都有自己的PEB信息。
    位于用户地址空间。在Win XP SP1下,进程环境块的地址对于每个进程来说是固定的,在0x7FFDF000处,这是用户地址空间,所以程序能够直接访问。
    准确的PEB地址应从系统的EPROCESS结构的0x1b0偏移处获得,但由于EPROCESS在系统地址空间,访问这个结构需要有ring0的权限。
    Windows SP2之后这个地址是随机映射的,所以PEB地址只能通过FS:[0x30]GS:[0x60]来取。

    // x64
    __readgsqword(0x60);
    // x86
    __readfsqword(0x30);
    

    为什么是0x30,请往下看

    TEB的结构

    因为winnt.h中并未提供TEB的结构,所以借助于WinDbg工具来观察 TEB 结构。

    dt _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
       +0x0c4 CurrentLocale    : Uint4B
       +0x0c8 FpSoftwareStatusRegister : Uint4B
       +0x0cc SystemReserved1  : [54] Ptr32 Void
       +0x1a4 ExceptionCode    : Int4B
       +0x1a8 ActivationContextStackPointer : Ptr32 _ACTIVATION_CONTEXT_STACK
       +0x1ac SpareBytes       : [36] UChar
       +0x1d0 TxFsContext      : Uint4B
       +0x1d4 GdiTebBatch      : _GDI_TEB_BATCH
       +0x6b4 RealClientId     : _CLIENT_ID
       +0x6bc GdiCachedProcessHandle : Ptr32 Void
       +0x6c0 GdiClientPID     : Uint4B
       +0x6c4 GdiClientTID     : Uint4B
       +0x6c8 GdiThreadLocalInfo : Ptr32 Void
       +0x6cc Win32ClientInfo  : [62] Uint4B
       +0x7c4 glDispatchTable  : [233] Ptr32 Void
       +0xb68 glReserved1      : [29] Uint4B
       +0xbdc glReserved2      : Ptr32 Void
       +0xbe0 glSectionInfo    : Ptr32 Void
       +0xbe4 glSection        : Ptr32 Void
       +0xbe8 glTable          : Ptr32 Void
       +0xbec glCurrentRC      : Ptr32 Void
       +0xbf0 glContext        : Ptr32 Void
       +0xbf4 LastStatusValue  : Uint4B
       +0xbf8 StaticUnicodeString : _UNICODE_STRING
       +0xc00 StaticUnicodeBuffer : [261] Wchar
       +0xe0c DeallocationStack : Ptr32 Void
       +0xe10 TlsSlots         : [64] Ptr32 Void
       +0xf10 TlsLinks         : _LIST_ENTRY
       +0xf18 Vdm              : Ptr32 Void
       +0xf1c ReservedForNtRpc : Ptr32 Void
       +0xf20 DbgSsReserved    : [2] Ptr32 Void
       +0xf28 HardErrorMode    : Uint4B
       +0xf2c Instrumentation  : [9] Ptr32 Void
       +0xf50 ActivityId       : _GUID
       +0xf60 SubProcessTag    : Ptr32 Void
       +0xf64 EtwLocalData     : Ptr32 Void
       +0xf68 EtwTraceData     : Ptr32 Void
       +0xf6c WinSockData      : Ptr32 Void
       +0xf70 GdiBatchCount    : Uint4B
       +0xf74 CurrentIdealProcessor : _PROCESSOR_NUMBER
       +0xf74 IdealProcessorValue : Uint4B
       +0xf74 ReservedPad0     : UChar
       +0xf75 ReservedPad1     : UChar
       +0xf76 ReservedPad2     : UChar
       +0xf77 IdealProcessor   : UChar
       +0xf78 GuaranteedStackBytes : Uint4B
       +0xf7c ReservedForPerf  : Ptr32 Void
       +0xf80 ReservedForOle   : Ptr32 Void
       +0xf84 WaitingOnLoaderLock : Uint4B
       +0xf88 SavedPriorityState : Ptr32 Void
       +0xf8c SoftPatchPtr1    : Uint4B
       +0xf90 ThreadPoolData   : Ptr32 Void
       +0xf94 TlsExpansionSlots : Ptr32 Ptr32 Void
       +0xf98 MuiGeneration    : Uint4B
       +0xf9c IsImpersonating  : Uint4B
       +0xfa0 NlsCache         : Ptr32 Void
       +0xfa4 pShimData        : Ptr32 Void
       +0xfa8 HeapVirtualAffinity : Uint4B
       +0xfac CurrentTransactionHandle : Ptr32 Void
       +0xfb0 ActiveFrame      : Ptr32 _TEB_ACTIVE_FRAME
       +0xfb4 FlsData          : Ptr32 Void
       +0xfb8 PreferredLanguages : Ptr32 Void
       +0xfbc UserPrefLanguages : Ptr32 Void
       +0xfc0 MergedPrefLanguages : Ptr32 Void
       +0xfc4 MuiImpersonation : Uint4B
       +0xfc8 CrossTebFlags    : Uint2B
       +0xfc8 SpareCrossTebBits : Pos 0, 16 Bits
       +0xfca SameTebFlags     : Uint2B
       +0xfca SafeThunkCall    : Pos 0, 1 Bit
       +0xfca InDebugPrint     : Pos 1, 1 Bit
       +0xfca HasFiberData     : Pos 2, 1 Bit
       +0xfca SkipThreadAttach : Pos 3, 1 Bit
       +0xfca WerInShipAssertCode : Pos 4, 1 Bit
       +0xfca RanProcessInit   : Pos 5, 1 Bit
       +0xfca ClonedThread     : Pos 6, 1 Bit
       +0xfca SuppressDebugMsg : Pos 7, 1 Bit
       +0xfca DisableUserStackWalk : Pos 8, 1 Bit
       +0xfca RtlExceptionAttached : Pos 9, 1 Bit
       +0xfca InitialThread    : Pos 10, 1 Bit
       +0xfca SpareSameTebBits : Pos 11, 5 Bits
       +0xfcc TxnScopeEnterCallback : Ptr32 Void
       +0xfd0 TxnScopeExitCallback : Ptr32 Void
       +0xfd4 TxnScopeContext  : Ptr32 Void
       +0xfd8 LockCount        : Uint4B
       +0xfdc SpareUlong0      : Uint4B
       +0xfe0 ResourceRetValue : Ptr32 Void
    

    以下是一份x86_NT_TEB结构实现,可供参考

    typedef struct _NT_TEB
    {
       NT_TIB Tib;                         // 00h
       PVOID EnvironmentPointer;           // 1Ch
       CLIENT_ID Cid;                      // 20h
       PVOID ActiveRpcInfo;                // 28h
       PVOID ThreadLocalStoragePointer;    // 2Ch
       PPEB Peb;                           // 30h
       ULONG LastErrorValue;               // 34h
       ULONG CountOfOwnedCriticalSections; // 38h
       PVOID CsrClientThread;              // 3Ch
       PVOID Win32ThreadInfo;              // 40h
       ULONG Win32ClientInfo[0x1F];        // 44h
       PVOID WOW32Reserved;                // C0h
       ULONG CurrentLocale;                // C4h
       ULONG FpSoftwareStatusRegister;     // C8h
       PVOID SystemReserved1[0x36];        // CCh
       PVOID Spare1;                       // 1A4h
       LONG ExceptionCode;                 // 1A8h
       ULONG SpareBytes1[0x28];            // 1ACh
       PVOID SystemReserved2[0xA];         // 1D4h
       GDI_TEB_BATCH GdiTebBatch;          // 1FCh
       ULONG gdiRgn;                       // 6DCh
       ULONG gdiPen;                       // 6E0h
       ULONG gdiBrush;                     // 6E4h
       CLIENT_ID RealClientId;             // 6E8h
       PVOID GdiCachedProcessHandle;       // 6F0h
       ULONG GdiClientPID;                 // 6F4h
       ULONG GdiClientTID;                 // 6F8h
       PVOID GdiThreadLocaleInfo;          // 6FCh
       PVOID UserReserved[5];              // 700h
       PVOID glDispatchTable[0x118];       // 714h
       ULONG glReserved1[0x1A];            // B74h
       PVOID glReserved2;                  // BDCh
       PVOID glSectionInfo;                // BE0h
       PVOID glSection;                    // BE4h
       PVOID glTable;                      // BE8h
       PVOID glCurrentRC;                  // BECh
       PVOID glContext;                    // BF0h
       NTSTATUS LastStatusValue;           // BF4h
       UNICODE_STRING StaticUnicodeString; // BF8h
       WCHAR StaticUnicodeBuffer[0x105];   // C00h
       PVOID DeallocationStack;            // E0Ch
       PVOID TlsSlots[0x40];               // E10h
       LIST_ENTRY TlsLinks;                // F10h
       PVOID Vdm;                          // F18h
       PVOID ReservedForNtRpc;             // F1Ch
       PVOID DbgSsReserved[0x2];           // F20h
       ULONG HardErrorDisabled;            // F28h
       PVOID Instrumentation[0x10];        // F2Ch
       PVOID WinSockData;                  // F6Ch
       ULONG GdiBatchCount;                // F70h
       ULONG Spare2;                       // F74h
       ULONG Spare3;                       // F78h
       ULONG Spare4;                       // F7Ch
       PVOID ReservedForOle;               // F80h
       ULONG WaitingOnLoaderLock;          // F84h
    
       PVOID StackCommit;                  // F88h
       PVOID StackCommitMax;               // F8Ch
       PVOID StackReserve;                 // F90h
    
       PVOID MessageQueue;                 // ???
    } NT_TEB, *PNT_TEB; 
    

    _NT_TIB的结构

    在上例中,第一行是一个_NT_TIB结构,占据0x1c的长度,结构在winnt.h中有实现:

    typedef struct _NT_TIB {
        struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
        PVOID StackBase;
        PVOID StackLimit;
        PVOID SubSystemTib;
    #if defined(_MSC_EXTENSIONS)
        union {
            PVOID FiberData;
            DWORD Version;
        };
    #else
        PVOID FiberData;
    #endif
        PVOID ArbitraryUserPointer;
        struct _NT_TIB *Self;
    } NT_TIB;
    typedef NT_TIB *PNT_TIB;
    

    可以看出最后一个成员是*Self,也就是在0x18的位置
    所以可以这么取FS:[0x18],从而得到TEB的地址
    winnt.h中是这么实现的:

    // x86
    return (struct _TEB *)__readfsqword(FIELD_OFFSET(NT_TIB, Self));
    

    x64 和 x86 中_NT_TIB结构的区别

    //
    // 32 and 64 bit specific version for wow64 and the debugger
    //
    typedef struct _NT_TIB32 {
        DWORD ExceptionList;
        DWORD StackBase;
        DWORD StackLimit;
        DWORD SubSystemTib;
    
    #if defined(_MSC_EXTENSIONS)
        union {
            DWORD FiberData;
            DWORD Version;
        };
    #else
        DWORD FiberData;
    #endif
    
        DWORD ArbitraryUserPointer;
        DWORD Self;
    } NT_TIB32, *PNT_TIB32;
    
    typedef struct _NT_TIB64 {
        DWORD64 ExceptionList;
        DWORD64 StackBase;
        DWORD64 StackLimit;
        DWORD64 SubSystemTib;
    
    #if defined(_MSC_EXTENSIONS)
        union {
            DWORD64 FiberData;
            DWORD Version;
        };
    
    #else
        DWORD64 FiberData;
    #endif
    
        DWORD64 ArbitraryUserPointer;
        DWORD64 Self;
    } NT_TIB64, *PNT_TIB64;
    

    取PEB地址

    看到没有 :

    +0x030 ProcessEnvironmentBlock : Ptr32 _PEB
    
      PPEB Peb;                           // 30h
    

    TEB偏移的0x30地址就是PEB的地址,所以上例使用FS:[0x30]即可取到,下面使用WinDbg来看看PEB的结构:

    dt _PEB
    内容太长,略过
    

    结构的实现如下

    typedef struct _PEB
    {
       UCHAR InheritedAddressSpace;                     // 00h
       UCHAR ReadImageFileExecOptions;                  // 01h
       UCHAR BeingDebugged;                             // 02h 这里就表示程序是否是在被调试模式
       UCHAR Spare;                                     // 03h
       PVOID Mutant;                                    // 04h
       PVOID ImageBaseAddress;                          // 08h
       PPEB_LDR_DATA Ldr;                               // 0Ch
       PRTL_USER_PROCESS_PARAMETERS ProcessParameters;  // 10h
       PVOID SubSystemData;                             // 14h
       PVOID ProcessHeap;                               // 18h
       PVOID FastPebLock;                               // 1Ch
       PPEBLOCKROUTINE FastPebLockRoutine;              // 20h
       PPEBLOCKROUTINE FastPebUnlockRoutine;            // 24h
       ULONG EnvironmentUpdateCount;                    // 28h
       PVOID* KernelCallbackTable;                      // 2Ch
       PVOID EventLogSection;                           // 30h
       PVOID EventLog;                                  // 34h
       PPEB_FREE_BLOCK FreeList;                        // 38h
       ULONG TlsExpansionCounter;                       // 3Ch
       PVOID TlsBitmap;                                 // 40h
       ULONG TlsBitmapBits[0x2];                        // 44h
       PVOID ReadOnlySharedMemoryBase;                  // 4Ch
       PVOID ReadOnlySharedMemoryHeap;                  // 50h
       PVOID* ReadOnlyStaticServerData;                 // 54h
       PVOID AnsiCodePageData;                          // 58h
       PVOID OemCodePageData;                           // 5Ch
       PVOID UnicodeCaseTableData;                      // 60h
       ULONG NumberOfProcessors;                        // 64h
       ULONG NtGlobalFlag;                              // 68h
       UCHAR Spare2[0x4];                               // 6Ch
       LARGE_INTEGER CriticalSectionTimeout;            // 70h
       ULONG HeapSegmentReserve;                        // 78h
       ULONG HeapSegmentCommit;                         // 7Ch
       ULONG HeapDeCommitTotalFreeThreshold;            // 80h
       ULONG HeapDeCommitFreeBlockThreshold;            // 84h
       ULONG NumberOfHeaps;                             // 88h
       ULONG MaximumNumberOfHeaps;                      // 8Ch
       PVOID** ProcessHeaps;                            // 90h
       PVOID GdiSharedHandleTable;                      // 94h
       PVOID ProcessStarterHelper;                      // 98h
       PVOID GdiDCAttributeList;                        // 9Ch
       PVOID LoaderLock;                                // A0h
       ULONG OSMajorVersion;                            // A4h
       ULONG OSMinorVersion;                            // A8h
       ULONG OSBuildNumber;                             // ACh
       ULONG OSPlatformId;                              // B0h
       ULONG ImageSubSystem;                            // B4h
       ULONG ImageSubSystemMajorVersion;                // B8h
       ULONG ImageSubSystemMinorVersion;                // C0h
       ULONG GdiHandleBuffer[0x22];                     // C4h
    
       PVOID ProcessWindowStation;                      // ???
    } PEB, *PPEB;
    

    ImageBaseAddress就是基址了

    WinDbg下可以使用!peb查看当前进程的PEB地址

    OllyDbg查看

    Windows XP Sp1为例:

    我这里写一个小程序里面就调用一个函数GetModuleHandle。


    image.png

    跟进这个函数去看看


    image.png
    这个就是这个函数的执行体了,咱们要关心的就是7C80B764这个地址的一句:
    mov eax,dword ptr fs:[18]
    

    fs:[0]寄存器里面存的就是指向TEB的地址,看看是什么地址啊,

    image.png
    看到没eax指向的就是TEB的地址,接着执行,teb地址偏移30由上面的头文件就可以看出是peb的地址了
    image.png
    此时可以确定peb的地址就是0x7FFDE000 image.png
    BeingDebugged的偏移是0x2,值为1,代表正在被调试中
    ImageBaseAddress的偏移是0x8,值为00400000,基址

    使用以下汇编代码判断程序是否被调试

    mov     eax, fs:[30h]               ;指向 PEB
    
    movzx   eax, byte ptr [eax + 2h]
    or      al, al
    jz      _Fine
    

    图文结构

    PEB结构

    TEB PEB PEB_LDR_DATA

    PEB 链表结构

    PEB_LDR_DATA LDR_MODULE

    根据上面的结构,结合上面两幅图诠释了TEB的内部结构:

    1. 取PEB地址指针有两种手段:
      手段一:FS:[0x18]+0x30
      手段二:FS:[0x30]
    2. TIB结构实际被包含在TEB的首部
    3. FS:[0]存放的是指向TIB结构的Exception List成员的指针
    4. PEB首地址加上偏移0xC的位置存放的指向PEB_LDR_DATA的指针
    5. PEB_LDR_DATA结构尾部实际上存放的是LIST_ENTRY的数组
    6. InLoadOrderModuleListFLINK存放的是指向LDR_MODULE的指针
    7. LDR_MODULE结构的首部存放的是LIST_ENTRY结构的数组

    异常链表结构如下

    typedef
    _IRQL_requires_same_
    _Function_class_(EXCEPTION_ROUTINE)
    EXCEPTION_DISPOSITION
    NTAPI
    EXCEPTION_ROUTINE (
        _Inout_ struct _EXCEPTION_RECORD *ExceptionRecord,
        _In_ PVOID EstablisherFrame,
        _Inout_ struct _CONTEXT *ContextRecord,
        _In_ PVOID DispatcherContext
        );
    
    typedef EXCEPTION_ROUTINE *PEXCEPTION_ROUTINE;
    
    typedef struct _EXCEPTION_REGISTRATION_RECORD {
        struct _EXCEPTION_REGISTRATION_RECORD *Next;
        PEXCEPTION_ROUTINE Handler;
    } EXCEPTION_REGISTRATION_RECORD;
    
    typedef EXCEPTION_REGISTRATION_RECORD *PEXCEPTION_REGISTRATION_RECORD;
    

    相关文章

      网友评论

          本文标题:用ollydbg浅识TEB和PEB用来反跟踪 x86

          本文链接:https://www.haomeiwen.com/subject/izzthxtx.html