Skip to content

Commit 953f5a4

Browse files
committed
[BOOTLIB]: Implement checksum calculation for PE header sum.
[BOOTLIB]: Implement most of ImgpLoadPEImage. The checksum of the mapped image file matches the checksum in the flat PE file, meaning our load loop works as designed. Next step are relocations and we'll be done. svn path=/trunk/; revision=70632
1 parent d5f0636 commit 953f5a4

File tree

1 file changed

+288
-0
lines changed
  • reactos/boot/environ/lib/misc

1 file changed

+288
-0
lines changed

reactos/boot/environ/lib/misc/image.c

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,54 @@ BlImgUnLoadImage (
651651
return BlImgUnallocateImageBuffer(ImageBase, ImageSize, ImageFlags);
652652
}
653653

654+
unsigned int BlUtlCheckSum(unsigned int PartialSum, PUCHAR Source, unsigned int Length, unsigned int Flags)
655+
{
656+
unsigned int Type; // eax@1
657+
int Type1; // eax@1
658+
unsigned int AlignedLength; // ebx@3
659+
unsigned int i; // ebx@21 MAPDST
660+
661+
Type = Flags & 3;
662+
Type1 = Type - 1;
663+
if (Type1)
664+
{
665+
if (Type1 == 1)
666+
{
667+
PartialSum = (unsigned __int16)PartialSum;
668+
AlignedLength = Length & ~1;
669+
if (Length & ~1)
670+
{
671+
i = 0;
672+
do
673+
{
674+
PartialSum += *(unsigned __int16 *)&Source[i];
675+
if (Flags & 0x10000)
676+
PartialSum = (unsigned __int16)((PartialSum >> 16) + PartialSum);
677+
i += 2;
678+
} while (i < AlignedLength);
679+
}
680+
681+
if (Length != AlignedLength)
682+
{
683+
PartialSum += (unsigned __int8)Source[AlignedLength];
684+
if (Flags & 0x10000)
685+
PartialSum = (unsigned __int16)((PartialSum >> 16) + PartialSum);
686+
}
687+
if (Flags & 0x40000)
688+
return ~PartialSum;
689+
PartialSum = (unsigned __int16)PartialSum;
690+
}
691+
}
692+
else
693+
{
694+
EfiPrintf(L"checksum type not supported\r\n");
695+
}
696+
697+
if (Flags & 0x40000)
698+
return ~PartialSum;
699+
return PartialSum;
700+
}
701+
654702
NTSTATUS
655703
ImgpLoadPEImage (
656704
_In_ PBL_IMG_FILE ImageFile,
@@ -670,11 +718,28 @@ ImgpLoadPEImage (
670718
ULONGLONG VirtualSize;
671719
PHYSICAL_ADDRESS PhysicalAddress;
672720
PIMAGE_NT_HEADERS NtHeaders;
721+
USHORT SectionCount;
722+
USHORT CheckSum, PartialSum;
723+
PIMAGE_SECTION_HEADER Section;
724+
ULONG_PTR EndOfHeaders, SectionStart;
725+
ULONG i;
726+
BOOLEAN First;
727+
ULONG_PTR Slack, SectionEnd;
728+
ULONG SectionSize, RawSize;
729+
ULONG BytesRead, RemainingLength;
730+
UCHAR LocalBuffer[1024];
731+
USHORT FinalSum;
732+
ULONG Offset;
733+
ULONG AlignSize;
673734

674735
/* Initialize locals */
675736
LocalFile = NULL;
676737
ImageBuffer = NULL;
677738
FileSize = 0;
739+
First = FALSE;
740+
VirtualAddress = NULL;
741+
Offset = 0;
742+
VirtualSize = 0;
678743

679744
/* Get the size of the image */
680745
Status = ImgpGetFileSize(ImageFile, &FileSize);
@@ -846,6 +911,229 @@ ImgpLoadPEImage (
846911
goto Quickie;
847912
}
848913

914+
First = FALSE;
915+
916+
/* Record how many sections we have */
917+
SectionCount = NtHeaders->FileHeader.NumberOfSections;
918+
919+
/* Capture the current checksum and reset it */
920+
CheckSum = NtHeaders->OptionalHeader.CheckSum;
921+
NtHeaders->OptionalHeader.CheckSum = 0;
922+
923+
/* Calculate the checksum of the header, and restore the original one */
924+
PartialSum = BlUtlCheckSum(0, VirtualAddress, HeaderSize, 0x10002);
925+
NtHeaders->OptionalHeader.CheckSum = CheckSum;
926+
927+
/* Record our current position (right after the headers) */
928+
EndOfHeaders = (ULONG_PTR)VirtualAddress + HeaderSize;
929+
930+
/* Get the first section and iterate through each one */
931+
Section = IMAGE_FIRST_SECTION(NtHeaders);
932+
for (i = 0; i < SectionCount; i++)
933+
{
934+
/* Compute where this section starts */
935+
SectionStart = (ULONG_PTR)VirtualAddress + Section->VirtualAddress;
936+
937+
/* Make sure that the section fits within the image */
938+
if ((VirtualSize < Section->VirtualAddress) ||
939+
((PVOID)SectionStart < VirtualAddress))
940+
{
941+
Status = STATUS_INVALID_IMAGE_FORMAT;
942+
goto Quickie;
943+
}
944+
945+
/* Check if there's slack space between header end and the section */
946+
if (!(First) && (EndOfHeaders < SectionStart))
947+
{
948+
/* Zero it out */
949+
Slack = SectionStart - EndOfHeaders;
950+
RtlZeroMemory((PVOID)EndOfHeaders, Slack);
951+
}
952+
953+
/* Get the section virtual size and the raw size */
954+
SectionSize = Section->Misc.VirtualSize;
955+
RawSize = Section->SizeOfRawData;
956+
957+
/* Safely align the raw size by 2 */
958+
Status = RtlULongAdd(RawSize, 1, &AlignSize);
959+
if (!NT_SUCCESS(Status))
960+
{
961+
goto Quickie;
962+
}
963+
AlignSize = ALIGN_DOWN_BY(AlignSize, 2);
964+
965+
/* IF we don't have a virtual size, use the raw size */
966+
if (!SectionSize)
967+
{
968+
SectionSize = RawSize;
969+
}
970+
971+
/* If we don't have raw data, ignore the raw size */
972+
if (!Section->PointerToRawData)
973+
{
974+
RawSize = 0;
975+
}
976+
else if (SectionSize < RawSize)
977+
{
978+
/* And if the virtual size is smaller, use it as the final size */
979+
RawSize = SectionSize;
980+
}
981+
982+
/* Make sure that the section doesn't overflow in memory */
983+
Status = RtlULongAdd(Section->VirtualAddress,
984+
SectionSize,
985+
&SectionEnd);
986+
if (!NT_SUCCESS(Status))
987+
{
988+
Status = STATUS_INVALID_IMAGE_FORMAT;
989+
goto Quickie;
990+
}
991+
992+
/* Make sure that it fits within the image */
993+
if (VirtualSize < SectionEnd)
994+
{
995+
Status = STATUS_INVALID_IMAGE_FORMAT;
996+
goto Quickie;
997+
}
998+
999+
/* Make sure it doesn't overflow on disk */
1000+
Status = RtlULongAdd(Section->VirtualAddress,
1001+
AlignSize,
1002+
&SectionEnd);
1003+
if (!NT_SUCCESS(Status))
1004+
{
1005+
Status = STATUS_INVALID_IMAGE_FORMAT;
1006+
goto Quickie;
1007+
}
1008+
1009+
/* Make sure that it fits within the disk image as well */
1010+
if (VirtualSize < SectionEnd)
1011+
{
1012+
Status = STATUS_INVALID_IMAGE_FORMAT;
1013+
goto Quickie;
1014+
}
1015+
1016+
/* So does this section have a valid size after all? */
1017+
if (RawSize)
1018+
{
1019+
/* Are we in the first iteration? */
1020+
if (!First)
1021+
{
1022+
/* Yes, read the section data */
1023+
Status = ImgpReadAtFileOffset(LocalFile,
1024+
AlignSize,
1025+
Section->PointerToRawData,
1026+
(PVOID)SectionStart,
1027+
NULL);
1028+
if (!NT_SUCCESS(Status))
1029+
{
1030+
goto Quickie;
1031+
}
1032+
1033+
/* Update our current offset */
1034+
Offset = AlignSize + Section->PointerToRawData;
1035+
1036+
/* Update the checksum to include this section */
1037+
PartialSum = BlUtlCheckSum(PartialSum,
1038+
(PUCHAR)SectionStart,
1039+
AlignSize,
1040+
0x10002);
1041+
}
1042+
}
1043+
1044+
/* Are we in the first iteration? */
1045+
if (!First)
1046+
{
1047+
/* Is there space at the end of the section? */
1048+
if (RawSize < SectionSize)
1049+
{
1050+
/* Zero out the slack space that's there */
1051+
Slack = SectionSize - RawSize;
1052+
RtlZeroMemory((PVOID)(SectionStart + RawSize), Slack);
1053+
}
1054+
1055+
/* Update our tail offset */
1056+
EndOfHeaders = SectionStart + SectionSize;
1057+
}
1058+
1059+
/* Move to the next section */
1060+
Section++;
1061+
}
1062+
1063+
/* Are we in the first iteration? */
1064+
if (!First)
1065+
{
1066+
/* Go to the end of the file */
1067+
SectionStart = (ULONG_PTR)VirtualAddress + VirtualSize;
1068+
1069+
/* Is there still some slack space left? */
1070+
if (EndOfHeaders < SectionStart)
1071+
{
1072+
/* Zero it out */
1073+
Slack = SectionStart - EndOfHeaders;
1074+
RtlZeroMemory((PVOID)EndOfHeaders, Slack);
1075+
}
1076+
}
1077+
1078+
/* Did the first iteration complete OK? */
1079+
if ((NT_SUCCESS(Status)) && !(First))
1080+
{
1081+
/* Check how many non-image bytes are left in the file */
1082+
RemainingLength = FileSize - Offset;
1083+
while (RemainingLength)
1084+
{
1085+
/* See if the read will fit into our local buffer */
1086+
if (RemainingLength >= sizeof(LocalBuffer))
1087+
{
1088+
/* Nope, cap it */
1089+
BytesRead = sizeof(LocalBuffer);
1090+
}
1091+
else
1092+
{
1093+
/* Yes, but there's less to read */
1094+
BytesRead = RemainingLength;
1095+
}
1096+
1097+
/* Read 1024 bytes into the local buffer */
1098+
Status = ImgpReadAtFileOffset(LocalFile,
1099+
BytesRead,
1100+
Offset,
1101+
LocalBuffer,
1102+
&BytesRead);
1103+
if (!(NT_SUCCESS(Status)) || !(BytesRead))
1104+
{
1105+
Status = STATUS_FILE_INVALID;
1106+
goto Quickie;
1107+
}
1108+
1109+
/* Advance the offset and reduce the length */
1110+
RemainingLength -= BytesRead;
1111+
Offset += BytesRead;
1112+
1113+
/* Compute the checksum of this leftover space */
1114+
PartialSum = BlUtlCheckSum(PartialSum,
1115+
LocalBuffer,
1116+
BytesRead,
1117+
0x10002);
1118+
}
1119+
1120+
/* Finally, calculate the final checksum and compare it */
1121+
FinalSum = FileSize + PartialSum;
1122+
if ((FinalSum != CheckSum) && (PartialSum == 0xFFFF))
1123+
{
1124+
/* It hit overflow, so set it to the file size */
1125+
FinalSum = FileSize;
1126+
}
1127+
1128+
/* If the checksum doesn't match, and caller is enforcing, bail out */
1129+
EfiPrintf(L"Final checksum: %lx. Original: %lx\r\n", FinalSum, CheckSum);
1130+
if ((FinalSum != CheckSum) && !(Flags & 0x10000))
1131+
{
1132+
Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
1133+
goto Quickie;
1134+
}
1135+
}
1136+
8491137
EfiPrintf(L"MORE PE TODO: %lx\r\n", NtHeaders->OptionalHeader.AddressOfEntryPoint);
8501138
EfiStall(100000000);
8511139

0 commit comments

Comments
 (0)