--- /dev/null
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __R2R_CHECKER_H__
+#define __R2R_CHECKER_H__
+
+#include <string>
+
+bool isR2RImage(std::string fileName);
+
+#endif /* __R2R_CHECKER_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <pal.h>
+#include <pal_endian.h>
+#include <ntimage.h>
+
+#include <inc/corhdr.h>
+#include <inc/readytorun.h>
+
+#include <log.h>
+#include <r2r_checker.h>
+
+static inline UINT AlignUp(UINT value, UINT alignment)
+{
+ return (value + alignment - 1) & ~(alignment - 1);
+}
+
+static inline UINT64 AlignUp(UINT64 value, UINT alignment)
+{
+ return (value + alignment - 1)& ~(UINT64)(alignment - 1);
+}
+
+static IMAGE_NT_HEADERS* getNTHeaders(void* pAddr)
+{
+ IMAGE_DOS_HEADER* pDOS = (IMAGE_DOS_HEADER*)pAddr;
+ if (pDOS->e_magic != VAL16(IMAGE_DOS_SIGNATURE)) return NULL;
+
+ return (IMAGE_NT_HEADERS*)((ULONG_PTR)pAddr + VAL32(pDOS->e_lfanew));
+}
+
+static IMAGE_DATA_DIRECTORY* getCorDirectoryEntry(IMAGE_NT_HEADERS* pNTHeaders)
+{
+ IMAGE_DATA_DIRECTORY* pDir = NULL;
+ if (pNTHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {
+ pDir = (IMAGE_DATA_DIRECTORY*)((ULONG_PTR)(pNTHeaders)
+ + offsetof(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory)
+ + IMAGE_DIRECTORY_ENTRY_COMHEADER * sizeof(IMAGE_DATA_DIRECTORY));
+ } else if (pNTHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
+ pDir = (IMAGE_DATA_DIRECTORY*)((ULONG_PTR)(pNTHeaders)
+ + offsetof(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory)
+ + IMAGE_DIRECTORY_ENTRY_COMHEADER * sizeof(IMAGE_DATA_DIRECTORY));
+ } else {
+ _SERR("Invalid Optional Header Magic Number: 0x%x", VAL16(pNTHeaders->OptionalHeader.Magic));
+ }
+
+ return pDir;
+}
+
+static IMAGE_SECTION_HEADER* findFirstSection(IMAGE_NT_HEADERS* pNTHeaders)
+{
+ return (IMAGE_SECTION_HEADER*)(
+ (ULONG_PTR)(pNTHeaders) +
+ offsetof(IMAGE_NT_HEADERS, OptionalHeader) +
+ VAL16(pNTHeaders->FileHeader.SizeOfOptionalHeader));
+}
+
+static IMAGE_SECTION_HEADER* getSection(IMAGE_NT_HEADERS* pNTHeaders, UINT rva) {
+ IMAGE_SECTION_HEADER* section = (IMAGE_SECTION_HEADER*)(findFirstSection(pNTHeaders));
+ IMAGE_SECTION_HEADER* sectionEnd = section + VAL16(pNTHeaders->FileHeader.NumberOfSections);
+ while (section < sectionEnd) {
+ if (rva < (VAL32(section->VirtualAddress)
+ + AlignUp((UINT)VAL32(section->Misc.VirtualSize), (UINT)VAL32(pNTHeaders->OptionalHeader.SectionAlignment)))) {
+ if (rva < VAL32(section->VirtualAddress)) {
+ return NULL;
+ } else {
+ return section;
+ }
+ }
+ section++;
+ }
+
+ return NULL;
+}
+
+static ULONG_PTR getDirectoryData(void* pBaseAddr, IMAGE_NT_HEADERS* pNTHeaders, IMAGE_DATA_DIRECTORY* pDir) {
+ UINT rva = pDir->VirtualAddress;
+ if (rva == 0) {
+ return 0;
+ }
+
+ IMAGE_SECTION_HEADER* section = getSection(pNTHeaders, rva);
+ if (!section) {
+ return 0;
+ }
+
+ return (ULONG_PTR)pBaseAddr + rva - VAL32(section->VirtualAddress) + VAL32(section->PointerToRawData);
+}
+
+static bool hasValidR2RHeader(void* pAddr)
+{
+ IMAGE_NT_HEADERS* pNTHeaders = getNTHeaders(pAddr);
+ if (!pNTHeaders) {
+ _SERR("Invalid NT Header");
+ return false;
+ }
+
+ IMAGE_DATA_DIRECTORY* pCorDir = getCorDirectoryEntry(pNTHeaders);
+ if (!pCorDir) {
+ _SERR("Invalid Cor Data Directory");
+ return false;
+ }
+
+ IMAGE_COR20_HEADER* pCor = (IMAGE_COR20_HEADER*)getDirectoryData(pAddr, pNTHeaders, pCorDir);
+ if (!pCor) {
+ _SERR("Invalid Cor Header");
+ return false;
+ }
+
+ IMAGE_DATA_DIRECTORY* pR2RDir = &pCor->ManagedNativeHeader;
+ if (VAL32(pR2RDir->Size) >= sizeof(READYTORUN_HEADER)) {
+ READYTORUN_HEADER* pR2RHeader = (READYTORUN_HEADER*)getDirectoryData(pAddr, pNTHeaders, pR2RDir);
+ if (!pR2RHeader) {
+ return false;
+ }
+
+ if (pR2RHeader->Signature != VAL16(READYTORUN_SIGNATURE)) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool isR2RImage(std::string fileName)
+{
+ int fd;
+ struct stat sb;
+ if ((fd = open(fileName.c_str(), O_RDONLY)) == -1) {
+ _SERR("File Not Found: %s", fileName.c_str());
+ return false;
+ }
+
+ if (fstat(fd, &sb) == -1) {
+ return false;
+ }
+
+ void* pAddr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (pAddr == MAP_FAILED) {
+ _SERR("Fail to Map File: %s", fileName.c_str());
+ close(fd);
+ return false;
+ }
+
+ bool ret = hasValidR2RHeader(pAddr);
+
+ munmap(pAddr, sb.st_size);
+ close(fd);
+ return ret;
+}