Add .NET metadata reader (ported from C++)
This commit is contained in:
parent
89f90d3e75
commit
0e70d020b4
|
@ -33,13 +33,15 @@ namespace de4dot.PE {
|
||||||
public DataDirectory vtableFixups;
|
public DataDirectory vtableFixups;
|
||||||
public DataDirectory exportAddressTableJumps;
|
public DataDirectory exportAddressTableJumps;
|
||||||
public DataDirectory managedNativeHeader;
|
public DataDirectory managedNativeHeader;
|
||||||
|
public Metadata metadata;
|
||||||
|
BinaryReader reader;
|
||||||
|
|
||||||
uint mdOffset, mdHeaderLength;
|
|
||||||
public uint MetadataOffset {
|
public uint MetadataOffset {
|
||||||
get { return mdOffset; }
|
get { return metadata.Offset; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint MetadataHeaderLength {
|
public uint MetadataHeaderLength {
|
||||||
get { return mdHeaderLength; }
|
get { return metadata.HeaderLength; }
|
||||||
}
|
}
|
||||||
|
|
||||||
uint offset;
|
uint offset;
|
||||||
|
@ -52,6 +54,7 @@ namespace de4dot.PE {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cor20Header(BinaryReader reader) {
|
public Cor20Header(BinaryReader reader) {
|
||||||
|
this.reader = reader;
|
||||||
offset = (uint)reader.BaseStream.Position;
|
offset = (uint)reader.BaseStream.Position;
|
||||||
cb = reader.ReadUInt32();
|
cb = reader.ReadUInt32();
|
||||||
majorRuntimeVersion = reader.ReadUInt16();
|
majorRuntimeVersion = reader.ReadUInt16();
|
||||||
|
@ -67,30 +70,12 @@ namespace de4dot.PE {
|
||||||
managedNativeHeader.read(reader);
|
managedNativeHeader.read(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initMetadataTable(BinaryReader reader) {
|
public void initMetadataTable() {
|
||||||
if (reader.ReadUInt32() != 0x424A5342)
|
metadata = new Metadata(reader);
|
||||||
return;
|
|
||||||
mdOffset = (uint)reader.BaseStream.Position - 4;
|
|
||||||
reader.ReadUInt16(); // major version
|
|
||||||
reader.ReadUInt16(); // minor version
|
|
||||||
reader.ReadUInt32(); // reserved
|
|
||||||
int slen = reader.ReadInt32();
|
|
||||||
reader.BaseStream.Position += slen;
|
|
||||||
reader.ReadUInt16(); // flags
|
|
||||||
int streams = reader.ReadUInt16();
|
|
||||||
for (int i = 0; i < streams; i++) {
|
|
||||||
uint offset = reader.ReadUInt32();
|
|
||||||
uint size = reader.ReadUInt32();
|
|
||||||
skipString(reader);
|
|
||||||
}
|
|
||||||
mdHeaderLength = (uint)reader.BaseStream.Position - mdOffset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void skipString(BinaryReader reader) {
|
public MetadataTables createMetadataTables() {
|
||||||
while (reader.ReadByte() != 0) {
|
return new MetadataTables(reader, metadata);
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
reader.BaseStream.Position = (reader.BaseStream.Position + 3) & ~3;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
46
de4dot.code/PE/DotNetStream.cs
Normal file
46
de4dot.code/PE/DotNetStream.cs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011 de4dot@gmail.com
|
||||||
|
|
||||||
|
This file is part of de4dot.
|
||||||
|
|
||||||
|
de4dot is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
de4dot is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace de4dot.PE {
|
||||||
|
class DotNetStream : IFileLocation {
|
||||||
|
public string name;
|
||||||
|
public uint fileOffset;
|
||||||
|
public uint length;
|
||||||
|
|
||||||
|
public uint Offset {
|
||||||
|
get { return fileOffset; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Length {
|
||||||
|
get { return length; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DotNetStream(string name, uint fileOffset, uint length) {
|
||||||
|
this.name = name;
|
||||||
|
this.fileOffset = fileOffset;
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return string.Format("{0:X8} {1:X8} {2}", fileOffset, length, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
110
de4dot.code/PE/Metadata.cs
Normal file
110
de4dot.code/PE/Metadata.cs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011 de4dot@gmail.com
|
||||||
|
|
||||||
|
This file is part of de4dot.
|
||||||
|
|
||||||
|
de4dot is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
de4dot is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace de4dot.PE {
|
||||||
|
class Metadata : IFileLocation {
|
||||||
|
uint magic;
|
||||||
|
ushort majorVersion, minorVersion;
|
||||||
|
uint reserved;
|
||||||
|
string versionString;
|
||||||
|
ushort flags;
|
||||||
|
DotNetStream[] streams;
|
||||||
|
|
||||||
|
uint offset, headerLength, length;
|
||||||
|
|
||||||
|
public uint Offset {
|
||||||
|
get { return offset; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Length {
|
||||||
|
get { return length; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint HeaderLength {
|
||||||
|
get { return headerLength; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint HeaderEnd {
|
||||||
|
get { return offset + headerLength; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Metadata(BinaryReader reader) {
|
||||||
|
magic = reader.ReadUInt32();
|
||||||
|
if (magic != 0x424A5342)
|
||||||
|
return;
|
||||||
|
|
||||||
|
offset = (uint)reader.BaseStream.Position - 4;
|
||||||
|
majorVersion = reader.ReadUInt16();
|
||||||
|
minorVersion = reader.ReadUInt16();
|
||||||
|
reserved = reader.ReadUInt32();
|
||||||
|
versionString = readString(reader, reader.ReadInt32());
|
||||||
|
flags = reader.ReadUInt16();
|
||||||
|
int numStreams = reader.ReadUInt16();
|
||||||
|
streams = new DotNetStream[numStreams];
|
||||||
|
uint lastOffset = offset;
|
||||||
|
for (int i = 0; i < numStreams; i++) {
|
||||||
|
uint fileOffset = offset + reader.ReadUInt32();
|
||||||
|
uint size = reader.ReadUInt32();
|
||||||
|
string name = readAsciizString(reader);
|
||||||
|
streams[i] = new DotNetStream(name, fileOffset, size);
|
||||||
|
lastOffset = Math.Max(lastOffset, fileOffset + size);
|
||||||
|
}
|
||||||
|
lastOffset = Math.Max(lastOffset, (uint)reader.BaseStream.Position);
|
||||||
|
length = lastOffset - offset;
|
||||||
|
headerLength = (uint)reader.BaseStream.Position - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DotNetStream getStream(string name) {
|
||||||
|
foreach (var stream in streams) {
|
||||||
|
if (stream.name == name)
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string readString(BinaryReader reader, int len) {
|
||||||
|
var sb = new StringBuilder(len);
|
||||||
|
var nextPos = reader.BaseStream.Position + len;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
byte b = reader.ReadByte();
|
||||||
|
if (b == 0)
|
||||||
|
break;
|
||||||
|
sb.Append((char)b);
|
||||||
|
}
|
||||||
|
reader.BaseStream.Position = nextPos;
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
string readAsciizString(BinaryReader reader) {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
while (true) {
|
||||||
|
byte b = reader.ReadByte();
|
||||||
|
if (b == 0)
|
||||||
|
break;
|
||||||
|
sb.Append((char)b);
|
||||||
|
}
|
||||||
|
reader.BaseStream.Position = (reader.BaseStream.Position + 3) & ~3;
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
151
de4dot.code/PE/MetadataTables.cs
Normal file
151
de4dot.code/PE/MetadataTables.cs
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011 de4dot@gmail.com
|
||||||
|
|
||||||
|
This file is part of de4dot.
|
||||||
|
|
||||||
|
de4dot is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
de4dot is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace de4dot.PE {
|
||||||
|
using MVT = MetadataVarType;
|
||||||
|
|
||||||
|
class MetadataTables {
|
||||||
|
BinaryReader reader;
|
||||||
|
Metadata metadata;
|
||||||
|
byte heapOffsetSizes;
|
||||||
|
MetadataType[] metadataTypes = new MetadataType[64];
|
||||||
|
|
||||||
|
public MetadataTables(BinaryReader reader, Metadata metadata) {
|
||||||
|
this.reader = reader;
|
||||||
|
this.metadata = metadata;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetadataType getMetadataType(MetadataIndex index) {
|
||||||
|
return metadataTypes[(int)index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void seek(uint fileOffset) {
|
||||||
|
reader.BaseStream.Position = fileOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MetadataVarType[] metadataVarType = new MetadataVarType[] {
|
||||||
|
MVT.byte2, MVT.stringIndex, MVT.guidIndex, MVT.guidIndex, MVT.guidIndex, MVT.end, // 0
|
||||||
|
MVT.resolutionScope, MVT.stringIndex, MVT.stringIndex, MVT.end, // 1
|
||||||
|
MVT.byte4, MVT.stringIndex, MVT.stringIndex, MVT.typeDefOrRef, MVT.fieldIndex, MVT.methodDefIndex, MVT.end, // 2
|
||||||
|
MVT.end, // 3
|
||||||
|
MVT.byte2, MVT.stringIndex, MVT.blobIndex, MVT.end, // 4
|
||||||
|
MVT.end, // 5
|
||||||
|
MVT.byte4, MVT.byte2, MVT.byte2, MVT.stringIndex, MVT.blobIndex, MVT.paramIndex, MVT.end, // 6
|
||||||
|
MVT.end, // 7
|
||||||
|
MVT.byte2, MVT.byte2, MVT.stringIndex, MVT.end, // 8
|
||||||
|
MVT.typeDefIndex, MVT.typeDefOrRef, MVT.end, // 9
|
||||||
|
MVT.memberRefParent, MVT.stringIndex, MVT.blobIndex, MVT.end, // 10
|
||||||
|
MVT.byte1, MVT.byte1, MVT.hasConstant, MVT.blobIndex, MVT.end, // 11
|
||||||
|
MVT.hasCustomAttribute, MVT.customAttributeType, MVT.blobIndex, MVT.end,// 12
|
||||||
|
MVT.hasFieldMarshal, MVT.blobIndex, MVT.end, // 13
|
||||||
|
MVT.byte2, MVT.hasDeclSecurity, MVT.blobIndex, MVT.end, // 14
|
||||||
|
MVT.byte2, MVT.byte4, MVT.typeDefIndex, MVT.end, // 15
|
||||||
|
MVT.byte4, MVT.fieldIndex, MVT.end, // 16
|
||||||
|
MVT.blobIndex, MVT.end, // 17
|
||||||
|
MVT.typeDefIndex, MVT.eventIndex, MVT.end, // 18
|
||||||
|
MVT.end, // 19
|
||||||
|
MVT.byte2, MVT.stringIndex, MVT.typeDefOrRef, MVT.end, // 20
|
||||||
|
MVT.typeDefIndex, MVT.propertyIndex, MVT.end, // 21
|
||||||
|
MVT.end, // 22
|
||||||
|
MVT.byte2, MVT.stringIndex, MVT.blobIndex, MVT.end, // 23
|
||||||
|
MVT.byte2, MVT.methodDefIndex, MVT.hasSemantics, MVT.end, // 24
|
||||||
|
MVT.typeDefIndex, MVT.methodDefOrRef, MVT.methodDefOrRef, MVT.end, // 25
|
||||||
|
MVT.stringIndex, MVT.end, // 26
|
||||||
|
MVT.blobIndex, MVT.end, // 27
|
||||||
|
MVT.byte2, MVT.memberForwarded, MVT.stringIndex, MVT.moduleRefIndex, MVT.end, // 28
|
||||||
|
MVT.byte4, MVT.fieldIndex, MVT.end, // 29
|
||||||
|
MVT.end, // 30
|
||||||
|
MVT.end, // 31
|
||||||
|
MVT.byte4, MVT.byte2, MVT.byte2, MVT.byte2, MVT.byte2, MVT.byte4, MVT.blobIndex, MVT.stringIndex, MVT.stringIndex, MVT.end, // 32
|
||||||
|
MVT.byte4, MVT.end, // 33
|
||||||
|
MVT.byte4, MVT.byte4, MVT.byte4, MVT.end, // 34
|
||||||
|
MVT.byte2, MVT.byte2, MVT.byte2, MVT.byte2, MVT.byte4, MVT.blobIndex, MVT.stringIndex, MVT.stringIndex, MVT.blobIndex, MVT.end, // 35
|
||||||
|
MVT.byte4, MVT.assemblyRefIndex, MVT.end, // 36
|
||||||
|
MVT.byte4, MVT.byte4, MVT.byte4, MVT.assemblyRefIndex, MVT.end, // 37
|
||||||
|
MVT.byte4, MVT.stringIndex, MVT.blobIndex, MVT.end, // 38
|
||||||
|
MVT.byte4, MVT.byte4, MVT.stringIndex, MVT.stringIndex, MVT.implementation, MVT.end,// 39
|
||||||
|
MVT.byte4, MVT.byte4, MVT.stringIndex, MVT.implementation, MVT.end, // 40
|
||||||
|
MVT.typeDefIndex, MVT.typeDefIndex, MVT.end, // 41
|
||||||
|
MVT.byte2, MVT.byte2, MVT.typeOrMethodDef, MVT.stringIndex, MVT.end, // 42
|
||||||
|
MVT.end, // 43
|
||||||
|
MVT.genericParamIndex, MVT.typeDefOrRef, MVT.end, // 44
|
||||||
|
MVT.end, // 45
|
||||||
|
MVT.end, // 46
|
||||||
|
MVT.end, // 47
|
||||||
|
MVT.end, // 48
|
||||||
|
MVT.end, // 49
|
||||||
|
MVT.end, // 50
|
||||||
|
MVT.end, // 51
|
||||||
|
MVT.end, // 52
|
||||||
|
MVT.end, // 53
|
||||||
|
MVT.end, // 54
|
||||||
|
MVT.end, // 55
|
||||||
|
MVT.end, // 56
|
||||||
|
MVT.end, // 57
|
||||||
|
MVT.end, // 58
|
||||||
|
MVT.end, // 59
|
||||||
|
MVT.end, // 60
|
||||||
|
MVT.end, // 61
|
||||||
|
MVT.end, // 62
|
||||||
|
MVT.end, // 63
|
||||||
|
|
||||||
|
MVT.stop
|
||||||
|
};
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
var streamTable = metadata.getStream("#~");
|
||||||
|
if (streamTable == null)
|
||||||
|
throw new ApplicationException("Could not find #~ stream");
|
||||||
|
|
||||||
|
seek(streamTable.Offset);
|
||||||
|
reader.ReadUInt32(); // reserved
|
||||||
|
reader.ReadUInt16(); // major + minor version
|
||||||
|
heapOffsetSizes = reader.ReadByte();
|
||||||
|
reader.ReadByte(); // always 1
|
||||||
|
ulong validMask = reader.ReadUInt64();
|
||||||
|
reader.ReadUInt64(); // sorted
|
||||||
|
|
||||||
|
var numRows = new uint[64];
|
||||||
|
for (int i = 0; validMask != 0; i++, validMask >>= 1) {
|
||||||
|
if ((validMask & 1) != 0)
|
||||||
|
numRows[i] = reader.ReadUInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new MetadataTypeBuilder(heapOffsetSizes, numRows);
|
||||||
|
uint fileOffset = (uint)reader.BaseStream.Position;
|
||||||
|
for (int i = 0, j = 0; ; i++) {
|
||||||
|
if (metadataVarType[i] == MVT.end) {
|
||||||
|
var mdType = builder.create();
|
||||||
|
mdType.rows = numRows[j];
|
||||||
|
mdType.fileOffset = fileOffset;
|
||||||
|
fileOffset += mdType.rows * mdType.totalSize;
|
||||||
|
metadataTypes[j++] = mdType;
|
||||||
|
}
|
||||||
|
else if (metadataVarType[i] == MVT.stop)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
builder.field(metadataVarType[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
89
de4dot.code/PE/MetadataType.cs
Normal file
89
de4dot.code/PE/MetadataType.cs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011 de4dot@gmail.com
|
||||||
|
|
||||||
|
This file is part of de4dot.
|
||||||
|
|
||||||
|
de4dot is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
de4dot is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace de4dot.PE {
|
||||||
|
enum MetadataIndex {
|
||||||
|
iModule = 0,
|
||||||
|
iTypeRef = 1,
|
||||||
|
iTypeDef = 2,
|
||||||
|
iField = 4,
|
||||||
|
iMethodDef = 6,
|
||||||
|
iParam = 8,
|
||||||
|
iInterfaceImpl = 9,
|
||||||
|
iMemberRef = 10,
|
||||||
|
iConstant = 11,
|
||||||
|
iCustomAttribute = 12,
|
||||||
|
iFieldMarshal = 13,
|
||||||
|
iDeclSecurity = 14,
|
||||||
|
iClassLayout = 15,
|
||||||
|
iFieldLayout = 16,
|
||||||
|
iStandAloneSig = 17,
|
||||||
|
iEventMap = 18,
|
||||||
|
iEvent = 20,
|
||||||
|
iPropertyMap = 21,
|
||||||
|
iProperty = 23,
|
||||||
|
iMethodSemantics = 24,
|
||||||
|
iMethodImpl = 25,
|
||||||
|
iModuleRef = 26,
|
||||||
|
iTypeSpec = 27,
|
||||||
|
iImplMap = 28,
|
||||||
|
iFieldRVA = 29,
|
||||||
|
iAssembly = 32,
|
||||||
|
iAssemblyProcessor = 33,
|
||||||
|
iAssemblyOS = 34,
|
||||||
|
iAssemblyRef = 35,
|
||||||
|
iAssemblyRefProcessor = 36,
|
||||||
|
iAssemblyRefOS = 37,
|
||||||
|
iFile = 38,
|
||||||
|
iExportedType = 39,
|
||||||
|
iManifestResource = 40,
|
||||||
|
iNestedClass = 41,
|
||||||
|
iGenericParam = 42,
|
||||||
|
iGenericParamConstraint = 44,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MetadataType {
|
||||||
|
public uint fileOffset;
|
||||||
|
public uint rows;
|
||||||
|
public uint totalSize;
|
||||||
|
public List<MetadataField> fields;
|
||||||
|
|
||||||
|
public MetadataType(List<MetadataField> fields) {
|
||||||
|
this.fields = fields;
|
||||||
|
totalSize = 0;
|
||||||
|
foreach (var field in fields)
|
||||||
|
totalSize += (uint)field.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return string.Format("MDType: {0:X8}, {1} rows, {2} bytes, {3} fields", fileOffset, rows, totalSize, fields.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MetadataField {
|
||||||
|
public int offset;
|
||||||
|
public int size;
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return string.Format("offset: {0}, size {1}", offset, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
203
de4dot.code/PE/MetadataTypeBuilder.cs
Normal file
203
de4dot.code/PE/MetadataTypeBuilder.cs
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011 de4dot@gmail.com
|
||||||
|
|
||||||
|
This file is part of de4dot.
|
||||||
|
|
||||||
|
de4dot is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
de4dot is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace de4dot.PE {
|
||||||
|
enum MetadataVarType {
|
||||||
|
end,
|
||||||
|
stop,
|
||||||
|
byte1,
|
||||||
|
byte2,
|
||||||
|
byte4,
|
||||||
|
stringIndex, // index into #String heap
|
||||||
|
guidIndex, // index into #GUID heap
|
||||||
|
blobIndex, // index into #Blob heap
|
||||||
|
resolutionScope,
|
||||||
|
typeDefOrRef,
|
||||||
|
fieldIndex,
|
||||||
|
methodDefIndex,
|
||||||
|
paramIndex,
|
||||||
|
typeDefIndex,
|
||||||
|
eventIndex,
|
||||||
|
propertyIndex,
|
||||||
|
moduleRefIndex,
|
||||||
|
assemblyRefIndex,
|
||||||
|
genericParamIndex,
|
||||||
|
memberRefParent,
|
||||||
|
hasConstant,
|
||||||
|
hasCustomAttribute,
|
||||||
|
customAttributeType,
|
||||||
|
hasFieldMarshal,
|
||||||
|
hasDeclSecurity,
|
||||||
|
hasSemantics,
|
||||||
|
methodDefOrRef,
|
||||||
|
memberForwarded,
|
||||||
|
implementation,
|
||||||
|
typeOrMethodDef,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MetadataTypeBuilder {
|
||||||
|
byte heapOffsetSizes;
|
||||||
|
uint[] numRows;
|
||||||
|
List<MetadataField> fields;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
public MetadataTypeBuilder(byte heapOffsetSizes, uint[] numRows) {
|
||||||
|
this.heapOffsetSizes = heapOffsetSizes;
|
||||||
|
this.numRows = numRows;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
offset = 0;
|
||||||
|
fields = new List<MetadataField>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetadataType create() {
|
||||||
|
var type = new MetadataType(fields);
|
||||||
|
reset();
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void field(MetadataVarType type) {
|
||||||
|
int size;
|
||||||
|
switch (type) {
|
||||||
|
case MetadataVarType.byte1:
|
||||||
|
size = 1;
|
||||||
|
break;
|
||||||
|
case MetadataVarType.byte2:
|
||||||
|
size = 2;
|
||||||
|
break;
|
||||||
|
case MetadataVarType.byte4:
|
||||||
|
size = 4;
|
||||||
|
break;
|
||||||
|
case MetadataVarType.stringIndex:
|
||||||
|
size = (heapOffsetSizes & 1) != 0 ? 4 : 2;
|
||||||
|
break;
|
||||||
|
case MetadataVarType.guidIndex:
|
||||||
|
size = (heapOffsetSizes & 2) != 0 ? 4 : 2;
|
||||||
|
break;
|
||||||
|
case MetadataVarType.blobIndex:
|
||||||
|
size = (heapOffsetSizes & 4) != 0 ? 4 : 2;
|
||||||
|
break;
|
||||||
|
case MetadataVarType.resolutionScope:
|
||||||
|
size = getSize(14, new MetadataIndex[] { MetadataIndex.iModule, MetadataIndex.iModuleRef, MetadataIndex.iAssemblyRef, MetadataIndex.iTypeRef });
|
||||||
|
break;
|
||||||
|
case MetadataVarType.typeDefOrRef:
|
||||||
|
size = getSize(14, new MetadataIndex[] { MetadataIndex.iTypeDef, MetadataIndex.iTypeRef, MetadataIndex.iTypeSpec });
|
||||||
|
break;
|
||||||
|
case MetadataVarType.memberRefParent:
|
||||||
|
size = getSize(13, new MetadataIndex[] { MetadataIndex.iTypeDef, MetadataIndex.iTypeRef, MetadataIndex.iModuleRef, MetadataIndex.iMethodDef, MetadataIndex.iTypeSpec });
|
||||||
|
break;
|
||||||
|
case MetadataVarType.hasConstant:
|
||||||
|
size = getSize(14, new MetadataIndex[] { MetadataIndex.iField, MetadataIndex.iParam, MetadataIndex.iProperty });
|
||||||
|
break;
|
||||||
|
case MetadataVarType.hasCustomAttribute:
|
||||||
|
size = getSize(11, new MetadataIndex[] {
|
||||||
|
MetadataIndex.iMethodDef, MetadataIndex.iField, MetadataIndex.iTypeRef,
|
||||||
|
MetadataIndex.iTypeDef, MetadataIndex.iParam, MetadataIndex.iInterfaceImpl,
|
||||||
|
MetadataIndex.iMemberRef, MetadataIndex.iModule /*TODO:, MetadataIndex.iPermission*/,
|
||||||
|
MetadataIndex.iProperty, MetadataIndex.iEvent, MetadataIndex.iStandAloneSig,
|
||||||
|
MetadataIndex.iModuleRef, MetadataIndex.iTypeSpec, MetadataIndex.iAssembly,
|
||||||
|
MetadataIndex.iAssemblyRef, MetadataIndex.iFile, MetadataIndex.iExportedType,
|
||||||
|
MetadataIndex.iManifestResource,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case MetadataVarType.customAttributeType:
|
||||||
|
size = getSize(13, new MetadataIndex[] { MetadataIndex.iMethodDef, MetadataIndex.iMemberRef }); // others aren't used
|
||||||
|
break;
|
||||||
|
case MetadataVarType.hasFieldMarshal:
|
||||||
|
size = getSize(15, new MetadataIndex[] { MetadataIndex.iField, MetadataIndex.iParam });
|
||||||
|
break;
|
||||||
|
case MetadataVarType.hasDeclSecurity:
|
||||||
|
size = getSize(14, new MetadataIndex[] { MetadataIndex.iTypeDef, MetadataIndex.iMethodDef, MetadataIndex.iAssembly });
|
||||||
|
break;
|
||||||
|
case MetadataVarType.hasSemantics:
|
||||||
|
size = getSize(15, new MetadataIndex[] { MetadataIndex.iEvent, MetadataIndex.iProperty });
|
||||||
|
break;
|
||||||
|
case MetadataVarType.methodDefOrRef:
|
||||||
|
size = getSize(15, new MetadataIndex[] { MetadataIndex.iMethodDef, MetadataIndex.iMemberRef });
|
||||||
|
break;
|
||||||
|
case MetadataVarType.memberForwarded:
|
||||||
|
size = getSize(15, new MetadataIndex[] { MetadataIndex.iField, MetadataIndex.iMethodDef });
|
||||||
|
break;
|
||||||
|
case MetadataVarType.implementation:
|
||||||
|
size = getSize(14, new MetadataIndex[] { MetadataIndex.iFile, MetadataIndex.iAssemblyRef, MetadataIndex.iExportedType });
|
||||||
|
break;
|
||||||
|
case MetadataVarType.typeOrMethodDef:
|
||||||
|
size = getSize(15, new MetadataIndex[] { MetadataIndex.iTypeDef, MetadataIndex.iMethodDef });
|
||||||
|
break;
|
||||||
|
case MetadataVarType.fieldIndex:
|
||||||
|
size = getSize(MetadataIndex.iField);
|
||||||
|
break;
|
||||||
|
case MetadataVarType.methodDefIndex:
|
||||||
|
size = getSize(MetadataIndex.iMethodDef);
|
||||||
|
break;
|
||||||
|
case MetadataVarType.paramIndex:
|
||||||
|
size = getSize(MetadataIndex.iParam);
|
||||||
|
break;
|
||||||
|
case MetadataVarType.typeDefIndex:
|
||||||
|
size = getSize(MetadataIndex.iTypeDef);
|
||||||
|
break;
|
||||||
|
case MetadataVarType.eventIndex:
|
||||||
|
size = getSize(MetadataIndex.iEvent);
|
||||||
|
break;
|
||||||
|
case MetadataVarType.propertyIndex:
|
||||||
|
size = getSize(MetadataIndex.iProperty);
|
||||||
|
break;
|
||||||
|
case MetadataVarType.moduleRefIndex:
|
||||||
|
size = getSize(MetadataIndex.iModuleRef);
|
||||||
|
break;
|
||||||
|
case MetadataVarType.assemblyRefIndex:
|
||||||
|
size = getSize(MetadataIndex.iAssemblyRef);
|
||||||
|
break;
|
||||||
|
case MetadataVarType.genericParamIndex:
|
||||||
|
size = getSize(MetadataIndex.iGenericParam);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ApplicationException("Unknown type");
|
||||||
|
}
|
||||||
|
|
||||||
|
var field = new MetadataField();
|
||||||
|
field.offset = offset;
|
||||||
|
field.size = size;
|
||||||
|
fields.Add(field);
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint getMaxRows(MetadataIndex[] indexes) {
|
||||||
|
uint maxRows = 0;
|
||||||
|
for (int i = 0; i < indexes.Length; i++)
|
||||||
|
maxRows = Math.Max(maxRows, numRows[(int)indexes[i]]);
|
||||||
|
return maxRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSize(int bits, MetadataIndex[] indexes) {
|
||||||
|
uint maxNum = 1U << bits;
|
||||||
|
uint maxRows = getMaxRows(indexes);
|
||||||
|
return maxRows <= maxNum ? 2 : 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSize(MetadataIndex index) {
|
||||||
|
return getSize(16, new MetadataIndex[] { index });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,6 +30,14 @@ namespace de4dot.PE {
|
||||||
Cor20Header cor20Header;
|
Cor20Header cor20Header;
|
||||||
SectionHeader dotNetSection;
|
SectionHeader dotNetSection;
|
||||||
|
|
||||||
|
public BinaryReader Reader {
|
||||||
|
get { return reader; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cor20Header Cor20Header {
|
||||||
|
get { return cor20Header; }
|
||||||
|
}
|
||||||
|
|
||||||
public PeImage(byte[] data)
|
public PeImage(byte[] data)
|
||||||
: this(new MemoryStream(data)) {
|
: this(new MemoryStream(data)) {
|
||||||
}
|
}
|
||||||
|
@ -75,7 +83,7 @@ namespace de4dot.PE {
|
||||||
cor20Header = new Cor20Header(reader);
|
cor20Header = new Cor20Header(reader);
|
||||||
dotNetSection = getSectionHeader(netOffset);
|
dotNetSection = getSectionHeader(netOffset);
|
||||||
seekRva(cor20Header.metaData.virtualAddress);
|
seekRva(cor20Header.metaData.virtualAddress);
|
||||||
cor20Header.initMetadataTable(reader);
|
cor20Header.initMetadataTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +133,21 @@ namespace de4dot.PE {
|
||||||
writer.Write(data);
|
writer.Write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte readByte(uint rva) {
|
||||||
|
seekRva(rva);
|
||||||
|
return reader.ReadByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort readUInt16(uint rva) {
|
||||||
|
seekRva(rva);
|
||||||
|
return reader.ReadUInt16();
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint readUInt32(uint rva) {
|
||||||
|
seekRva(rva);
|
||||||
|
return reader.ReadUInt32();
|
||||||
|
}
|
||||||
|
|
||||||
public int readInt32(uint rva) {
|
public int readInt32(uint rva) {
|
||||||
seekRva(rva);
|
seekRva(rva);
|
||||||
return reader.ReadInt32();
|
return reader.ReadInt32();
|
||||||
|
@ -134,5 +157,21 @@ namespace de4dot.PE {
|
||||||
seekRva(rva);
|
seekRva(rva);
|
||||||
return reader.ReadBytes(size);
|
return reader.ReadBytes(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public uint offsetRead(uint offset, int size) {
|
||||||
|
if (size == 2) return offsetReadUInt16(offset);
|
||||||
|
if (size == 4) return offsetReadUInt32(offset);
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort offsetReadUInt16(uint offset) {
|
||||||
|
seek(offset);
|
||||||
|
return reader.ReadUInt16();
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint offsetReadUInt32(uint offset) {
|
||||||
|
seek(offset);
|
||||||
|
return reader.ReadUInt32();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,9 +113,14 @@
|
||||||
<Compile Include="PE\DataDirectory.cs" />
|
<Compile Include="PE\DataDirectory.cs" />
|
||||||
<Compile Include="PE\FileHeader.cs" />
|
<Compile Include="PE\FileHeader.cs" />
|
||||||
<Compile Include="PE\IFileLocation.cs" />
|
<Compile Include="PE\IFileLocation.cs" />
|
||||||
|
<Compile Include="PE\Metadata.cs" />
|
||||||
|
<Compile Include="PE\MetadataTables.cs" />
|
||||||
|
<Compile Include="PE\MetadataType.cs" />
|
||||||
|
<Compile Include="PE\MetadataTypeBuilder.cs" />
|
||||||
<Compile Include="PE\OptionalHeader.cs" />
|
<Compile Include="PE\OptionalHeader.cs" />
|
||||||
<Compile Include="PE\PeImage.cs" />
|
<Compile Include="PE\PeImage.cs" />
|
||||||
<Compile Include="PE\SectionHeader.cs" />
|
<Compile Include="PE\SectionHeader.cs" />
|
||||||
|
<Compile Include="PE\DotNetStream.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="renamer\DefinitionsRenamer.cs" />
|
<Compile Include="renamer\DefinitionsRenamer.cs" />
|
||||||
|
|
Loading…
Reference in New Issue
Block a user