#include <assert.h>\r
#ifdef __GNUC__\r
#include <unistd.h>\r
+#else\r
+#include <direct.h>\r
#endif\r
\r
#include <FvLib.h>\r
#include "ParseGuidedSectionTools.h"\r
#include "StringFuncs.h"\r
#include "ParseInf.h"\r
+#include "PeCoffLib.h"\r
\r
//\r
// Utility global variables\r
\r
CHAR8* mUtilityFilename = NULL;\r
\r
+BOOLEAN EnableHash = FALSE;\r
+CHAR8 *OpenSslPath = NULL;\r
+\r
EFI_STATUS\r
ParseGuidBaseNameFile (\r
CHAR8 *FileName\r
IN CHAR8* FirmwareVolumeFilename\r
);\r
\r
+EFI_STATUS\r
+CombinePath (\r
+ IN CHAR8* DefaultPath,\r
+ IN CHAR8* AppendPath,\r
+ OUT CHAR8* NewPath\r
+);\r
+\r
void\r
Usage (\r
VOID\r
int Offset;\r
BOOLEAN ErasePolarity;\r
UINT64 LogLevel;\r
+ CHAR8 *OpenSslEnv;\r
+ CHAR8 *OpenSslCommand;\r
\r
SetUtilityName (UTILITY_NAME);\r
//\r
argv += 2;\r
continue;\r
}\r
+ if ((stricmp (argv[0], "--hash") == 0)) {\r
+ if (EnableHash == TRUE) {\r
+ //\r
+ // --hash already given in the option, ignore this one\r
+ //\r
+ argc --;\r
+ argv ++;\r
+ continue;\r
+ }\r
+ EnableHash = TRUE;\r
+ OpenSslCommand = "openssl";\r
+ OpenSslEnv = getenv("OPENSSL_PATH");\r
+ if (OpenSslEnv == NULL) {\r
+ OpenSslPath = OpenSslCommand;\r
+ } else {\r
+ OpenSslPath = malloc(strlen(OpenSslEnv)+strlen(OpenSslCommand)+1);\r
+ if (OpenSslPath == NULL) {\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+ return GetUtilityStatus ();\r
+ }\r
+ CombinePath(OpenSslEnv, OpenSslCommand, OpenSslPath);\r
+ }\r
+ if (OpenSslPath == NULL){\r
+ Error (NULL, 0, 3000, "Open SSL command not available. Please verify PATH or set OPENSSL_PATH.", NULL);\r
+ return GetUtilityStatus ();\r
+ }\r
+ argc --;\r
+ argv ++;\r
+ continue;\r
+ }\r
\r
if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {\r
SetPrintLevel (VERBOSE_LOG_LEVEL);\r
return EFI_SUCCESS;\r
}\r
\r
+EFI_STATUS\r
+RebaseImageRead (\r
+ IN VOID *FileHandle,\r
+ IN UINTN FileOffset,\r
+ IN OUT UINT32 *ReadSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
+\r
+Arguments:\r
+\r
+ FileHandle - The handle to the PE/COFF file\r
+\r
+ FileOffset - The offset, in bytes, into the file to read\r
+\r
+ ReadSize - The number of bytes to read from the file starting at FileOffset\r
+\r
+ Buffer - A pointer to the buffer to read the data into.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
+\r
+--*/\r
+{\r
+ CHAR8 *Destination8;\r
+ CHAR8 *Source8;\r
+ UINT32 Length;\r
+\r
+ Destination8 = Buffer;\r
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
+ Length = *ReadSize;\r
+ while (Length--) {\r
+ *(Destination8++) = *(Source8++);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+SetAddressToSectionHeader (\r
+ IN CHAR8 *FileName,\r
+ IN OUT UINT8 *FileBuffer,\r
+ IN UINT64 NewPe32BaseAddress\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set new base address into the section header of PeImage\r
+\r
+Arguments:\r
+\r
+ FileName - Name of file\r
+ FileBuffer - Pointer to PeImage.\r
+ NewPe32BaseAddress - New Base Address for PE image.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Set new base address into this image successfully.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+ UINTN Index;\r
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
+\r
+ //\r
+ // Initialize context\r
+ //\r
+ memset (&ImageContext, 0, sizeof (ImageContext));\r
+ ImageContext.Handle = (VOID *) FileBuffer;\r
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead;\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName);\r
+ return Status;\r
+ }\r
+\r
+ if (ImageContext.RelocationsStripped) {\r
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get PeHeader pointer\r
+ //\r
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset);\r
+\r
+ //\r
+ // Get section header list\r
+ //\r
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
+ (UINTN) ImgHdr +\r
+ sizeof (UINT32) +\r
+ sizeof (EFI_IMAGE_FILE_HEADER) +\r
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
+ );\r
+\r
+ //\r
+ // Set base address into the first section header that doesn't point to code section.\r
+ //\r
+ for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
+ if ((SectionHeader->Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {\r
+ *(UINT64 *) &SectionHeader->PointerToRelocations = NewPe32BaseAddress;\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // BaseAddress is set to section header.\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+RebaseImage (\r
+ IN CHAR8 *FileName,\r
+ IN OUT UINT8 *FileBuffer,\r
+ IN UINT64 NewPe32BaseAddress\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set new base address into PeImage, and fix up PeImage based on new address.\r
+\r
+Arguments:\r
+\r
+ FileName - Name of file\r
+ FileBuffer - Pointer to PeImage.\r
+ NewPe32BaseAddress - New Base Address for PE image.\r
+\r
+Returns:\r
+\r
+ EFI_INVALID_PARAMETER - BaseAddress is not valid.\r
+ EFI_SUCCESS - Update PeImage is correctly.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+ UINTN Index;\r
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
+ UINT8 *MemoryImagePointer;\r
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
+\r
+ //\r
+ // Initialize context\r
+ //\r
+ memset (&ImageContext, 0, sizeof (ImageContext));\r
+ ImageContext.Handle = (VOID *) FileBuffer;\r
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead;\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName);\r
+ return Status;\r
+ }\r
+\r
+ if (ImageContext.RelocationsStripped) {\r
+ Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get PeHeader pointer\r
+ //\r
+ ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset);\r
+\r
+ //\r
+ // Load and Relocate Image Data\r
+ //\r
+ MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+ if (MemoryImagePointer == NULL) {\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+ ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((INT64)ImageContext.SectionAlignment - 1));\r
+\r
+ Status = PeCoffLoaderLoadImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);\r
+ free ((VOID *) MemoryImagePointer);\r
+ return Status;\r
+ }\r
+\r
+ ImageContext.DestinationAddress = NewPe32BaseAddress;\r
+ Status = PeCoffLoaderRelocateImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);\r
+ free ((VOID *) MemoryImagePointer);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Copy Relocated data to raw image file.\r
+ //\r
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (\r
+ (UINTN) ImgHdr +\r
+ sizeof (UINT32) +\r
+ sizeof (EFI_IMAGE_FILE_HEADER) +\r
+ ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
+ );\r
+\r
+ for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
+ CopyMem (\r
+ FileBuffer + SectionHeader->PointerToRawData,\r
+ (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),\r
+ SectionHeader->SizeOfRawData\r
+ );\r
+ }\r
+\r
+ free ((VOID *) MemoryImagePointer);\r
+\r
+ //\r
+ // Update Image Base Address\r
+ //\r
+ if ((ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) && (ImgHdr->Pe32.FileHeader.Machine != IMAGE_FILE_MACHINE_IA64)) {\r
+ ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress;\r
+ } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
+ ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;\r
+ } else {\r
+ Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",\r
+ ImgHdr->Pe32.OptionalHeader.Magic,\r
+ FileName\r
+ );\r
+ return EFI_ABORTED;\r
+ }\r
+\r
+ //\r
+ // Set new base address into section header\r
+ //\r
+ Status = SetAddressToSectionHeader (FileName, FileBuffer, NewPe32BaseAddress);\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+CombinePath (\r
+ IN CHAR8* DefaultPath,\r
+ IN CHAR8* AppendPath,\r
+ OUT CHAR8* NewPath\r
+)\r
+{\r
+ UINT32 DefaultPathLen;\r
+ DefaultPathLen = strlen(DefaultPath);\r
+ strcpy(NewPath, DefaultPath);\r
+ UINT64 Index = 0;\r
+ for (; Index < DefaultPathLen; Index ++) {\r
+ if (NewPath[Index] == '\\' || NewPath[Index] == '/') {\r
+ if (NewPath[Index + 1] != '\0') {\r
+ NewPath[Index] = '/';\r
+ }\r
+ }\r
+ }\r
+ if (NewPath[Index -1] != '/') {\r
+ NewPath[Index] = '/';\r
+ NewPath[Index + 1] = '\0';\r
+ }\r
+ strcat(NewPath, AppendPath);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
EFI_STATUS\r
ParseSection (\r
IN UINT8 *SectionBuffer,\r
UINT16 DataOffset;\r
UINT16 Attributes;\r
UINT32 RealHdrLen;\r
+ CHAR8 *ToolInputFileName;\r
+ CHAR8 *ToolOutputFileName;\r
\r
ParsedLength = 0;\r
+ ToolInputFileName = NULL;\r
+ ToolOutputFileName = NULL;\r
+\r
while (ParsedLength < BufferLength) {\r
Ptr = SectionBuffer + ParsedLength;\r
\r
SectionHeaderLen = GetSectionHeaderLength((EFI_COMMON_SECTION_HEADER *)Ptr);\r
\r
SectionName = SectionNameToStr (Type);\r
- printf ("------------------------------------------------------------\n");\r
- printf (" Type: %s\n Size: 0x%08X\n", SectionName, (unsigned) SectionLength);\r
- free (SectionName);\r
+ if (SectionName != NULL) {\r
+ printf ("------------------------------------------------------------\n");\r
+ printf (" Type: %s\n Size: 0x%08X\n", SectionName, (unsigned) SectionLength);\r
+ free (SectionName);\r
+ }\r
\r
switch (Type) {\r
case EFI_SECTION_RAW:\r
- case EFI_SECTION_PE32:\r
case EFI_SECTION_PIC:\r
case EFI_SECTION_TE:\r
// default is no more information\r
break;\r
\r
+ case EFI_SECTION_PE32:\r
+ if (EnableHash) {\r
+ ToolInputFileName = "edk2Temp_InputEfi.tmp";\r
+ ToolOutputFileName = "edk2Temp_OutputHash.tmp";\r
+ RebaseImage(ToolInputFileName, (UINT8*)Ptr + SectionHeaderLen, 0);\r
+ PutFileImage (\r
+ ToolInputFileName,\r
+ (CHAR8*)Ptr + SectionHeaderLen,\r
+ SectionLength - SectionHeaderLen\r
+ );\r
+\r
+ SystemCommandFormatString = "%s sha1 -out %s %s";\r
+ SystemCommand = malloc (\r
+ strlen (SystemCommandFormatString) +\r
+ strlen (OpenSslPath) +\r
+ strlen (ToolInputFileName) +\r
+ strlen (ToolOutputFileName) +\r
+ 1\r
+ );\r
+ if (SystemCommand == NULL) {\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ sprintf (\r
+ SystemCommand,\r
+ SystemCommandFormatString,\r
+ OpenSslPath,\r
+ ToolOutputFileName,\r
+ ToolInputFileName\r
+ );\r
+\r
+ if (system (SystemCommand) != EFI_SUCCESS) {\r
+ Error (NULL, 0, 3000, "Open SSL command not available. Please verify PATH or set OPENSSL_PATH.", NULL);\r
+ }\r
+ else {\r
+ FILE *fp;\r
+ CHAR8 *StrLine;\r
+ CHAR8 *NewStr;\r
+ UINT32 nFileLen;\r
+ if((fp = fopen(ToolOutputFileName,"r")) == NULL) {\r
+ Error (NULL, 0, 0004, "Hash the PE32 image failed.", NULL);\r
+ }\r
+ else {\r
+ fseek(fp,0,SEEK_SET);\r
+ fseek(fp,0,SEEK_END);\r
+ nFileLen = ftell(fp);\r
+ fseek(fp,0,SEEK_SET);\r
+ StrLine = malloc(nFileLen);\r
+ if (StrLine == NULL) {\r
+ fclose(fp);\r
+ free (SystemCommand);\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ fgets(StrLine, nFileLen, fp);\r
+ NewStr = strrchr (StrLine, '=');\r
+ printf (" SHA1: %s\n", NewStr + 1);\r
+ free (StrLine);\r
+ fclose(fp);\r
+ }\r
+ }\r
+ remove(ToolInputFileName);\r
+ remove(ToolOutputFileName);\r
+ free (SystemCommand);\r
+ }\r
+ break;\r
+\r
case EFI_SECTION_USER_INTERFACE:\r
- printf (" String: %ls\n", (CHAR16 *) &((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString);\r
+ printf (" String: %ls\n", (wchar_t *) &((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString);\r
break;\r
\r
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:\r
}\r
\r
ScratchBuffer = malloc (ScratchSize);\r
+ if (ScratchBuffer == NULL) {\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
UncompressedBuffer = malloc (UncompressedLength);\r
- if ((ScratchBuffer == NULL) || (UncompressedBuffer == NULL)) {\r
+ if (UncompressedBuffer == NULL) {\r
+ free (ScratchBuffer);\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
return EFI_OUT_OF_RESOURCES;\r
}\r
Status = DecompressFunction (\r
close(fd2);\r
#endif\r
\r
+ if ((ToolInputFile == NULL) || (ToolOutputFile == NULL)) {\r
+ if (ToolInputFile != NULL) {\r
+ free (ToolInputFile);\r
+ }\r
+ if (ToolOutputFile != NULL) {\r
+ free (ToolOutputFile);\r
+ }\r
+ free (ExtractionTool);\r
+\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
//\r
// Construction 'system' command string\r
//\r
strlen (ToolOutputFile) +\r
1\r
);\r
+ if (SystemCommand == NULL) {\r
+ free (ToolInputFile);\r
+ free (ToolOutputFile);\r
+ free (ExtractionTool);\r
+\r
+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
sprintf (\r
SystemCommand,\r
SystemCommandFormatString,\r
);\r
remove (ToolOutputFile);\r
free (ToolOutputFile);\r
+ free (SystemCommand);\r
if (EFI_ERROR (Status)) {\r
Error (NULL, 0, 0004, "unable to read decoded GUIDED section", NULL);\r
return EFI_SECTION_ERROR;\r
{\r
FILE *Fptr;\r
CHAR8 Line[MAX_LINE_LEN];\r
+ CHAR8 *FormatString;\r
+ INTN FormatLength;\r
GUID_TO_BASENAME *GPtr;\r
\r
if ((Fptr = fopen (LongFilePath (FileName), "r")) == NULL) {\r
return EFI_DEVICE_ERROR;\r
}\r
\r
+ //\r
+ // Generate the format string for fscanf\r
+ //\r
+ FormatLength = snprintf (\r
+ NULL,\r
+ 0,\r
+ "%%%us %%%us",\r
+ (unsigned) sizeof (GPtr->Guid) - 1,\r
+ (unsigned) sizeof (GPtr->BaseName) - 1\r
+ ) + 1;\r
+\r
+ FormatString = (CHAR8 *) malloc (FormatLength);\r
+ if (FormatString == NULL) {\r
+ fclose (Fptr);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ snprintf (\r
+ FormatString,\r
+ FormatLength,\r
+ "%%%us %%%us",\r
+ (unsigned) sizeof (GPtr->Guid) - 1,\r
+ (unsigned) sizeof (GPtr->BaseName) - 1\r
+ );\r
+\r
while (fgets (Line, sizeof (Line), Fptr) != NULL) {\r
//\r
// Allocate space for another guid/basename element\r
//\r
GPtr = malloc (sizeof (GUID_TO_BASENAME));\r
if (GPtr == NULL) {\r
+ free (FormatString);\r
+ fclose (Fptr);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
memset ((char *) GPtr, 0, sizeof (GUID_TO_BASENAME));\r
- if (sscanf (Line, "%s %s", GPtr->Guid, GPtr->BaseName) == 2) {\r
+ if (sscanf (Line, FormatString, GPtr->Guid, GPtr->BaseName) == 2) {\r
GPtr->Next = mGuidBaseNameList;\r
mGuidBaseNameList = GPtr;\r
} else {\r
}\r
}\r
\r
+ free (FormatString);\r
fclose (Fptr);\r
return EFI_SUCCESS;\r
}\r
fprintf (stdout, " -f OFFSET, --offset OFFSET\n\\r
The offset from the start of the input file to start \n\\r
processing an FV\n");\r
+ fprintf (stdout, " --hash\n\\r
+ Generate HASH value of the entire PE image\n");\r
fprintf (stdout, " --sfo\n\\r
Reserved for future use\n");\r
}\r