Skip to content
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion CAPE/CAPE.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,33 @@ extern void UnpackerInit();
extern BOOL SetInitialBreakpoints(PVOID ImageBase);
extern BOOL BreakpointsSet, TraceRunning;
extern lookup_t g_dotnet_jit;

dotnet_module_cache_t g_dotnet_modules[128] = {0};
int g_dotnet_modules_count = 0;

void CacheDotNetModule(ULONG_PTR ModuleBase, DWORD MetadataRVA, DWORD MetadataSize) {
if (g_dotnet_modules_count >= 128) return;
// Prevent duplicate caching
for (int i = 0; i < g_dotnet_modules_count; i++) {
if (g_dotnet_modules[i].ModuleBase == ModuleBase) {
return;
}
}
g_dotnet_modules[g_dotnet_modules_count].ModuleBase = ModuleBase;
g_dotnet_modules[g_dotnet_modules_count].MetadataRVA = MetadataRVA;
g_dotnet_modules[g_dotnet_modules_count].MetadataSize = MetadataSize;
g_dotnet_modules_count++;
DebugOutput("CacheDotNetModule: Cached module base 0x%p (Metadata RVA 0x%x, Size 0x%x).\n", (PVOID)ModuleBase, MetadataRVA, MetadataSize);
}

dotnet_module_cache_t* FindCachedDotNetModule(ULONG_PTR ModuleBase) {
for (int i = 0; i < g_dotnet_modules_count; i++) {
if (g_dotnet_modules[i].ModuleBase == ModuleBase) {
return &g_dotnet_modules[i];
}
}
return NULL;
}
extern char* StringsFile;
extern HANDLE Strings;

Expand Down Expand Up @@ -824,7 +851,7 @@ PVOID GetFunctionAddress(HMODULE ModuleBase, PCHAR FunctionName)
}


if (!FunctionAddress && ModuleBase == GetModuleHandle("clr"))
if (!FunctionAddress && (ModuleBase == GetModuleHandle("clr") || ModuleBase == GetModuleHandle("mscorwks") || ModuleBase == GetModuleHandle("coreclr")))
return GetCLRAddress(ModuleBase, FunctionName);

if (!FunctionAddress && ModuleBase == GetModuleHandle("clrjit"))
Expand Down
12 changes: 12 additions & 0 deletions CAPE/CAPE.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ void DumpStrings(void);
BOOL ProcessDumped;
unsigned int DumpCount, DotNetCacheDumpCount;

typedef struct {
ULONG_PTR ModuleBase;
DWORD MetadataRVA;
DWORD MetadataSize;
} dotnet_module_cache_t;

extern dotnet_module_cache_t g_dotnet_modules[128];
extern int g_dotnet_modules_count;

void CacheDotNetModule(ULONG_PTR ModuleBase, DWORD MetadataRVA, DWORD MetadataSize);
dotnet_module_cache_t* FindCachedDotNetModule(ULONG_PTR ModuleBase);

SYSTEM_INFO SystemInfo;
PVOID CallingModule;

Expand Down
62 changes: 62 additions & 0 deletions CAPE/ScyllaHarness.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,65 @@ extern "C" int ScyllaDumpProcess(HANDLE hProcess, DWORD_PTR ModuleBase, DWORD_PT
return 0;
}

static void HealDotNetPEHeaders(DWORD_PTR Buffer) {
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)Buffer;

// 1. Heal DOS Signature ("MZ" = 0x5A4D)
if (pDos->e_magic != IMAGE_DOS_SIGNATURE) {
pDos->e_magic = IMAGE_DOS_SIGNATURE;
pDos->e_lfanew = 0x80; // Standard NT header offset
}

PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((PBYTE)Buffer + pDos->e_lfanew);

// 2. Heal NT Signature ("PE\0\0" = 0x00004550)
if (pNt->Signature != IMAGE_NT_SIGNATURE) {
pNt->Signature = IMAGE_NT_SIGNATURE;
#ifdef _WIN64
pNt->FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64; // Set to standard 64-bit AMD64 machine target
pNt->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
#else
pNt->FileHeader.Machine = IMAGE_FILE_MACHINE_I386; // Set to standard 32-bit x86 machine target
pNt->OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
#endif
pNt->FileHeader.NumberOfSections = 3; // Standard fallback section count
}

// 3. Heal CLR COM Descriptor Directory (index 14)
PIMAGE_DATA_DIRECTORY pClrDir = &pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
if (pClrDir->VirtualAddress == 0 || pClrDir->Size == 0) {
dotnet_module_cache_t* pCache = FindCachedDotNetModule((ULONG_PTR)Buffer);
DWORD metadataRVA = pCache ? pCache->MetadataRVA : 0;
DWORD metadataSize = pCache ? pCache->MetadataSize : 0;

// Fallback: If no cached metadata RVA exists, dynamically scan the buffer for the "BSJB" magic (0x424A5342)
if (metadataRVA == 0) {
__try {
PBYTE pStart = (PBYTE)Buffer;
// Limit scan to 2MB to keep it safe and fast
PBYTE pEnd = pStart + 0x200000;
for (PBYTE p = pStart + 0x200; p < pEnd - 4; p++) {
if (*(DWORD*)p == 0x424A5342) { // "BSJB"
metadataRVA = (DWORD)(p - pStart);
metadataSize = 0x10000; // Safe default fallback size (64KB)
DebugOutput("HealDotNetPEHeaders: Successfully found BSJB metadata magic in memory at offset 0x%x without cache.\n", metadataRVA);
break;
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
DebugOutput("HealDotNetPEHeaders: Exception occurred scanning for BSJB magic.\n");
}
}

if (metadataRVA != 0) {
pClrDir->VirtualAddress = metadataRVA;
pClrDir->Size = metadataSize;
DebugOutput("HealDotNetPEHeaders: Successfully healed zeroed CLR Data Directory to RVA 0x%x (Size 0x%x).\n", metadataRVA, metadataSize);
}
}
}

//**************************************************************************************
extern "C" int ScyllaDumpPE(DWORD_PTR Buffer)
//**************************************************************************************
Expand All @@ -417,6 +476,9 @@ extern "C" int ScyllaDumpPE(DWORD_PTR Buffer)

ProcessAccessHelp::setCurrentProcessAsTarget();

// Surgically heal zeroed/mangled PE headers and CLR directories in-memory right before Scylla is called
HealDotNetPEHeaders(Buffer);

DebugOutput("DumpPE: Instantiating PeParser with address: 0x%p.\n", Buffer);

peFile = new PeParser((DWORD_PTR)Buffer, TRUE);
Expand Down
5 changes: 5 additions & 0 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,11 @@ void parse_config_line(char* line)
if (g_config.trace_all)
DebugOutput("Config: Trace all enabled.\n");
}
else if (!stricmp(key, "jit-trace-all")) {
g_config.jit_trace_all = value[0] == '1';
if (g_config.jit_trace_all)
DebugOutput("Config: JIT verbose tracing enabled.\n");
}
else if (!stricmp(key, "trace-into-api")) {
unsigned int x = 0;
char *p2;
Expand Down
1 change: 1 addition & 0 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ struct _g_config {
char *str[MAX_PATH];

int trace_all;
int jit_trace_all;
int step_out;
int file_offsets;
int no_logs;
Expand Down
Loading