summaryrefslogtreecommitdiff
path: root/src/ildasm/dres.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ildasm/dres.cpp')
-rw-r--r--src/ildasm/dres.cpp317
1 files changed, 317 insertions, 0 deletions
diff --git a/src/ildasm/dres.cpp b/src/ildasm/dres.cpp
new file mode 100644
index 0000000000..0f23fcc036
--- /dev/null
+++ b/src/ildasm/dres.cpp
@@ -0,0 +1,317 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Win32 Resource extractor
+//
+#include "ildasmpch.h"
+
+#ifndef FEATURE_PAL
+#include "debugmacros.h"
+#include "corpriv.h"
+#include "dasmenum.hpp"
+#include "dasmgui.h"
+#include "formattype.h"
+#include "dis.h"
+#include "resource.h"
+#include "ilformatter.h"
+#include "outstring.h"
+
+#include "ceeload.h"
+#include "dynamicarray.h"
+extern IMAGE_COR20_HEADER * g_CORHeader;
+extern IMDInternalImport* g_pImport;
+extern PELoader * g_pPELoader;
+extern IMetaDataImport2* g_pPubImport;
+extern char g_szAsmCodeIndent[];
+extern unsigned g_uConsoleCP;
+
+struct ResourceHeader
+{
+ DWORD dwDataSize;
+ DWORD dwHeaderSize;
+ DWORD dwTypeID;
+ DWORD dwNameID;
+ DWORD dwDataVersion;
+ WORD wMemFlags;
+ WORD wLangID;
+ DWORD dwVersion;
+ DWORD dwCharacteristics;
+ ResourceHeader()
+ {
+ memset(this,0,sizeof(ResourceHeader));
+ dwHeaderSize = sizeof(ResourceHeader);
+ dwTypeID = dwNameID = 0xFFFF;
+ };
+};
+
+struct ResourceNode
+{
+ ResourceHeader ResHdr;
+ IMAGE_RESOURCE_DATA_ENTRY DataEntry;
+ WCHAR* wzType;
+ WCHAR* wzName;
+ ResourceNode(DWORD tid, DWORD nid, DWORD lid, DWORD dataOffset, BYTE* ptrBase)
+ {
+ if(tid & 0x80000000)
+ {
+ ResHdr.dwTypeID = 0;
+ tid &= 0x7FFFFFFF;
+ WORD L = *((WORD*)(ptrBase+tid));
+ wzType = new WCHAR[L+1];
+ memcpy(wzType,ptrBase+tid+sizeof(WORD),L*sizeof(WCHAR));
+ wzType[L]=0;
+ }
+ else
+ {
+ ResHdr.dwTypeID = (0xFFFF |((tid & 0xFFFF)<<16));
+ wzType = NULL;
+ }
+
+ if(nid & 0x80000000)
+ {
+ ResHdr.dwNameID = 0;
+ nid &= 0x7FFFFFFF;
+ WORD L = *((WORD*)(ptrBase+nid));
+ wzName = new WCHAR[L+1];
+ memcpy(wzName, ptrBase+nid+sizeof(WORD), L*sizeof(WCHAR));
+ wzName[L]=0;
+ }
+ else
+ {
+ ResHdr.dwNameID = (0xFFFF |((nid & 0xFFFF)<<16));
+ wzName = NULL;
+ }
+
+ //ResHdr.dwTypeID = (tid & 0x80000000) ? tid : (0xFFFF |((tid & 0xFFFF)<<16));
+ //ResHdr.dwNameID = (nid & 0x80000000) ? nid : (0xFFFF |((nid & 0xFFFF)<<16));
+ ResHdr.wLangID = (WORD)lid;
+ if(ptrBase) memcpy(&DataEntry,(ptrBase+dataOffset),sizeof(IMAGE_RESOURCE_DATA_ENTRY));
+ ResHdr.dwDataSize = DataEntry.Size;
+ };
+ ~ResourceNode()
+ {
+ if(wzType) VDELETE(wzType);
+ if(wzName) VDELETE(wzName);
+ };
+ void Save(FILE* pF)
+ {
+ // Dump them to pF
+ BYTE* pbData;
+ DWORD dwFiller = 0;
+ BYTE bNil[3] = {0,0,0};
+ // For each resource write header and data
+ if(g_pPELoader->getVAforRVA(VAL32(DataEntry.OffsetToData), (void **) &pbData))
+ {
+ //fwrite(&(g_prResNodePtr[i]->ResHdr),g_prResNodePtr[i]->ResHdr.dwHeaderSize,1,pF);
+ ResHdr.dwHeaderSize = sizeof(ResourceHeader);
+ if(wzType) ResHdr.dwHeaderSize += (DWORD)((wcslen(wzType) + 1)*sizeof(WCHAR) - sizeof(DWORD));
+ if(wzName) ResHdr.dwHeaderSize += (DWORD)((wcslen(wzName) + 1)*sizeof(WCHAR) - sizeof(DWORD));
+
+ //---- Constant part of the header: DWORD,DWORD
+ fwrite(&ResHdr.dwDataSize, sizeof(DWORD),1,pF);
+ fwrite(&ResHdr.dwHeaderSize, sizeof(DWORD),1,pF);
+ //--- Variable part of header: type and name
+ if(wzType)
+ {
+ fwrite(wzType,(wcslen(wzType) + 1)*sizeof(WCHAR), 1, pF);
+ dwFiller += (DWORD)wcslen(wzType) + 1;
+ }
+ else
+ fwrite(&ResHdr.dwTypeID,sizeof(DWORD),1,pF);
+ if(wzName)
+ {
+ fwrite(wzName,(wcslen(wzName) + 1)*sizeof(WCHAR), 1, pF);
+ dwFiller += (DWORD)wcslen(wzName) + 1;
+ }
+ else
+ fwrite(&ResHdr.dwNameID,sizeof(DWORD),1,pF);
+
+ // Align remaining fields on DWORD
+ if(dwFiller & 1)
+ fwrite(bNil,2,1,pF);
+
+ //---- Constant part of the header: DWORD,WORD,WORD,DWORD,DWORD
+ fwrite(&ResHdr.dwDataVersion,8*sizeof(WORD),1,pF);
+ //---- Header done, now data
+ fwrite(pbData,VAL32(DataEntry.Size),1,pF);
+ dwFiller = VAL32(DataEntry.Size) & 3;
+ if(dwFiller)
+ {
+ dwFiller = 4 - dwFiller;
+ fwrite(bNil,dwFiller,1,pF);
+ }
+ }
+ };
+};
+
+
+#define RES_FILE_DUMP_ENABLED
+
+DWORD DumpResourceToFile(__in __nullterminated WCHAR* wzFileName)
+{
+
+ BYTE* pbResBase;
+ FILE* pF = NULL;
+ DWORD ret = 0;
+ DWORD dwResDirRVA;
+ DWORD dwResDirSize;
+ unsigned ulNumResNodes=0;
+ DynamicArray<ResourceNode*> g_prResNodePtr;
+
+ if (g_pPELoader->IsPE32())
+ {
+ IMAGE_OPTIONAL_HEADER32 *pOptHeader = &(g_pPELoader->ntHeaders32()->OptionalHeader);
+
+ dwResDirRVA = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
+ dwResDirSize = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
+ }
+ else
+ {
+ IMAGE_OPTIONAL_HEADER64 *pOptHeader = &(g_pPELoader->ntHeaders64()->OptionalHeader);
+
+ dwResDirRVA = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
+ dwResDirSize = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
+ }
+
+ if(dwResDirRVA && dwResDirSize)
+ {
+ if(g_pPELoader->getVAforRVA(dwResDirRVA, (void **) &pbResBase))
+ {
+ // First, pull out all resource nodes (tree leaves), see ResourceNode struct
+ PIMAGE_RESOURCE_DIRECTORY pirdType = (PIMAGE_RESOURCE_DIRECTORY)pbResBase;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeType = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbResBase+sizeof(IMAGE_RESOURCE_DIRECTORY));
+ DWORD dwTypeID;
+ unsigned short i = 0,N = pirdType->NumberOfNamedEntries+pirdType->NumberOfIdEntries;
+ PAL_CPP_TRY {
+ for(i=0; i < N; i++, pirdeType++)
+ {
+ dwTypeID = VAL32(IMAGE_RDE_NAME(pirdeType));
+ if(IMAGE_RDE_OFFSET_FIELD(pirdeType, DataIsDirectory))
+ {
+ BYTE* pbNameBase = pbResBase + VAL32(IMAGE_RDE_OFFSET_FIELD(pirdeType, OffsetToDirectory));
+ PIMAGE_RESOURCE_DIRECTORY pirdName = (PIMAGE_RESOURCE_DIRECTORY)pbNameBase;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeName = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbNameBase+sizeof(IMAGE_RESOURCE_DIRECTORY));
+ DWORD dwNameID;
+ unsigned short i,N = VAL16(pirdName->NumberOfNamedEntries)+VAL16(pirdName->NumberOfIdEntries);
+
+ for(i=0; i < N; i++, pirdeName++)
+ {
+ dwNameID = VAL32(IMAGE_RDE_NAME(pirdeName));
+ if(IMAGE_RDE_OFFSET_FIELD(pirdeName, DataIsDirectory))
+ {
+ BYTE* pbLangBase = pbResBase + VAL32(IMAGE_RDE_OFFSET_FIELD(pirdeName, OffsetToDirectory));
+ PIMAGE_RESOURCE_DIRECTORY pirdLang = (PIMAGE_RESOURCE_DIRECTORY)pbLangBase;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeLang = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbLangBase+sizeof(IMAGE_RESOURCE_DIRECTORY));
+ DWORD dwLangID;
+ unsigned short i,N = VAL16(pirdLang->NumberOfNamedEntries)+VAL16(pirdLang->NumberOfIdEntries);
+
+ for(i=0; i < N; i++, pirdeLang++)
+ {
+ dwLangID = VAL32(IMAGE_RDE_NAME(pirdeLang));
+ if(IMAGE_RDE_OFFSET_FIELD(pirdeLang, DataIsDirectory))
+ {
+ _ASSERTE(!"Resource hierarchy exceeds three levels");
+ }
+ else
+ {
+ g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,dwNameID,dwLangID, VAL32(IMAGE_RDE_OFFSET(pirdeLang)),pbResBase);
+ }
+ }
+ }
+ else
+ {
+ g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,dwNameID,0,VAL32(IMAGE_RDE_OFFSET(pirdeName)),pbResBase);
+ }
+ }
+ }
+ else
+ {
+ g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,0,0,VAL32(IMAGE_RDE_OFFSET(pirdeType)),pbResBase);
+ }
+ }
+ } PAL_CPP_CATCH_ALL {
+ ret= 0xDFFFFFFF;
+ ulNumResNodes = 0;
+ }
+ PAL_CPP_ENDTRY
+ // OK, all tree leaves are in ResourceNode structs, and ulNumResNodes ptrs are in g_prResNodePtr
+ if(ulNumResNodes)
+ {
+ ret = 1;
+#ifdef RES_FILE_DUMP_ENABLED
+
+ _wfopen_s(&pF,wzFileName,L"wb");
+ if(pF)
+ {
+ // Dump them to pF
+ // Write dummy header
+ ResourceHeader *pRH = new ResourceHeader();
+ fwrite(pRH,sizeof(ResourceHeader),1,pF);
+ SDELETE(pRH);
+ // For each resource write header and data
+ PAL_CPP_TRY {
+ for(i=0; i < ulNumResNodes; i++)
+ {
+ /*
+ sprintf_s(szString,SZSTRING_SIZE,"// Res.# %d Type=0x%X Name=0x%X Lang=0x%X DataOffset=0x%X DataLength=%d",
+ i+1,
+ g_prResNodePtr[i]->ResHdr.dwTypeID,
+ g_prResNodePtr[i]->ResHdr.dwNameID,
+ g_prResNodePtr[i]->ResHdr.wLangID,
+ VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData),
+ VAL32(g_prResNodePtr[i]->DataEntry.Size));
+ printLine(NULL,szString);
+ */
+ g_prResNodePtr[i]->Save(pF);
+ SDELETE(g_prResNodePtr[i]);
+ }
+ }
+ PAL_CPP_CATCH_ALL {
+ ret= 0xDFFFFFFF;
+ }
+ PAL_CPP_ENDTRY
+ fclose(pF);
+ }// end if file opened
+ else ret = 0xEFFFFFFF;
+#else
+ // Dump to text, using wzFileName as GUICookie
+ //char szString[4096];
+ void* GUICookie = (void*)wzFileName;
+ BYTE* pbData;
+ printLine(GUICookie,"");
+ sprintf(szString,"// ========== Win32 Resource Entries (%d) ========",ulNumResNodes);
+ for(i=0; i < ulNumResNodes; i++)
+ {
+ printLine(GUICookie,"");
+ sprintf(szString,"// Res.# %d Type=0x%X Name=0x%X Lang=0x%X DataOffset=0x%X DataLength=%d",
+ i+1,
+ g_prResNodePtr[i]->ResHdr.dwTypeID,
+ g_prResNodePtr[i]->ResHdr.dwNameID,
+ g_prResNodePtr[i]->ResHdr.wLangID,
+ VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData),
+ VAL32(g_prResNodePtr[i]->DataEntry.Size));
+ printLine(GUICookie,szString);
+ if(g_pPELoader->getVAforRVA(VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData), (void **) &pbData))
+ {
+ strcat(g_szAsmCodeIndent,"// ");
+ strcpy(szString,g_szAsmCodeIndent);
+ DumpByteArray(szString,pbData,VAL32(g_prResNodePtr[i]->DataEntry.Size),GUICookie);
+ printLine(GUICookie,szString);
+ g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-4] = 0;
+ }
+ SDELETE(g_prResNodePtr[i]);
+ }
+ ret = 1;
+#endif
+ } // end if there are nodes
+ }// end if got ptr to resource
+ else ret = 0xFFFFFFFF;
+ } // end if there is resource
+ else ret = 0;
+
+ return ret;
+}
+#endif // FEATURE_PAL
+