Hmily 发表于 2009-6-21 11:25

CsrWalker v1.0



Seek'n'Hide game was always interesting. Especially when this seek'n'hide stuff is related to Windows Processes objects.

As you probably know exists a lot of "ultimate" hidden processes proof-of-concepts, which main idea is to hide the user land process from a different detection methods.

This article is about building conceptual pure user mode hidden processes detection software and also it contains source code of the PoC.


There is just a little list of available conceptual processes hiders (most of them out-of-dated, some really new):

Hacker Defender
FU/FUTO
rkdemo (1.0-1.2)
phide_ex
Z0mBiE
Several others not listed here.

Their main idea - is subverting Windows internals by doing a manupalations with a internals objects to hide them from Windows users and programs like TaskManager or Process Explorer.

From the other side exists a lot of public (or not public ) detectors, which main idea - reveal such hidden stuff by doing numerous checks of OS internals.

Each new hider bypasses all of them (or at least 90% of them) because it is always known how these detectors will check for hidden stuff. Most of detection methods based on locating EPROCESS or ETHREAD objects with several different ways such as PspCidTable (handle table) parsing, Scheduler lists analysis (as for example in GMER v1.14), checking of the specified EPROCESS fields such as all LIST_ENTRY, hooking KiSwapContext function, looking for threads, brute-forcing etc. Actually this all is enough for any kind of existing malware which is hiding processes while work. If exists some "unpublic malware" which is doing better hiding job, then it isn't meaningful, because it is "unpublic malware".

This was a preamble.

The mysterious CSRSS was always interesting to me, simple because it is playing a supervisor role for user land stuff. All win32 processes should notify it at process creation stage to continue work. Exactly this stuff doing all job of initializing processes subsystems (from csrsrv.dll which is a heart of CSRSS).

And exactly it - a "new" processes detector (actually build into NT since beginning). All this is completely undocumented. All what I got when tried to find any reference to this was ReactOs code, which is not complete and simple different.

It's takes a huge amount of time to reverse and rebuild the whole subsystem manager code but it was really fun and not so hard with a little piece of source code . The csrss is not a very complex thing to reverse and all most interesting stuff located in csrsrv.dll

Inside it exists not exported symbol called CsrRootProcess. It is playing a huge role in all CSRSS, because of this: CsrRootProcess is the pointer to CSR_PROCESS structure which looks like this.

//Vista/2008 csrsrv.dll (valid also for XP, 2003)

typedef struct _CSR_PROCESS {
struct _CLIENT_ID ClientId;
struct _LIST_ENTRY ListLink;
struct _LIST_ENTRY ThreadList;
struct _CSR_NT_SESSION* NtSession;
ULONG ExpectedVersion;
void* ClientPort;
char* ClientViewBase;
char* ClientViewBounds;
void* ProcessHandle;
ULONG SequenceNumber;
ULONG Flags;
ULONG DebugFlags;
ULONG ReferenceCount;
ULONG ProcessGroupId;
ULONG ProcessGroupSequence;
ULONG fVDM;
ULONG ThreadCount;
ULONG LastMessageSequence;
ULONG NumOutstandingMessages;
ULONG ShutdownLevel;
ULONG ShutdownFlags;
struct _LUID Luid;
void* ServerDllPerProcessData;
} CSR_PROCESS, *PCSR_PROCESS;


Here the field ListLink which is LIST_ENTRY.
In csrsrv exist another unexported internal function called
CsrInsertProcess. It is inserting a other CSR_PROCESS structure to
this list entry of the CsrRootProcess.

CsrInsertProcess was a key to me, to find a CsrRootProcess.
It is called from CsrCreateProcess exported but not documented function, nearly to the end.

text:75B15E94 call CsrSetBackgroundPriority
.text:75B15E99 mov dword ptr , 280h
.text:75B15EA0 mov eax, large fs:18h
.text:75B15EA6 mov eax,
.text:75B15EA9 push esi ; a3
.text:75B15EAA push dword ptr ; a2
.text:75B15EAD xor esi, esi
.text:75B15EAF push esi ; Session
.text:75B15EB0 call CsrInsertProcess

CsrInsertProcess looks very interesting.

.text:75B14CC9 ; int __stdcall CsrInsertProcess(int Session, int a2, int a3)
.text:75B14CC9 CsrInsertProcess proc near ; CODE XREF: sub_75B13BF8+12Ap
.text:75B14CC9 ; CsrCreateProcess+214p
.text:75B14CC9
.text:75B14CC9 Session = dword ptr 8
.text:75B14CC9 a2 = dword ptr 0Ch
.text:75B14CC9 a3 = dword ptr 10h
.text:75B14CC9
.text:75B14CC9 mov edi, edi
.text:75B14CCB push ebp
.text:75B14CCC mov ebp, esp
.text:75B14CCE mov eax,
.text:75B14CD1 push esi
.text:75B14CD2 mov esi,
.text:75B14CD5 mov , eax
.text:75B14CD8 mov ecx, CsrRootProcess
.text:75B14CDE mov edx,
.text:75B14CE1 add ecx, 8
.text:75B14CE4 lea eax,
.text:75B14CE7 mov , ecx
.text:75B14CE9 mov , edx
.text:75B14CEC push edi
.text:75B14CED mov , eax
.text:75B14CEF mov , eax
.text:75B14CF2 xor edi, edi
.text:75B14CF4
.text:75B14CF4 loc_75B14CF4: ; CODE XREF: CsrInsertProcess+48j
.text:75B14CF4 mov eax, CsrLoadedServerDll
.text:75B14CFA test eax, eax
.text:75B14CFC jz short loc_75B14D0B
.text:75B14CFE mov eax,
.text:75B14D01 test eax, eax
.text:75B14D03 jz short loc_75B14D0B
.text:75B14D05 push esi
.text:75B14D06 push
.text:75B14D09 call eax
.text:75B14D0B
.text:75B14D0B loc_75B14D0B: ; CODE XREF: CsrInsertProcess+33j
.text:75B14D0B ; CsrInsertProcess+3Aj
.text:75B14D0B add edi, 4
.text:75B14D0E cmp edi, 10h
.text:75B14D11 jb short loc_75B14CF4
.text:75B14D13 pop edi
.text:75B14D14 pop esi
.text:75B14D15 pop ebp
.text:75B14D16 retn 0Ch
.text:75B14D16 CsrInsertProcess endp

Regarding on this I've build a pseudo code for it.

CsrInsertProcess( .... )
{
PCSR_SERVER_DLL ServerDll;
ULONG i;

InsertToList(&CsrRootProcess->ListLink, &CsrProcess->ListLink);

for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
{
ServerDll = CsrLoadedServerDll;

if (ServerDll && ServerDll->NewProcessCallback)
{
(*ServerDll->NewProcessCallback)(CurrentProcess, CsrProcess);
}
}
}

As you see CsrRootProcess contains a linked list of processes.
But this is not very good way to locate this unexported symbol.
There is another exported function from which is easy extract this symbol.
It is CsrLockProcessByClientId.

.text:75B152D3 CsrLockProcessByClientId proc near
.text:75B152D3
.text:75B152D3 arg_0 = dword ptr 8
.text:75B152D3 arg_4 = dword ptr 0Ch
.text:75B152D3
.text:75B152D3 mov edi, edi
.text:75B152D5 push ebp
.text:75B152D6 mov ebp, esp
.text:75B152D8 push ebx
.text:75B152D9 push esi
.text:75B152DA push edi
.text:75B152DB mov edi, offset unk_75B189A0
.text:75B152E0 push edi
.text:75B152E1 call ds:RtlEnterCriticalSection
.text:75B152E7 mov edx,
.text:75B152EA and dword ptr , 0
.text:75B152ED mov esi, CsrRootProcess
.text:75B152F3 add esi, 8

Once you get CsrRootProcess it is possible to list most of existing processes via simple list entry parsing, where each list entry belongs to CSR_PROCESS structure. However I found this detection method is quite unstable. I don't know why, maybe because of not enough List locking, but to check this it will be required inject detectors code inside csrss.exe address space and try to get list of processes. Since this is more than should be for PoC I'm leaving this idea and problem for everybody else, who wants to try this.

Besides this csrss also keeps a list of threads in another unexported symbol called CsrHashThread. It is a array of 256 items, where every item represents LIST_ENTRY. Each list entry item related to _CSR_THREAD structure.

typedef struct _CSR_THREAD { //
union _LARGE_INTEGER CreateTime;
struct _LIST_ENTRY Link;
struct _LIST_ENTRY HashLinks;
struct _CLIENT_ID ClientId;
struct _CSR_PROCESS* Process;
struct _CSR_WAIT_BLOCK* WaitBlock;
void* ThreadHandle;
unsigned long Flags;
unsigned long ReferenceCount;
unsigned long ImpersonateCount;
} CSR_THREAD, *PCSR_THREAD;

This CsrHashThread symbol can be easily obtained from exported function CsrLockThreadByClientId

.text:75B15353 CsrLockThreadByClientId proc near
.text:75B15353
.text:75B15353 a1 = dword ptr 8
.text:75B15353 a2 = dword ptr 0Ch
.text:75B15353
.text:75B15353 mov edi, edi
.text:75B15355 push ebp
.text:75B15356 mov ebp, esp
.text:75B15358 push ebx
.text:75B15359 push esi
.text:75B1535A push edi
.text:75B1535B mov esi, offset unk_75B189A0
.text:75B15360 push esi
.text:75B15361 call ds:RtlEnterCriticalSection
.text:75B15367 mov ebx,
.text:75B1536A mov edi,
.text:75B1536D and dword ptr , 0
.text:75B15370 mov eax, ebx
.text:75B15372 and eax, 0FFh
.text:75B15377 lea edx, CsrHashThread.anonymous_0
.text:75B1537E mov ecx,

With it help I was able to build another list of processes.

So the most valuable here CsrRootProcess parsing. But only CLIENT_ID and some little information is available.

I've spend some time on building a little proof-of-concept detector which will take advantage of CsrRootProcess and CsrHashThread array parsing.

Results with rootktis was really amazing. Even if CSRSS internal structures doesn't gives a lot of information about processes (there is no useful pointers to ETHREAD nor EPROCESS, or maybe I must to clean my glasses?) even the little piece of information was enough to detect EVERYTHING from PoC I've.

However I do believe, that such kind of detection is useless, because of restricted information it provides. So because of this you are reading this now

See screenshots (they are not fake). Please do not bother me with asking a samples to test. If you don't have them now, then it must the reasons why you haven't them.

CsrWalker against RKDEMO v1.2.

http://img129.imageshack.us/my.php?image=cwalker2rkdemo12rq1.gif

CsrWalker against PHIDE_EX

http://img360.imageshack.us/my.php?image=cwalker3phideexpocbh1.gif

CsrWalker against Z0mBiE v1.1

http://img367.imageshack.us/my.php?image=cwalker2z0mbiepocra1.gif

CsrWalker against n0name PoC

http://img212.imageshack.us/my.php?image=cwalker1n0namepocdb0.gif

The most cool part of this -> all this done from User Mode, and all this easy to port on every NT version since 2000 till 2008.

Important Vista addition.

Since Vista there are few csrss.exe presents in memory. This was done for more isolation of the SYSTEM account processes from all others (I suppose each new user account now have its own csrss.exe). So under Vista these method of processes detection was slightly updated. Before parsing csrss.exe it is required to build a list of csrss.exe processes and then parse each of them.

It was simple for XP - get a csrss.exe process by using CsrGetProcessId function. All what it is doing -> reading variable that holds process id of csrss.exe

.text:77F5BAE2 public CsrGetProcessId
.text:77F5BAE2 CsrGetProcessId proc near
.text:77F5BAE2 mov eax, CsrProcessId
.text:77F5BAE7 retn
.text:77F5BAE7 CsrGetProcessId endp

Since Vista we can't anymore relay only on this value. The best way to get list of available csrss.exe processes will be allocate global table of the handles, and try to retrieve their names, because csrss exclusively keeps two handles of type Port/ALPC named ApiPort and SbApiPort. However ALPC object under Vista have some open/query restrictions (for example try to look on it properties with Process Explorer you will be surprised), and this is not a way. There are few possible solutions one of them already implemented in CsrWalker. First - search for all csrss.exe named processes and try to parse them. Not bad solution, but not true hackers way. Second will be try to do experiment and inject your code in one of the SYSTEM account processes - for example one of the svchost.exe, then try from it call the same CsrGetProcessId. I'm left all this to somebody who wants to try and improve/bypass CsrWalker.

Keep in mind - this is a PoC. So it can work, and it can not work. No BSOD's I promise.

CsrWalker v1.0
Partial source code included.
Supported 2000/XP/2003/Vista/2008
http://rapidshare.com/files/144084988/CsrWalker.rar.html
(forced to use rapidshare, because there no place for this)

freecat 发表于 2009-11-16 04:52

学习一下了

mlwy 发表于 2013-8-17 13:50

{:eweqw:}
这个不错啊。。。。。很需要这个。。。

mlwy 发表于 2013-8-17 13:55

{:17_1050:}来看看现在能不花钱的软件太少

6fingers 发表于 2014-9-29 20:06

我喜欢命令行界面的工具
页: [1]
查看完整版本: CsrWalker v1.0