📄 easyunpack.asm
字号:
mov g_context.ContextFlags, CONTEXT_FULL
invoke GetThreadContext, ProcInfo2.hThread, addr g_context
mov g_context.iDr0, 0
mov g_context.iDr7, 0
invoke SetThreadContext, ProcInfo2.hThread, addr g_context
invoke _OutputInfo, g_hOutputCtl, CTXT("抓取进程...")
invoke _Dump, ProcInfo2.hProcess, dwImageBase, dwSizeOfImage, lpMem
invoke TerminateProcess, ProcInfo2.hProcess, 0
invoke ContinueDebugEvent, DbgEvent.dwProcessId, DbgEvent.dwThreadId, DBG_CONTINUE
.continue
.endif
.endif
invoke ContinueDebugEvent, DbgEvent.dwProcessId, DbgEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED
.endw
invoke CloseHandle, ProcInfo2.hThread
invoke CloseHandle, ProcInfo2.hProcess
mov ProcInfo2.hProcess, 0
;--------------------------------------------------------------------------------
;修正抓取的映象文件
invoke _OutputInfo, g_hOutputCtl, CTXT("修正映象文件...")
mov eax, dwOEP
sub eax, dwImageBase
invoke _DumpFix, lpMem, eax
;--------------------------------------------------------------------------------
;保存文件
invoke _OutputInfo, g_hOutputCtl, CTXT("保存文件...")
invoke GetPathOnly, addr szFile, addr g_buffer
invoke lstrcat, addr g_buffer, addr g_szDumpedName
invoke RtlZeroMemory, addr g_ofn, sizeof g_ofn
mov g_ofn.lStructSize, sizeof g_ofn
m2m g_ofn.hwndOwner, hWnd
m2m g_ofn.hInstance, g_hInst
lea eax, g_buffer
mov g_ofn.lpstrFile, eax
mov g_ofn.nMaxFile, sizeof g_buffer
mov g_ofn.Flags, OFN_FILEMUSTEXIST + OFN_PATHMUSTEXIST + OFN_OVERWRITEPROMPT
mov g_ofn.lpstrFilter, offset g_szFilter
mov g_ofn.lpstrTitle, offset g_szSaveTitle
invoke GetSaveFileName, addr g_ofn
.if eax
invoke CreateFile, addr g_buffer, GENERIC_READ + GENERIC_WRITE,
FILE_SHARE_READ + FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, 0
.if eax==INVALID_HANDLE_VALUE
invoke _OutputInfo, g_hOutputCtl, CTXT("保存文件出错!!!")
jmp l_exit
.endif
mov hFileDumped, eax
invoke WriteFile, hFileDumped, lpMem, dwSizeOfImage, addr dwSizeReturn, 0
invoke CloseHandle, hFileDumped
mov hFileDumped, 0
.else
invoke _OutputInfo, g_hOutputCtl, CTXT("被取消,文件没有保存!!!")
jmp l_exit
.endif
;--------------------------------------------------------------------------------
;重建输入表
invoke SendMessage, g_hRebIAT, BM_GETCHECK, 0, 0
.if eax
.if g_lpRebuildImport
invoke CreateProcess, NULL, addr szFile, NULL, NULL, NULL, NORMAL_PRIORITY_CLASS, \
NULL, NULL, addr StartupInfo, addr ProcInfo3
invoke WaitForInputIdle, ProcInfo3.hProcess, -1
invoke _OutputInfo, g_hOutputCtl, CTXT("重建输入表...")
mov ecx, dwOEP
sub ecx, dwImageBase
lea eax, g_buffer
push eax
push 5
push 0
push ecx
push ProcInfo3.dwProcessId
call g_lpRebuildImport ;调用 ImpREC.dll 中的 RebuildImport 函数重建输入表
.if eax==0
invoke _OutputInfo, g_hOutputCtl, CTXT("重建输入表失败!!!")
.else
invoke DeleteFile, addr g_buffer
lea esi, g_buffer
invoke lstrlen, esi
add esi, eax
sub esi, 4
invoke lstrcpy, esi, CTXT("_.exe")
.endif
invoke TerminateProcess, ProcInfo3.hProcess, 0
.endif
.endif
invoke SendMessage, g_hOptFile, BM_GETCHECK, 0, 0
.if eax
invoke _OutputInfo, g_hOutputCtl, CTXT("优化文件结构...")
invoke _RebuildPE, addr g_buffer
.endif
invoke _OutputInfo, g_hOutputCtl, CTXT("脱壳完成!!! *^_^*")
;--------------------------------------------------------------------------------
;清除工作
l_exit:
.if pMemory
invoke UnmapViewOfFile, pMemory
.endif
.if hMapFile
invoke CloseHandle, hMapFile
mov hMapFile, 0
.endif
.if hFile
invoke CloseHandle, hFile
.endif
.if ProcInfo.hProcess
invoke CloseHandle, ProcInfo.hThread
invoke CloseHandle, ProcInfo.hProcess
.endif
.if ProcInfo2.hProcess
invoke CloseHandle, ProcInfo2.hThread
invoke CloseHandle, ProcInfo2.hProcess
.endif
.if ProcInfo3.hProcess
invoke CloseHandle, ProcInfo3.hThread
invoke CloseHandle, ProcInfo3.hProcess
.endif
.if lpMem
invoke GlobalFree, lpMem
.endif
.if hFileDumped
invoke CloseHandle, hFileDumped
.endif
ret
_Unpack endp
;优化 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 edx, edi
dec edi
xor eax, eax
mov ecx, eax
dec ecx
std
repz scasb
;在节的末尾的 4 个 00h 字节有可能是指令的一部分
add edi, 6
.if edi>edx
mov edi, edx
.endif
mov ecx, edi
;把有用字节保存起来
mov esi, [ebx].PointerToRawData
add esi, lpDosHeader
sub ecx, esi
mov eax, ecx
mov edi, lpNewSection
cld
rep movsb
;计算下一个节的开始位置
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -