首页
社区
课程
招聘
[原创]CsrssWalker学习笔记(附源代码)
发表于: 2009-5-24 09:35 16129

[原创]CsrssWalker学习笔记(附源代码)

2009-5-24 09:35
16129
学习了一下古老的CsrssWalker,写点笔记~~
在Csrss.exe中,保存着所有Win32子系统进程的进程信息,这些信息以链表的形式保存。
正常情况下,每一个新创建的进程都会通知Csrss.exe,Csrss.exe接收这些信息然后保存起来,所以遍历这个链表就可以得到所有Win32子系统进程的信息。首先就是找链表头了,链表头为CsrssRootProcess,在CSRSRV.DLL导出的函数中有对CsrssRootProcess的操作,因此可以通过CSRSRV.DLL的导出函数找到CsrssRootProcess。
比较方便一点的,是从CsrLockProcessByClientId中找到CsrssRootProcess.
mov     edx, [ebp+arg_4]
and     dword ptr [edx], 0
mov     esi, dword_75AA891C ; Base=75AA0000
add     esi, 8
mov     [ebp+arg_4], 0C0000001h

75AA891C处就是CsrssRootProcess的指针了,这个指针的值可以通过特征匹配找到,具体请参考代码。读取其内容,得到CsrssRootProcess=0x001629C0(这个只是我的系统上的)
从这里读就可以得到CsrssRootProcess的内容了,然后遍历Link即可
涉及到的一些数据结构在CsrssStruct.h中。
进程信息的结构如下:
typedef struct _CSR_PROCESS
{
    CLIENT_ID ClientId; //这里可以得到进程PID和主线程TID
    LIST_ENTRY ListLink; //就是这个链表
  LIST_ENTRY ThreadList;
    struct _CSR_PROCESS *Parent;
    PCSR_NT_SESSION NtSession;
    ULONG ExpectedVersion;
    HANDLE ClientPort;
    ULONG_PTR ClientViewBase;
    ULONG_PTR ClientViewBounds;
    HANDLE ProcessHandle;
    ULONG SequenceNumber;
    ULONG Flags;
    ULONG DebugFlags;
    CLIENT_ID DebugCid;
    ULONG ReferenceCount;
    ULONG ProcessGroupId;
    ULONG ProcessGroupSequence;
    ULONG fVDM;
    ULONG ThreadCount;
    ULONG PriorityClass;
    ULONG Reserved;
    ULONG ShutdownLevel;
    ULONG ShutdownFlags;
    PVOID ServerData[];
} CSR_PROCESS, *PCSR_PROCESS;


但是因为这不是在当前进程中,所以每次都要先读取出来,遍历时与普通的遍历双链表操作稍有差别,但是也很容易实现。
具体的步骤为:
1.找到Csrss.exe进程(这个很简单,Vista要注意有不止一个Csrss进程)
2.遍历Csrss.exe中的模块列表,找到CSRSRV.DLL的基址。
3.在CSRSRV.DLL中根据导出函数CsrLockProcessByClientId找CsrssRootProcess指针
4.构建当前进程名称列表,为输出作准备
5.根据CsrssRootProcess指针的地址,从Csrss.exe进程中读取和遍历每个进程的信息并输出

在Csrss.exe中同样还保存着所有Win32线程的信息,由于线程数目较多,Csrss中采用Hash表的形式来保存线程信息。同样从CSRSRV.DLL的导出函数CsrLockThreadByClientId可以得到CsrThreadHashTable的地址,这是一个Hash表,定义为:
LIST_ENTRY CsrThreadHashTable[256];

Hash算法为:

#define CsrHashThread(t) \
    (HandleToUlong(t)&(256 - 1))
   
很简单的算法,查找CsrThreadHashTable的方法及遍历方法与前面遍CsrssRootProcessLink基本相同,不多说。这部分我并未在代码中实现,有兴趣的自己写一写吧,很简单。
对于Vista等较新的系统,由于Session隔离,系统中会有不止一个Csrss进程,这样就需要对这几个Csrss进程都进行处理。就说这么多了,具体地看代码吧~~

[课程]Android-CTF解题方法汇总!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (15)
雪    币: 93920
活跃值: (200199)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
2
Support.
2009-5-24 09:40
0
雪    币: 359
活跃值: (430)
能力值: ( LV9,RANK:150 )
在线值:
发帖
回帖
粉丝
3
强大,支持

下载收藏(俺最喜欢干的事…………)
2009-5-24 10:11
0
雪    币: 564
活跃值: (42)
能力值: ( LV12,RANK:230 )
在线值:
发帖
回帖
粉丝
4
俺是来支持下........
2009-5-24 11:17
0
雪    币: 211
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
下载收藏,哈哈
2009-5-24 11:17
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
支持一下啊~
2009-5-24 17:20
0
雪    币: 129
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
up 非常好,值得学习,下了看看,顺便在此谢谢achillis给我很多帮助!
2009-5-24 18:43
0
雪    币: 234
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
恩。。有代码就是最好的了....
2009-5-24 19:49
0
雪    币: 410
活跃值: (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
thanks man
2009-5-24 20:13
0
雪    币: 471
活跃值: (3708)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
10
good job,可以学习一下代码了
2009-5-25 15:19
0
雪    币: 248
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
谢谢,, 下载来  慢慢折腾
2009-7-12 01:13
0
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
教主太强大了
2009-10-1 16:03
0
雪    币: 203
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
我利用你的代码编译了一下,在xp下可以列出进程,但是在win2000下不可以,问题在于特征码不通用,我经过测试发现通过函数CsrAddStaticServerThread()搜索有着更好的通用性,因为CsrAddStaticServerThread在最后要将线程加入到CsrssRootProcess链表内是,所在以可以在CsrAddStaticServerThread结尾处找到

下面我们先看看win2k winxp win2k3里的CsrLockProcessByClientId()函数要找的区域:

win2000里CsrLockProcessByClientId():

5FF852F6  |.  68 6089F85F   PUSH CSRSRV.5FF88960
5FF852FB  |.  FF15 2011F85F CALL DWORD PTR DS:[<&ntdll.RtlEnterCriti>;  ntdll.RtlEnterCriticalSection
5FF85301  |.  8B5C24 14     MOV EBX,DWORD PTR SS:[ESP+14]
5FF85305  |.  85DB          TEST EBX,EBX
5FF85307  |.  74 03         JE SHORT CSRSRV.5FF8530C
5FF85309  |.  8323 00       AND DWORD PTR DS:[EBX],0
5FF8530C  |>  A1 5489F85F   MOV EAX,DWORD PTR DS:[5FF88954] <----这里就是
5FF85311  |.  8B5424 10     MOV EDX,DWORD PTR SS:[ESP+10]
5FF85315  |.  83C0 08       ADD EAX,8
5FF85318  |.  BF 010000C0   MOV EDI,C0000001
5FF8531D  |.  8BC8          MOV ECX,EAX

winxp里CsrLockProcessByClientId()

75B452E0  |.  57            PUSH EDI
75B452E1  |.  FF15 1811B475 CALL DWORD PTR DS:[<&ntdll.RtlEnterCriti>;  ntdll.RtlEnterCriticalSection
75B452E7  |.  8B55 0C       MOV EDX,DWORD PTR SS:[EBP+C]
75B452EA  |.  8322 00       AND DWORD PTR DS:[EDX],0
75B452ED  |.  8B35 1C89B475 MOV ESI,DWORD PTR DS:[75B4891C]  <----这里是
75B452F3  |.  83C6 08       ADD ESI,8
75B452F6  |.  C745 0C 01000>MOV DWORD PTR SS:[EBP+C],C0000001

win2003里CsrLockProcessByClientId()

759550E1  |.  FF15 10119575 CALL DWORD PTR DS:[<&ntdll.RtlEnterCriti>;  ntdll.RtlEnterCriticalSection
759550E7  |.  8B55 0C       MOV EDX,DWORD PTR SS:[EBP+C]
759550EA  |.  8322 00       AND DWORD PTR DS:[EDX],0
759550ED  |.  8B35 BC889575 MOV ESI,DWORD PTR DS:[759588BC] <----这里
759550F3  |.  83C6 08       ADD ESI,8
759550F6  |.  C745 0C 01000>MOV DWORD PTR SS:[EBP+C],C0000001

再来看看CsrAddStaticServerThread()在三大系统里的结尾部分

win2000里CsrAddStaticServerThread()结尾部分:

5FF855E4  |.  890A          MOV DWORD PTR DS:[EDX],ECX
5FF855E6  |.  8948 04       MOV DWORD PTR DS:[EAX+4],ECX
5FF855E9  |.  A1 5489F85F   MOV EAX,DWORD PTR DS:[5FF88954]<----这里就是
5FF855EE  |.  FF40 58       INC DWORD PTR DS:[EAX+58]
5FF855F1  |>  57            PUSH EDI
5FF855F2  |.  FF15 1C11F85F CALL DWORD PTR DS:[<&ntdll.RtlLeaveCriti>;  ntdll.RtlLeaveCriticalSection
5FF855F8  |.  8BC6          MOV EAX,ESI
5FF855FA  |.  5F            POP EDI
5FF855FB  |.  5E            POP ESI
5FF855FC  \.  C2 0C00       RETN 0C

winxp里CsrAddStaticServerThread()结尾部分:

75B45412  |.  8908          MOV DWORD PTR DS:[EAX],ECX
75B45414  |.  8950 04       MOV DWORD PTR DS:[EAX+4],EDX
75B45417  |.  8902          MOV DWORD PTR DS:[EDX],EAX
75B45419  |.  8941 04       MOV DWORD PTR DS:[ECX+4],EAX
75B4541C  |.  A1 1C89B475   MOV EAX,DWORD PTR DS:[75B4891C] <---这里就是
75B45421  |.  FF40 58       INC DWORD PTR DS:[EAX+58]
75B45424  |>  57            PUSH EDI
75B45425  |.  FF15 1011B475 CALL DWORD PTR DS:[<&ntdll.RtlLeaveCriti>;  ntdll.RtlLeaveCriticalSection
75B4542B  |.  5F            POP EDI
75B4542C  |.  8BC6          MOV EAX,ESI
75B4542E  |.  5E            POP ESI
75B4542F  |.  5D            POP EBP
75B45430  \.  C2 0C00       RETN 0C

win2003里CsrAddStaticServerThread结尾部分:
759551F2  |.  8902          MOV DWORD PTR DS:[EDX],EAX
759551F4  |.  8941 04       MOV DWORD PTR DS:[ECX+4],EAX
759551F7  |.  A1 BC889575   MOV EAX,DWORD PTR DS:[759588BC] <----这里就是
759551FC  |.  FF40 54       INC DWORD PTR DS:[EAX+54]
759551FF  |>  57            PUSH EDI
75955200  |.  FF15 08119575 CALL DWORD PTR DS:[<&ntdll.RtlLeaveCriti>;  ntdll.RtlLeaveCriticalSection
75955206  |.  5F            POP EDI
75955207  |.  8BC6          MOV EAX,ESI
75955209  |.  5E            POP ESI
7595520A  \.  C2 0C00       RETN 0C

通过上面可以看到win2000里不是MOV ESI,DWORD PTR DS:[xxxxxxx],而是MOV EAX,DWORD PTR DS:[xxxxxxxx]  而且后面不再是add Exx,8 而是MOV EDX,DWORD PTR SS:[ESP+10],所以特征码通用性不是很,

比较了三个系统CsrAddStaticServerThread()结尾部分,发现可以更好的实现通用性,

下面是我修改的GetCsrssRootProcessPointerOffset()函数部分:

ULONG GetCsrssRootProcessPointerOffset()
{
        char szDllName[MAX_PATH];
        unsigned char *pfnCsrLockProcessByClientId;
        HMODULE hCsrsrv=NULL;
        ULONG Offset;
        unsigned char *p;
        GetSystemDirectory(szDllName,MAX_PATH);
        strcat(szDllName,"\\csrsrv.dll");
        hCsrsrv=LoadLibraryEx(szDllName,NULL,DONT_RESOLVE_DLL_REFERENCES);
        if (hCsrsrv)
        {
                printf("Csrsrv ModuleBase=0x%08X\n",hCsrsrv);
                pfnCsrLockProcessByClientId=(unsigned char*)GetProcAddress(hCsrsrv,"CsrAddStaticServerThread");
                //printf("CsrLockProcessByClientId=0x%08X\n",pfnCsrLockProcessByClientId);
                /*
                75AA52ED    8B35 1C89AA75          mov esi,dword ptr ds:[75AA891C]
                75AA52F3    83C6 08                add esi,8
                */
                //下面根据特征来查找CsrssRootProcess指针的地址,即上面的75AA891C
                //一个小技巧:确定特征码匹配的特征码时,不要包含寄存器信息(如上面的esi),只含操作码信息即可,可以增强通用性
                //我在XP的CSRSRV.DLL中找的特征码,同样适用于Vista的CSSRV.DLL
                //李天东注:后面加上79是为了更接近CsrAddStaticServerThread()的结尾部分,即特征码部分.
                p=(unsigned char *)pfnCsrLockProcessByClientId+79;
                for (int i=0;i<0x50;i++)
                {
                        printf("%#x:0x%02x\r\n",&p[i],p[i]);
                        if (p[i]==0xA1 && p[i+5]==0xFF && p[i+6]==0x40)
                        {
                                Offset=*(ULONG*)&p[i+1];
                                Offset=Offset-(ULONG)hCsrsrv;
                                printf("dongdong:Offset=0x%08X\n",Offset);
                                break;
                        }
                }
                FreeLibrary(hCsrsrv);
                return Offset;
        }
        else
        {
                printf("[-]Load csrsrv.dll Failed\n");
                return 0;
        }
}

由于win vista我没有装,所以windows vista没有测试,请大家忙测试看看,是否通用
2010-2-24 17:12
0
雪    币: 5033
活跃值: (3434)
能力值: ( LV13,RANK:283 )
在线值:
发帖
回帖
粉丝
15
唉,枚举进程方法好多啊
2010-2-24 22:20
0
雪    币: 20
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
貌似还能通过CSR_PROCESS结构来判断调试器,收藏,回去看看
2010-5-9 15:05
0
雪    币: 97
活跃值: (43)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
17
先收藏了,比较喜欢看这种笔记的东西,能获得很多帮助。谢谢楼主
2010-5-9 16:24
0
游客
登录 | 注册 方可回帖
返回
//