2 * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include <pal_endian.h>
26 #include <inc/corhdr.h>
27 #include <inc/readytorun.h>
30 #include <r2r_checker.h>
32 static inline UINT AlignUp(UINT value, UINT alignment)
34 return (value + alignment - 1) & ~(alignment - 1);
37 static inline UINT64 AlignUp(UINT64 value, UINT alignment)
39 return (value + alignment - 1)& ~(UINT64)(alignment - 1);
42 static IMAGE_NT_HEADERS* getNTHeaders(void* pAddr)
44 IMAGE_DOS_HEADER* pDOS = (IMAGE_DOS_HEADER*)pAddr;
45 if (pDOS->e_magic != VAL16(IMAGE_DOS_SIGNATURE)) return NULL;
47 return (IMAGE_NT_HEADERS*)((ULONG_PTR)pAddr + VAL32(pDOS->e_lfanew));
50 static IMAGE_DATA_DIRECTORY* getCorDirectoryEntry(IMAGE_NT_HEADERS* pNTHeaders)
52 IMAGE_DATA_DIRECTORY* pDir = NULL;
53 if (pNTHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {
54 pDir = (IMAGE_DATA_DIRECTORY*)((ULONG_PTR)(pNTHeaders)
55 + offsetof(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory)
56 + IMAGE_DIRECTORY_ENTRY_COMHEADER * sizeof(IMAGE_DATA_DIRECTORY));
57 } else if (pNTHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
58 pDir = (IMAGE_DATA_DIRECTORY*)((ULONG_PTR)(pNTHeaders)
59 + offsetof(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory)
60 + IMAGE_DIRECTORY_ENTRY_COMHEADER * sizeof(IMAGE_DATA_DIRECTORY));
62 _SERR("Invalid Optional Header Magic Number: 0x%x", VAL16(pNTHeaders->OptionalHeader.Magic));
68 static IMAGE_SECTION_HEADER* findFirstSection(IMAGE_NT_HEADERS* pNTHeaders)
70 return (IMAGE_SECTION_HEADER*)(
71 (ULONG_PTR)(pNTHeaders) +
72 offsetof(IMAGE_NT_HEADERS, OptionalHeader) +
73 VAL16(pNTHeaders->FileHeader.SizeOfOptionalHeader));
76 static IMAGE_SECTION_HEADER* getSection(IMAGE_NT_HEADERS* pNTHeaders, UINT rva) {
77 IMAGE_SECTION_HEADER* section = (IMAGE_SECTION_HEADER*)(findFirstSection(pNTHeaders));
78 IMAGE_SECTION_HEADER* sectionEnd = section + VAL16(pNTHeaders->FileHeader.NumberOfSections);
79 while (section < sectionEnd) {
80 if (rva < (VAL32(section->VirtualAddress)
81 + AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(pNTHeaders->OptionalHeader.SectionAlignment)))) {
82 if (rva < VAL32(section->VirtualAddress)) {
94 static ULONG_PTR getDirectoryData(void* pBaseAddr, IMAGE_NT_HEADERS* pNTHeaders, IMAGE_DATA_DIRECTORY* pDir) {
95 UINT rva = pDir->VirtualAddress;
100 IMAGE_SECTION_HEADER* section = getSection(pNTHeaders, rva);
105 return (ULONG_PTR)pBaseAddr + rva - VAL32(section->VirtualAddress) + VAL32(section->PointerToRawData);
108 static bool hasValidR2RHeader(void* pAddr)
110 IMAGE_NT_HEADERS* pNTHeaders = getNTHeaders(pAddr);
112 _SERR("Invalid NT Header");
116 IMAGE_DATA_DIRECTORY* pCorDir = getCorDirectoryEntry(pNTHeaders);
118 _SERR("Invalid Cor Data Directory");
122 IMAGE_COR20_HEADER* pCor = (IMAGE_COR20_HEADER*)getDirectoryData(pAddr, pNTHeaders, pCorDir);
124 _SERR("Invalid Cor Header");
128 IMAGE_DATA_DIRECTORY* pR2RDir = &pCor->ManagedNativeHeader;
129 if (VAL32(pR2RDir->Size) >= sizeof(READYTORUN_HEADER)) {
130 READYTORUN_HEADER* pR2RHeader = (READYTORUN_HEADER*)getDirectoryData(pAddr, pNTHeaders, pR2RDir);
135 if (pR2RHeader->Signature != VAL16(READYTORUN_SIGNATURE)) {
143 bool isR2RImage(std::string fileName)
147 if ((fd = open(fileName.c_str(), O_RDONLY)) == -1) {
148 _SERR("File Not Found: %s", fileName.c_str());
152 if (fstat(fd, &sb) == -1) {
156 void* pAddr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
157 if (pAddr == MAP_FAILED) {
158 _SERR("Fail to Map File: %s", fileName.c_str());
163 bool ret = hasValidR2RHeader(pAddr);
165 munmap(pAddr, sb.st_size);