PE Dump 的实现
是PE文件字码查看器,利用它可以查看和总计指定的PE文件的十六进制字节码,帮助我们更好地分析PE结构
列一:是地址。地址的值是第(n*16+1)个字节在文件中的位置
列二:是由空格分隔符分隔的16个字节的十六进制显示
列三:这16个字节对应的ASCII码值。
打开PE文件---》获取文件大小totalSize----》求循环显示16字节数据-----》显示剩余totalSize%16个字节
内存映射文件
是指将硬盘上的文件不做修改地装载到内存中。这样,文件中的字节与字节之间就是顺序排列的了。
在硬盘上,文件被分割成若干簇,这些簇不一定会按照文件内容顺序排列在一起,当我们访问磁盘上的文件时,需要计算机首先将不同位置的内容读取到内存。有了内存映射文件,访问就会变得更轻松和快捷,由于读取磁盘的操作集中到了一起执行,读写效率会提高很多。被一次性读取到内存的文件字节按线性排序,访问相对简单,速度也提升了不少。
PE内存映像:
是指将PE文件按照一定的规则装载到内存中,装入后整个文件头内容不会发生变化,但PE文件的某一部分如节的内容会按照字段中的对齐方式在内存中对齐,从而使得内存中的PE映像与装载前的PE文件不同。
PE文件是由操作系统装载进内存的,其目的是为了运行。为了配合操作系统的运行,方便高度,提高运行效率,PE映像必须按照一定的格式对齐,所以内存中的PE映像和原来硬盘上的文件是不同的,当然与内存映射文件也就不一样了。
1)RC文件
编译:rc -r PEDump.rc#include <resource.h>
#define ICON_MAIN 1000
#define DLG_MAIN 1000
#define IDC_INFO 1001
#define IDM_MAIN 2000
#define IDM_OPEN 2001
#define IDM_EXIT 2002
#define IDM_1 4000
#define IDM_2 4001
#define IDM_3 4002
#define IDM_4 4003
ICO_MAIN ICON "main.ico"
DLG_MAIN DIALOG 50,50,544,399
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "PE Dump by evan"
MENU IDM_MAIN
FONT 9,"宋体"
BEGIN
CONTROL "",IDC_INFO,"RichEdit20A",196|ES_WANTRETURN|WS_CHILD|ES_READONLY|
WS_VISIBLE|WS_BORDER|WS_VSCROLL|WS_TABSTOP,0,0,540,396
END
IDM_MAIN menu discardable
BEGIN
POPUP "File(&F)"
BEGIN
menuitem "Open File(&O)...",IDM_OPEN
menuitem separator
menuitem "Exit(&X)",IDM_EXIT
END
POPUP "Edit(&E)"
BEGIN
menuitem separator
END
POPUP "Format"
BEGIN
menuitem separator
END
POPUP "View"
BEGIN
menuitem "StopDump..",IDM_1
menuitem "Alpha",IDM_2
menuitem separator
menuitem "Size",IDM_3
menuitem "Width",IDM_4
END
POPUP "Help(&H)"
BEGIN
menuitem separator
END
END
2)Asm文件
生成PEDump.obj
ml -c -coff PEDump.asm
链接生成可执行文件
link -subsystem:windows PEDump.obj PEDump.res
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include comdlg32.inc
includelib comdlg32.lib
ICO_MAIN equ 1000
DLG_MAIN equ 1000
IDC_INFO equ 1001
IDM_MAIN equ 2000
IDM_OPEN equ 2001
IDM_EXIT equ 2002
IDM_1 equ 4000
IDM_2 equ 4001
IDM_3 equ 4002
.data
hInstance dd ? ;进程实例句柄
hRichEdit dd ? ;富文本动态链接库句柄
hWinMain dd ? ;窗口句柄
hWinEdit dd ? ;文本控件句柄
totalSize dd ? ;文件大小
lpMemory dd ? ;内存映像文件在内存的起始位置
szFileName dd MAX_PATH dup(?) ;要打开的文件路径及名称名
lpServicesBuffer db 100 dup(0) ;所有内容
bufDisplay db 50 dup(0) ;第三列ASCII码字符显示
szBuffer db 200 dup(0) ;临时缓冲区
lpszFilterFmt4 db '%08x ',0
lpszManyBlanks db ' ',0
lpszBlanks db ' ',0
lpszSplit db '-',0
lpszScanFmt db '%02x',0
lpszHexArr db '0123456789ABCDEF',0
lpszReturn db 0dh,0ah,0
lpszDoubleReturn db 0dh,0ah,0dh,0ah,0
lpszOut1 db '文件大小:%d',0
dwStop dd 0
.const
szDllEdit db 'RichEd20.dll',0
szClassEdit db 'RichEdit20A',0
szFont db '宋体',0
szExtPe db 'PE File',0,'*.exe;*.dll;*.scr;*.fon;*.drv',0
db 'All Files(*.*)',0,'*.*',0,0
szErr db '文件格式错误!',0
szErrFormat db '操作文件时出现错误!',0
.code
;---------------------
;初始化窗口程序
;---------------------
_init proc
local @stCf:CHARFORMAT
invoke GetDlgItem,hWinMain,IDC_INFO
mov hWinEdit,eax
;为窗口设置图标
invoke LoadIcon,hInstance,ICO_MAIN
invoke SendMessage,hWinMain,WM_SETICON,ICON_BIG,eax
;设置编辑控件
invoke SendMessage,hWinEdit,EM_SETTEXTMODE,TM_PLAINTEXT,0
invoke RtlZeroMemory,addr @stCf,sizeof @stCf
mov @stCf.cbSize,sizeof @stCf
mov @stCf.yHeight,14*1440/96
mov @stCf.dwMask,CFM_FACE or CFM_SIZE or CFM_BOLD
invoke lstrcpy,addr @stCf.szFaceName,addr szFont
invoke SendMessage,hWinEdit,EM_SETCHARFORMAT,0,addr @stCf
invoke SendMessage,hWinEdit,EM_EXLIMITTEXT,0,-1
ret
_init endp
;---------------------------
;错误handler
;---------------------------
_Handler proc _lpExceptionRecord,_lpSEH,_lpContext,_lpDispathcerContext
pushad
mov esi,_lpExceptionRecord
mov edi,_lpContext
assume esi:ptr EXCEPTION_RECORD,edi:ptr CONTEXT
mov eax,_lpSEH
push [eax+0ch]
pop [edi].regEbp
push [eax+8]
pop [edi].regEip
push [eax]
pop [edi].regEsp
assume esi:nothing,edi:nothing
popad
mov eax,ExceptionContinueExecution
ret
_Handler endp
;---------------------------
;向文本框中追加文本
;---------------------------
_appendInfo proc _lpsz
local @stCR:CHARRANGE
pushad
invoke GetWindowTextLength,hWinEdit
mov @stCR.cpMin,eax;将插入点移动到最后
mov @stCR.cpMax,eax
invoke SendMessage,hWinEdit,EM_EXSETSEL,0,addr @stCR
invoke SendMessage,hWinEdit,EM_REPLACESEL,FALSE,_lpsz
popad
ret
_appendInfo endp
;---------------------------
;打开PE文件并处理
;---------------------------
_openFile proc
local @stOF:OPENFILENAME
local @hFile,@hMapFile
local @bufTemp1 ;十六进制字节码
local @bufTemp2 ;第一列
local @dwCount ;计数,逢16则重新计
local @dwCount1 ;地址序号
local @dwBlanks ;最后一行空格数
invoke RtlZeroMemory,addr @stOF,sizeof @stOF
mov @stOF.lStructSize,sizeof @stOF
push hWinMain
pop @stOF.hwndOwner
mov @stOF.lpstrFilter,offset szExtPe
mov @stOF.lpstrFile,offset szFileName
mov @stOF.nMaxFile,MAX_PATH
mov @stOF.Flags,OFN_PATHMUSTEXIST or OFN_FILEMUSTEXIST
invoke GetOpenFileName,addr @stOF ;让用户选择打开的文件
.if !eax
jmp @F
.endif
invoke CreateFile,addr szFileName,GENERIC_READ,FILE_SHARE_READ or FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL
.if eax != INVALID_HANDLE_VALUE
mov @hFile,eax
invoke GetFileSize,eax,NULL;获取文件大小
mov totalSize,eax
.if eax
invoke CreateFileMapping,@hFile,NULL,PAGE_READONLY,0,0,NULL
.if eax
mov @hMapFile,eax
invoke MapViewOfFile,eax,FILE_MAP_READ,0,0,0
.if eax
mov lpMemory,eax ;获得文件在内存的映像起始位置
assume fs:nothing
push ebp
push offset _ErrFormat
push offset _Handler
push fs:[0]
mov fs:[0],esp
;开始处理文件
;缓冲区初始化
invoke RtlZeroMemory,addr @bufTemp1,10
invoke RtlZeroMemory,addr @bufTemp2,20
invoke RtlZeroMemory,addr lpServicesBuffer,100
invoke RtlZeroMemory,addr bufDisplay,50
mov @dwCount,1
mov esi,lpMemory
mov edi,offset bufDisplay
;将第一列写入lpServicesBuffer
mov @dwCount1,0
invoke wsprintf,addr @bufTemp2,addr lpszFilterFmt4,@dwCount1
invoke lstrcat,addr lpServicesBuffer,addr @bufTemp2
;求最后一行的空格数(16-长度%16)*3
xor edx,edx
mov eax,totalSize
mov ecx,16
div ecx
mov eax,16
sub eax,edx
xor edx,edx
mov ecx,3
mul ecx
mov @dwBlanks,eax
;invoke wsprintf,addr szBuffer,addr lpszOut1,totalSize
;invoke MessageBox,NULL,addr szBuffer,NULL,MB_OK
.while TRUE
.if totalSize ==0 ; 最后一行
;填充空格
.while TRUE
.break .if @dwBlanks==0
invoke lstrcat,addr lpServicesBuffer,addr lpszBlanks
dec @dwBlanks
.endw
; 第二列与第三列中间的空格
invoke lstrcat,addr lpServicesBuffer,addr lpszManyBlanks
; 第三列内容
invoke lstrcat,addr lpServicesBuffer,addr bufDisplay
; 回车换行符号
invoke lstrcat,addr lpServicesBuffer,addr lpszReturn
.break
.endif
;将al翻译成可以显示的ascii码字符,注意不能破坏al的值
mov al,byte ptr[esi]
.if al>20h && al<7eh
mov ah,al
.else ;如果不是ASCII码值,则显示"."
mov ah,2Eh
.endif
;写入第三列的值
mov byte ptr[edi],ah
;win2k 不支持al字节级别,经常导致程序无帮结束
;因此用以下方法替代
;invoke wsprintf,addr @bufTemp1,addr lpszFilterFmt3,al
mov bl,al
xor edx,edx
xor eax,eax
mov al,bl
mov cx,16
div cx ;结果高位在al中,余数在dl中
;组合字节的十六进制字符串到@bufTemp1中,类似于:"7F \0"
push edi
xor bx,bx
mov bl,al
movzx edi,bx
mov bl,byte ptr lpszHexArr[edi]
mov byte ptr @bufTemp1[0],bl
xor bx,bx
mov bl,dl
movzx edi,bx
mov bl,byte ptr lpszHexArr[edi]
mov byte ptr @bufTemp1[1],bl
mov bl,20h
mov byte ptr @bufTemp1[2],bl
mov bl,0
mov byte ptr @bufTemp1[3],bl
pop edi
; 将第二列写入lpServicesBuffer
invoke lstrcat,addr lpServicesBuffer,addr @bufTemp1
.if @dwCount==16 ;已到16个字节
;第二列与第三列中间的空格
invoke lstrcat,addr lpServicesBuffer,addr lpszManyBlanks
;显示第三列字符
invoke lstrcat,addr lpServicesBuffer,addr bufDisplay
;回车换行
invoke lstrcat,addr lpServicesBuffer,addr lpszReturn
;写入内容
invoke _appendInfo,addr lpServicesBuffer
invoke RtlZeroMemory,addr lpServicesBuffer,100
.break .if dwStop==1
;显示下一行的地址
inc @dwCount1
invoke wsprintf,addr @bufTemp2,addr lpszFilterFmt4,@dwCount1
invoke lstrcat,addr lpServicesBuffer,addr @bufTemp2
dec @dwCount1
mov @dwCount,0
invoke RtlZeroMemory,addr bufDisplay,50
mov edi,offset bufDisplay
;为了能和后面的inc edi配合使edi正确定位到bufDisplay片
dec edi
.endif
dec totalSize
inc @dwCount
inc esi
inc edi
inc @dwCount1
.endw
;添加最后一行
invoke _appendInfo,addr lpServicesBuffer
;处理文件 结束
jmp _ErrorExit
_ErrFormat:
invoke MessageBox,hWinMain,offset szErrFormat,NULL,MB_OK
_ErrorExit:
pop fs:[0]
add esp,0ch
invoke UnmapViewOfFile,lpMemory
.endif
invoke CloseHandle,@hMapFile
.endif
invoke CloseHandle,@hFile
.endif
.endif
@@:
ret
_openFile endp
;---------------------
;窗口回调函数
;---------------------
_ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam
local @szClient
mov eax,wMsg
.if eax==WM_CLOSE
invoke EndDialog,hWnd,NULL
.elseif eax==WM_INITDIALOG ;初始化
push hWnd
pop hWinMain
call _init
.elseif eax==WM_COMMAND ;菜单
mov eax,wParam
.if eax==IDM_OPEN
mov dwStop,0
invoke CreateThread,NULL,0,addr _openFile,addr @szClient,0,NULL
; invoke _openFile
.elseif eax==IDM_1
mov dwStop,1
.elseif eax==IDM_2
.elseif eax==IDM_3
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
_ProcDlgMain endp
start:
invoke LoadLibrary,offset szDllEdit
mov hRichEdit,eax
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL
invoke FreeLibrary,hRichEdit
invoke ExitProcess,NULL
end start