01.18
If it ain't broke, don't fix it. But what if it is? What if the file you are trying to unpack with your unpacker is broken, then what? Do you just chuck it marking it as crapware or do you try to fix it? This raises many many question in file handling. Its foolish to assume that every file your unpacker receives is a valid portable executable. So, how does TitanEngine cope with this?
As you may know TitanEngine has two built in functions to identify and fix damaged PE32/PE32+ files. Those two functions are: IsPE32FileValidExW and FixBrokenPE32FileExW in their UNICODE implementation. If you remember, not too long ago we published a PE validation tool built around our validation function which is available here. Today we pay attention on how to use these two functions.
Ideally before initializing the dynamic unpacking process you would validate the file you are unpacking to see if it will actually execute on the system. Windows loader can also show error messages about the broken file but since we are building our own application which might batch files its best to handle these cases statically before the application runs. And TitanEngine's validation function works in just such a way. It statically inspects the file making sure that it is valid or providing as much information about the errors found as possible. If we take a look at the FILE_STATUS_INFO structure we see all aspects of PE file being inspected.
typedef struct{ BYTE OveralEvaluation; bool EvaluationTerminatedByException; bool FileIs64Bit; bool FileIsDLL; bool FileIsConsole; bool MissingDependencies; bool MissingDeclaredAPIs; BYTE SignatureMZ; BYTE SignaturePE; BYTE EntryPoint; BYTE ImageBase; BYTE SizeOfImage; BYTE FileAlignment; BYTE SectionAlignment; BYTE ExportTable; BYTE RelocationTable; BYTE ImportTable; BYTE ImportTableSection; BYTE ImportTableData; BYTE IATTable; BYTE TLSTable; BYTE LoadConfigTable; BYTE BoundImportTable; BYTE COMHeaderTable; BYTE ResourceTable; BYTE ResourceData; BYTE SectionTable; }FILE_STATUS_INFO, *PFILE_STATUS_INFO;
Most important field for file validation purposes is the OveralEvaluation field which can have the following values:
- UE_RESULT_FILE_OK
- UE_RESULT_FILE_INVALID_FORMAT
- UE_RESULT_FILE_INVALID_AND_NON_FIXABLE
- UE_RESULT_FILE_INVALID_BUT_FIXABLE
No matter if the file is fixable or not the rest of the structure will be filled with information about defects found in the file. File is considered invalid and non fixable if the file OveralEvaluation says so, but that doesn't mean that the file will execute. If there are missing dependencies in the file it might not execute but that can be easily fixed by installing the Nexus plugin. If however OveralEvaluation claims that file can be fixed we can call FixBrokenPE32FileExW function to try to repair the file. While file is being repaired following structure will be filled:
typedef struct{ BYTE OveralEvaluation; bool FixingTerminatedByException; bool FileFixPerformed; bool StrippedRelocation; bool DontFixRelocations; DWORD OriginalRelocationTableAddress; DWORD OriginalRelocationTableSize; bool StrippedExports; bool DontFixExports; DWORD OriginalExportTableAddress; DWORD OriginalExportTableSize; bool StrippedResources; bool DontFixResources; DWORD OriginalResourceTableAddress; DWORD OriginalResourceTableSize; bool StrippedTLS; bool DontFixTLS; DWORD OriginalTLSTableAddress; DWORD OriginalTLSTableSize; bool StrippedLoadConfig; bool DontFixLoadConfig; DWORD OriginalLoadConfigTableAddress; DWORD OriginalLoadConfigTableSize; bool StrippedBoundImports; bool DontFixBoundImports; DWORD OriginalBoundImportTableAddress; DWORD OriginalBoundImportTableSize; bool StrippedIAT; bool DontFixIAT; DWORD OriginalImportAddressTableAddress; DWORD OriginalImportAddressTableSize; bool StrippedCOM; bool DontFixCOM; DWORD OriginalCOMTableAddress; DWORD OriginalCOMTableSize; }FILE_FIX_INFO, *PFILE_FIX_INFO;
This structure is input/output one. It can be used to set options to what will be fixed in and what will be left as it is. This is totally optional and this structure can be left zeroed before calling the file fixing function. Field OveralEvaluation can have the same values like in the FILE_STATUS_INFO structure and its used the same way. Additionally the value of variable FileFixPerformed indicates if the the file has been fixed. However not all field can be fixed, some can only be temporarily stripped. These fields are saved in the FILE_FIX_INFO structure and must be restored once the file has been dumped to disk. Most commonly this refers to resources which can be corrupted on disk but valid once the file has been decompressed in memory. Currently there isn't a function to automatically restore these fields so it must be done by the unpacker code. This will change for next major release.
To make this blog a little more then just a documentation clarification we have modified our existing UPX unpacker sample to support basic file fixing. Sample which is included in the package has damaged SizeOfImage field and incorrect code section attributes. This is fixed by the unpacked and saved in a new file which is then used for unpacking. As always binary, source code and the samples are included with the blog. Until next week...
TitanEngine![]() ReversingLabs Corporation |
RL!deUPX |
