Windows kernel Analysis-implementation of kernel debugging mechanisms (Ntcreatedebugobject, dbgkppostfakeprocesscreatemessages, dbgkppostfakethreadmessages analysis)

Source: Internet
Author: User
Tags mutex secure copy

This paper mainly analyzes several kernel functions related to debugging in the kernel.

The first is the Ntcreatedebugobject function, which is used to create a kernel debug object, and the parser shows that it is just a layer of obcreateobject encapsulation and initializes some struct members.

I'll write some notes about the management of the Window object, and I'll analyze the object creation process.

From WRK1.2
Ntstatusntcreatedebugobject (out Phandle debugobjecthandle, in Access_mask desiredaccess, in POBJECT_ATTRIBUTES Objectattributes, in ULONG Flags) {NTSTATUS Status; HANDLE HANDLE; Kprocessor_mode Previousmode; Pdebug_object Debugobject; Detects the IRQL level at which the macro is located, which is equivalent to an assertion that determines the current IRQL allow paging paged_code (); Gets whether the current operating mode is kernel or user Previousmode = Kegetpreviousmode (); try {if (Previousmode! = KernelMode) {//Verify read-write (verify parameter correctness) Probeforwritehandle (debugobjecthandle); } *debugobjecthandle = NULL; } except (Exsystemexceptionfilter ()) {return GetExceptionCode (); } if (Flags & ~debug_kill_on_close) {return status_invalid_parameter; }////Create Debug object//Status = Obcreateobject (Previousmode, Dbgkdebugobjecttype, Objectattributes, Previousmode, NULL, sizeof (Debug_OBJECT), 0, 0, &debugobject); if (! Nt_success (status)) {return status; } Exinitializefastmutex (&debugobject->mutex);//Initialize debug event chain list in debug kernel object Initializelisthead (&DebugObject-> EventList); Keinitializeevent (&debugobject->eventspresent, notificationevent, FALSE); if (Flags & debug_kill_on_close) {debugobject->flags = Debug_object_kill_on_close; } else {debugobject->flags = 0; }//Debug object inserts the handle table of the current process Status = Obinsertobject (Debugobject, NULL, Desiredaccess, 0, NULL, &handl e/* returns a handle */); if (! Nt_success (status)) {return status; }//secure copy with exception handling try {*debugobjecthandle = Handle; } except (Exsystemexceptionfilter ()) {Status = GetExceptionCode (); } return Status;

The Windows debugging mechanism in 29th writes the () function in the learning note DebugActiveProcess , which is called to zwdebugactiveprocess () and the function is finally executed to ntdebugactiveprocess ()

And the key call in this function is Dbgkppostfakeprocesscreatemessages () and Dbgkpsetprocessdebugobject ().

Ntstatusntdebugactiveprocess (in HANDLE processhandle, in HANDLE debugobjecthandle) {NTSTATUS Status;    Kprocessor_mode Previousmode;    Pdebug_object debugobject;//Returns the value of the Debug object peprocess Process;    Pethread lastthread;//detects the IRQL level at the location of the macro, which is equivalent to an assertion that determines the current IRQL allow paging paged_code ();                                        Previousmode = Kegetpreviousmode ();//handle using process Kernel object Status = Obreferenceobjectbyhandle (ProcessHandle,                                        Process_set_port, Psprocesstype,    Previousmode, &process, NULL); if (!    Nt_success (status)) {return status;    }//Don ' t let us debug ourselves or the system process. Verify parameter legality if (Process = = psgetcurrentprocess ()/* Whether you want to debug yourself */| | Process = = psinitialsystemprocess/* cannot debug the system process, PID is 4*/) {obdereferenceobject (process);//de-count return Statu    s_access_denied; }//using a handle to debug internal checksLike Status = Obreferenceobjectbyhandle (Debugobjecthandle, Debug_process_assign,                                        Dbgkdebugobjecttype, Previousmode,    &debugobject, NULL); if (nt_success (Status)) {//We'll be touching process address space.    Block process Rundown. Lock to prevent the process from exiting if (Exacquirerundownprotection (&process->rundownprotect)) {//This is a key function, and the following will be done for the analysis                                                         The function is to send forged debug information//based on the literal meaning of sending a forged process to create debug information Status = Dbgkppostfakeprocesscreatemessages (Process,             Debugobject, &lastthread); Set the debug port.                            If This fails it would remove any faked messages.//above is wrk comes with the comment Status = Dbgkpsetprocessdebugobject (Process,                     Debugobject, Status,        Lastthread);//Release lock Exreleaserundownprotection (&process->rundownprotect);        }else {Status = status_process_is_terminating;    } obdereferenceobject (Debugobject);    } obdereferenceobject (Process); return Status;}

Note that dbgkppostfakeprocesscreatemessages () is used to debug information that has been forged to the debugger. Why fake debugging information? Because it is for the complete debugging information.

Imagine a scenario in which you attach a running process. If you do not forge debug information then the debugger will not work, because you attach when the process has been running, the previous debugging information you are not received,

The debugger will not work properly. Forgery debugging information is to complete the debugging information re-sent to the debugger was born.

Let's look at the function of Dbgkppostfakeprocesscreatemessages (), and we can see that this is actually just a layer of encapsulation. There are two functions, dbgkppostfakethreadmessages and dbgkppostfakemodulemessages, that are useful.

Ntstatusdbgkppostfakeprocesscreatemessages (in Peprocess Process, in Pdebug_object debugobject, in PETHREAD *pLa    Stthread) {NTSTATUS Status;    Kapc_state apcstate;    Pethread Thread;    Pethread Lastthread;  Paged_code ();//attach to the target process kestackattachprocess (&PROCESS->PCB, &apcstate);//Send false thread creation information (the main function is implemented here) Status =                                          Dbgkppostfakethreadmessages (Process, Debugobject, NULL, &thread, &last    Thread);        if (nt_success (Status)) {//send module message Status = Dbgkppostfakemodulemessages (Process, Thread, Debugobject); if (!            Nt_success (Status)) {obdereferenceobject (lastthread);        Lastthread = NULL;    } obdereferenceobject (Thread);    } else {lastthread = NULL;    }//Lifting additional keunstackdetachprocess (&apcstate);    *plastthread = Lastthread; RetuRN Status;} 

The Dbgkppostfakethreadmessages function is analyzed as follows

1. Send process to create forged debug information

2. Send the Create forged debug information for each thread in turn

3. Put each message in a debug event in the list of debug objects

The bogus debugging information here is using the

DBGKM_APIMSG structure

typedef struct _DBGKM_APIMSG {
port_message H;
Dbgkm_apinumber Apinumber;
NTSTATUS returnedstatus;
Union {
dbgkm_exception EXCEPTION;
Dbgkm_create_thread CreateThread;
dbgkm_create_process Createprocessinfo;
Dbgkm_exit_thread ExitThread;
dbgkm_exit_process exitprocess;
Dbgkm_load_dll Loaddll;
Dbgkm_unload_dll Unloaddll;
} u;
} dbgkm_apimsg, *pdbgkm_apimsg;

typedef struct _DBGKM_CREATE_PROCESS {
ULONG Subsystemkey;
HANDLE FileHandle;
PVOID baseofimage;
ULONG Debuginfofileoffset;
ULONG debuginfosize;
Dbgkm_create_thread Initialthread;
} dbgkm_create_process, *pdbgkm_create_process;

Note that this structure is finally written to the debug event

Ntstatusdbgkppostfakethreadmessages (in Peprocess Process, in Pdebug_object debugobject, in Pethread StartThread    , out Pethread *pfirstthread, out Pethread *plastthread) {NTSTATUS Status;    Pethread Thread, Firstthread, Lastthread;    Dbgkm_apimsg apimsg;    BOOLEAN first = TRUE;    BOOLEAN Isfirstthread;    Pimage_nt_headers ntheaders;    ULONG Flags;    NTSTATUS status1;//Verification IRQL Paged_code ();    Lastthread = Firstthread = NULL;   Status = status_unsuccessful;    Note that the above pass is NULL!!! if (startthread! = NULL) {//startthread!=null indicates that the current thread has an ID that the current thread is not the initial thread first = false;//is not a firstthread = Startt        Hread;    Obreferenceobject (Firstthread); } else {//==0 indicates that the current thread is the initial thread.        It also indicates that the process is being created. Startthread = Psgetnextprocessthread (Process, NULL);//What is obtained here is the initial thread first = true;//is the number one} for (thread = Startt         Hread; Thread! = NULL; Traverse each thread of the process, thread = psgetnextprocessthread (process, thread)) {//Set debug event not to wait for Flags = Debug_event_NOWAIT;        if (lastthread! = NULL) {obdereferenceobject (lastthread);        }//is used to record the last thread lastthread = thread;        Obreferenceobject (Lastthread); Locks the thread to prevent the thread from terminating if (Exacquirerundownprotection (&thread->rundownprotect)) {Flags |= debug_event_re lease;//determines whether the obtained thread is the system thread if (!is_system_thread (thread)) {//suspend thread Status1 = Pssuspendthread (threa                D, NULL);                if (nt_success (STATUS1)) {//pause succeeded, plus a pause flag flags |= debug_event_suspend;        }}} else {//Get lock failed, plus tag flags |= debug_event_protect_failed; }//constructs a APIMSG structure (dbgkm_apimsg type) rtlzeromemory (&apimsg, sizeof (APIMSG));//If the application succeeds and this thread is the first thread//description is the process created//this will happen Process Create forged message if (first && (flags&debug_event_protect_failed) = = 0 &&!is_system_thread ( Thread) && thread->grantedaccess! = 0) {Isfirstthread = true;//description is the thread creation andProcess Creation} else {isfirstthread = FALSE;            } if (Isfirstthread) {//Here the process is set to create a forged message structure apimsg.apinumber = DBGKMCREATEPROCESSAPI;  if (process->sectionobject! = NULL)//{//The file handle of the process Master module is saved in the structure of the forged message Apimsg.u.createprocessinfo.filehandle            = Dbgkpsectiontofilehandle (Process->sectionobject);            } else {apimsg.u.createprocessinfo.filehandle = NULL;            }//the base of the process Master module is stored in the structure of the forged information Apimsg.u.createprocessinfo.baseofimage = process->sectionbaseaddress;//enhanced stability with exception handling                try {//NT head ntheaders = Rtlimagentheader (process->sectionbaseaddress) for PE structure;  if (ntheaders) {apimsg.u.createprocessinfo.initialthread.startaddress = NULL;//Filling This in breaks msdev!//parsing the debug information in NT header and putting it into the structure of forged information Apimsg.u.createprocessinfo.debuginfofileoffset = Ntheaders->filehea Der.                    pointertosymboltable; Apimsg.u.createprocessinfo.Debuginfosize = Ntheaders->fileheader.numberofsymbols;}                } except (exception_execute_handler) {apimsg.u.createprocessinfo.initialthread.startaddress = NULL;                Apimsg.u.createprocessinfo.debuginfofileoffset = 0;            apimsg.u.createprocessinfo.debuginfosize = 0;            }} else {///is not the first, the description is thread creation, set a thread to create a forged information structure apimsg.apinumber = DBGKMCREATETHREADAPI;        Apimsg.u.createthread.startaddress = thread->startaddress;                                    }//Insert the message packet constructed above into the queue Status = Dbgkpqueuemessage (Process, Thread, &apimsg, Flags, Debugobject); Error handling if (!            Nt_success (Status) {if (flags&debug_event_suspend) {psresumethread (Thread, NULL); } if (flags&debug_event_release) {exreleaserundownprotection (&Thread->rundownprotect);                } if (Apimsg.apinumber = = Dbgkmcreateprocessapi && apimsg.u.createprocessinfo.filehandle! = NULL) {            Obclosehandle (Apimsg.u.createprocessinfo.filehandle, KernelMode);            } psquitnextprocessthread (Thread);        Break            } else if (isfirstthread) {first = false;//has finished processing the obreferenceobject (Thread);        Firstthread = Thread; }} if (!        Nt_success (Status) {if (firstthread) {obdereferenceobject (firstthread);        } if (Lastthread! = NULL) {obdereferenceobject (lastthread);            }} else {if (firstthread) {*pfirstthread = Firstthread;        *plastthread = Lastthread;        } else {Status = status_unsuccessful; }} return Status;}

This is what it says about the Debug events list for debug objects

Ntstatusdbgkpqueuemessage (in Peprocess-Process, in Pethread-Thread, in-out pdbgkm_apimsg apimsg, in ULONG Fl AGS, in Pdebug_object targetdebugobject) {pdebug_event debugevent;//apimsg will eventually be encapsulated into this structure debug_event staticdebug    Event;    Pdebug_object Debugobject;    NTSTATUS Status; Paged_code ();//Determines whether a synchronization event or an asynchronous event ... if (flags&debug_event_nowait) {///asynchronous event is handled this way//allocate space for debug events DebugEvent = Exallocate Poolwithquotatag (nonpagedpool|                                                 Pool_quota_fail_instead_of_raise, sizeof (*debugevent),        ' EGBD ');        if (DebugEvent = = NULL) {return status_insufficient_resources; }//setting debug_event structure information debugevent->flags = flags|        debug_event_inactive;        Obreferenceobject (Process);        Obreferenceobject (Thread);        Debugevent->backoutthread = Psgetcurrentthread ();    Debugobject = Targetdebugobject; } else {//sync event This process//synchronous processing does not open pool memory for the structure        DebugEvent = &staticdebugevent;//directly given a local variable, because the processing is done within the function, the local variable can satisfy the condition debugevent->flags = flags;//Get the same        Step lock Exacquirefastmutex (&dbgkpprocessdebugportmutex);        Debugobject = process->debugport;        See if the Create message has already been sent.            if (Apimsg->apinumber = = Dbgkmcreatethreadapi | | Apimsg->apinumber = = Dbgkmcreateprocessapi) {if (thread->crossthreadflags&ps_cross_thread_flags_skip_        creation_msg) {debugobject = NULL;}}  See if this exit message was for a thread that never had a create//if (Apimsg->apinumber = =            Dbgkmexitthreadapi | | Apimsg->apinumber = = Dbgkmexitprocessapi) {if (thread->crossthreadflags&ps_cross_thread_flags_skip_te            rmination_msg) {debugobject = NULL; }}} keinitializeevent (&debugevent->continueevent, SynchronizationEvent, FALSE);//Fill DebugEvent De Bugevent->process = Process;    Debugevent->thread = Thread;    Debugevent->apimsg = *apimsg;    Debugevent->clientid = thread->cid;    if (Debugobject = = NULL) {Status = Status_port_not_set;        } else {/////We must not use a debug port thats got no handles left.        Gets the lock Exacquirefastmutex (&debugobject->mutex) of a debug object;        If The object is a delete pending then don ' t use this object. if ((debugobject->flags&debug_object_delete_pending) = = 0) {//Insert debug events into the list in the Debug object inserttaillist            (&debugobject->eventlist, &debugevent->eventlist); Set the event to say there is a unread event in the object/if (Flags&debug            _event_nowait) = = 0) {//If it is synchronous, notify the debugger to handle the KeSetEvent (&debugobject->eventspresent, 0, FALSE);        } Status = Status_success; } else {Status = Status_debugger_inactive;    } Exreleasefastmutex (&debugobject->mutex);        } if ((flags&debug_event_nowait) = = 0) {Exreleasefastmutex (&dbgkpprocessdebugportmutex);                                   if (nt_success (Status)) {//waits for the debugger to return information KeWaitForSingleObject (&debugevent->continueevent,                                   Executive, KernelMode, FALSE,            NULL);            Status = debugevent->status;        *apimsg = debugevent->apimsg; }}} else {if (!            Nt_success (Status)) {obdereferenceobject (Process);            Obdereferenceobject (Thread);        Exfreepool (DebugEvent); }} return Status;}

Windows kernel Analysis-implementation of kernel debugging mechanisms (Ntcreatedebugobject, dbgkppostfakeprocesscreatemessages, dbgkppostfakethreadmessages analysis)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.