📄 rebuilder.asm
字号:
;优化 PE 文件,分两方面优化文件
;第一: 去掉 Dos Stub 来压缩文件头的大小,第二: 去掉每个节中的无用字节来压缩节的大小
_RebuildPE proc lpszFile:DWORD
LOCAL hFile, hMapFile, pMemory
LOCAL lpMem, dwFileSize, dwReturn
LOCAL lpDosHeader
LOCAL lpNewSection
pushad
;--------------------------------------------------------------------------------
;打开文件,创建内存映射文件
invoke CreateFile, lpszFile, GENERIC_READ + GENERIC_WRITE, FILE_SHARE_READ,
0, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, 0
.if eax==INVALID_HANDLE_VALUE
;invoke _OutputInfo, g_hOutputCtl, CTXT("打开文件出错!!!")
popad
ret
.endif
mov hFile, eax
invoke CreateFileMapping, hFile, 0, PAGE_READWRITE, 0, 0, 0
.if !eax
;invoke _OutputInfo, g_hOutputCtl, CTXT("创建内存映射文件出错!!!")
invoke CloseHandle, hFile
popad
ret
.endif
mov hMapFile, eax
invoke MapViewOfFile, hMapFile, FILE_MAP_WRITE, 0, 0, 0
.if !eax
;invoke _OutputInfo, g_hOutputCtl, CTXT("把文件映射进内存时出错!!!")
invoke CloseHandle, hMapFile
invoke CloseHandle, hFile
popad
ret
.endif
mov pMemory, eax
invoke GetFileSize, hFile, 0
invoke GlobalAlloc, GMEM_FIXED + GMEM_ZEROINIT, eax
.if !eax
;invoke _OutputInfo, g_hOutputCtl, CTXT("内存分配出错,文件优化不成功!!!")
invoke UnmapViewOfFile, pMemory
invoke CloseHandle, hMapFile
invoke CloseHandle, hFile
popad
ret
.endif
mov lpMem, eax
;--------------------------------------------------------------------------------
;检查 PE 文件是否合法
mov eax, pMemory
mov lpDosHeader, eax
assume eax : ptr IMAGE_DOS_HEADER
.if [eax].e_magic == IMAGE_DOS_SIGNATURE
mov ebx, eax
add ebx, [eax].e_lfanew
assume ebx : ptr IMAGE_NT_HEADERS
.if [ebx].Signature == IMAGE_NT_SIGNATURE
jmp @F
.endif
.endif
;invoke _OutputInfo, g_hOutputCtl, CTXT("不是合法的 PE 文件!!!")
invoke UnmapViewOfFile, pMemory
invoke CloseHandle, hMapFile
invoke CloseHandle, hFile
invoke GlobalFree, lpMem
popad
ret
@@:
;--------------------------------------------------------------------------------
;计算第一个节调整后的位置
movzx eax, [ebx].FileHeader.NumberOfSections
inc eax
imul eax, sizeof IMAGE_SECTION_HEADER
movzx ecx, [ebx].FileHeader.SizeOfOptionalHeader
add ecx, 18h
add eax, ecx
add eax, sizeof IMAGE_DOS_HEADER ;eax = DosHeader+NtHeader+SectionHeader 的大小
cdq
mov ecx, 200h
div ecx
test edx, edx
jz @F
inc eax
@@:
mul ecx ;依 200h 对齐
add eax, lpMem
mov lpNewSection, eax
;--------------------------------------------------------------------------------
;计算节的位置和大小,构造节
movzx edx, [ebx].FileHeader.NumberOfSections
movzx ecx, [ebx].FileHeader.SizeOfOptionalHeader
lea ebx, [ebx+ecx+18h]
assume ebx : ptr IMAGE_SECTION_HEADER
;edx = 节的个数,ebx 指向节表。然后循环每个节,从节的末尾开始
;查找节中的无用字节(00h 就是无用字节)
.while edx
push edx
;从节的末尾开始倒序查找 00h 字节
mov edi, [ebx].PointerToRawData
add edi, [ebx].SizeOfRawData
add edi, lpDosHeader
mov eax, edi
sub eax, [ebx].SizeOfRawData
push eax ;***
mov edx, edi
dec edi
xor eax, eax
mov ecx, eax
dec ecx
std
repz scasb
pop eax ;***
;在节的末尾的 4 个 00h 字节有可能是指令的一部分
add edi, 6
.if SDWORD ptr edi<eax
mov edi, eax
.endif
.if edi>edx
mov edi, edx
.endif
mov ecx, edi ;calc err?
;把有用字节保存起来
mov esi, [ebx].PointerToRawData
add esi, lpDosHeader
sub ecx, esi
mov eax, ecx
mov edi, lpNewSection
cld
rep movsb;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BUG?????????????/
;计算下一个节的开始位置
mov ecx, lpNewSection
sub ecx, lpMem
mov [ebx].PointerToRawData, ecx
mov [ebx].SizeOfRawData, eax
cdq
mov ecx, 200h
div ecx
test edx, edx
jz @F
inc eax
@@:
mul ecx
add lpNewSection, eax
add ebx, sizeof IMAGE_SECTION_HEADER
pop edx
dec edx
.endw
assume ebx : nothing
;计算优化后的文件大小
mov eax, lpNewSection
sub eax, lpMem
mov dwFileSize, eax
;--------------------------------------------------------------------------------
;去掉 Dos Stub,构造 Nt Header 和 Section Header
mov ebx, lpDosHeader
assume ebx : ptr IMAGE_DOS_HEADER
add ebx, [ebx].e_lfanew
assume ebx : ptr IMAGE_NT_HEADERS
mov [ebx].OptionalHeader.FileAlignment, 200h ;修正文件对齐
movzx ecx, [ebx].FileHeader.NumberOfSections
inc ecx
imul ecx, sizeof IMAGE_SECTION_HEADER
movzx edx, [ebx].FileHeader.SizeOfOptionalHeader
add edx, 18h
add ecx, edx
mov esi, ebx
mov edi, lpMem
add edi, sizeof IMAGE_DOS_HEADER
rep movsb
;--------------------------------------------------------------------------------
;构造 Dos Header
mov esi, lpDosHeader
mov edi, lpMem
mov ecx, sizeof IMAGE_DOS_HEADER
assume esi : ptr IMAGE_DOS_HEADER
mov [esi].e_lfanew, ecx ;修正 Dos Header
rep movsb
invoke UnmapViewOfFile, pMemory
invoke CloseHandle, hMapFile
invoke CloseHandle, hFile
;--------------------------------------------------------------------------------
;打开文件把优化后的数据写入
invoke CreateFile, lpszFile, GENERIC_READ + GENERIC_WRITE, FILE_SHARE_READ,
0, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, 0
.if eax==INVALID_HANDLE_VALUE
;invoke _OutputInfo, g_hOutputCtl, CTXT("打开文件出错!!!")
ret
.endif
mov hFile, eax
invoke WriteFile, hFile, lpMem, dwFileSize, addr dwReturn, 0
invoke CloseHandle, hFile
invoke GlobalFree, lpMem
popad
ret
_RebuildPE endp
assume esi:nothing
assume eax:nothing
assume ebx:nothing
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -