/** @file Copyright (c) 2023, Marvin Häuser. All rights reserved. SPDX-License-Identifier: BSD-3-Clause **/ #include "ImageTool.h" #include #include #include "PeScan.h" #include "UeScan.h" static bool ScanUefiImageGetHeaderInfo ( OUT image_tool_header_info_t *HeaderInfo, IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context ) { RETURN_STATUS Status; UINT64 Address; HeaderInfo->BaseAddress = UefiImageGetBaseAddress (Context); HeaderInfo->EntryPointAddress = UefiImageGetEntryPointAddress (Context); HeaderInfo->Machine = UefiImageGetMachine (Context); if (HeaderInfo->Machine == 0xFFFF) { DEBUG_RAISE (); return false; } HeaderInfo->Subsystem = UefiImageGetSubsystem (Context); Status = UefiImageGetFixedAddress (Context, &Address); if (!RETURN_ERROR (Status)) { if (Address != HeaderInfo->BaseAddress) { fprintf ( stderr, "ImageTool: Images with a fixed address different from their base address are not supported.\n" ); return false; } HeaderInfo->FixedAddress = true; } else if (Status != RETURN_NOT_FOUND) { return false; } return true; } static RETURN_STATUS ScanUefiImageGetRelocInfo ( OUT image_tool_reloc_info_t *RelocInfo, IN const image_tool_segment_info_t *SegmentInfo, IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context ) { UINT8 FormatIndex; FormatIndex = UefiImageGetFormat (Context); RelocInfo->RelocsStripped = UefiImageGetRelocsStripped (Context); if (FormatIndex == UefiImageFormatPe) { return ScanPeGetRelocInfo (RelocInfo, &Context->Ctx.Pe); } // LCOV_EXCL_START if (FormatIndex == UefiImageFormatUe) { // LCOV_EXCL_STOP return ScanUeGetRelocInfo (RelocInfo, SegmentInfo, &Context->Ctx.Ue); } // LCOV_EXCL_START fprintf ( stderr, "ImageTool: Unsupported UefiImage format %u\n", FormatIndex ); assert (false); return RETURN_UNSUPPORTED; // LCOV_EXCL_STOP } static RETURN_STATUS ScanUefiImageGetSegmentInfo ( OUT image_tool_segment_info_t *SegmentInfo, IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context ) { UINT8 FormatIndex; FormatIndex = UefiImageGetFormat (Context); SegmentInfo->SegmentAlignment = UefiImageGetSegmentAlignment (Context); if (FormatIndex == UefiImageFormatPe) { return ScanPeGetSegmentInfo (SegmentInfo, &Context->Ctx.Pe); } // LCOV_EXCL_START if (FormatIndex == UefiImageFormatUe) { // LCOV_EXCL_STOP return ScanUeGetSegmentInfo (SegmentInfo, &Context->Ctx.Ue); } // LCOV_EXCL_START fprintf ( stderr, "ImageTool: Unsupported UefiImage format %u\n", FormatIndex ); assert (false); return RETURN_UNSUPPORTED; // LCOV_EXCL_STOP } RETURN_STATUS ScanUefiImageGetDebugInfo ( OUT image_tool_debug_info_t *DebugInfo, IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context ) { RETURN_STATUS Status; const CHAR8 *SymbolsPath; UINT32 SymbolsPathSize; Status = UefiImageGetSymbolsPath (Context, &SymbolsPath, &SymbolsPathSize); if (Status == RETURN_NOT_FOUND || Status == RETURN_UNSUPPORTED) { return RETURN_SUCCESS; } if (RETURN_ERROR (Status)) { fprintf (stderr, "ImageTool: Could not get SymbolsPath\n"); return Status; } assert (SymbolsPathSize >= 1); DebugInfo->SymbolsPath = AllocateCopyPool (SymbolsPathSize, SymbolsPath); if (DebugInfo->SymbolsPath == NULL) { fprintf (stderr, "ImageTool: Could not allocate memory for SymbolsPath\n"); return RETURN_OUT_OF_RESOURCES; } assert (DebugInfo->SymbolsPath[SymbolsPathSize - 1] == '\0'); DebugInfo->SymbolsPathLen = SymbolsPathSize - 1; return RETURN_SUCCESS; } RETURN_STATUS ScanUefiImageGetHiiInfo ( OUT image_tool_hii_info_t *HiiInfo, IN UEFI_IMAGE_LOADER_IMAGE_CONTEXT *Context ) { RETURN_STATUS Status; UINT32 HiiRva; UINT32 HiiSize; const char *ImageBuffer; Status = UefiImageGetHiiDataRva (Context, &HiiRva, &HiiSize); if (Status == RETURN_NOT_FOUND) { return RETURN_SUCCESS; } if (RETURN_ERROR (Status)) { fprintf (stderr, "ImageTool: Malformed HII data\n"); return Status; } ImageBuffer = (char *)UefiImageLoaderGetImageAddress (Context); HiiInfo->Data = AllocateCopyPool (HiiSize, ImageBuffer + HiiRva); if (HiiInfo->Data == NULL) { fprintf (stderr, "ImageTool: Could not allocate memory for HiiInfo Data\n"); return RETURN_OUT_OF_RESOURCES; } HiiInfo->DataSize = HiiSize; return RETURN_SUCCESS; } RETURN_STATUS ToolContextConstructUefiImage ( OUT image_tool_image_info_t *Image, OUT int8_t *Format, IN const void *File, IN uint32_t FileSize ) { RETURN_STATUS Status; UEFI_IMAGE_LOADER_IMAGE_CONTEXT Context; UINT32 ImageSize; UINT32 ImageAlignment; UINT32 DestinationPages; UINT32 DestinationSize; void *Destination; bool Success; assert (File != NULL || FileSize == 0); Status = UefiImageInitializeContext ( &Context, File, (UINT32)FileSize, UEFI_IMAGE_SOURCE_FV, UefiImageOriginFv ); if (RETURN_ERROR (Status)) { return Status; } *Format = (int8_t)UefiImageGetFormat (&Context); ImageSize = UefiImageGetImageSize (&Context); DestinationPages = EFI_SIZE_TO_PAGES (ImageSize); DestinationSize = EFI_PAGES_TO_SIZE (DestinationPages); ImageAlignment = UefiImageGetSegmentAlignment (&Context); Destination = AllocateAlignedCodePages (DestinationPages, ImageAlignment); if (Destination == NULL) { fprintf (stderr, "ImageTool: Could not allocate Destination buffer\n"); return RETURN_OUT_OF_RESOURCES; } Status = UefiImageLoadImage (&Context, Destination, DestinationSize); // LCOV_EXCL_START if (RETURN_ERROR (Status)) { fprintf (stderr, "ImageTool: Could not Load Image\n"); FreeAlignedPages (Destination, DestinationPages); return Status; } // LCOV_EXCL_STOP memset (Image, 0, sizeof (*Image)); Success = ScanUefiImageGetHeaderInfo (&Image->HeaderInfo, &Context); if (!Success) { fprintf (stderr, "ImageTool: Could not retrieve header info\n"); ToolImageDestruct (Image); FreeAlignedPages (Destination, DestinationPages); return RETURN_VOLUME_CORRUPTED; } Status = ScanUefiImageGetSegmentInfo (&Image->SegmentInfo, &Context); if (RETURN_ERROR (Status)) { fprintf (stderr, "ImageTool: Could not retrieve segment info\n"); ToolImageDestruct (Image); FreeAlignedPages (Destination, DestinationPages); return Status; } Status = ScanUefiImageGetRelocInfo ( &Image->RelocInfo, &Image->SegmentInfo, &Context ); if (RETURN_ERROR (Status)) { fprintf (stderr, "ImageTool: Could not retrieve reloc info\n"); ToolImageDestruct (Image); FreeAlignedPages (Destination, DestinationPages); return Status; } Status = ScanUefiImageGetHiiInfo (&Image->HiiInfo, &Context); if (RETURN_ERROR (Status)) { fprintf (stderr, "ImageTool: Could not retrieve HII info\n"); ToolImageDestruct (Image); FreeAlignedPages (Destination, DestinationPages); return Status; } Status = ScanUefiImageGetDebugInfo (&Image->DebugInfo, &Context); if (RETURN_ERROR (Status)) { fprintf (stderr, "ImageTool: Could not retrieve debug info\n"); ToolImageDestruct (Image); FreeAlignedPages (Destination, DestinationPages); return Status; } FreeAlignedPages (Destination, DestinationPages); return RETURN_SUCCESS; }