; offs.asm - Win32Asm example program for the PeLib library. ; ; offs.asm converts between RVA and file offsets using the functionality ; of the PeLib library. ; ; Copyright (c) 2004 Sebastian Porst (webmaster@the-interweb.com) ; All rights reserved. ; ; This software is licensed under the zlib/libpng License. ; For more details see http://www.opensource.org/licenses/zlib-license.php ; or the license information file (license.htm) in the root directory ; of PeLib. .386 .model flat, stdcall option casemap : none include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\comdlg32.inc include \masm32\include\user32.inc includelib \masm32\lib\comdlg32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\user32.lib MainWndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD MAXSIZE equ 511 FNAME_FIELD equ 3000 IMGBASE_FIELD equ 3001 RVA_FIELD equ 3002 OFFS_FIELD equ 3003 SNAME_FIELD equ 3004 .data PeLib db 'PeLib',0 PeLib_dll db 'PeLib.dll',0 PeLib_dll_offset dd 0 PeLib_openFile db 'PeLib_openFile',0 PeLib_openFile_offset dd 0 PeLib_closeFile db 'PeLib_closeFile',0 PeLib_closeFile_offset dd 0 PeFile_peHeader db 'PeFile_peHeader',0 PeFile_peHeader_offset dd 0 PeFile_readMzHeader db 'PeFile_readMzHeader',0 PeFile_readMzHeader_offset dd 0 PeFile_readPeHeader db 'PeFile_readPeHeader',0 PeFile_readPeHeader_offset dd 0 PeHeader_offsetToRva db 'PeHeader_offsetToRva',0 PeHeader_offsetToRva_offset dd 0 PeHeader_rvaToOffset db 'PeHeader_rvaToOffset',0 PeHeader_rvaToOffset_offset dd 0 PeHeader_getImageBase db 'PeHeader_getImageBase',0 PeHeader_getImageBase_offset dd 0 PeHeader_getSectionWithOffset db 'PeHeader_getSectionWithOffset',0 PeHeader_getSectionWithOffset_offset dd 0 PeHeader_getSectionName db 'PeHeader_getSectionName',0 PeHeader_getSectionName_offset dd 0 DllFailureMessage db 'Loading PeLib.dll failed',0 hInstance dd 0 dialogfilter db "PE Files",0,"*.exe; *.dll",0,0 hexconv db "%08X",0 error db 'Error',0 PeFile dd 0 PeHeader dd 0 empty db 0 ofn OPENFILENAME <> .data? FilenameBuffer db 512 dup(?) buffer db 512 dup(?) .code start: ; Load PeLib.dll and get the addresses of all necessary functions. call InitializeDll test eax, eax je @Failure invoke GetModuleHandle,0 mov hInstance, eax ; Load and display the main window. invoke DialogBoxParam, eax, 100, 0, ADDR MainWndProc, 0 ret @Failure: ; Couldn't load the PeLib.dll library. invoke MessageBoxA, 0, ADDR DllFailureMessage, ADDR PeLib, 0 ret ; htodw from Iczelion htodw proc uses ebx ecx edi edx esi String:DWORD ;------------------------------------ ; Convert hex string into dword value ; Return value in eax ;------------------------------------ LOCAL Result:DWORD mov Result, 0 xor ecx, ecx mov edi, String invoke lstrlen, String mov ebx, 16 mov esi, eax .while esi != 0 mov al, [edi] .if al >= "0" && al <= "9" sub al, "0" .elseif al >= "a" && al <= "f" sub al, "a" add al, 10 .else sub al, "A" add al, 10 .endif movzx eax, al mov ecx, esi dec ecx .while ecx > 0 mul ebx dec ecx .endw add Result, eax inc edi dec esi .endw mov eax, Result ret htodw endp ; This procedure is called after a file was selected from the OpenFile dialog. LoadFile proc hWin:DWORD cmp PeFile, 0 je @NoFile ; If a file is currently open it needs to be closed first. ; Actually it's only recommended to close it, the other option is a memory leak though. push PeFile call PeLib_closeFile_offset add esp, 4 @NoFile: ; Open the new file push OFFSET FilenameBuffer call PeLib_openFile_offset add esp, 4 mov PeFile, eax ; Read the file's MZ header. push PeFile call PeFile_readMzHeader_offset add esp, 4 ; It would be great (and recommended) to check if the MZ header is valid by calling the ; appropriate PeLib functions here. It's not critical though, that's why I decided against it. ; Read the file's PE header. push PeFile call PeFile_readPeHeader_offset add esp, 4 ; It would be great (and recommended) to check if the PE header is valid by calling the ; appropriate PeLib functions here. It's not critical though, that's why I decided against it. ; Get a pointer to the file's PE header. push PeFile call PeFile_peHeader_offset mov PeHeader, eax add esp, 4 ; Write the filename to the appropriate text field. invoke SetDlgItemTextA, hWin, FNAME_FIELD, ADDR FilenameBuffer ; Get the file's ImageBase. push PeHeader call PeHeader_getImageBase_offset add esp, 4 ; Write the image base to the appropriate text field. invoke wsprintfA, ADDR buffer, ADDR hexconv, eax invoke SetDlgItemTextA, hWin, IMGBASE_FIELD, ADDR buffer ret LoadFile endp ConvertOffset proc offs:DWORD, conversion:DWORD push offs push PeHeader .IF conversion == 0 ; RVA => File offset call PeHeader_rvaToOffset_offset .ELSE ; File offset => RVA call PeHeader_offsetToRva_offset .ENDIF add esp, 8 ret ConvertOffset endp GetOffset proc hWin:DWORD, hwnd:DWORD, buff:DWORD invoke GetDlgItemTextA, hWin, hwnd, buff, 9 invoke htodw, buff ret GetOffset endp GetSection proc offs:DWORD, buff:DWORD push offs push PeHeader call PeHeader_getSectionWithOffset_offset add esp, 8 ; A return value of 0xFFFF means it's outside of any section. That means it's an offset in the header ; because if it's not an offset from any section or the header the above call to rvaToOffset would ; have returned -1. Note again: The return value of -1 from getSectionWithOffset once again only ; indicates an error with a certainty of 99.9999999% (or something). A return value of 0xFFFF (= -1) ; could also mean the offset is in the 65535th section of the file. It is however rare enough to find ; a file with more than 12-15 sections, I am not even sure if a file with 65535 sections is even ; accepted by the PE loader. cmp ax, -1 je @OffsetToRvaNoSection ; Get the name of the section. push 9 ; Buffer size. The buffer is actually larger than that but section names are max 8 bytes long. push buff push eax push PeHeader call PeHeader_getSectionName_offset add esp, 16 ret @OffsetToRvaNoSection: mov eax, -1 ret GetSection endp ; Message loop of the main window. MainWndProc proc uses ebx hWin:DWORD, uMsg: DWORD, wParam: DWORD, lParam: DWORD ; Terminate the process if the window is being closed. .IF uMsg == WM_CLOSE invoke ExitProcess, 0 mov eax, 1 ret ; Handle the user input. .ELSEIF uMsg == WM_COMMAND mov eax, wParam .IF lParam == 0 ; Menu input call ChooseFile .IF eax != 0 invoke LoadFile, hWin .ENDIF .ELSEIF (ax == RVA_FIELD) shr eax, 16 .IF ax == EN_CHANGE && PeHeader != 0 ; RVA was changed. invoke GetFocus push eax invoke GetDlgItem, hWin, RVA_FIELD pop ebx .IF eax == ebx invoke GetOffset, hWin, RVA_FIELD, ADDR buffer invoke ConvertOffset, eax, 0 .IF eax != -1 push eax invoke wsprintfA, ADDR buffer, ADDR hexconv, eax invoke SetDlgItemTextA, hWin, OFFS_FIELD, ADDR buffer pop eax invoke GetSection, eax, ADDR buffer .IF eax != -1 invoke SetDlgItemTextA, hWin, SNAME_FIELD, ADDR buffer .ELSEIF invoke SetDlgItemTextA, hWin, SNAME_FIELD, ADDR empty .ENDIF .ENDIF .ENDIF .ENDIF .ELSEIF (ax == OFFS_FIELD) shr eax, 16 .IF ax == EN_CHANGE && PeHeader != 0 ; Offset was changed. invoke GetFocus push eax invoke GetDlgItem, hWin, OFFS_FIELD pop ebx .IF eax == ebx invoke GetOffset, hWin, OFFS_FIELD, ADDR buffer push eax invoke ConvertOffset, eax, 1 .IF eax != -1 invoke wsprintfA, ADDR buffer, ADDR hexconv, eax invoke SetDlgItemTextA, hWin, RVA_FIELD, ADDR buffer pop eax invoke GetSection, eax, ADDR buffer .IF eax != -1 invoke SetDlgItemTextA, hWin, SNAME_FIELD, ADDR buffer .ELSEIF invoke SetDlgItemTextA, hWin, SNAME_FIELD, ADDR empty .ENDIF .ELSEIF pop eax .ENDIF .ENDIF .ENDIF .ENDIF mov eax, 1 .ENDIF xor eax, eax ret MainWndProc endp ; Let the user choose a file. ChooseFile proc mov ofn.lStructSize,SIZEOF ofn push hInstance pop ofn.hInstance mov ofn.lpstrFilter, OFFSET dialogfilter mov ofn.lpstrFile, OFFSET FilenameBuffer mov ofn.nMaxFile,MAXSIZE mov ofn.Flags, OFN_FILEMUSTEXIST or \ OFN_PATHMUSTEXIST or OFN_LONGNAMES or\ OFN_EXPLORER or OFN_HIDEREADONLY invoke GetOpenFileName, ADDR ofn ret ChooseFile endp ; Initialize the PeLib DLL and all necessary functions. Returns 0 if an error occured, otherwise 1. InitializeDll proc invoke LoadLibrary, ADDR PeLib_dll test eax, eax je @DllFailure mov PeLib_dll_offset, eax invoke GetProcAddress, PeLib_dll_offset, ADDR PeLib_openFile test eax, eax je @DllFailure mov PeLib_openFile_offset, eax invoke GetProcAddress, PeLib_dll_offset, ADDR PeLib_closeFile test eax, eax je @DllFailure mov PeLib_closeFile_offset, eax invoke GetProcAddress, PeLib_dll_offset, ADDR PeFile_readMzHeader test eax, eax je @DllFailure mov PeFile_readMzHeader_offset, eax invoke GetProcAddress, PeLib_dll_offset, ADDR PeFile_readPeHeader test eax, eax je @DllFailure mov PeFile_readPeHeader_offset, eax invoke GetProcAddress, PeLib_dll_offset, ADDR PeHeader_offsetToRva test eax, eax je @DllFailure mov PeHeader_offsetToRva_offset, eax invoke GetProcAddress, PeLib_dll_offset, ADDR PeHeader_rvaToOffset test eax, eax je @DllFailure mov PeHeader_rvaToOffset_offset, eax invoke GetProcAddress, PeLib_dll_offset, ADDR PeHeader_getImageBase test eax, eax je @DllFailure mov PeHeader_getImageBase_offset, eax invoke GetProcAddress, PeLib_dll_offset, ADDR PeHeader_getSectionWithOffset test eax, eax je @DllFailure mov PeHeader_getSectionWithOffset_offset, eax invoke GetProcAddress, PeLib_dll_offset, ADDR PeHeader_getSectionName test eax, eax je @DllFailure mov PeHeader_getSectionName_offset, eax invoke GetProcAddress, PeLib_dll_offset, ADDR PeFile_peHeader test eax, eax je @DllFailure mov PeFile_peHeader_offset, eax mov eax, 1 ret @DllFailure: xor eax, eax ret InitializeDll endp ret end start