Title: [original] Hide Your debugport in ring0
Author: wowelf
Time: 2009-01-26, 11: 00: 30
Chain: http://bbs.pediy.com/showthread.php? T = 80971
When a program is debugged by the ring3 debugger, many debugging features can be detected. This forum also has a special post for details, however, there is a very fundamental identifier ring3 that few people can detect, namely _ eprocess. debugport. Debugport is very important for the ring3 debugger. Without its normal ring3 debugging, it cannot be performed. Of course, the premise for detecting this flag is that the program can read ring0 memory. A very simple method for systems above XP is to use the sysdbgreadvirtualmemory method of zwsystemdebugcontrol. We can also map physicalmemory for operations. Before checking debugport, you must first obtain the eprocess address of the process, which can be obtained through the systemhandleinformation method of zwquerysysteminformation, or you can directly search for the eprocess structure of ring0 memory.
For ring3 to directly detect debugport, we can prevent this process from accessing the ring0 memory. However, once the target uses a driver for detection, this is very troublesome. The following describes a hidden _ eprocess. debugport method. The basic idea of this method is to set the debugport of a normal debugging process to zero and correct all affected functions so that our debugger can proceed normally. These functions are as follows:
Pspcreateprocess, mmcreatepeb Process Creation, set debugport
Dbgkcreatethread refers to debugging information created by the sending thread or process.
Kidispatchexception, dbgkforwardexception, and dbgkpqueuemessage send exception debugging information
Debugging information about pspexitthread, dbgkexitthread, and dbgkexitprocess sending thread exit and process exit
Dbgkmapviewofsection and dbgkunmapviewofsection send image loading/unloading debugging information
Dbgkpsetprocessdebugobject and dbgkpmarkprocesspeb set debugport when the debugger attaches a process
There are a lot of such functions. If they are all handled by hook, It would be terrible. Here we use a very simple method: steal dragon and convert it into a Phoenix. We can see that the code used by the system to access debugport is like this (XP)
8b89bc000000 mov ECx, dword ptr [ECx + 0bch] // 0bch is the offset of debugport
We can transfer the debugport to another location of _ eprocess. For example, if I use + 0x070 createtime, it records the process creation time. After the process is created, the system does not modify the process before it exits, and The modification does not affect the system or process. In this way, we can change the above Code to this
8b8970000000 mov ECx, dword ptr [ECx + 070 H] // point to createtime, the actual debugport has been moved here
You only need to modify one byte, which is very simple.
Of course, the most troublesome part of this method is to locate the function that references debugport (I have exhausted all the signatures created for different XP systems). These functions are not exported. If they are specific systems, the simplest method is windbg-> UF ***. It takes only a few minutes to find the hard-coded IP address.
Code:
BOOLEAN InitHackAddress(){ _SEH_TRY { g_KernelBase = GetKernelBaseAndSize( &g_KernelSize ); g_HackPspCreateProcess = SearchHackPspCreateProcess( &g_NopPspCreateProcess.Address ); g_HackKiDispatchException = SearchKiDispatchException( g_KernelBase,g_KernelSize ); g_HackDbgkpQueueMessage = SearchDbgkpQueueMessage( g_KernelBase,g_KernelSize ); g_HackDbgkCreateThread = SearchDbgkCreateThread( g_KernelBase,g_KernelSize ); SearchDbgkNotifyRoutine( g_KernelBase,g_KernelSize ); g_HackPspExitThread = SearchPspExitThread(); g_HackMmCreatePeb = SearchMmCreatePeb( g_HackPspCreateProcess ); SearchDbgkpSetProcessDebugObject( g_KernelBase,g_KernelSize ); if( g_HackDbgkpSetProcessDebugObject[3] ) g_HackDbgkpMarkProcessPeb = SearchDbgkpMarkProcessPeb( g_HackDbgkpSetProcessDebugObject[3] ) ; if( g_NopPspCreateProcess.Address != 0 ){ RtlFillMemory( g_NopPspCreateProcess.NopCode,sizeof(g_NopPspCreateProcess.NopCode),0x90 ); g_NopPspCreateProcess.Size = 9; RtlCopyMemory( g_NopPspCreateProcess.OrigCode,(PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.Size ); } if( g_NopDbgkForwardException.Address != 0 ){ RtlFillMemory( g_NopDbgkForwardException.NopCode,sizeof(g_NopDbgkForwardException.NopCode),0x90 ); RtlCopyMemory( g_NopDbgkForwardException.OrigCode,(PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.Size ); } if( g_NopDbgkExitThread.Address != 0 ){ RtlFillMemory( g_NopDbgkExitThread.NopCode,sizeof(g_NopDbgkExitThread.NopCode),0x90 ); RtlCopyMemory( g_NopDbgkExitThread.OrigCode,(PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.Size ); } if( g_NopDbgkExitProcess.Address != 0 ){ RtlFillMemory( g_NopDbgkExitProcess.NopCode,sizeof(g_NopDbgkExitProcess.NopCode),0x90 ); RtlCopyMemory( g_NopDbgkExitProcess.OrigCode,(PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.Size ); } if( g_NopDbgkMapViewOfSection.Address != 0){ RtlFillMemory( g_NopDbgkMapViewOfSection.NopCode,sizeof(g_NopDbgkMapViewOfSection.NopCode),0x90 ); RtlCopyMemory( g_NopDbgkMapViewOfSection.OrigCode,(PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.Size ); } if( g_NopDbgkUnMapViewOfSection.Address != 0 ){ RtlFillMemory( g_NopDbgkUnMapViewOfSection.NopCode,sizeof(g_NopDbgkUnMapViewOfSection.NopCode),0x90 ); RtlCopyMemory( g_NopDbgkUnMapViewOfSection.OrigCode,(PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.Size ); } } _SEH_HANDLER { DbgPrint( "InitHackAddress Exception!\n" ); } return ( g_HackPspCreateProcess != 0 && g_HackKiDispatchException != 0 && g_HackDbgkForwardException != 0 && g_HackDbgkpQueueMessage != 0 && g_NopPspCreateProcess.Address != 0 && g_NopDbgkForwardException.Address != 0 && g_HackDbgkCreateThread != 0 && g_HackDbgkExitThread != 0 && g_NopDbgkExitThread.Address != 0 && g_HackDbgkExitProcess != 0 && g_NopDbgkExitProcess.Address != 0 && g_HackDbgkMapViewOfSection != 0 && g_NopDbgkMapViewOfSection.Address != 0 && g_HackDbgkUnMapViewOfSection != 0 && g_NopDbgkUnMapViewOfSection.Address != 0 && g_HackPspExitThread != 0 && g_HackMmCreatePeb != 0 && g_HackDbgkpSetProcessDebugObject[0] != 0 && g_HackDbgkpSetProcessDebugObject[1] != 0 && g_HackDbgkpSetProcessDebugObject[2] != 0 && g_HackDbgkpSetProcessDebugObject[3] != 0 && g_HackDbgkpMarkProcessPeb != 0 );}
Code:
// Modify the debugport location of the running process Boolean changeprocessdebugport (Boolean hide) {ulong eprocess = (ulong) psinitialsystemprocess; plist_entry plisthead, plistwalk; ulong debugobject; If (! G_bisaddressstartup) {return false;} plisthead = (plist_entry) (eprocess + active_links_offset); plistwalk = plisthead; _ seh_try {do {If (plistwalk = NULL | eprocess = 0) break; eprocess = (ulong) plistwalk-active_links_offset); If (hide) {debugobject = * (ulong *) (eprocess + debug_port_offset); * (ulong *) (eprocess + create_time_offset) = debugobject; * (ulong *) (eprocess + debug_port _ Offset) = 0;} else {debugobject = * (ulong *) (eprocess + create_time_offset); * (ulong *) (eprocess + debug_port_offset) = debugobject ;} plistwalk = plistwalk-> flink;} while (plistwalk! = Plisthead);} _ seh_handler {dbuplint ("changeprocessdebugport exception! \ N ") ;}return true ;}
Code:
BOOLEAN ModifyDebugFunction(){ if( !g_bIsAddressStartup ){ return FALSE; } __asm{ cli mov eax,cr0 and eax,not 10000h mov cr0,eax } *(ULONG*)g_HackPspCreateProcess = CREATE_TIME_OFFSET; *(ULONG*)g_HackKiDispatchException = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkForwardException = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkpQueueMessage = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkCreateThread = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkExitThread = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkExitProcess = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkMapViewOfSection = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkUnMapViewOfSection = CREATE_TIME_OFFSET; *(ULONG*)g_HackPspExitThread = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkpMarkProcessPeb = CREATE_TIME_OFFSET; *(ULONG*)g_HackMmCreatePeb = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkpSetProcessDebugObject[0] = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkpSetProcessDebugObject[1] = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkpSetProcessDebugObject[2] = CREATE_TIME_OFFSET; *(ULONG*)g_HackDbgkpSetProcessDebugObject[3] = CREATE_TIME_OFFSET; RtlCopyMemory( (PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.NopCode,g_NopPspCreateProcess.Size ); RtlCopyMemory( (PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.NopCode,g_NopDbgkForwardException.Size ); RtlCopyMemory( (PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.NopCode,g_NopDbgkExitThread.Size ); RtlCopyMemory( (PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.NopCode,g_NopDbgkExitProcess.Size ); RtlCopyMemory( (PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.NopCode,g_NopDbgkMapViewOfSection.Size ); RtlCopyMemory( (PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.NopCode,g_NopDbgkUnMapViewOfSection.Size ); __asm{ mov eax,cr0 or eax,10000h mov cr0,eax sti } return TRUE;}BOOLEAN WriteBackDebugFunction(){ if( !g_bIsAddressStartup ){ return FALSE; } __asm{ cli mov eax,cr0 and eax,not 10000h mov cr0,eax } *(ULONG*)g_HackPspCreateProcess = DEBUG_PORT_OFFSET; *(ULONG*)g_HackKiDispatchException = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkForwardException = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkpQueueMessage = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkCreateThread = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkExitThread = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkExitProcess = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkMapViewOfSection = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkUnMapViewOfSection = DEBUG_PORT_OFFSET; *(ULONG*)g_HackPspExitThread = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkpMarkProcessPeb = DEBUG_PORT_OFFSET; *(ULONG*)g_HackMmCreatePeb = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkpSetProcessDebugObject[0] = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkpSetProcessDebugObject[1] = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkpSetProcessDebugObject[2] = DEBUG_PORT_OFFSET; *(ULONG*)g_HackDbgkpSetProcessDebugObject[3] = DEBUG_PORT_OFFSET; RtlCopyMemory( (PVOID)g_NopPspCreateProcess.Address,g_NopPspCreateProcess.OrigCode,g_NopPspCreateProcess.Size ); RtlCopyMemory( (PVOID)g_NopDbgkForwardException.Address,g_NopDbgkForwardException.OrigCode,g_NopDbgkForwardException.Size ); RtlCopyMemory( (PVOID)g_NopDbgkExitThread.Address,g_NopDbgkExitThread.OrigCode,g_NopDbgkExitThread.Size ); RtlCopyMemory( (PVOID)g_NopDbgkExitProcess.Address,g_NopDbgkExitProcess.OrigCode,g_NopDbgkExitProcess.Size ); RtlCopyMemory( (PVOID)g_NopDbgkMapViewOfSection.Address,g_NopDbgkMapViewOfSection.OrigCode,g_NopDbgkMapViewOfSection.Size ); RtlCopyMemory( (PVOID)g_NopDbgkUnMapViewOfSection.Address,g_NopDbgkUnMapViewOfSection.OrigCode,g_NopDbgkUnMapViewOfSection.Size ); __asm{ mov eax,cr0 or eax,10000h mov cr0,eax sti } return TRUE;}
I want to give it a bit again. The code above shows that many functions have a nopcode, which is actually used to deal with the thread ps_cross_thread_flags_hidefromdbg. After NOP drops the relevant content, even if the thread is set to threadhidefromdebugger, the debugger cannot be blocked from receiving debugging information.