about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYang Liu <liuyang22@iscas.ac.cn>2025-05-06 19:45:38 +0800
committerGitHub <noreply@github.com>2025-05-06 13:45:38 +0200
commit8d7db7f1fb1002adf06a9a3a59302d6a8f8f989a (patch)
treefd5675bec67ddd8ecdc568b4de7885d53e8e8202 /src
parent11563f3b62be60d443bcbcd33d02555ef6aa1ba5 (diff)
downloadbox64-8d7db7f1fb1002adf06a9a3a59302d6a8f8f989a.tar.gz
box64-8d7db7f1fb1002adf06a9a3a59302d6a8f8f989a.zip
Added a simple PE loaded dedicated for volatileMetadata (#2607)
Diffstat (limited to 'src')
-rw-r--r--src/include/pe_tools.h7
-rw-r--r--src/include/wine_tools.h2
-rw-r--r--src/tools/pe_tools.c316
-rw-r--r--src/tools/wine_tools.c13
-rw-r--r--src/wrapped/wrappedlibc.c10
5 files changed, 337 insertions, 11 deletions
diff --git a/src/include/pe_tools.h b/src/include/pe_tools.h
new file mode 100644
index 00000000..54c3d42e
--- /dev/null
+++ b/src/include/pe_tools.h
@@ -0,0 +1,7 @@
+#ifndef __PE_TOOLS_H__
+#define __PE_TOOLS_H__
+
+
+void ParseVolatileMetadata(char* filename, void* addr);
+
+#endif // __PE_TOOLS_H__
diff --git a/src/include/wine_tools.h b/src/include/wine_tools.h
index 4bb0aa3a..d8cefcbc 100644
--- a/src/include/wine_tools.h
+++ b/src/include/wine_tools.h
@@ -10,6 +10,6 @@ void* get_wine_prereserve(void);
 void dynarec_wine_prereserve(void);
 #endif
 
-void DetectUnityPlayer(int fd);
+void DetectUnityPlayer(char* filename);
 
 #endif //__WINE_TOOLS_H__
diff --git a/src/tools/pe_tools.c b/src/tools/pe_tools.c
new file mode 100644
index 00000000..46c8a203
--- /dev/null
+++ b/src/tools/pe_tools.c
@@ -0,0 +1,316 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stddef.h>
+
+#include "debug.h"
+
+typedef uint8_t BYTE;
+typedef uint16_t WORD;
+typedef uint32_t DWORD;
+typedef int32_t LONG;
+typedef uint32_t ULONG;
+typedef uint64_t ULONGLONG;
+
+#define IMAGE_DOS_SIGNATURE               0x5A4D
+#define IMAGE_NT_SIGNATURE                0x00004550
+#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
+#define IMAGE_NT_OPTIONAL_HDR32_MAGIC     0x10B
+#define IMAGE_NT_OPTIONAL_HDR64_MAGIC     0x20B
+
+typedef struct _IMAGE_DOS_HEADER {
+    WORD e_magic;
+    WORD e_cblp;
+    WORD e_cp;
+    WORD e_crlc;
+    WORD e_cparhdr;
+    WORD e_minalloc;
+    WORD e_maxalloc;
+    WORD e_ss;
+    WORD e_sp;
+    WORD e_csum;
+    WORD e_ip;
+    WORD e_cs;
+    WORD e_lfarlc;
+    WORD e_ovno;
+    WORD e_res[4];
+    WORD e_oemid;
+    WORD e_oeminfo;
+    WORD e_res2[10];
+    LONG e_lfanew;
+} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
+
+typedef struct _IMAGE_FILE_HEADER {
+    WORD Machine;
+    WORD NumberOfSections;
+    DWORD TimeDateStamp;
+    DWORD PointerToSymbolTable;
+    DWORD NumberOfSymbols;
+    WORD SizeOfOptionalHeader;
+    WORD Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+
+typedef struct _IMAGE_DATA_DIRECTORY {
+    DWORD VirtualAddress;
+    DWORD Size;
+} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
+
+typedef struct _IMAGE_OPTIONAL_HEADER64 {
+    WORD Magic;
+    BYTE MajorLinkerVersion;
+    BYTE MinorLinkerVersion;
+    DWORD SizeOfCode;
+    DWORD SizeOfInitializedData;
+    DWORD SizeOfUninitializedData;
+    DWORD AddressOfEntryPoint;
+    DWORD BaseOfCode;
+    ULONGLONG ImageBase;
+    DWORD SectionAlignment;
+    DWORD FileAlignment;
+    WORD MajorOperatingSystemVersion;
+    WORD MinorOperatingSystemVersion;
+    WORD MajorImageVersion;
+    WORD MinorImageVersion;
+    WORD MajorSubsystemVersion;
+    WORD MinorSubsystemVersion;
+    DWORD Win32VersionValue;
+    DWORD SizeOfImage;
+    DWORD SizeOfHeaders;
+    DWORD CheckSum;
+    WORD Subsystem;
+    WORD DllCharacteristics;
+    ULONGLONG SizeOfStackReserve;
+    ULONGLONG SizeOfStackCommit;
+    ULONGLONG SizeOfHeapReserve;
+    ULONGLONG SizeOfHeapCommit;
+    DWORD LoaderFlags;
+    DWORD NumberOfRvaAndSizes;
+    IMAGE_DATA_DIRECTORY DataDirectory[16];
+} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
+
+typedef struct _IMAGE_NT_HEADERS64 {
+    DWORD Signature;
+    IMAGE_FILE_HEADER FileHeader;
+    IMAGE_OPTIONAL_HEADER64 OptionalHeader;
+} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
+
+typedef struct _IMAGE_SECTION_HEADER {
+    BYTE Name[8];
+    union {
+        DWORD PhysicalAddress;
+        DWORD VirtualSize;
+    } Misc;
+    DWORD VirtualAddress;
+    DWORD SizeOfRawData;
+    DWORD PointerToRawData;
+    DWORD PointerToRelocations;
+    DWORD PointerToLinenumbers;
+    WORD NumberOfRelocations;
+    WORD NumberOfLinenumbers;
+    DWORD Characteristics;
+} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
+
+typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64 {
+    DWORD Size;
+    DWORD TimeDateStamp;
+    WORD MajorVersion;
+    WORD MinorVersion;
+    DWORD GlobalFlagsClear;
+    DWORD GlobalFlagsSet;
+    DWORD CriticalSectionDefaultTimeout;
+    ULONGLONG DeCommitFreeBlockThreshold;
+    ULONGLONG DeCommitTotalFreeThreshold;
+    ULONGLONG LockPrefixTable;
+    ULONGLONG MaximumAllocationSize;
+    ULONGLONG VirtualMemoryThreshold;
+    ULONGLONG ProcessAffinityMask;
+    DWORD ProcessHeapFlags;
+    WORD CSDVersion;
+    WORD DependentLoadFlags;
+    ULONGLONG EditList;
+    ULONGLONG SecurityCookie;
+    ULONGLONG SEHandlerTable;
+    ULONGLONG SEHandlerCount;
+    ULONGLONG GuardCFCheckFunctionPointer;
+    ULONGLONG GuardCFDispatchFunctionPointer;
+    ULONGLONG GuardCFFunctionTable;
+    ULONGLONG GuardCFFunctionCount;
+    DWORD GuardFlags;
+    ULONGLONG CodeIntegrity;
+    ULONGLONG GuardAddressTakenIatEntryTable;
+    ULONGLONG GuardAddressTakenIatEntryCount;
+    ULONGLONG GuardLongJumpTargetTable;
+    ULONGLONG GuardLongJumpTargetCount;
+    ULONGLONG DynamicValueRelocTable;
+    ULONGLONG CHPEMetadataPointer;
+    ULONGLONG GuardRFFailureRoutine;
+    ULONGLONG GuardRFFailureRoutineFunctionPointer;
+    DWORD DynamicValueRelocTableOffset;
+    WORD DynamicValueRelocTableSection;
+    WORD Reserved2;
+    ULONGLONG GuardRFVerifyStackPointerFunctionPointer;
+    DWORD HotPatchTableOffset;
+    DWORD Reserved3;
+    ULONGLONG EnclaveConfigurationPointer;
+    ULONGLONG VolatileMetadataPointer;
+    ULONGLONG GuardEHContinuationTable;
+    ULONGLONG GuardEHContinuationCount;
+    ULONGLONG GuardXFGCheckFunctionPointer;
+    ULONGLONG GuardXFGDispatchFunctionPointer;
+    ULONGLONG GuardXFGTableDispatchFunctionPointer;
+    ULONGLONG CastGuardOsDeterminedFailureMode;
+    ULONGLONG GuardMemcpyFunctionPointer;
+} IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;
+
+typedef struct _IMAGE_VOLATILE_METADATA {
+    DWORD Size;
+    DWORD Version;
+    DWORD VolatileAccessTable;
+    DWORD VolatileAccessTableSize;
+    DWORD VolatileInfoRangeTable;
+    DWORD VolatileInfoRangeTableSize;
+} IMAGE_VOLATILE_METADATA, *PIMAGE_VOLATILE_METADATA;
+
+typedef struct _IMAGE_VOLATILE_RVA_METADATA {
+    ULONG Rva;
+} IMAGE_VOLATILE_RVA_METADATA, *PIMAGE_VOLATILE_RVA_METADATA;
+
+typedef struct _IMAGE_VOLATILE_RANGE_METADATA {
+    ULONG Rva;
+    ULONG Size;
+} IMAGE_VOLATILE_RANGE_METADATA, *PIMAGE_VOLATILE_RANGE_METADATA;
+
+static int HasSuffix(const char* str, const char* suffix)
+{
+    size_t lenstr = strlen(str);
+    size_t lensuffix = strlen(suffix);
+    if (lensuffix > lenstr) return 0;
+    return strcmp(str + lenstr - lensuffix, suffix) == 0;
+}
+
+DWORD RVAToFileOffset(PIMAGE_SECTION_HEADER sections, DWORD numberOfSections, DWORD rva, BYTE* fileBuffer, size_t fileSize)
+{
+    for (DWORD i = 0; i < numberOfSections; i++) {
+        PIMAGE_SECTION_HEADER section = &sections[i];
+        if (rva >= section->VirtualAddress && rva < section->VirtualAddress + section->SizeOfRawData) {
+            DWORD offset = rva - section->VirtualAddress + section->PointerToRawData;
+            if (offset < fileSize) {
+                return offset;
+            }
+        }
+    }
+    return 0;
+}
+
+void ParseVolatileMetadata(char* filename, void* addr)
+{
+    if (!filename) return;
+    if (!HasSuffix(filename, ".dll")) {
+        return;
+    }
+
+    FILE* file = fopen(filename, "rb");
+    if (!file) return;
+
+    fseek(file, 0, SEEK_END);
+    long size = ftell(file);
+    fseek(file, 0, SEEK_SET);
+
+    char* buffer = (char*)malloc(size);
+    if (!buffer) {
+        fclose(file);
+        return;
+    }
+
+    if (fread(buffer, 1, size, file) != size) {
+        free(buffer);
+        fclose(file);
+        return;
+    }
+    fclose(file);
+
+    IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)buffer;
+    if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
+        free(buffer);
+        return;
+    }
+
+    PIMAGE_NT_HEADERS64 ntHeaders64 = (PIMAGE_NT_HEADERS64)(buffer + dosHeader->e_lfanew);
+    if (ntHeaders64->Signature != IMAGE_NT_SIGNATURE || ntHeaders64->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+        free(buffer);
+        return;
+    }
+
+    int numberOfSections = ntHeaders64->FileHeader.NumberOfSections;
+    if (numberOfSections <= 0) {
+        free(buffer);
+        return;
+    }
+    IMAGE_DATA_DIRECTORY loadConfigDir = ntHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];
+    if (loadConfigDir.VirtualAddress == 0 || loadConfigDir.Size == 0) {
+        free(buffer);
+        return;
+    }
+
+    PIMAGE_SECTION_HEADER sectionHeaders = (PIMAGE_SECTION_HEADER)((void*)ntHeaders64 + sizeof(IMAGE_NT_HEADERS64)); // immediately follows the optional header, if any.
+    DWORD loadConfigOffset = RVAToFileOffset(sectionHeaders, numberOfSections, loadConfigDir.VirtualAddress, (BYTE*)buffer, ntHeaders64->OptionalHeader.SizeOfImage);
+    if (loadConfigOffset == 0) {
+        free(buffer);
+        return;
+    }
+
+    PIMAGE_LOAD_CONFIG_DIRECTORY64 loadConfig = (PIMAGE_LOAD_CONFIG_DIRECTORY64)(buffer + loadConfigOffset);
+    if (loadConfig->Size < offsetof(IMAGE_LOAD_CONFIG_DIRECTORY64, VolatileMetadataPointer) + sizeof(ULONGLONG)) {
+        free(buffer);
+        return;
+    }
+    DWORD volatileMetadataPointer = (DWORD)(loadConfig->VolatileMetadataPointer - ntHeaders64->OptionalHeader.ImageBase);
+    if (volatileMetadataPointer == 0) {
+        free(buffer);
+        return;
+    }
+
+    DWORD volatileMetadataOffset = RVAToFileOffset(sectionHeaders, numberOfSections, volatileMetadataPointer, (BYTE*)buffer, ntHeaders64->OptionalHeader.SizeOfImage);
+    if (volatileMetadataOffset == 0) {
+        free(buffer);
+        return;
+    }
+
+    PIMAGE_VOLATILE_METADATA volatileMetadata = (PIMAGE_VOLATILE_METADATA)(buffer + volatileMetadataOffset);
+    if (volatileMetadata->VolatileAccessTable && volatileMetadata->VolatileAccessTableSize) {
+        printf_log(LOG_INFO, "Parsing volatile metadata of file: %s\n", filename);
+
+        DWORD volatileAccessTableOffset = RVAToFileOffset(sectionHeaders, numberOfSections, volatileMetadata->VolatileAccessTable, (BYTE*)buffer, ntHeaders64->OptionalHeader.SizeOfImage);
+        if (volatileAccessTableOffset == 0) {
+            free(buffer);
+            return;
+        }
+
+        DWORD numEntries = volatileMetadata->VolatileAccessTableSize / sizeof(IMAGE_VOLATILE_RVA_METADATA);
+        PIMAGE_VOLATILE_RVA_METADATA volatileAccessTable = (PIMAGE_VOLATILE_RVA_METADATA)(buffer + volatileAccessTableOffset);
+
+        for (DWORD i = 0; i < numEntries; i++) {
+            ULONG entry = volatileAccessTable[i].Rva;
+            printf_log(LOG_INFO, "Volatile Access Table Entry %d: %08X\n", i, entry);
+        }
+    }
+
+    if (volatileMetadata->VolatileInfoRangeTable && volatileMetadata->VolatileInfoRangeTableSize) {
+        DWORD volatileInfoRangeTableOffset = RVAToFileOffset(sectionHeaders, numberOfSections, volatileMetadata->VolatileInfoRangeTable, (BYTE*)buffer, ntHeaders64->OptionalHeader.SizeOfImage);
+        if (volatileInfoRangeTableOffset == 0) {
+            free(buffer);
+            return;
+        }
+
+        DWORD numEntries = volatileMetadata->VolatileInfoRangeTableSize / sizeof(IMAGE_VOLATILE_RANGE_METADATA);
+        PIMAGE_VOLATILE_RANGE_METADATA volatileRangeMetadata = (PIMAGE_VOLATILE_RANGE_METADATA)(buffer + volatileInfoRangeTableOffset);
+
+        for (DWORD i = 0; i < numEntries; i++) {
+            ULONG Rva = volatileRangeMetadata[i].Rva;
+            ULONG Size = volatileRangeMetadata[i].Size;
+            printf_log(LOG_INFO, "Volatile Range Metadata Entry %d: %08X Size: %08X\n", i, Rva, Size);
+        }
+    }
+}
diff --git a/src/tools/wine_tools.c b/src/tools/wine_tools.c
index 8b0edf14..86a91598 100644
--- a/src/tools/wine_tools.c
+++ b/src/tools/wine_tools.c
@@ -136,16 +136,11 @@ void dynarec_wine_prereserve()
 }
 #endif
 
-void DetectUnityPlayer(int fd)
+void DetectUnityPlayer(char* filename)
 {
     static int unityplayer_detected = 0;
-    if (fd > 0 && BOX64ENV(unityplayer) && !unityplayer_detected) {
-        char filename[4096];
-        char buf[128];
-        sprintf(buf, "/proc/self/fd/%d", fd);
-        ssize_t r = readlink(buf, filename, sizeof(filename) - 1);
-        if (r != -1) filename[r] = 0;
-        if (r > 0 && strlen(filename) > strlen("UnityPlayer.dll") && !strcasecmp(filename + strlen(filename) - strlen("UnityPlayer.dll"), "UnityPlayer.dll")) {
+    if (!filename && BOX64ENV(unityplayer) && !unityplayer_detected) {
+        if (strlen(filename) > strlen("UnityPlayer.dll") && !strcasecmp(filename + strlen(filename) - strlen("UnityPlayer.dll"), "UnityPlayer.dll")) {
             printf_log(LOG_NONE, "Detected UnityPlayer.dll\n");
 #ifdef DYNAREC
             if (!BOX64ENV(dynarec_strongmem)) {
@@ -156,4 +151,4 @@ void DetectUnityPlayer(int fd)
             unityplayer_detected = 1;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/wrapped/wrappedlibc.c b/src/wrapped/wrappedlibc.c
index 58ecd5b4..3761f609 100644
--- a/src/wrapped/wrappedlibc.c
+++ b/src/wrapped/wrappedlibc.c
@@ -68,6 +68,7 @@
 #include "globalsymbols.h"
 #include "env.h"
 #include "wine_tools.h"
+#include "pe_tools.h"
 #include "cleanup.h"
 #ifndef LOG_INFO
 #define LOG_INFO 1
@@ -3032,7 +3033,14 @@ EXPORT void* my_mmap64(x64emu_t* emu, void *addr, size_t length, int prot, int f
     #endif
     if(ret!=MAP_FAILED) {
         if(emu && !(flags&MAP_ANONYMOUS) && (fd>0)) {
-            DetectUnityPlayer(fd);
+            char filename[4096];
+            char buf[128];
+            sprintf(buf, "/proc/self/fd/%d", fd);
+            ssize_t r = readlink(buf, filename, sizeof(filename) - 1);
+            if (r != -1) filename[r] = 0;
+
+            DetectUnityPlayer(filename);
+            // ParseVolatileMetadata(filename, addr);
             // the last_mmap will allow mmap created by wine, even those that have hole, to be fully tracked as one single mmap
             if((ret>=last_mmap_addr[0]) && ret+length<(last_mmap_addr[0]+last_mmap_len[0]))
                 RecordEnvMappings((uintptr_t)last_mmap_addr[0], last_mmap_len[0], fd);