Added a simple PE loaded dedicated for volatileMetadata (#2607)

This commit is contained in:
Yang Liu 2025-05-06 19:45:38 +08:00 committed by GitHub
parent 11563f3b62
commit 8d7db7f1fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 338 additions and 11 deletions

View File

@ -403,6 +403,7 @@ set(ELFLOADER_SRC
"${BOX64_ROOT}/src/tools/rbtree.c"
"${BOX64_ROOT}/src/tools/env.c"
"${BOX64_ROOT}/src/tools/wine_tools.c"
"${BOX64_ROOT}/src/tools/pe_tools.c"
"${BOX64_ROOT}/src/wrapped/generated/wrapper.c"
)
if(NOT STATICBUILD)

7
src/include/pe_tools.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef __PE_TOOLS_H__
#define __PE_TOOLS_H__
void ParseVolatileMetadata(char* filename, void* addr);
#endif // __PE_TOOLS_H__

View File

@ -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__

316
src/tools/pe_tools.c Normal file
View File

@ -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);
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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);