关于IsDebuggerPresent

IsDebuggerPresent函数可以用来检测本进程是否处于被调试状态,当然,这种方法的实用性不大。

此函数在winbase.h中声明如下:WINBASEAPI BOOL WINAPI IsDebuggerPresent(void);
如果本进程当前正在被调试则返回1,否则返回0。

直接调用此函数的源程序在用VC6.0编译时会报连接错误,原因是kernel32.lib中找不到_IsDebuggerPresent这个符号。为了使用此函数,你不得不使用LoadLibrary动态加载kernel32.dll,或者使用GetModuleHandle获取kernel32.dll的映像地址,然后使用GetProcAddress取得IsDebuggerPresent的地址。

反汇编kernel32.dll观察IsDebuggerPresent的代码可以看到:----
7C813093  64:A1 18000000   mov     eax, dword ptr fs:[18]  |kernel32.IsDebuggerPresent
7C813099  8B40 30          mov     eax, dword ptr [eax+30]
7C81309C  0FB640 02        movzx   eax, byte ptr [eax+2]
7C8130A0  C3               retn
----
这里牵涉到两个重要的结构:
1 TEB (Thread Enviroment Block)
TEB at 7FFDE000
    ExceptionList:    12f830                \   0x0
    Stack Base:       130000                |   0x4
    Stack Limit:      126000                |   0x8
    SubSystemTib:     0                     |   0xC     这里其实是 NT_TIB 的一个结构
    FiberData:        1e00                  |   0x10
    ArbitraryUser:    0                     |   0x14
    Self:             7ffde000              /   0x18
    EnvironmentPtr:   0                         0x1C
    ClientId:         4cc.4c8                   0x20
    Real ClientId:    4cc.4c8                   0x24
    RpcHandle:        0                         0x28
    Tls Storage:      0                         0x2C
    PEB Address:      7ffdf000                  0x30  这里指向 PEB 表,即进程环境块
    LastErrorValue:   0
    LastStatusValue:  8000001a
    Count Owned Locks:0
    HardErrorsMode:   0

2 PEB (Process Enviroment Block)
struct   _PEB (sizeof=488)
+000 byte     InheritedAddressSpace
+001 byte     ReadImageFileExecOptions
+002 byte     BeingDebugged                   //Debug运行标志
+003 byte     SpareBool
+004 void     *Mutant
+008 void     *ImageBaseAddress               //这里就是程序加载的基地址了
+00c struct   _PEB_LDR_DATA *Ldr
+010 struct   _RTL_USER_PROCESS_PARAMETERS *ProcessParameters
+014 void     *SubSystemData
+018 void     *ProcessHeap
+01c void     *FastPebLock
+020 void     *FastPebLockRoutine
+024 void     *FastPebUnlockRoutine
+028 uint32   EnvironmentUpdateCount
+02c void     *KernelCallbackTable
+030 uint32   SystemReserved[2]
+038 struct   _PEB_FREE_BLOCK *FreeList
+03c uint32   TlsExpansionCounter
+040 void     *TlsBitmap
+044 uint32   TlsBitmapBits[2]
+04c void     *ReadOnlySharedMemoryBase
+050 void     *ReadOnlySharedMemoryHeap
+054 void     **ReadOnlyStaticServerData
+058 void     *AnsiCodePageData
+05c void     *OemCodePageData
+060 void     *UnicodeCaseTableData
+064 uint32   NumberOfProcessors
+068 uint32   NtGlobalFlag
+070 union    _LARGE_INTEGER CriticalSectionTimeout
+070    uint32   LowPart
+074    int32    HighPart
+070    struct   __unnamed3 u
+070       uint32   LowPart
+074       int32    HighPart
+070    int64    QuadPart
+078 uint32   HeapSegmentReserve
+07c uint32   HeapSegmentCommit
+080 uint32   HeapDeCommitTotalFreeThreshold
+084 uint32   HeapDeCommitFreeBlockThreshold
+088 uint32   NumberOfHeaps
+08c uint32   MaximumNumberOfHeaps
+090 void     **ProcessHeaps
+094 void     *GdiSharedHandleTable
+098 void     *ProcessStarterHelper
+09c uint32   GdiDCAttributeList
+0a0 void     *LoaderLock
+0a4 uint32   OSMajorVersion
+0a8 uint32   OSMinorVersion
+0ac uint16   OSBuildNumber
+0ae uint16   OSCSDVersion
+0b0 uint32   OSPlatformId
+0b4 uint32   ImageSubsystem
+0b8 uint32   ImageSubsystemMajorVersion
+0bc uint32   ImageSubsystemMinorVersion
+0c0 uint32   ImageProcessAffinityMask
+0c4 uint32   GdiHandleBuffer[34]
+14c function *PostProcessInitRoutine
+150 void     *TlsExpansionBitmap
+154 uint32   TlsExpansionBitmapBits[32]
+1d4 uint32   SessionId
+1d8 void     *AppCompatInfo
+1dc struct   _UNICODE_STRING CSDVersion
+1dc    uint16   Length
+1de    uint16   MaximumLength
+1e0    uint16   *Buffer

如何获得本线程的TEB和本进程的PEB呢?使用FS寄存器就可以,在Windows NT中,FS寄存在Ring3模式下指向TEB的首部,因此FS:[18]就是TEB的地址,FS:[30]就是PEB的地址,PEB+2这个BYTE为1时表示进程正在被调试,为0则表示进程没有被调试。至此,IsDebuggerPresent的原理已经揭开。

不能免俗的贴一份源代码:
// isdebugged.c  This program demonstrates how to use IsDebuggerPresent.
// Tested on Windows XP and VC6.0
// 龙第九子 2008/05/17

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

BOOL (*IsDebuggerPresent)();
int counter = 1000;

int main()
{
    HMODULE krn = GetModuleHandle("kernel32.dll");
    IsDebuggerPresent = (BOOL(*)())GetProcAddress(krn, "IsDebuggerPresent");
    if(IsDebuggerPresent == NULL)
    {
        fprintf(stderr, "Cannot get procedure address!\n");
        exit(1);
    }

    while(counter--)
    {
        printf("%d\t", counter);
        if(IsDebuggerPresent())
            printf("Being debugged...\n");
        else
            printf("Not being debugged...\n");
        Sleep(1000);
    }
    return 0;
}

参考资料:
  1 看雪论坛<<笑解 API 函数 -- API 绝密档案系列之一>> 作者gzgzlxg
     地址: http://bbs.pediy.com/showthread.php?t=21959
  2 利用FS寄存器获取KERNEL32.DLL基址算法的证明
     地址: http://blog.csdn.net/int2e/archive/2008/01/09/2032732.aspx
  3 Windows中FS段寄存器
     地址: http://hi.baidu.com/happyman/blog/item/9483b545a9d21f22cffca3ac.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值