MCPcopy Create free account
hub / github.com/avast/retdec / parseMetadataStream

Method parseMetadataStream

src/fileformat/file_format/pe/pe_format.cpp:2341–2545  ·  view source on GitHub ↗

* Parses .NET metadata stream. * @param baseAddress Base address of .NET metadata header. * @param offset Offset of metadata stream. * @param size Size of stream. */

Source from the content-addressed store, hash-verified

2339 * @param size Size of stream.
2340 */
2341void PeFormat::parseMetadataStream(std::uint64_t baseAddress, std::uint64_t offset, std::uint64_t size)
2342{
2343 const std::uint64_t metadataStreamHeaderSize = 24;
2344 if (size <= metadataStreamHeaderSize)
2345 {
2346 return;
2347 }
2348
2349 metadataStream = std::make_unique<MetadataStream>(offset, size);
2350 auto address = baseAddress + offset;
2351
2352 std::uint64_t majorVersion, minorVersion, heapOffsetSizes, valid, sorted;
2353 if (!get1Byte(address + 4, majorVersion)
2354 || !get1Byte(address + 5, minorVersion)
2355 || !get1Byte(address + 6, heapOffsetSizes)
2356 || !get8Byte(address + 8, valid)
2357 || !get8Byte(address + 16, sorted))
2358 {
2359 return;
2360 }
2361
2362 metadataStream->setMajorVersion(majorVersion);
2363 metadataStream->setMinorVersion(minorVersion);
2364
2365 // 'heapOffsetSizes' define whether we should use std::uint16_t or dstd::uint16_t for indexes into different streams
2366 metadataStream->setStringStreamIndexSize(heapOffsetSizes & 0x01 ? 4 : 2);
2367 metadataStream->setGuidStreamIndexSize(heapOffsetSizes & 0x02 ? 4 : 2);
2368 metadataStream->setBlobStreamIndexSize(heapOffsetSizes & 0x04 ? 4 : 2);
2369
2370 // Tables that are present in the stream are marked with bit 1 in 'valid' attribute
2371 // At first we need to create all tables with their sizes because we don't know how many of them is there,
2372 // so we don't know where to start to parse table content.
2373 std::uint64_t currentAddress = address + metadataStreamHeaderSize;
2374 for (std::size_t i = 0; i < 64; ++i)
2375 {
2376 if ((valid >> i) & 1)
2377 {
2378 std::uint64_t tableSize;
2379 if (!get4Byte(currentAddress, tableSize))
2380 {
2381 return;
2382 }
2383
2384 // If the size of the metadata table would be larger than there are data available, we just end. This must be corrupted.
2385 if (tableSize > getLoadedFileLength())
2386 {
2387 return;
2388 }
2389
2390 metadataStream->addMetadataTable(static_cast<MetadataTableType>(i), tableSize);
2391 currentAddress += 4;
2392 }
2393 }
2394 // ExtraData flags means there is extra 4 bytes at the end Rows array that contaisn the rows sizes
2395 // I don't see anything about in at ECMA-335, but I can see in real samples and in IlSpy source
2396 // that understands it and correctly decompiles, sample: 5b5817fe2d4f0989501802b0e2bb4451583ff27fd0723f40bb7f8b0417dd7c58
2397 if (heapOffsetSizes & 0x40)
2398 {

Callers

nothing calls this directly

Calls 8

addMetadataTableMethod · 0.80
getMetadataTableMethod · 0.80
setMajorVersionMethod · 0.45
setMinorVersionMethod · 0.45
getTypeMethod · 0.45

Tested by

no test coverage detected