Results 1 to 11 of 11

Thread: Debugger detection methods... WHEN to call them?

  1. #1
    kunai
    Guest

    Debugger detection methods... WHEN to call them?

    Hi. I've implemented various ant-re methods to detect debugger presence. I'm not trying to create unbreakable app, just wanting to see how it all works. So, having those method I can call them at the beginning of program and they will do what they should... but if app is not debugged at that time but instead dbg will be attached later - the whole mechanism is broken.

    So here's my question - when and how often should those method be called? Should I have separate thread for this? (somehow it does not sound reliable...)
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  2. #2
    o The ring of transitions.
    - Features implementing functions of converting trap-frame. For example: register using Gs instead of the Ds(debugger its zeroes, ie the trace is not available), context on return from service and current(Ecx & Edx, EFlags etc., morph perfect technique..), the use of zeroing in segments between the ring switching(Iret, Retf. if the selector is zero, then the field of RPL reset the processor), determining whether a swapping(Smsw), etc.
    o The use of delays in the trace and using the debug port(SEH, VEH, UEF), measurement of the delay in between the ring transitions(Int 0x2A etc).
    o Direct detection of the debug port and its removal(ProcessDebugObjectHandle, NtRemoveProcessDebug etc.)
    o Exit from a trace(NtContinue, Int 0x2B - very effective ways to U-mode impossible to cheat ).
    o And many, many other ways

  3. #3
    kunai
    Guest
    Indy, thank you for your answer
    I think, however, that you misunderstood my question. The second option is that your answer is too complex for me to understand

    I have already implemented some anti-re methods, not so complex as those that you described, although for now I will stick to what I already have.

    Let's say I have GUI app. At the beginning of main() I do bunch of anti-re checks. If they completed successfully it means no debugger is attached. Then app starts doing some real code, like secret algorithm. And NOW someone attach debugger which obviously is not detected in this approach.

    My ideas are to either put those checks in one of (often triggered) event handlers, or into separate thread. Which one is better?
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  4. #4
    kunai
    This is a simple and effective methods. Can be divided into several types:
    o Detection of trace(TF).
    o Detection of breakpoints.
    o Detection of debug port.
    o Outside of trace.
    o Bypass breakpoints.
    o Disable debug port or hide the thread of it.

    To reset the TF can use the following methods:
    o Services NtSetContextThread, NtRaiseException and NtContinue allow you to load in the context of flags without imposing on them a mask for TF. Например:
    Code:
    Context.TF -> 0
    NtContinue(@Context)
    o Using the shadow callbacks. There is a stack of shadow callbacks. For each entry stored context and on return from callback loaded into the processor. In the context of TF also copied a previously saved:
    Code:
    ; +
    ; Сохранение контекста.
    ; o Eax: ID NtUserEnumDisplayMonitors.
    ; o Esi: адрес возврата.
    ; o Edi: ссылка на стек.
    ;
    TsSave proc C
    	xor ecx,ecx
    	push esp	; Параметр для калбэка - ссылка на стек для его восстановления.
    	Call @f	; Ссылка на калбэк.
    ; Калбэк.
    ; typedef BOOL (CALLBACK* MONITORENUMPROC)(HMONITOR, HDC, LPRECT, LPARAM);
    	mov esp,dword ptr [esp + 4*4]	; Восстанавливаем стек, ссылка для восстановления передаётся параметром.
    	xor eax,eax
    	retn
    @@:
    	push ecx
    	push ecx
    	mov edx,esp
    ; BOOL
    ; NtUserEnumDisplayMonitors(
    ;     IN HDC             hdc,
    ;     IN LPCRECT         lprcClip,
    ;     IN MONITORENUMPROC lpfnEnum,
    ;     IN LPARAM          dwData)
    	Int 2EH	; NtUserEnumDisplayMonitors
    ; При восстановлении контекста возвращается не ноль.
    	.if !Eax	; Калбэк не был вызван изза исчерпания лимита вызовов/вложенности(0x2C).
    	add esp,4*4	; Удаляем параметры сервиса.
    	mov eax,STATUS_STACK_OVERFLOW
    	retn
    	.else
    	mov esp,edi
    	add eax,3*4	; Ссылка на стек, который был при вызове TsLoad(для передачи параметров).
    	jmp esi
    	.endif
    TsSave endp
    
    ; +
    ; Восстановление контекста.
    ;
    TsLoad proc C	; stdcall
    	xor eax,eax
    	mov edx,3*4
    	push eax
    	push eax
    	push esp
    	mov ecx,esp
    	Int 2BH
    	add esp,3*4
    	retn		; В случае ошибки возвратит STATUS_NO_CALLBACK_ACTIVE.
    TsLoad endp
    or macro:
    Code:
    QUERY_SERVICE_ID macro
    	mov eax,dword ptr [_imp__EnumDisplayMonitors]
    	mov eax,dword ptr [eax + 1]	; ID NtUserEnumDisplayMonitors
    endm
    
    ; +
    ; Сохранение контекста.
    ; o Сохраняются регистры:
    ;   - EFlags
    ;   - Ebp
    ;   - Ebx
    ;   - Esp
    ; o NPX не сохраняется.
    ;
    SAVE_TASK_STATE macro Ip
    Local Break
    	mov esi,Ip
    	mov edi,esp
    	Call @f
    	jmp Break
    @@:	
    	pushad
    	xor ecx,ecx
    	push esp
    	Call @f
    	mov esp,dword ptr [esp + 4*4]
    	popad
    	retn
    @@:
    	push ecx
    	push ecx
    	QUERY_SERVICE_ID
    	mov edx,esp
    	Int 2EH
    	xor eax,eax
    	mov esp,edi
    	jmp esi
    Break:
    endm
    
    ; Восстановление контекста.
    ;
    RESTORE_TASK_STATE macro
    	xor eax,eax
    	mov edx,3*4
    	push eax
    	push eax
    	push eax
    	mov ecx,esp
    	Int 2BH
    endm
    This method is not possible to cheat in U-mode. Stack of shadow callbacks in the kernel and is not available to user code, even for reading
    http://wasm.ru/forum/viewtopic.php?id=37300

    o At the kernel of TF can be reset, loading descriptor in the IDT and calling gateway.

    o Removing breakpoints. They can be of several types(hardware Dr*, in memory and on memory). Hardware detected and cleared as well as TF. For memory type PAGE_GUARD duped change attribute memory or load limits of the region in TEB.Tib(StackBase & StackLimit). Then the memory manager will not deploy an exception. Setting breakpoints in memory can be disabled altogether. To this end, the code must be placed in not the file section of the map only for reading. This mechanism can be used for the entire module, remap all its file sections. After such a manipulation of a write in memory will not be possible.

    o Disable debug port is a system mechanism. Service NtQueryInformationProcess(ProcessDebugObjectHandle) copies handle port, then port is disconnected(service NtRemoveProcessDebug). It is also a way to detect the port. Thread can be marked for exclude from the Dbg-processing(NtSetInformationThread(ThreadHideFromDebugger)). In the presence of a debug port of the processing speed of exceptions is slow in reduced to ~200%2000 times.

    o Using registry Gs. This register is not changed scheduler, and reset when converting trap-frame in the context. The code uses it can not be traced without changing the kernel http://wasm.ru/forum/viewtopic.php?id=38465&p=1

    o Detection of TF in the context of the just, for this there are many ways and it makes no sense to describe them.
    Last edited by Indy; November 23rd, 2010 at 21:42.

  5. #5
    To crash or not to crash
    Join Date
    Dec 2001
    Posts
    120
    I think it's best to not notify the user instantly. You are better of killing your app a step at a time when you detect a debugger. The checks are often not very time consuming. So throw one check in a timer, another one when a user clicks a button, another when a user selects a menuitem and mess with the results of the program if your check returns positive. If there is no messagebox or program termination it's much harder to detect the antidebugger code.

  6. #6
    Iwarez
    For example the use of Gs in the trace itself is not possible, and no other checks are not needed. Can proceed as follows. Assemble code into a special format(mutation independed), to create a graph for it, modify it by introducing a set of prefixes Gs and compile the graph. Ie use morphing. This code will normally displayed in the disassembler(debugger), but tracing it is very problematic - for this will need to patch the kernel. For example:
    Code:
    	push ds
    	pop gs	; KGDT_R3_DATA | RPL_MASK
    	mov eax,dword ptr gs:[Var]

  7. #7
    indy, may i make you a question? The NtContinue trick is cool, but I am having some problem with the R3 callback.

    * we call directly a GDI r0 function that uses R3 callback - ok (by the way, do we need to go manually on it, or we can just use the 'legal' call?)
    * Since the GDI needs to support multiple calls to the kernel, as callbacks can call the kernel, a sequence of stack frames are saved, including processor state for each sequence.
    * You start with a call to the R0 function then we let allthe code executes normally, then let's say we start tracing the code with a debugger, at some point in the traced code we execute the 'end of callback' code, so our previous register status (with TF=0) gets restored and we are freed of tracing, right?

    The GS trick: I am a bit of lost for it - I will try it for sure, but i would like to understand why...
    hmm... the base of GS selector is changed like FS for addressing kernel structures, so that while stepping you HAVE kernel kicked in so the base is restored with kernel gs base...
    however, if you catch a random interrupt in beneath pop and mov during normal execution??
    Last edited by Maximus; November 26th, 2010 at 07:11.
    I want to know God's thoughts ...the rest are details.
    (A. Einstein)
    --------
    ..."a shellcode is a command you do at the linux shell"...

  8. #8
    Maximus
    The GS trick: I am a bit of lost for it - I will try it for sure, but i would like to understand why...
    Kernel manipulates his native state of the task. This is a trap frame. When the conversion to a custom structure describes the context run some amendments. You can follow any responses to see it in the functions KeContextFromKframes() & KeContextToKframes(). The scheduler uses these functions, moreover all the segment registers stored in the trap frame. The scheduler does not cause these functions, moreover all the segment registers stored in the trap frame. This does not affect the planning. The debugger calls these functions to get/change the context. And he can not get/set register Gs, since it is reset by these functions.

    we call directly a GDI r0 function that uses R3 callback - ok (by the way, do we need to go manually on it, or we can just use the 'legal' call?)
    We can use a large number of system services, causing shadow callbacks. When you entry into the kernel trap frame is stored, must be cleared by TF. When you entry into the kernel of callback service is completed and saved the trap frame is loaded into the processor. This mechanism supports is full of recursive calls. See KeUserModeCallback(), KiCallbackReturn(), NtCallbackReturn() etc.

  9. #9
    Build a simple sample. Code MessageBox() is transferred to the buffer that is in the map does not file section, available for R/E. In this case, change the memory access is impossible, ie to put breaks in the memory will not work:

    Code:
    	_imp__MessageBoxA proto :HANDLE, :PSTR, :PSTR, :ULONG
    	
    %NTERR macro
    	.if Eax
    	Int 3
    	.endif
    endm
    
    .data
    
    $Message	CHAR 16 DUP (?)
    
    .code
    	include Gcbe.inc
    
    %ALLOC macro vBase, vSize, vProtect, cSize, Reg32
    	mov vBase,NULL
    	mov vSize,cSize
    	invoke ZwAllocateVirtualMemory, NtCurrentProcess, addr vBase, 0, addr vSize, MEM_COMMIT, PAGE_READWRITE
    	mov Reg32,vBase
    	%NTERR
    	add vBase,cSize - X86_PAGE_SIZE
    	mov vSize,X86_PAGE_SIZE
    	invoke ZwProtectVirtualMemory, NtCurrentProcess, addr vBase, addr vSize, PAGE_NOACCESS, addr vProtect
    	%NTERR	
    endm
    
    $Title	CHAR "Ip's:",0
    
    Ep proc
    Local GpSize:ULONG
    Local Snapshot:GP_SNAPSHOT
    Local Protect:ULONG
    Local CsBase:PVOID, CsSize:ULONG
    Local BiBase:PVOID, BiSize:ULONG
    Local ObjAttr:OBJECT_ATTRIBUTES
    Local SectionSize:LARGE_INTEGER
    Local SectionOffset:LARGE_INTEGER
    Local ViewBase:PVOID, ViewSize:ULONG
    Local SectionHandle:HANDLE
    	%ALLOC Snapshot.GpBase, GpSize, Protect, 200H * X86_PAGE_SIZE, Ebx
    	mov Snapshot.GpLimit,ebx
    	mov Snapshot.GpBase,ebx
    	lea ecx,Snapshot.GpLimit
    	push eax
    	push eax
    	push eax
    	push eax
    	push eax
    	push 4
    	push GCBE_PARSE_SEPARATE
    	push ecx
    	push dword ptr [_imp__MessageBoxA]
    	%GPCALL GP_PARSE
    	%NTERR
    	mov eax,Snapshot.GpLimit
    	xor edx,edx
    	sub eax,ebx
    	mov ecx,ENTRY_HEADER_SIZE
    	div ecx
    	invoke udw2str, Eax, addr $Message
    	%ALLOC CsBase, CsSize, Protect, 200H * X86_PAGE_SIZE, Esi
    ;	%ALLOC BiBase, BiSize, Protect, 200H * X86_PAGE_SIZE, Edi
    	xor eax,eax
    	cld
    	mov ecx,sizeof(OBJECT_ATTRIBUTES)/4
    	lea edi,ObjAttr
    	mov dword ptr [SectionSize],100H * X86_PAGE_SIZE
    	mov dword ptr [SectionSize + 4],eax
    	rep stosd
    	mov ObjAttr.uLength,sizeof(OBJECT_ATTRIBUTES)
    	invoke ZwCreateSection, addr SectionHandle, SECTION_ALL_ACCESS, addr ObjAttr, addr SectionSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL
    	%NTERR
    	mov ViewBase,eax
    	mov ViewSize,eax
    	mov dword ptr [SectionOffset],eax
    	mov dword ptr [SectionOffset + 4],eax
    	invoke ZwMapViewOfSection, SectionHandle, NtCurrentProcess, addr ViewBase, 0, 0, addr SectionOffset, addr ViewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE
    	%NTERR
    	push ViewBase	; push edi
    	push esi
    	push Snapshot.GpLimit
    	push Snapshot.GpBase
    	%GPCALL GP_BUILD_GRAPH
    	%NTERR
    	invoke ZwUnmapViewOfSection, NtCurrentProcess, ViewBase
    	%NTERR
    	invoke ZwMapViewOfSection, SectionHandle, NtCurrentProcess, addr ViewBase, 0, 0, addr SectionOffset, addr ViewSize, ViewShare, NULL, PAGE_EXECUTE_READ
    	%NTERR
    	push MB_OK
    	push offset $Title
    	push offset $Message
    	push eax
    	call ViewBase
    	ret
    Ep endp
    Hidfn.zip
    Possible to automatically generate a series of Gs-prefixes. This will make the debugger useless

    The same manipulation can be done remap image.

  10. #10
    Hi Indy - thanks alot.

    Unfortunately I'm on an x64 system, and I am scared to even think of using WinDBG for anything different from crash analysis... I'll re-setup a VM and put something like Syser or such on it for examining the calls you suggest.

    nice shared library, by the way
    I want to know God's thoughts ...the rest are details.
    (A. Einstein)
    --------
    ..."a shellcode is a command you do at the linux shell"...

  11. #11
    Sample displays a message. The code is automatically reconstructed and added to Gs-series. Tracing is not possible.

    GsTest.zip

Similar Threads

  1. Replies: 0
    Last Post: April 24th, 2008, 09:42
  2. Replies: 0
    Last Post: April 24th, 2008, 09:42
  3. Replies: 0
    Last Post: April 24th, 2008, 09:42
  4. Two VM detection methods, reported by Sirmabus
    By dELTA in forum Advanced Reversing and Programming
    Replies: 1
    Last Post: January 17th, 2008, 06:41
  5. Where are the Class methods?
    By 5aLIVE in forum The Newbie Forum
    Replies: 1
    Last Post: July 28th, 2005, 04:25

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •