代码 |
.386 .model flat,stdcall locals extrn ExitProcess:PROC .data db 0 .code start: IMAGE_DOS_SIGNATURE equ 5A4Dh ;ZM IMAGE_NT_SIGNATURE equ 4550h ;EP ;nop ;代码开头当然你也可以设置一些别的东西 db '$Packer_Begin$' ;ShellCode技术~~方便提取代码 BeginTempStub: ; these fields are if we load at right base (0x00400000) ; and the section is assumed to start at VA 4000h since ; basic masm project does that ImportDescStart: dd 0 ; Orig First Thunk dd 0 ; no dd 0 ; no ddRvaName dd 1234567h ; dd 4028h (name of dll (rva)) ddFirstThunk dd 896969h ; dd 4035h (first thunk (rva)) ImportDescEnd: db 20 dup(0) ; end of Import Desc szUser32 db "KERNEL32.DLL",0 dwFirstThunk dd 0 ; 403Dh ; rva to beep dwSecondThunk dd 0 dd 0 wImportHint dw 0 szApiGetModule db "LoadLibraryA",0 wImportHinted dw 0 szApiGetProc db "GetProcAddress",0 nop nop nop nop nop nop nop nop nop call GetDelta ;PE Virus最经典的技术..代码自定位 GetDelta: pop ebp ;ebp中保存当前代码段的地址 sub ebp, offset GetDelta ;ebp-GetDalta的数据偏移~ebp中就保存了当前代码段的地址 jmp OverData ;跳转到初始化数据结束的地方 BeginData: szKernel db "KERNEL32.DLL",0 ;k32的字符串信息 dwBeginVirtAddr dd 0 ;虚拟地址开始长度 dwTotalSize dd 0 ; div by 4 ;加密的长度 dwCurrentKey dd 0 ;加密密钥 dwOldOEP dd 0 ;保存老的OEP地址 dwOrigDesc dd 0 dwBaseOfDLL dd 0 ;DLL的基址-主要是保存k32的基址 ddCurrentBase dd 0 ;一个临时变量存储基址用的 szIsDebuggerPresent db "IsDebuggerPresent",0;这个函数都知道吧 _IsDebuggerPresent dd 0 ;函数地址存储位置 szExitProcess db "ExitProcess",0 ;呵呵~ _ExitProcess dd 0 szCreateFileA db "CreateFileA",0 ;^_^~ _CreateFileA dd 0 szSleep db "Sleep",0 ;吼吼 _Sleep dd 0 szNtIce db "/.NTICE",0 szRegIce db "/.SICE",0 ;SoftICE的后门指令判断SoftICE是否存在 db 090h db 0CCh ; these are filled in ddCheckAppDebug dd 0 ddCheckSoftice dd 0 ddDelayTimeWait dd 0 OverData: ; get KERNEL32 base lea ebx, [ebp+szKernel] ;首先将szKernel的数据存入ebx push ebx call dword ptr [ebp+dwFirstThunk] ;dwFirstThunk-中保存的是LoadLibraryA函数地址 mov dword ptr [ebp+dwBaseOfDLL], eax ; get ExitProcess API lea ebx, [ebp+szExitProcess] ;将ExitProcess字符串保存在ebx中 push ebx push eax ;其实此时eax中保存的也是k32的基址 call dword ptr [ebp+dwSecondThunk] ;dwSecondThunk-中保存的是GetProcAddress地址 mov dword ptr [ebp+_ExitProcess], eax ;将获取的地址存入_ExitProcess变量中 ; get CreateFileA API lea ebx, [ebp+szCreateFileA] ;开始获取CreateFileA函数地址 push ebx push dword ptr [ebp+dwBaseOfDLL] ;eax中保存着调用完API后的返回值 call dword ptr [ebp+dwSecondThunk] ;开始调用GetProcAddress获取地址 mov dword ptr [ebp+_CreateFileA], eax ;保存CreateFileA函数地址 ; get Sleep API lea ebx, [ebp+szSleep] ;获取Sleep函数 push ebx push dword ptr [ebp+dwBaseOfDLL] ;压入k32基址 call dword ptr [ebp+dwSecondThunk] ;开始调用GetProcAddress获取地址Sleep地址 mov dword ptr [ebp+_Sleep], eax ;保存地址 cmp dword ptr [ebp+ddCheckAppDebug], 0 ;判断是否要检测调试器 jz NoDebugger ;如果不需要就直接跳转过去 ; check for Application Debugger ;下面是检测是否有调试器 lea ebx, [ebp+szIsDebuggerPresent] ;老问题~压入IsDebuggerPresent字符串 push ebx push dword ptr [ebp+dwBaseOfDLL] call dword ptr [ebp+dwSecondThunk] ;获取IsDebuggerPresent函数地址 mov dword ptr [ebp+_IsDebuggerPresent],eax;保存函数地址 call eax ;此时eax中保存的是IsDebuggerPresent的地址 or eax, eax ;判断是否有调试器 jz NoDebugger ;如果没有就跳转到NoDebugger push 0 call dword ptr [ebp+_ExitProcess] ;如果有就退出进程 NoDebugger: cmp dword ptr [ebp+ddCheckSoftice], 0 ;判断是否要要检测SoftICE jz JmpOverSoftDbg ;不需要就跳转到JmpOverSoftDbg push 0 push 0 push 3 push 0 push 1 push 080000000h or 040000000h lea esi, [ebp+szNtIce] push esi call dword ptr [ebp+_CreateFileA] ;使用SoftICE给自己留的一个内核后门检测 inc eax ;至于如何判断出来的~你去查查看雪论坛精华贴就知道了 jnz SoftDebug ;检测到即跳转到~SoftDebug dec eax push 0 push 0 push 3 push 0 push 1 push 080000000h or 040000000h lea esi, [ebp+szRegIce] push esi call dword ptr [ebp+_CreateFileA] ;开始检测第二个后门指令 inc eax jz JmpOverSoftDbg ;没有检测到就跳转到JmpOverSoftDbg处 dec eax SoftDebug: push 0 call dword ptr [ebp+_ExitProcess] ;如果检测到有SotfICE就退出进程 ;PS:太温柔了吧~应该是ExitWindowEx嘿嘿~~ JmpOverSoftDbg: call GetBaseOfPE ;检测完毕以后就开始获取PE基址 GetBaseOfPE: ;edx中保存着PE Base pop edx LoopToFindMZ: cmp word ptr [edx], IMAGE_DOS_SIGNATURE ;循环查找MZ标记函数 jz LoopToFindNT ;跳转到查找PE头部的地方 dec edx ;edx-1 jmp LoopToFindMZ LoopToFindNT: movzx ecx, word ptr [edx+3ch] add ecx, edx cmp dword ptr [ecx], IMAGE_NT_SIGNATURE ;判断是否是PE标记 jz FinishLooping jmp LoopToFindMZ FinishLooping: mov dword ptr [ebp+ddCurrentBase], edx ;当前地址 mov esi, edx add esi, dword ptr [ebp+dwBeginVirtAddr];程序开始段的虚拟地址 mov edi, dword ptr [ebp+dwCurrentKey] ;将加密密钥保存到edi mov ecx, dword ptr [ebp+dwTotalSize] ;将需要解密的总字节保存到ecx中 LoopXorLoop: xor dword ptr [esi], edi ;开始异或解密 add esi, 4 ;地址+4 loop LoopXorLoop ; time to patch the IAT mov esi, dword ptr [ebp+dwOrigDesc] ; add esi, dword ptr [ebp+ddCurrentBase] ; sub esi, 20 ; BeginPatchIAT: ;解密代码完毕开始人工填写IAT add esi, 20 ;esi+20 cmp dword ptr [esi], 0 ;IAT是否更新完毕~完毕的话就跳转到JmpOutOf jz JmpOutOf ; mov ebx, dword ptr [esi+12] add ebx, dword ptr [ebp+ddCurrentBase] push esi push ebx call dword ptr [ebp+dwFirstThunk] pop esi mov dword ptr [ebp+dwBaseOfDLL], eax BeginPatch: ;开始填写导入表 mov edi, dword ptr [esi+16] add edi, dword ptr [ebp+ddCurrentBase] BeginFoo: ;开始IAT cmp dword ptr [edi], 0 jz BeginPatchIAT mov ebx, dword ptr [edi] add ebx, dword ptr [ebp+ddCurrentBase] add ebx, 2 ; fuck u word!! push edi push ebx push dword ptr [ebp+dwBaseOfDLL] call dword ptr [ebp+dwSecondThunk] pop edi mov dword ptr [edi], eax add edi, 4 jmp BeginFoo JmpOutOf: ;填写导入表完毕 ; use delay load feature mov ebx, dword ptr [ebp+ddDelayTimeWait] push ebx call dword ptr [ebp+_Sleep] ; data unencrypted so jmp back to orig host. mov edx, dword ptr [ebp+ddCurrentBase] add edx, dword ptr [ebp+dwOldOEP] ;计算老的OEP jmp edx ;跳转到OEP int 3h ;这句没用的~放着吓唬别人的 db '$Packer_End$' ;代码结束标记方便提取PackStub代码 FinishTempStub: end start |
<script type="text/javaScript">function doZoom(size){ document.getElementById('zoom').style.fontSize=size+'px'}</script>