1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
6 // Win32 Resource extractor
11 #include "debugmacros.h"
13 #include "dasmenum.hpp"
14 #include "formattype.h"
17 #include "ilformatter.h"
18 #include "outstring.h"
21 #include "dynamicarray.h"
22 extern IMAGE_COR20_HEADER * g_CORHeader;
23 extern IMDInternalImport* g_pImport;
24 extern PELoader * g_pPELoader;
25 extern IMetaDataImport2* g_pPubImport;
26 extern char g_szAsmCodeIndent[];
27 extern unsigned g_uConsoleCP;
39 DWORD dwCharacteristics;
42 memset(this,0,sizeof(ResourceHeader));
43 dwHeaderSize = sizeof(ResourceHeader);
44 dwTypeID = dwNameID = 0xFFFF;
50 ResourceHeader ResHdr;
51 IMAGE_RESOURCE_DATA_ENTRY DataEntry;
54 ResourceNode(DWORD tid, DWORD nid, DWORD lid, DWORD dataOffset, BYTE* ptrBase)
60 WORD L = *((WORD*)(ptrBase+tid));
61 wzType = new WCHAR[L+1];
62 memcpy(wzType,ptrBase+tid+sizeof(WORD),L*sizeof(WCHAR));
67 ResHdr.dwTypeID = (0xFFFF |((tid & 0xFFFF)<<16));
75 WORD L = *((WORD*)(ptrBase+nid));
76 wzName = new WCHAR[L+1];
77 memcpy(wzName, ptrBase+nid+sizeof(WORD), L*sizeof(WCHAR));
82 ResHdr.dwNameID = (0xFFFF |((nid & 0xFFFF)<<16));
86 //ResHdr.dwTypeID = (tid & 0x80000000) ? tid : (0xFFFF |((tid & 0xFFFF)<<16));
87 //ResHdr.dwNameID = (nid & 0x80000000) ? nid : (0xFFFF |((nid & 0xFFFF)<<16));
88 ResHdr.wLangID = (WORD)lid;
89 if(ptrBase) memcpy(&DataEntry,(ptrBase+dataOffset),sizeof(IMAGE_RESOURCE_DATA_ENTRY));
90 ResHdr.dwDataSize = DataEntry.Size;
94 if(wzType) VDELETE(wzType);
95 if(wzName) VDELETE(wzName);
102 BYTE bNil[3] = {0,0,0};
103 // For each resource write header and data
104 if(g_pPELoader->getVAforRVA(VAL32(DataEntry.OffsetToData), (void **) &pbData))
106 //fwrite(&(g_prResNodePtr[i]->ResHdr),g_prResNodePtr[i]->ResHdr.dwHeaderSize,1,pF);
107 ResHdr.dwHeaderSize = sizeof(ResourceHeader);
108 if(wzType) ResHdr.dwHeaderSize += (DWORD)((wcslen(wzType) + 1)*sizeof(WCHAR) - sizeof(DWORD));
109 if(wzName) ResHdr.dwHeaderSize += (DWORD)((wcslen(wzName) + 1)*sizeof(WCHAR) - sizeof(DWORD));
111 //---- Constant part of the header: DWORD,DWORD
112 fwrite(&ResHdr.dwDataSize, sizeof(DWORD),1,pF);
113 fwrite(&ResHdr.dwHeaderSize, sizeof(DWORD),1,pF);
114 //--- Variable part of header: type and name
117 fwrite(wzType,(wcslen(wzType) + 1)*sizeof(WCHAR), 1, pF);
118 dwFiller += (DWORD)wcslen(wzType) + 1;
121 fwrite(&ResHdr.dwTypeID,sizeof(DWORD),1,pF);
124 fwrite(wzName,(wcslen(wzName) + 1)*sizeof(WCHAR), 1, pF);
125 dwFiller += (DWORD)wcslen(wzName) + 1;
128 fwrite(&ResHdr.dwNameID,sizeof(DWORD),1,pF);
130 // Align remaining fields on DWORD
134 //---- Constant part of the header: DWORD,WORD,WORD,DWORD,DWORD
135 fwrite(&ResHdr.dwDataVersion,8*sizeof(WORD),1,pF);
136 //---- Header done, now data
137 fwrite(pbData,VAL32(DataEntry.Size),1,pF);
138 dwFiller = VAL32(DataEntry.Size) & 3;
141 dwFiller = 4 - dwFiller;
142 fwrite(bNil,dwFiller,1,pF);
149 #define RES_FILE_DUMP_ENABLED
151 DWORD DumpResourceToFile(__in __nullterminated WCHAR* wzFileName)
159 unsigned ulNumResNodes=0;
160 DynamicArray<ResourceNode*> g_prResNodePtr;
162 if (g_pPELoader->IsPE32())
164 IMAGE_OPTIONAL_HEADER32 *pOptHeader = &(g_pPELoader->ntHeaders32()->OptionalHeader);
166 dwResDirRVA = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
167 dwResDirSize = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
171 IMAGE_OPTIONAL_HEADER64 *pOptHeader = &(g_pPELoader->ntHeaders64()->OptionalHeader);
173 dwResDirRVA = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
174 dwResDirSize = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
177 if(dwResDirRVA && dwResDirSize)
179 if(g_pPELoader->getVAforRVA(dwResDirRVA, (void **) &pbResBase))
181 // First, pull out all resource nodes (tree leaves), see ResourceNode struct
182 PIMAGE_RESOURCE_DIRECTORY pirdType = (PIMAGE_RESOURCE_DIRECTORY)pbResBase;
183 PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeType = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbResBase+sizeof(IMAGE_RESOURCE_DIRECTORY));
185 unsigned short i = 0,N = pirdType->NumberOfNamedEntries+pirdType->NumberOfIdEntries;
187 for(i=0; i < N; i++, pirdeType++)
189 dwTypeID = VAL32(IMAGE_RDE_NAME(pirdeType));
190 if(IMAGE_RDE_OFFSET_FIELD(pirdeType, DataIsDirectory))
192 BYTE* pbNameBase = pbResBase + VAL32(IMAGE_RDE_OFFSET_FIELD(pirdeType, OffsetToDirectory));
193 PIMAGE_RESOURCE_DIRECTORY pirdName = (PIMAGE_RESOURCE_DIRECTORY)pbNameBase;
194 PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeName = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbNameBase+sizeof(IMAGE_RESOURCE_DIRECTORY));
196 unsigned short i,N = VAL16(pirdName->NumberOfNamedEntries)+VAL16(pirdName->NumberOfIdEntries);
198 for(i=0; i < N; i++, pirdeName++)
200 dwNameID = VAL32(IMAGE_RDE_NAME(pirdeName));
201 if(IMAGE_RDE_OFFSET_FIELD(pirdeName, DataIsDirectory))
203 BYTE* pbLangBase = pbResBase + VAL32(IMAGE_RDE_OFFSET_FIELD(pirdeName, OffsetToDirectory));
204 PIMAGE_RESOURCE_DIRECTORY pirdLang = (PIMAGE_RESOURCE_DIRECTORY)pbLangBase;
205 PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeLang = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbLangBase+sizeof(IMAGE_RESOURCE_DIRECTORY));
207 unsigned short i,N = VAL16(pirdLang->NumberOfNamedEntries)+VAL16(pirdLang->NumberOfIdEntries);
209 for(i=0; i < N; i++, pirdeLang++)
211 dwLangID = VAL32(IMAGE_RDE_NAME(pirdeLang));
212 if(IMAGE_RDE_OFFSET_FIELD(pirdeLang, DataIsDirectory))
214 _ASSERTE(!"Resource hierarchy exceeds three levels");
218 g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,dwNameID,dwLangID, VAL32(IMAGE_RDE_OFFSET(pirdeLang)),pbResBase);
224 g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,dwNameID,0,VAL32(IMAGE_RDE_OFFSET(pirdeName)),pbResBase);
230 g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,0,0,VAL32(IMAGE_RDE_OFFSET(pirdeType)),pbResBase);
233 } PAL_CPP_CATCH_ALL {
238 // OK, all tree leaves are in ResourceNode structs, and ulNumResNodes ptrs are in g_prResNodePtr
242 #ifdef RES_FILE_DUMP_ENABLED
244 _wfopen_s(&pF,wzFileName,L"wb");
248 // Write dummy header
249 ResourceHeader *pRH = new ResourceHeader();
250 fwrite(pRH,sizeof(ResourceHeader),1,pF);
252 // For each resource write header and data
254 for(i=0; i < ulNumResNodes; i++)
257 sprintf_s(szString,SZSTRING_SIZE,"// Res.# %d Type=0x%X Name=0x%X Lang=0x%X DataOffset=0x%X DataLength=%d",
259 g_prResNodePtr[i]->ResHdr.dwTypeID,
260 g_prResNodePtr[i]->ResHdr.dwNameID,
261 g_prResNodePtr[i]->ResHdr.wLangID,
262 VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData),
263 VAL32(g_prResNodePtr[i]->DataEntry.Size));
264 printLine(NULL,szString);
266 g_prResNodePtr[i]->Save(pF);
267 SDELETE(g_prResNodePtr[i]);
275 }// end if file opened
276 else ret = 0xEFFFFFFF;
278 // Dump to text, using wzFileName as GUICookie
279 //char szString[4096];
280 void* GUICookie = (void*)wzFileName;
282 printLine(GUICookie,"");
283 sprintf_s(szString, _countof(szString), "// ========== Win32 Resource Entries (%d) ========",ulNumResNodes);
284 for(i=0; i < ulNumResNodes; i++)
286 printLine(GUICookie,"");
287 sprintf_s(szString, _countof(szString), "// Res.# %d Type=0x%X Name=0x%X Lang=0x%X DataOffset=0x%X DataLength=%d",
289 g_prResNodePtr[i]->ResHdr.dwTypeID,
290 g_prResNodePtr[i]->ResHdr.dwNameID,
291 g_prResNodePtr[i]->ResHdr.wLangID,
292 VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData),
293 VAL32(g_prResNodePtr[i]->DataEntry.Size));
294 printLine(GUICookie,szString);
295 if(g_pPELoader->getVAforRVA(VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData), (void **) &pbData))
297 strcat(g_szAsmCodeIndent,"// ");
298 strcpy(szString,g_szAsmCodeIndent);
299 DumpByteArray(szString,pbData,VAL32(g_prResNodePtr[i]->DataEntry.Size),GUICookie);
300 printLine(GUICookie,szString);
301 g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-4] = 0;
303 SDELETE(g_prResNodePtr[i]);
307 } // end if there are nodes
308 }// end if got ptr to resource
309 else ret = 0xFFFFFFFF;
310 } // end if there is resource
315 #endif // FEATURE_PAL