PE Tutorial 2: Test the effectiveness of the PE file
In this tutorial, we will learn how to detect a given file is a valid PE file. Download example
theory:
How can I verify whether the specified file is a valid PE file? This problem is difficult to answer, depending on the degree of precision you want. You can check the individual data structures in the PE file format, or only check some key data structures. In most cases, there is no need to verify each data structure in the file, as long as some key data structures are valid, we think it is a valid PE file. Let's implement the previous assumption.
The important data structure we have to verify is PE Header. From a programming perspective, Pe Header is actually an Image_NT_Headers structure. Defined as follows:
Image_nt_headers Struct Signature DD? FileHeader Image_File_Header <> OptionalHeader Image_Optional_Header32 <> iMage_NT_HEADERS Ends
Signature is a DWORD type, a value of 50h, 45h, 00h, 00h (PE / 0/0). The domain is a PE tag, we can identify if a given file is a valid PE file. FileHeader This domain contains information about the physical distribution of PE files, such as the number of nodes, file execution machines, and the like. OptionalHeader This domain contains information about the logical distribution of PE files, although the domain name is "optional", but in fact this structure always exists.
Our purpose is clear. If image_nt_headers' signature domain value is equal to "PE / 0/0", it is a valid PE file. In fact, in order to be more convenient, Microsoft has defined constant image_nt_signature for us to use.
Image_dos_signature EQU 5A4DH Image_OS2_SIGNATURE EQU 454EH Image_OS2_SIGNATURE_LEQU 454CH image_vxd_signature EQU 454ch image_nt_signature EQU 4550H
The next question is: How to locate the PE Header? The answer is simple: DOS MZ Header already contains the file offset to PE Header. DOS MZ HEADER also defines the structure image_dos_header. Query Windows.inc and we know that the E_LFANew member of the image_dos_header structure is the file offset pointing to PE Header.
Now summarize all steps:
First check whether the value of the first word of the file header is equal to Image_DOS_SIGNATURE, which is valid. Once the DOS Header of the document is proved, you can use E_LFANEW to locate Pe Header. Comparing whether the value of the first word of Pe Head is equal to Image_NT_Header. If the two values before and after match, then we think that the file is a valid PE file.
EXAMPLE:
.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/user32.lib includelib /masm32/lib/kernel32.lib includelib /masm32/lib/comdlg32.lib SEH struct PrevLink dd;? the address of the previous seh structure CurrentHandler dd;? the address of the exception handler SafeOffset dd? ; The offset where it's safe to continue execution PrevEsp dd;? the old value in esp PrevEbp dd;? The old value in ebp SEH ends.data AppName db "PE tutorial no.2", 0 ofn OPENFILENAME <> FilterString db "Executable Files (* .exe, * .dll) ", 0," *. EXE; *. DLL ", 0 DB" All Files ", 0," *. * ", 0, 0 FileOpener DB" Cannot Open THE FILE for FOR Reading ", 0 FileOpenMappinger DB" Cannot Open THE FILE for MAMORY MAPPING ", 0 Filemappinger DB" Cannot Map The File Into Memory, 0 FileValidpe DB "this File IS A Valid PE", 0 FileInvalidpe DB "TH Is File Is Not a Valid PE ", 0 .data? Buffer DB 512 DUP (?) HFILE DD? HMApping DD? PMApping DD? Validpe Dd? .code Start Procal SEH: SEH MOV OFN.LSTRUCTSIZE, SIZEOF OFN MOV OFN.. lpstrFilter, OFFSET FilterString mov ofn.lpstrFile, OFFSET buffer mov ofn.nMaxFile, 512 mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY invoke GetOpenFileName, aDDR ofn .if eax == TRUE invoke CreateFile, addr buffer, GENERIC_READ, File_share_read, null, open_existing, file_attribute_normal, null .if eax! =
INVALID_HANDLE_VALUE mov hFile, eax invoke CreateFileMapping, hFile, NULL, PAGE_READONLY, 0,0,0 .if eax! = NULL mov hMapping, eax invoke MapViewOfFile, hMapping, FILE_MAP_READ, 0,0,0 .if eax! = NULL mov pMapping, Eax Assume Fs: Nothing Push Fs: [0] Pop Seh.Prevlink Mov Seh.currenthandler, Offset Sehhandler Mov Seh.SAFEOFFSET, OFFSET FINALEXIT LEA EAX, SEH MOV FS: [0], ESP MOV SEH.PREVESP, ESP MOV SEH. PrevEbp, ebp mov edi, pMapping assume edi: ptr IMAGE_DOS_HEADER .if [edi] .e_magic == IMAGE_DOS_SIGNATURE add edi, [edi] .e_lfanew assume edi: ptr IMAGE_NT_HEADERS .if [edi] .Signature == IMAGE_NT_SIGNATURE mov ValidPE, TRUE. Else Mov Validpe, False .ndif .else mov ValidPE, FALSE .endif FinalExit: .if ValidPE == TRUE invoke MessageBox, 0, addr FileValidPE, addr AppName, MB_OK MB_ICONINFORMATION .else invoke MessageBox, 0, addr FileInValidPE, addr AppName, MB_OK MB_ICONINFORMATION .endif push seh.PrevLink pop fs: [0] invoke UnmapViewOfFile, pMapping .else invoke MessageBox, 0, addr FileMappingError, addr AppName, MB_OK MB_ICONERROR .endif invoke CloseHandle, hMapping .else invoke MessageBox, 0, addr FileOpenMappingError, addr AppName, MB_OK
MB_ICONERROR .endif invoke CloseHandle, hFile .else invoke MessageBox, 0, addr FileOpenError, addr AppName, MB_OK MB_ICONERROR .endif .endif invoke ExitProcess, 0 start endp SEHHandler proc uses edx pExcept: DWORD, pFrame: DWORD, pContext: DWORD, pDispatch : DWORD MOV EDX, PFRAME Assume Edx: Ptr Seh Mov Eax, PCONText Assume Eax: Ptr Context Push [EDX] .safeoffset Pop [EAX] .Regeip Push [EDX] .pregesp PUSH [EDX] .pregesp Push [EDX] .prevebp POP [EAX] .Regebp Mov Validpe, False Mov Eax, ExceptionContinueexecution Ret SEHHANDLER END Start Analysis:
This routine opens a file, first check if DOS Header is valid, and then check the validity of Pe Header, and OK is considered to be a valid PE file. Here, we also use structural exception handling (SEH), which does not have to check each possible error: If there is an error, it is considered that PE detection is invalid, so we give our error information. In fact, the internal use of SEH is generally used to verify the validity of parameter transmission. If you are interested in SEH, you can read the Jeremy Gordon's article.
Program Call Opens the File General dialog box, after the user selects the execution file, the program opens the file and maps to memory. And established a SEH before the validity test:
assume fs: nothing push fs: [0] pop seh.PrevLink mov seh.CurrentHandler, offset SEHHandler mov seh.SafeOffset, offset FinalExit lea eax, seh mov fs: [0], eax mov seh.PrevEsp, esp mov seh.PrevEbp EBP
Assuming the register fs is empty (Assume Fs: Nothing). Remember this step cannot be saved, because MASM assumes that the FS register is ERROR. Next, the old SEH processing function address used by Windows is saved in our own defined structure, while saving our SEH processing function addresses and exception processing, so once the error occurs, can be safely restored by the exception handler . It also saves the current ESP and EBP values so that our SEH processing function returns the stack to the normal state.
MOV EDI, PMApping Assume EDI: Ptr Image_dos_Header .IF [EDI] .e_magic == Image_DOS_SIGNATURE
Continue to check the test after successfully establishing SEH. Set the first byte address of the target file to EDI to point to the first one of DOS HEADER. For ease of comparison, we tell the compiler that the EDI is pointing to the image_dos_header structure (this is true). Then compare whether the preamble of the DOS HEADER is equal to the string "MZ", which utilizes the image_dos_signature constant defined in Windows.Ic. If it is successful, continue to PE Header, otherwise set the validpe value is false, meaning the file is not a valid PE file. Add Edi, [EDI] .e_lfanew assoc_nt_headers .if [EDI]. Signature == Image_NT_SIGNATURE MOV VALIDPE, TRUE .ELSE MOV VALIDPE, FALSE .Endif
To locate the PE Header, you need to read the E_LFANEW domain value in the DOS HEADER. This domain contains the offset of the relative file header in the file. EDI plus this value is being positioned to the first byte of Pe Header. This may be wrong here. If the file is not a PE file, the E_LFANew value is incorrect, plus this value as a pointer may result in an exception. If you don't have SEH, we must check if the E_LFANew value exceeds the file size, which is not a good way. If everything is OK, we compare whether the preamble of Pe Head is a string "PE". Here, constant image_nt_signature here is used, and equal is considered a valid PE file. If the value of the E_LFANEW is incorrect, our SEH processing function will be executed to execute control, simply restore the stack pointer and the base stamp pointer, and then restore it according to the SAFEOFFSET value to the FINALEXIT tab.
FinalExit: .if ValidPE == TRUE invoke MessageBox, 0, addr FileValidPE, addr AppName, MB_OK MB_ICONINFORMATION .else invoke MessageBox, 0, addr FileInValidPE, addr AppName, MB_OK MB_ICONINFORMATION .endif
The above code is simple and clear, and the corresponding information is displayed according to the value of VALIDPE.
Push seh.prevlink pop fs: [0]
Once SEH is no longer used, it must be disconnected from the SEH chain.
Translation: IAMGUFENG [ICZelion's Win32 Assembly Home] [Luoyunbin's Win32 ASM Page]