首页
社区
课程
招聘
Hide user mode debuggers[转帖]
发表于: 2005-4-22 10:34 7445

Hide user mode debuggers[转帖]

2005-4-22 10:34
7445
Hide user mode debuggers from executables with debbuger detection
By: j0epub

原文出处:

http://www.rootkit.com/newsread.php?newsid=284

There are various techniques that copy protection schemes can use to detect whether their

applications are being debugged. What I inted to do is to prevent these types of

applications from detecting a user mode debbuger using the top two common methods. Please

note that the method used for detecting user mode debuggers do not apply to kernel mode

debuggers like SoftIce. There are other methods used to detect debuggers like SoftIce but I

will not cover those in this article.

Some of the methods used

Calling the kernel32 function IsDebuggerPresent
Checking a flag within the PEB (via fs:30h or fs:18h)
NtQueryInformationProcess with a class type of ProcessDebugPort

All the above methods are used by a commonly known commercial CD copy protection scheme

(cough cough), and by implementing the hooks the software no longer detected the attached

debugger (WinDbg, IDA and VS.NET tested)

The IsDebbugerPresent call basicly uses the fs:18h method to get a pointer the the TIB and

then from there retrevies a pointer to the PEB to retreive the relevant flag. So we will

eliminate the API IsDebuggerPresent call via solving the second method.

PEB (Process Enviroment Block) is a structure that all processes have present which contain

information related to that particualr process.
Here is the top of the undocumented PEB structure, notice the BeingDebugged member which is

what we will be concentrating on

typedef struct _PEB
{
    BOOL InheritedAddressSpace;
    BOOL ReadImageFileExecOptions;
    BOOL BeingDebugged;
    BOOL Spare;
    HANDLE Mutant;
    PVOID ImageBaseAddress;
    PPEB_LDR_DATA LoaderData

Using rootkit native API redirection methods I hooked ZwQueryInformationProcess to attack

the ProcessDebugPort method and ZwCreateProcessEx so that the PEB member BeginDebugged can

be set to FALSE.

Now the problem we have is that ZwCreateProcessEx is not actually exported from

ntoskern.exe, the closest we can get is NtCreateProcessEx which is exported from ntdll.dll.

So we have two options, we can either

1. Lookup up the address of NtCreateProcessEx from within the driver, and move 1 byte in

from the start address to get the index within KeServiceDescriptorTable

or

2. Manually disassemble ntdll.dll to get the service index for each OS.

I am going to pick option two because i'm lazy, so from the snippet below as you can see the

service index for NtCreateProcess is 30h (Based of XP SP1)

ntdll.dll:77F5B738 ntdll_NtCreateProcessEx:
ntdll.dll:77F5B738 mov     eax, 30h
ntdll.dll:77F5B73D mov     edx, offset loc_7FFE0300
ntdll.dll:77F5B742 call    edx ; loc_7FFE0300
ntdll.dll:77F5B744 retn    24h

debug015:7FFE0300 loc_7FFE0300:                           ; CODE XREF: ntdll.dll:77F5B742p
debug015:7FFE0300                                         ; DATA XREF: ntdll.dll:77F5B73Do
debug015:7FFE0300 mov     edx, esp
debug015:7FFE0302 sysenter
debug015:7FFE0304 retn

Eliminating NtQueryInformationProcess it quite simple as you can see from the code snippet

below

    status = sa.ZwQueryInformationProcess

(ProcessHandle,ProcessInformationClass,ProcessInformation,ProcessInformationLength,ReturnLen

gth);

    if(NT_SUCCESS(status))
    {
        //check to see if an application is querying wether it's debug port is set
        //and do some sanity checks also just in case
        if(ProcessInformationClass == ProcessDebugPort && ProcessInformation != NULL &&

ProcessInformationLength >= 4)
        {
            DbgPrint ("ZwQueryInformationProcess - ProcessDebugPort request - setting to

NULL\n");
            *(ULONG*)ProcessInformation = 0;    //forcefuly set port to 0 to that calling

applications
                                                //assumes no debugger is attached
        }

    }

ZwCreateProcessEx is slightly more complicated because we have to write to the foreign

process address space and set the relevant PEB member to FALSE. There is a DebugPort

parameter to the ZwCreateProcessEx function but I imagine that if you fail to pass this

through onto the real ZwCreateProcessEx then essential debuggee information will not be set

up correctly and the debugger wont function correctly

Interestingly, if you attach a debugger to an application that uses protected WMA's (Windows

Media Player for instance) it still detects the debugger, so there is scope for change to

add support for this. When I find out how it did this then I will update the code.

The code for the article can be found in my vault (anti-debug.c) and is by no means complete

but gives you an idea on how it can be done.

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 161
活跃值: (231)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
英文看不懂,谁翻译一下
2005-4-22 11:16
0
雪    币: 427
活跃值: (412)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
一人想到的新检测方法:
a few ideas for debugger detection

I had a few other ideas for debugger detection... I have no idea if anyone uses these, but you might want to consider them:

1) CSRSS and/or SMSS may keep some information on who is debugging and who is being debugged... Maybe it's possible to find this information using ReadProcessMemory, or maybe you can just ask them over LPC? (for a place to start, you can load SMSS.EXE with symbols and search for "HashTable")

2) If a process is created in a debugger, and it's allowed to initialize before you clear the "being debugged" flag, LdrpInitialize will create the process heap with certain flags, I think HEAP_TAIL_CHECKING_ENABLED and HEAP_FREE_CHECKING_ENABLED but I'm not sure. This could be a giveaway, but it's a theoretically-poor technique because possibly other factors (NtGlobalFlag?) could set these heap flags as well.

3) Here's the best one: a process can raise a 40010006h (DBG_PRINTEXCEPTION_C) exception, and if it's being debugged, this exception will be swallowed by WaitForDebugEvent (it's what OutputDebugString and DbgPrint use to send debug output) and regurgitated as an OUTPUT_DEBUG_STRING_EVENT instead of an EXCEPTION_DEBUG_EVENT. If it's not being debugged, then the thread's KiUserExceptionDispatcher will be called as normal. A very crafty debugger could do all the LPC itself and actually see the 0x40010006 exception, but a normal debugger using WaitForDebugEvent doesn't get a choice.

It appears that RaiseException(0x80000003) (STATUS_BREAKPOINT) may get special treatment by NTOSKRNL, and 0x80000003 and 0x80000004 (STATUS_SINGLE_STEP) may be recognized specially by SMSS, which passes it to the debugger. These might be worth exploring further, since special processing in NTOSKRNL, CSRSS, or SMSS could preclude the debugger from any chance of receiving the original message, a discrepancy that could be exploited as an anti-debugging trick.

Sorry for the lack of hard facts, this is just a kinda cursory brainstorm on anti-debugging tricks.
2005-4-22 15:15
0
游客
登录 | 注册 方可回帖
返回
//