diff options
author | Yonghong Zhu <yonghong.zhu@intel.com> | 2016-04-07 13:56:44 +0800 |
---|---|---|
committer | Yonghong Zhu <yonghong.zhu@intel.com> | 2016-04-12 13:14:21 +0800 |
commit | 9947f5769f457c6efd4e917da0bddd702a82de69 (patch) | |
tree | 919081d739936b4378edcb1e0834a62ab42b1b8d /BaseTools | |
parent | 479d5c4175e77f1cd7e61855fa3c9f83c330ef4f (diff) | |
download | edk2-9947f5769f457c6efd4e917da0bddd702a82de69.tar.gz edk2-9947f5769f457c6efd4e917da0bddd702a82de69.tar.bz2 edk2-9947f5769f457c6efd4e917da0bddd702a82de69.zip |
BaseTools/VolInfo: generate HASH value for each PE image
VolInfo Tool add new option --hash to use openssl to generate hash value
for each PE image. If the image base address is not zero, we will rebase
its base address to zero before generate hash value.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Yonghong Zhu <yonghong.zhu@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
Diffstat (limited to 'BaseTools')
-rw-r--r-- | BaseTools/Source/C/VolInfo/VolInfo.c | 375 |
1 files changed, 374 insertions, 1 deletions
diff --git a/BaseTools/Source/C/VolInfo/VolInfo.c b/BaseTools/Source/C/VolInfo/VolInfo.c index 84bfa69ea2..5c4a5036c2 100644 --- a/BaseTools/Source/C/VolInfo/VolInfo.c +++ b/BaseTools/Source/C/VolInfo/VolInfo.c @@ -19,6 +19,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include <assert.h>
#ifdef __GNUC__
#include <unistd.h>
+#else
+#include <direct.h>
#endif
#include <FvLib.h>
@@ -40,6 +42,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "ParseGuidedSectionTools.h"
#include "StringFuncs.h"
#include "ParseInf.h"
+#include "PeCoffLib.h"
//
// Utility global variables
@@ -74,6 +77,9 @@ EFI_HANDLE mParsedGuidedSectionTools = NULL; CHAR8* mUtilityFilename = NULL;
+BOOLEAN EnableHash = FALSE;
+CHAR8 *OpenSslPath = NULL;
+
EFI_STATUS
ParseGuidBaseNameFile (
CHAR8 *FileName
@@ -130,6 +136,13 @@ LoadGuidedSectionToolsTxt ( IN CHAR8* FirmwareVolumeFilename
);
+EFI_STATUS
+CombinePath (
+ IN CHAR8* DefaultPath,
+ IN CHAR8* AppendPath,
+ OUT CHAR8* NewPath
+);
+
void
Usage (
VOID
@@ -165,6 +178,8 @@ Returns: int Offset;
BOOLEAN ErasePolarity;
UINT64 LogLevel;
+ CHAR8 *OpenSslEnv;
+ CHAR8 *OpenSslCommand;
SetUtilityName (UTILITY_NAME);
//
@@ -242,6 +257,24 @@ Returns: argv += 2;
continue;
}
+ if ((stricmp (argv[0], "--hash") == 0)) {
+ EnableHash = TRUE;
+ OpenSslCommand = "openssl";
+ OpenSslEnv = getenv("OPENSSL_PATH");
+ if (OpenSslEnv == NULL) {
+ OpenSslPath = OpenSslCommand;
+ } else {
+ OpenSslPath = malloc(strlen(OpenSslEnv)+strlen(OpenSslCommand)+1);
+ CombinePath(OpenSslEnv, OpenSslCommand, OpenSslPath);
+ }
+ if (OpenSslPath == NULL){
+ Error (NULL, 0, 3000, "Open SSL command not available. Please verify PATH or set OPENSSL_PATH.", NULL);
+ return GetUtilityStatus ();
+ }
+ argc --;
+ argv ++;
+ continue;
+ }
if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {
SetPrintLevel (VERBOSE_LOG_LEVEL);
@@ -1235,6 +1268,283 @@ Returns: }
EFI_STATUS
+RebaseImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINT32 *ReadSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
+
+Arguments:
+
+ FileHandle - The handle to the PE/COFF file
+
+ FileOffset - The offset, in bytes, into the file to read
+
+ ReadSize - The number of bytes to read from the file starting at FileOffset
+
+ Buffer - A pointer to the buffer to read the data into.
+
+Returns:
+
+ EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+--*/
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+ UINT32 Length;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
+ Length = *ReadSize;
+ while (Length--) {
+ *(Destination8++) = *(Source8++);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+SetAddressToSectionHeader (
+ IN CHAR8 *FileName,
+ IN OUT UINT8 *FileBuffer,
+ IN UINT64 NewPe32BaseAddress
+ )
+/*++
+
+Routine Description:
+
+ Set new base address into the section header of PeImage
+
+Arguments:
+
+ FileName - Name of file
+ FileBuffer - Pointer to PeImage.
+ NewPe32BaseAddress - New Base Address for PE image.
+
+Returns:
+
+ EFI_SUCCESS Set new base address into this image successfully.
+
+--*/
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ UINTN Index;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;
+
+ //
+ // Initialize context
+ //
+ memset (&ImageContext, 0, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) FileBuffer;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead;
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName);
+ return Status;
+ }
+
+ if (ImageContext.RelocationsStripped) {
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName);
+ return Status;
+ }
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset);
+
+ //
+ // Get section header list
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINTN) ImgHdr +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
+ );
+
+ //
+ // Set base address into the first section header that doesn't point to code section.
+ //
+ for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {
+ if ((SectionHeader->Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
+ *(UINT64 *) &SectionHeader->PointerToRelocations = NewPe32BaseAddress;
+ break;
+ }
+ }
+
+ //
+ // No available section header is found.
+ //
+ if (Index == ImgHdr->Pe32.FileHeader.NumberOfSections) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // BaseAddress is set to section header.
+ //
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+RebaseImage (
+ IN CHAR8 *FileName,
+ IN OUT UINT8 *FileBuffer,
+ IN UINT64 NewPe32BaseAddress
+ )
+/*++
+
+Routine Description:
+
+ Set new base address into PeImage, and fix up PeImage based on new address.
+
+Arguments:
+
+ FileName - Name of file
+ FileBuffer - Pointer to PeImage.
+ NewPe32BaseAddress - New Base Address for PE image.
+
+Returns:
+
+ EFI_INVALID_PARAMETER - BaseAddress is not valid.
+ EFI_SUCCESS - Update PeImage is correctly.
+
+--*/
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ UINTN Index;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
+ UINT8 *MemoryImagePointer;
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;
+
+ //
+ // Initialize context
+ //
+ memset (&ImageContext, 0, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) FileBuffer;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead;
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName);
+ return Status;
+ }
+
+ if (ImageContext.RelocationsStripped) {
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName);
+ return Status;
+ }
+
+ //
+ // Get PeHeader pointer
+ //
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset);
+
+ //
+ // Load and Relocate Image Data
+ //
+ MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
+ if (MemoryImagePointer == NULL) {
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
+ ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((INT64)ImageContext.SectionAlignment - 1));
+
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
+ free ((VOID *) MemoryImagePointer);
+ return Status;
+ }
+
+ ImageContext.DestinationAddress = NewPe32BaseAddress;
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);
+ free ((VOID *) MemoryImagePointer);
+ return Status;
+ }
+
+ //
+ // Copy Relocated data to raw image file.
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINTN) ImgHdr +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
+ );
+
+ for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {
+ CopyMem (
+ FileBuffer + SectionHeader->PointerToRawData,
+ (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),
+ SectionHeader->SizeOfRawData
+ );
+ }
+
+ free ((VOID *) MemoryImagePointer);
+
+ //
+ // Update Image Base Address
+ //
+ if ((ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) && (ImgHdr->Pe32.FileHeader.Machine != IMAGE_FILE_MACHINE_IA64)) {
+ ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress;
+ } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;
+ } else {
+ Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
+ ImgHdr->Pe32.OptionalHeader.Magic,
+ FileName
+ );
+ return EFI_ABORTED;
+ }
+
+ //
+ // Set new base address into section header
+ //
+ Status = SetAddressToSectionHeader (FileName, FileBuffer, NewPe32BaseAddress);
+
+ return Status;
+}
+
+EFI_STATUS
+CombinePath (
+ IN CHAR8* DefaultPath,
+ IN CHAR8* AppendPath,
+ OUT CHAR8* NewPath
+)
+{
+ UINT32 DefaultPathLen;
+ DefaultPathLen = strlen(DefaultPath);
+ strcpy(NewPath, DefaultPath);
+ UINT64 Index = 0;
+ for (; Index < DefaultPathLen; Index ++) {
+ if (NewPath[Index] == '\\' || NewPath[Index] == '/') {
+ if (NewPath[Index + 1] != '\0') {
+ NewPath[Index] = '/';
+ }
+ }
+ }
+ if (NewPath[Index -1] != '/') {
+ NewPath[Index] = '/';
+ NewPath[Index + 1] = '\0';
+ }
+ strcat(NewPath, AppendPath);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
ParseSection (
IN UINT8 *SectionBuffer,
IN UINT32 BufferLength
@@ -1290,8 +1600,13 @@ Returns: UINT16 DataOffset;
UINT16 Attributes;
UINT32 RealHdrLen;
+ CHAR8 *ToolInputFileName;
+ CHAR8 *ToolOutputFileName;
ParsedLength = 0;
+ ToolInputFileName = NULL;
+ ToolOutputFileName = NULL;
+
while (ParsedLength < BufferLength) {
Ptr = SectionBuffer + ParsedLength;
@@ -1321,12 +1636,68 @@ Returns: switch (Type) {
case EFI_SECTION_RAW:
- case EFI_SECTION_PE32:
case EFI_SECTION_PIC:
case EFI_SECTION_TE:
// default is no more information
break;
+ case EFI_SECTION_PE32:
+ if (EnableHash) {
+ ToolInputFileName = "edk2Temp_InputEfi.tmp";
+ ToolOutputFileName = "edk2Temp_OutputHash.tmp";
+ RebaseImage(ToolInputFileName, (UINT8*)Ptr + SectionHeaderLen, 0);
+ PutFileImage (
+ ToolInputFileName,
+ (CHAR8*)Ptr + SectionHeaderLen,
+ SectionLength - SectionHeaderLen
+ );
+
+ SystemCommandFormatString = "%s sha1 -out %s %s";
+ SystemCommand = malloc (
+ strlen (SystemCommandFormatString) +
+ strlen (OpenSslPath) +
+ strlen (ToolInputFileName) +
+ strlen (ToolOutputFileName) +
+ 1
+ );
+ sprintf (
+ SystemCommand,
+ SystemCommandFormatString,
+ OpenSslPath,
+ ToolOutputFileName,
+ ToolInputFileName
+ );
+
+ if (system (SystemCommand) != EFI_SUCCESS) {
+ Error (NULL, 0, 3000, "Open SSL command not available. Please verify PATH or set OPENSSL_PATH.", NULL);
+ }
+ else {
+ FILE *fp;
+ CHAR8 *StrLine;
+ CHAR8 *NewStr;
+ UINT32 nFileLen;
+ if((fp = fopen(ToolOutputFileName,"r")) == NULL) {
+ Error (NULL, 0, 0004, "Hash the PE32 image failed.", NULL);
+ }
+ else {
+ fseek(fp,0,SEEK_SET);
+ fseek(fp,0,SEEK_END);
+ nFileLen = ftell(fp);
+ fseek(fp,0,SEEK_SET);
+ StrLine = malloc(nFileLen);
+ fgets(StrLine, nFileLen, fp);
+ NewStr = strrchr (StrLine, '=');
+ printf (" SHA1: %s\n", NewStr + 1);
+ free (StrLine);
+ }
+ fclose(fp);
+ }
+ remove(ToolInputFileName);
+ remove(ToolOutputFileName);
+ free (SystemCommand);
+ }
+ break;
+
case EFI_SECTION_USER_INTERFACE:
printf (" String: %ls\n", (CHAR16 *) &((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString);
break;
@@ -1911,6 +2282,8 @@ Returns: fprintf (stdout, " -f OFFSET, --offset OFFSET\n\
The offset from the start of the input file to start \n\
processing an FV\n");
+ fprintf (stdout, " --hash\n\
+ Generate HASH value of the entire PE image\n");
fprintf (stdout, " --sfo\n\
Reserved for future use\n");
}
|