Sunday, May 15, 2016

Windows Internals [Process II - Code]


Before I begin, please comment on the posts, so I know what is wrong and what is right with the posts. Please consider that I am not charging you for this information and your comments will be a motivation.

If you haven't read the part I of this, I would recommend you to do so now. And if you have then let us go directly to the code.

//****************************************************************************/
NTSTATUS DriverEntry(IN PDRIVER_OBJECT _pdrvobj,IN PUNICODE_STRING _CM_Entry)
{
        char *eproc;
        long cpid;
       
        _pdrvobj->DriverUnload=Kext_Unload;

         eproc = (char*)PsGetCurrentProcess();
         cpid = *((long*)(eproc + 156));
    
         while(1)
         {
                DbgPrint("%d : %s", *((long*)(eproc + 156)),eproc + 508);
                eproc =    (char*)(((char*)(((LIST_ENTRY*)(eproc + 160))->Flink)) - 160);
                if( cpid == *((long*)(eproc + 156)) )break;
         }
        
   
    return STATUS_SUCCESS;
}
//******************************************************************************/

A small piece of code isn't it? :)   So what are we seeing here. First we use a documented function that is accessible to driver writers easily to get a pointer to the structure EPROCESS (PsGetCurrentProcess()). Remember that I am using the Windows 2000 driver kit to compile and every bit of compatibility that I am explaining and assuring is tested. At this point I am keeping it bare metal so I am only going to use pointers and simple data types to manipulate the kernel info in the algorithm not high-level structures.  So if you add 156 bytes from the start of EPROCESS you get the process ID which is declared long. long takes 4 bytes. So now that we dereference that memory location, we can get the PID of a process. Since this is driver entry called in arbitrary context , I assume mostly it will show the current process as "System". You can see that in the part I of this article. It is system that is the first process in the list. Next is the grand loop. Inside this, I use the existing pointer to EPROCESS and go to offset 508 to get the process name. Ok what is the next line that is a mess? Couple of things are done here. So, after the PID the next information that is stored in EPROCESS is LIST_ENTRY. As driver writers would know this is used for managing a doubly linked list and driver writers often use this. It is a self-referential structure with a forward and a backward link. What do they store? As you can imagine they store pointer to the next LIST_ENTRY. And the next important question is not, what the next ENTRY points to but where it is contained. It is contained in the next EPROCESS structure or structure that is created to inform about the next process. So if we jump 160 bytes from start of EPROCESS use the value contained in that address, go to that address and subtract 160 from it, we get starting address of next EPROCESS. I have done a lot of casting to char*. We need to cast the so extracted LIST_ENTRY address before subtracting 160. Otherwise it will subtract LIST_ENTRY sized value from that (pointer arithmetic). A lot of that code can be simplified if we introduce, the EPROCESS structure itself and cast some of these addresses to be of type EPROCESS.

Therefore you can re-write that to the below having declared structures necessarily...

//****************************************************************************/
typedef struct EPROC
{
        char blah[156]; //At this point we are not worried about what is in these 156 bytes
        long pid;
        LIST_ENTRY *Flink,*Blink;
}__EPROCESS,*__PEPROCESS;

NTSTATUS DriverEntry(IN PDRIVER_OBJECT _pdrvobj,IN PUNICODE_STRING _CM_Entry)
{

         __PEPROCESS eproc;
        long pid;
           
        eproc = (__PEPROCESS)PsGetCurrentProcess();
        cpid = eproc->pid;

        while(1)
        {
              DbgPrint("%d:%s",eproc->pid,(char*)eproc + 508);

              eproc = (__PEPROCESS) ((char*)eproc->Flink - 160);
               
              if(eproc->pid == cpid) break;
        }                                  
}
//****************************************************************************/

But would we ever stop with that? For starters, you could manipulate these pointers and change their values causing certain havoc. This is what root kits do like hiding the process. Similar structures exist for everything else managed by the kernel - security related structures, networking related, file system related.. imagine what power we have now, having understood how to manipulate the low level structures? There are so many websites and blogs that talk about these. One is a blog that I follow myself. Joanna's Invisible things. She is definitely one of my most favorite Gray Hats. :)

Of course you cannot easily do that now, since Windows has kernel patch guard etc. And if you didn't know already, similar techniques are used in the other operating systems and no system is immune to these attacks. For there is always a way if there is the will... So what do you have in your mind?

No comments:

Post a Comment