隐藏debug探秘

作者:太空独角兽    发布于:

#写在最前

这篇文章的原理自于加密解密(第三版),读者有兴趣可以自行实现这个检测和隐藏debugger的小功能。

原理很简单:使用debugger的时候,程序会带上debugger的标记,我们需要做的就是找到标记点然后清除这个标记。

标记:

debug的连锁反应:

BeingDebugged->NtGlobalFlag->flag->heap magic

不过笔者认为纸上得来终觉浅,实际操作解决各种不知道那里冒出来的问题才会提升自己的能力(所以多写多练方才是正道)。在整个学习过程中,笔者花了大部分的时间在于使用win的API编程和规范代码。

#检测

#BeingDebugged

位置:peb+2
大小:byte
影响范围:NtGlobalFlag
被调试 正常
1 0

#NtGlobalFlag

位置:peb+68h
大小:byte
影响范围:heap magic
被调试 正常
70h 0

值得注意的是:如果BeingDebugged为True,NtGlobalFlag的70h并非直接赋值,而是通过一系列标志设置(如FLG_HEAP_ENABLE_CHECK)。而由此所引发的连锁反应可就不那么简单了。他将留下许多的痕迹(笑:)

#heap magic,Flags

Heap位置:peb+18h
Heap->Flags位置:heap+0ch
Heap->ForceFlags位置:heap+10h
影响范围:堆相关

依据NtGlobalFlag的值来设置了堆的Flags,堆的Flags会影响进程堆的Flags和ForceFlags,同时函数RtlCreateHeap需要Flags的值来创建堆栈。故此堆栈会带上Flags的印记。

NTSYSAPI PVOID RtlCreateHeap(
  ULONG                Flags,
  PVOID                HeapBase,
  SIZE_T               ReserveSize,
  SIZE_T               CommitSize,
  PVOID                Lock,
  PRTL_HEAP_PARAMETERS Parameters
);

其中调试堆会被标记填充一些奇怪的东西,一般为以下三个

BAADF00D
FEEEFEEE
ABABABAB

可以通过对调试堆中检测以上三个来判定是否被调试。这是对创建堆结果的检测来判断是否被调试。

不过根据《加密解密》其中更简单的方法检测Heap 的Flags和ForceFlags的值,这是对创建堆源头检测来判断是否被调试。

正常 被调试(通常)
Flags 2 50000062h
ForceFlags 0 40000060h

可惜这种方法在编写程序和查看的时候并没有得到印证,数据跟书中所说并不符合。这里留个疑问,以后解决


代码

bool MyIsDebugger(ULONG PebBase, HANDLE hProcess) {
//读取目标进程PEB
_myPEB* Peb_buffer = (_myPEB*)malloc(sizeof(_myPEB));
memset((void *)Peb_buffer, 0, sizeof(_myPEB));
int ret = ReadProcessMemory(hProcess, (LPCVOID)PebBase, Peb_buffer, sizeof(_myPEB), NULL);
//读取成功
if (ret == 1) {
    //判断BeingDebugged,NtGlobalFlag标志
    byte bedebugged = Peb_buffer->bBeingDebugged;
    DWORD NtGlobalFlag = Peb_buffer->dwNtGlobalFlag;
    cout << "-----------------------show status----------------\n" << endl;
    if ((int)bedebugged == 1 || (int)NtGlobalFlag == 0x70)
    {
        //判断堆中Magic信息

        cout << "your are debugging me\n" << endl;
    }
    else {
        cout << "your are not debugging me\n" << endl;
    }
    cout << "-------------------------------------------------\n" << endl;
}
//读取失败
else {
    cout << "读取目标进程的内存失败" << endl;
    //perror("perror say");
    char buffer[256];
    strerror_s(buffer, 100, GetLastError());
    cout << "error:" << GetLastError() << ":" << buffer << endl;

    free(Peb_buffer);
    return FALSE;
}
}

修改

//清除PEB中BeingDebugged,NtGlobalFlag信息
bool clearBeingDebugged(ULONG PebBase, HANDLE hProcess) {

//清空BeingDebugged为0
byte flag = 0;

int ret = WriteProcessMemory(hProcess, (LPVOID)(PebBase + 2), &flag, sizeof(byte), NULL);
int ret2 = WriteProcessMemory(hProcess, (LPVOID)(PebBase + 0x68), &flag, sizeof(byte), NULL);
//写入成功
if (ret != 0 && ret2 != 0) {
    cout << "----------------------\n清空BeingDebugged,NtGlobalFlag为0写入成功,隐藏debug-----------\n " << endl;
    return TRUE;
}
//写入失败
else {
    cout << "----------------------\n读取目标进程的内存失败------------------\n" << endl;
    //perror("perror say");
    char buffer[256];
    strerror_s(buffer, 100, GetLastError());
    cout << "error:" << GetLastError() << ":" << buffer << endl;
    return FALSE;
}
}

#效果

input pid
12068
pid:12068        PebBase: 0xe64000
-----------------------show status----------------

your are debugging me

-------------------------------------------------

PEB: e64000
BeingDebugged: 1
NtGlobalFlag:0x70
Heap->Flags:0x2
Heap->ForceFlags:0x12f00a4
----------------------
清空BeingDebugged,NtGlobalFlag为0写入成功,隐藏debug-----------

PEB: e64000
BeingDebugged: 0
NtGlobalFlag:0x0
Heap->Flags:0x2
Heap->ForceFlags:0x12f00a4
-----------------------show status----------------

your are not debugging me

-------------------------------------------------

可从上面运行结果显示如果清除BeingDebuggedNtGlobalFlag可以得到很好的效果,但是其他影响却不能得到很好的印证,例如heap的Flags和ForceFlags的值确实跟书中提及到的不同。猜测OS版本的更新导致了细微的变化。

#检测进阶

使用CheckRemoteDebuggerPresent来检测是否使用调试器,这个函数检测的是用户调试接口ProcessDebugPort(代号7)。

由于这种检测方式是直接检测接口,所以方式很直观,没有什么好说的。


代码

bool CheckDebugger(HANDLE hProcess) {
    HINSTANCE hModule;
    BOOL bDebuggerPresent = FALSE;
    check_remote_debugger_present CheckRemoteDebuggerPresent;
    hModule = GetModuleHandleA("kernel32");
    CheckRemoteDebuggerPresent = (check_remote_debugger_present)GetProcAddress(hModule, "CheckRemoteDebuggerPresent");

    bool retn = CheckRemoteDebuggerPresent(hProcess, &bDebuggerPresent)?bDebuggerPresent:FALSE;
    if (retn == TRUE)
        cout<< "your are  debugging me\n" <<endl;
    else {
        cout<< "your are not debugging me\n" <<endl;
    }
    return retn;

}

#修改进阶

format_list_numbered

(无)

  1. 1. #写在最前
  • #检测
    1. 1. #BeingDebugged
    2. 2. #NtGlobalFlag
    3. 3. #heap magic,Flags
  • 修改
    1. 1. #效果
  • #检测进阶
  • #修改进阶
  • vertical_align_top

    Copyright © 2018 太空独角兽