// Loads a single table, returns pointer to table in memory. public static void *LoadSingleTable(tMetaData *pThis, tRVA *pRVA, int tableID, void **ppTable) { int numRows = (int)pThis->tables.numRows[tableID]; int rowLen = tableRowSize[tableID]; int i, row; /*char**/ byte *pDef = tableDefs[tableID]; int defLen = (int)S.strlen(pDef); void * pRet; byte * pSource = (byte *)*ppTable; byte * pDest; uint v = 0; SIZE_T p = 0; // Allocate memory for destination table pRet = Mem.malloc((SIZE_T)(numRows * rowLen)); pDest = (byte *)pRet; // Load table int srcLen = 0; for (row = 0; row < numRows; row++) { byte *pSrcStart = pSource; for (i = 0; i < defLen; i += 2) { byte d = pDef[i]; if (d < MAX_TABLES) { if (pThis->tables.numRows[d] < 0x10000) { // Use 16-bit offset v = GetU16(pSource); pSource += 2; } else { // Use 32-bit offset v = GetU32(pSource); pSource += 4; } v |= (uint)d << 24; } else { switch ((char)d) { case 'c': // 8-bit value v = *(byte *)pSource; pSource++; break; case 's': // 16-bit short v = GetU16(pSource); pSource += 2; break; case 'i': // 32-bit int v = GetU32(pSource); pSource += 4; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': { int ofs = pDef[i] - '0'; /*char*/ byte *pCoding = codedTags[ofs]; int tagBits = codedTagBits[ofs]; byte tag = (byte)(*pSource & ((1 << tagBits) - 1)); int idxIntoTableID = pCoding[tag]; // The actual table index that we're looking for if (idxIntoTableID < 0 || idxIntoTableID > MAX_TABLES) { Sys.Crash("Error: Bad table index: 0x%02x\n", idxIntoTableID); } if (pThis->tables.codedIndex32Bit[ofs] != 0) { // Use 32-bit number v = GetU32(pSource) >> tagBits; pSource += 4; } else { // Use 16-bit number v = GetU16(pSource) >> tagBits; pSource += 2; } v |= (uint)idxIntoTableID << 24; } break; case 'S': // index into string heap if (pThis->index32BitString != 0) { v = GetU32(pSource); pSource += 4; } else { v = GetU16(pSource); pSource += 2; } p = (PTR)(pThis->strings.pStart + v); // NOTE: Quick way to validate metadata loading, check if all strings are valid! if (S.isvalidstr((byte *)p) == 0) { Sys.Crash("Invalid string %s", (PTR)p); } break; case 'G': // index into GUID heap if (pThis->index32BitGUID != 0) { v = GetU32(pSource); pSource += 4; } else { v = GetU16(pSource); pSource += 2; } p = (PTR)(pThis->GUIDs.pGUID1 + ((v - 1) * 16)); break; case 'B': // index into BLOB heap if (pThis->index32BitBlob != 0) { v = GetU32(pSource); pSource += 4; } else { v = GetU16(pSource); pSource += 2; } p = (PTR)(pThis->blobs.pStart + v); break; case '^': // RVA to convert to pointer v = GetU32(pSource); pSource += 4; p = (PTR)RVA.FindData(pRVA, v); break; case 'm': // Pointer to this metadata p = (PTR)pThis; break; case 'l': // Is this the last table entry? v = (row == numRows - 1) ? (uint)1 : (uint)0; break; case 'I': // Original table index v = MetaData.MAKE_TABLE_INDEX((uint)tableID, (uint)(row + 1)); break; case 'x': // Nothing, use 0 v = 0; p = 0; break; default: Sys.Crash("Cannot handle MetaData source definition character '%c' (0x%02X)\n", d, d); break; } } switch ((char)pDef[i + 1]) { case '*': *(SIZE_T *)pDest = p; pDest += sizeof(SIZE_T); break; case 'i': *(uint *)pDest = v; pDest += 4; break; case 's': *(ushort *)pDest = (ushort)v; pDest += 2; break; case 'c': *(byte *)pDest = (byte)v; pDest++; break; case 'x': // Do nothing break; default: Sys.Crash("Cannot handle MetaData destination definition character '%c'\n", pDef[i + 1]); break; } } if (srcLen == 0) { srcLen = (int)(pSource - pSrcStart); } } Sys.log_f(1, "Loaded MetaData table 0x%02X; %d rows %d len\n", tableID, numRows, srcLen); // Update the parameter to the position after this table *ppTable = pSource; // Return new table information return(pRet); }
private static tCLIFile *LoadPEFile(byte[] image) { tCLIFile *pRet = ((tCLIFile *)Mem.malloc((SIZE_T)sizeof(tCLIFile))); System.Runtime.InteropServices.GCHandle handle = System.Runtime.InteropServices.GCHandle.Alloc(image, GCHandleType.Pinned); byte *pData = (byte *)handle.AddrOfPinnedObject(); byte *pMSDOSHeader = (byte *)&(((byte *)pData)[0]); byte *pPEHeader; byte *pPEOptionalHeader; byte *pPESectionHeaders; byte *pCLIHeader; byte *pRawMetaData; int i; uint lfanew; ushort machine; int numSections; //uint imageBase; //int fileAlignment; uint cliHeaderRVA; //uint cliHeaderSize; uint metaDataRVA; //uint metaDataSize; tMetaData *pMetaData; pRet->pRVA = RVA.New(); pRet->gcHandle = (PTR)(System.IntPtr)handle; pRet->pMetaData = pMetaData = MetaData.New(); lfanew = *(uint *)&(pMSDOSHeader[0x3c]); pPEHeader = pMSDOSHeader + lfanew + 4; pPEOptionalHeader = pPEHeader + 20; pPESectionHeaders = pPEOptionalHeader + 224; machine = *(ushort *)&(pPEHeader[0]); if (machine != DOT_NET_MACHINE) { return(null); } numSections = *(ushort *)&(pPEHeader[2]); //imageBase = *(uint*)&(pPEOptionalHeader[28]); //fileAlignment = *(int*)&(pPEOptionalHeader[36]); for (i = 0; i < numSections; i++) { byte *pSection = pPESectionHeaders + i * 40; RVA.Create(pRet->pRVA, pData, pSection); } cliHeaderRVA = *(uint *)&(pPEOptionalHeader[208]); //cliHeaderSize = *(uint*)&(pPEOptionalHeader[212]); pCLIHeader = (byte *)RVA.FindData(pRet->pRVA, cliHeaderRVA); metaDataRVA = *(uint *)&(pCLIHeader[8]); //metaDataSize = *(uint*)&(pCLIHeader[12]); pRet->entryPoint = *(uint *)&(pCLIHeader[20]); pRawMetaData = (byte *)RVA.FindData(pRet->pRVA, metaDataRVA); // Load all metadata { uint versionLen = *(uint *)&(pRawMetaData[12]); uint ofs, numberOfStreams; void *pTableStream = null; uint tableStreamSize = 0; pRet->pVersion = &(pRawMetaData[16]); Sys.log_f(1, "CLI version: %s\n", (PTR)pRet->pVersion); ofs = 16 + versionLen; numberOfStreams = *(ushort *)&(pRawMetaData[ofs + 2]); ofs += 4; for (i = 0; i < (int)numberOfStreams; i++) { uint streamOffset = *(uint *)&pRawMetaData[ofs]; uint streamSize = *(uint *)&pRawMetaData[ofs + 4]; byte *pStreamName = &pRawMetaData[ofs + 8]; void *pStream = pRawMetaData + streamOffset; ofs += (uint)((S.strlen(pStreamName) + 4) & (~0x3)) + 8; if (S.strcasecmp(pStreamName, "#Strings") == 0) { MetaData.LoadStrings(pMetaData, pStream, streamSize); } else if (S.strcasecmp(pStreamName, "#US") == 0) { MetaData.LoadUserStrings(pMetaData, pStream, streamSize); } else if (S.strcasecmp(pStreamName, "#Blob") == 0) { MetaData.LoadBlobs(pMetaData, pStream, streamSize); } else if (S.strcasecmp(pStreamName, "#GUID") == 0) { MetaData.LoadGUIDs(pMetaData, pStream, streamSize); } else if (S.strcasecmp(pStreamName, "#~") == 0) { pTableStream = pStream; tableStreamSize = streamSize; } } // Must load tables last if (pTableStream != null) { MetaData.LoadTables(pMetaData, pRet->pRVA, pTableStream, (uint)tableStreamSize); } } // Mark all generic definition type and methods as such for (i = (int)pMetaData->tables.numRows[MetaDataTable.MD_TABLE_GENERICPARAM]; i > 0; i--) { tMD_GenericParam * pGenericParam; /*IDX_TABLE*/ uint ownerIdx; pGenericParam = (tMD_GenericParam *)MetaData.GetTableRow (pMetaData, MetaData.MAKE_TABLE_INDEX(MetaDataTable.MD_TABLE_GENERICPARAM, (uint)i)); ownerIdx = pGenericParam->owner; switch (MetaData.TABLE_ID(ownerIdx)) { case MetaDataTable.MD_TABLE_TYPEDEF: { tMD_TypeDef *pTypeDef = (tMD_TypeDef *)MetaData.GetTableRow(pMetaData, ownerIdx); pTypeDef->isGenericDefinition = 1; } break; case MetaDataTable.MD_TABLE_METHODDEF: { tMD_MethodDef *pMethodDef = (tMD_MethodDef *)MetaData.GetTableRow(pMetaData, ownerIdx); pMethodDef->isGenericDefinition = 1; } break; default: Sys.Crash("Wrong generic parameter owner: 0x%08x", ownerIdx); break; } } // Mark all nested classes as such for (i = (int)pMetaData->tables.numRows[MetaDataTable.MD_TABLE_NESTEDCLASS]; i > 0; i--) { tMD_NestedClass *pNested; tMD_TypeDef * pParent; tMD_TypeDef * pChild; pNested = (tMD_NestedClass *)MetaData.GetTableRow(pMetaData, MetaData.MAKE_TABLE_INDEX(MetaDataTable.MD_TABLE_NESTEDCLASS, (uint)i)); pParent = (tMD_TypeDef *)MetaData.GetTableRow(pMetaData, pNested->enclosingClass); pChild = (tMD_TypeDef *)MetaData.GetTableRow(pMetaData, pNested->nestedClass); pChild->pNestedIn = pParent; } return(pRet); }