|
Scala example source code file (PEFile.java)
The Scala PEFile.java source code/* * System.Reflection-like API for access to .NET assemblies (DLL & EXE) */ package ch.epfl.lamp.compiler.msil; import ch.epfl.lamp.compiler.msil.util.*; import ch.epfl.lamp.compiler.msil.util.Table.*; import ch.epfl.lamp.compiler.msil.Type; import ch.epfl.lamp.compiler.msil.Module; import java.io.File; import java.io.RandomAccessFile; import java.io.PrintStream; import java.io.IOException; import java.io.FileNotFoundException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.MappedByteBuffer; import java.util.Date; /** * A class that represents a .NET PE/COFF image. * * @author Nikolay Mihaylov * @version 1.0 * @see <a href="http://www.ecma-international.org/publications/standards/Ecma-335.htm">Standard ECMA-335: Common Language Infrastructure (CLI), 4th edition (June 2006) */ public class PEFile { //########################################################################## public static final int INT_SIZE = 4; protected final int PE_SIGNATURE_OFFSET; protected final int COFF_HEADER_OFFSET; protected final int PE_HEADER_OFFSET; protected final int numOfSections; protected final int CLI_RVA; protected final int CLI_Length; public final int rvaMetadata; public final int posMetadata; protected final int numOfStreams; protected final int optHeaderSize; protected final File underlyingFile; protected final RandomAccessFile file; protected final MappedByteBuffer buf; protected final PESection [] sections; public PEStream Meta, Strings, US, Blob, GUID; private final Table [] tables = new Table[Table.MAX_NUMBER]; public final boolean isDLL; protected final int heapSizes; public final boolean StringIsShort, BlobIsShort, GUIDIsShort; protected PEModule pemodule = null; //########################################################################## // PEFile constructor private static void fileFormatCheck(boolean cond, String s) { if (cond) throw new RuntimeException(s); } /** */ public PEFile(String filename) throws FileNotFoundException { this.underlyingFile = new File(filename); this.file = new RandomAccessFile(underlyingFile, "r"); FileChannel fc = file.getChannel(); MappedByteBuffer bb = null; try { bb = fc.map(FileChannel.MapMode.READ_ONLY, 0L, fc.size()); } catch (IOException e) { throw new RuntimeException(e); } /** Ecma 335, 25 File format extensions to PE: * * "Unless stated otherwise, all binary values are stored in little-endian format." */ bb.order(java.nio.ByteOrder.LITTLE_ENDIAN); this.buf = bb; /** Ecma 335, 25.2.1 MS-DOS header: * * "The PE format starts with an MS-DOS stub of exactly the following 128 bytes to * be placed at the front of the module." * * We are only checking for MZ (Mark Zbikowski) */ seek(0); fileFormatCheck(readByte() != 0x4d, "Invalid PE file format: " + filename); // 'M' fileFormatCheck(readByte() != 0x5a, "Invalid PE file format: " + filename); // 'Z' /** Ecma 335, 25.2.1 MS-DOS header: * * "At offset 0x3c in the DOS header is a 4-byte unsigned integer offset, lfanew, * to the PE signature (shall be "PE\0\0"), immediately followed by the PE file header." */ seek(0x3c); PE_SIGNATURE_OFFSET = readInt(); seek(PE_SIGNATURE_OFFSET); // start of PE signature (a signature that is just 4 bytes long) fileFormatCheck(readByte() != 0x50, "Invalid PE file format: " + filename); // 'P' fileFormatCheck(readByte() != 0x45, "Invalid PE file format: " + filename); // 'E' fileFormatCheck(readByte() != 0x00, "Invalid PE file format: " + filename); // 0 fileFormatCheck(readByte() != 0x00, "Invalid PE file format: " + filename); // 0 //trace("PE signature offset = 0x" + Table.int2hex(PE_SIGNATURE_OFFSET)); COFF_HEADER_OFFSET = PE_SIGNATURE_OFFSET + 4; PE_HEADER_OFFSET = COFF_HEADER_OFFSET + 20; seek(COFF_HEADER_OFFSET); /* start of PE file header, Sec. 25.2.2 in Partition II */ skip(2); // Machine (always 0x14c) numOfSections = readShort(); // Number of sections; indicates size of the Section Table Date timeStamp = new Date(readInt() * 1000L); skip(2 * INT_SIZE); // skip Pointer to Symbol Table (always 0) and Number of Symbols (always 0) optHeaderSize = readShort(); int characteristics = readShort(); isDLL = (characteristics & 0x2000) != 0; seek(PE_HEADER_OFFSET + 208); // p.157, Partition II CLI_RVA = readInt(); // called "Data Directory Table" in Ch. 4 of Expert IL book CLI_Length = readInt(); //trace("CLI_RVA = 0x" + Table.int2hex(CLI_RVA)); //trace("CLI_Length = 0x" + Table.int2hex(CLI_Length)); sections = new PESection[numOfSections]; seek(PE_HEADER_OFFSET + optHeaderSize); // go to the sections descriptors for (int i = 0; i < numOfSections; i++) { seek(PE_HEADER_OFFSET + optHeaderSize + i * 40); sections[i] = new PESection(this); //sections[i].dump(System.out); } seek(fromRVA(CLI_RVA)); skip(8); rvaMetadata = readInt(); posMetadata = fromRVA(rvaMetadata); //trace("rvaMetadata = 0x" + Table.int2hex(rvaMetadata)); //trace("posMetadata = 0x" + Table.int2hex(posMetadata)); seek(posMetadata); int magic = readInt(); //trace("Magic metadata signature = 0x" + Table.int2hex(magic)); fileFormatCheck(magic != 0x424a5342, "Invalid metadata signature!"); skip(8); int strlength = readInt(); //trace("version name string length = " + strlength); skip(strlength); align(INT_SIZE, posMetadata); //trace("position of flags = 0x" + Table.int2hex((int)pos())); skip(2); // ignore the flags numOfStreams = readShort(); //trace("Number of metadata streams = " + numOfStreams); for (int i = 0; i < numOfStreams; i++) { PEStream strm = new PEStream(this); //strm.dump(System.out); if (strm.name.equals("#~") || strm.name.equals("#-")) Meta = strm; if (strm.name.equals("#Strings")) Strings = strm; if (strm.name.equals("#US")) US = strm; if (strm.name.equals("#Blob")) Blob = strm; if (strm.name.equals("#GUID")) GUID = strm; } seek(Meta.offset); skip(6); heapSizes = readByte(); StringIsShort = (heapSizes & 0x01) == 0; GUIDIsShort = (heapSizes & 0x02) == 0; BlobIsShort = (heapSizes & 0x04) == 0; skip(1); long tablesMask = readLong(); long nonStandardTables = tablesMask & ~Table.VALID_TABLES_MASK; skip(8); //go to the list of number of rows for (int i = 0; i < tables.length; i++) { tables[i] = Table.newTable (this, i, ((tablesMask >> i) & 0x01) != 0 ? readInt() : 0); } initIndexSize(); initTableRefs(); // populate the tables from the CLI image file long start = pos(); for (int i = 0; i < tables.length; i++) start = tables[i].init(start); } // PEFile() public final int[] indexSize = new int[Table.TABLE_SET_LENGTH]; private void initIndexSize() { for (int i = 0; i < Table.TABLE_SET_LENGTH; i++) { indexSize[i] = 2; int[] tableSet = Table.TableSet[i]; int treshold = (65536 >> Table.NoBits[i]); for (int j = 0; j < tableSet.length; j++) { if (tableSet[j] >= 0) { Table t = tables[tableSet[j]]; if (t.rows >= treshold) { indexSize[i] = 4; break; } } } } } protected void initModule(PEModule module) { if (pemodule != null) throw new RuntimeException("File " + this + " has already been assigned module " + pemodule + "; new module is " + module); this.pemodule = module; } //########################################################################## public ModuleDef ModuleDef; public ModuleDef ModuleDef(int i) { ModuleDef.readRow(i); return ModuleDef; } public TypeRef TypeRef; public TypeDef TypeDef; public TypeDef TypeDef(int i) { TypeDef.readRow(i); return TypeDef; } public FieldTrans FieldTrans; public FieldTrans FieldTrans(int i) { FieldTrans.readRow(i); return FieldTrans; } public FieldDef FieldDef; public FieldDef FieldDef(int i) { FieldDef.readRow(i); return FieldDef; } public MethodTrans MethodTrans; public MethodTrans MethodTrans(int i) { MethodTrans.readRow(i); return MethodTrans; } public MethodDef MethodDef; public MethodDef MethodDef(int i) { MethodDef.readRow(i); return MethodDef; } public ParamDef ParamDef; public ParamDef ParamDef(int i) { ParamDef.readRow(i); return ParamDef; } public GenericParam GenericParam; public GenericParam GenericParam(int i) { GenericParam.readRow(i); return GenericParam; } public MethodSpec MethodSpec; public MethodSpec MethodSpec(int i) { MethodSpec.readRow(i); return MethodSpec; } public GenericParamConstraint GenericParamConstraint; public GenericParamConstraint GenericParamConstraint(int i) { GenericParamConstraint.readRow(i); return GenericParamConstraint; } public InterfaceImpl InterfaceImpl; public MemberRef MemberRef; public Constant Constant; public CustomAttribute CustomAttribute; public FieldMarshal FieldMarshal; public DeclSecurity DeclSecurity; public ClassLayout ClassLayout; public FieldLayout FieldLayout; public StandAloneSig StandAloneSig; public EventMap EventMap; public EventDef EventDef; public PropertyMap PropertyMap; public PropertyDef PropertyDef; public MethodSemantics MethodSemantics; public MethodImpl MethodImpl; public ModuleRef ModuleRef; public TypeSpec TypeSpec; public ImplMap ImplMap; public FieldRVA FieldRVA; public AssemblyDef AssemblyDef; public AssemblyRef AssemblyRef; public FileDef FileDef; public ExportedType ExportedType; public ManifestResource ManifestResource; public NestedClass NestedClass; private void initTableRefs() { ModuleDef = (ModuleDef) getTable(Table.ModuleDef.ID); TypeRef = (TypeRef) getTable(Table.TypeRef.ID); TypeDef = (TypeDef) getTable(Table.TypeDef.ID); FieldTrans = (FieldTrans) getTable(Table.FieldTrans.ID); FieldDef = (FieldDef) getTable(Table.FieldDef.ID); MethodTrans = (MethodTrans) getTable(Table.MethodTrans.ID); MethodDef = (MethodDef) getTable(Table.MethodDef.ID); ParamDef = (ParamDef) getTable(Table.ParamDef.ID); InterfaceImpl = (InterfaceImpl) getTable(Table.InterfaceImpl.ID); MemberRef = (MemberRef) getTable(Table.MemberRef.ID); Constant = (Constant) getTable(Table.Constant.ID); CustomAttribute = (CustomAttribute) getTable(Table.CustomAttribute.ID); FieldMarshal = (FieldMarshal) getTable(Table.FieldMarshal.ID); DeclSecurity = (DeclSecurity) getTable(Table.DeclSecurity.ID); ClassLayout = (ClassLayout) getTable(Table.ClassLayout.ID); FieldLayout = (FieldLayout) getTable(Table.FieldLayout.ID); StandAloneSig = (StandAloneSig) getTable(Table.StandAloneSig.ID); EventMap = (EventMap) getTable(Table.EventMap.ID); EventDef = (EventDef) getTable(Table.EventDef.ID); PropertyMap = (PropertyMap) getTable(Table.PropertyMap.ID); PropertyDef = (PropertyDef) getTable(Table.PropertyDef.ID); MethodSemantics = (MethodSemantics) getTable(Table.MethodSemantics.ID); MethodImpl = (MethodImpl) getTable(Table.MethodImpl.ID); ModuleRef = (ModuleRef) getTable(Table.ModuleRef.ID); TypeSpec = (TypeSpec) getTable(Table.TypeSpec.ID); ImplMap = (ImplMap) getTable(Table.ImplMap.ID); FieldRVA = (FieldRVA) getTable(Table.FieldRVA.ID); AssemblyDef = (AssemblyDef) getTable(Table.AssemblyDef.ID); AssemblyRef = (AssemblyRef) getTable(Table.AssemblyRef.ID); FileDef = (FileDef) getTable(Table.FileDef.ID); ExportedType = (ExportedType) getTable(Table.ExportedType.ID); NestedClass = (NestedClass) getTable(Table.NestedClass.ID); ManifestResource = (ManifestResource) getTable(Table.ManifestResource.ID); GenericParam = (GenericParam) getTable(Table.GenericParam.ID); MethodSpec = (MethodSpec) getTable(Table.MethodSpec.ID); GenericParamConstraint = (GenericParamConstraint) getTable(Table.GenericParamConstraint.ID); } public static String long2hex(long a) { StringBuffer str = new StringBuffer("0000000000000000"); str.append(Long.toHexString(a)); int l = str.length(); return str.substring(l - 16, l); } public static String int2hex(int a) { StringBuffer str = new StringBuffer("00000000"); str.append(Integer.toHexString(a)); int l = str.length(); return str.substring(l - 8, l); } public static String short2hex(int a) { StringBuffer str = new StringBuffer("0000"); str.append(Integer.toHexString(a)); int l = str.length(); return str.substring(l - 4, l); } public static String byte2hex(int a) { StringBuffer str = new StringBuffer("00"); str.append(Integer.toHexString(a)); int l = str.length(); return str.substring(l - 2, l); } public static String bytes2hex(byte[] buf) { StringBuffer str = new StringBuffer(); for (int i = 0; i < buf.length; i++) { str.append(byte2hex(buf[i])); if (i < buf.length - 1) str.append(" "); } return str.toString(); } //########################################################################## // filename public File getUnderlyingFile() { return underlyingFile; } /** * @return the absolute path of the file */ public String getAbsolutePath() { return underlyingFile.getAbsolutePath(); } /** * @return the name of this file */ public String getName() { return underlyingFile.getName(); } /** * @return */ public String getParent() { return underlyingFile.getParent(); } /** * @return the file representing the directory the file belongs to */ public File getParentFile() { return underlyingFile.getParentFile(); } public String toString() { return getAbsolutePath(); } //########################################################################## // file pointer manipulation methods /** Returns the current position in the file. */ public int pos() { return buf.position(); } /** Go to the specified position in the file. */ public void seek(int pos) { buf.position(pos); } /** Align the current position in the file. */ public void align(int base) { align(base, 0); } /** Align the current position in a section starting at offset. */ public void align(int base, int offset) { int p = pos() - offset; seek( offset + ((p % base) == 0 ? p : (p/base + 1) * base)); } /** Computes the position in the file that corresponds to the given RVA. */ public int fromRVA(int rva) { int i; for(i = 0; i < numOfSections; i++) if(sections[i].virtAddr <= rva && rva <= (sections[i].virtAddr + sections[i].virtSize)) return rva - sections[i].virtAddr + sections[i].realAddr; throw new RuntimeException("RVA 0x" + Integer.toHexString(rva) + " is not within this file's sections!"); } /** Go to the specified RVA (Relative Virtual Address). */ public void gotoRVA(int rva) { seek(fromRVA(rva)); } /** Move the forward in the file by the specified number of bytes. */ public void skip(int n) { buf.position(buf.position() + n); } /** * Returns a memory mapped little-endian buffer * for the specified region of the file. */ public MappedByteBuffer mapBuffer(long offset, int size) { try { MappedByteBuffer b = file.getChannel() .map(FileChannel.MapMode.READ_ONLY, offset, size); b.order(java.nio.ByteOrder.LITTLE_ENDIAN); return b; } catch (IOException e) { throw new RuntimeException(e); } } /** Returns a buffer from the given offset to the end of the file. */ public ByteBuffer getBuffer(long offset, int size) { buf.mark(); buf.position((int)offset); ByteBuffer bb = buf.slice(); buf.reset(); bb.limit(size); bb.order(java.nio.ByteOrder.LITTLE_ENDIAN); return bb; } //########################################################################## // file read methods /** * Read bs.length number of bytes */ public void read(byte[] bs) { buf.get(bs); } /** * Read 1-byte integer from the current position in the file. */ public int readByte() { return buf.get(); } /** * Read 2-byte integer from the current position in the file. */ public int readShort() { return buf.getShort(); } /** * Read 4-byte integer from the current position in the file. */ public int readInt() { return buf.getInt(); } /** * Read 8-byte integer from the current position in the file. */ public long readLong() { return buf.getLong(); } /** * @return the size of string indeces for this file. */ public int getStringIndexSize() { return StringIsShort ? 2 : 4; } /** * @return the size of GUID indeces for this file. */ public int getGUIDIndexSize() { return GUIDIsShort ? 2 : 4; } /** * @return the size of Blob indeces for this file. */ public int getBlobIndexSize() { return BlobIsShort ? 2 : 4; } /** * @return the size of the index to tableID for this file; * @param tableID the ID of the table */ public int getTableIndexSize(int tableID) { return tables[tableID].isShort ? 2 : 4; } /** * @return the size of the index to a set of tables with the given @param TableSetID * @param tableSetID the ID of the table set */ public int getTableSetIndexSize(int tableSetID) { return indexSize[tableSetID]; } /** * Read a String index from the current position in the file. * @return an index into the String stream */ public int readStringIndex() { return StringIsShort ? readShort() : readInt(); } /** * Read a GUID index from the current position in the file. * @return an index in to the GUID stream */ public int readGUIDIndex() { return GUIDIsShort ? readShort() : readInt(); } /** * Read a Blob index from the current position in the file. * @return an index into the Blob stream */ public int readBlobIndex() { return BlobIsShort ? readShort() : readInt(); } /** Read an entry interpreted as index into table @param tableID. */ public int readTableIndex(int tableId) { return tables[tableId].isShort ? readShort() : readInt(); } /***/ public int readTableSetIndex(int tableSetId) { return indexSize[tableSetId] == 2 ? readShort() : readInt(); } /** * Read a string from the String stream * @return the string at the given position * @param pos the position of the string in the String stream */ public String getString(int pos) { String s = Strings.getString(pos); return s;//.length() == 0 ? null : s; } /** * Read a string from the US (User Strings) stream * @return the string at the given position * @param pos the position of the string in the US stream */ public String getUString(int pos) { return US.getString(pos); } /** * Read a blob from the Blob Stream * @return the blob at the given position * @param pos the position of the blob in the Blob stream */ public byte[] getBlob(int pos) { return Blob.getBlob(pos); } /***/ public Sig getSignature(int pos) { //return new Sig(getBlob(pos)); return Blob.getSignature(pos); } /***/ public byte[] getGUID(int pos) { return GUID.getGUID(pos); } /** * @return the table with the corresponding ID. */ public final Table getTable(int tableID) { return tables[tableID]; } //########################################################################## /***/ void trace(String msg) { System.out.println("[trace] " + msg); } //########################################################################## public Sig newSignature(ByteBuffer buf) { return new Sig(buf); } /** */ public class Sig implements Signature { //###################################################################### // instance members protected final ByteBuffer buf; protected final int pos; protected final int length; public Sig(ByteBuffer buf) { this.buf = buf; //int tmpPos = buf.position(); length = decodeInt(); this.pos = buf.position(); } public String toString() { StringBuffer b = new StringBuffer("("); int savedPos = buf.position(); reset(); for (int i = 0; i < length; i++) { b.append(byte2hex(readByte())); if (i < length - 1) b.append(" "); } buf.position(savedPos); return b.append(")").toString(); } public Sig reset() { buf.position(pos); return this; } public int pos() { return buf.position() - pos; } /** @return the byte at the current position in the signature Blob. * Stay at the same position */ public int getByte() { return (buf.get(buf.position()) + 0x100) & 0xff; } /** @return the byte at the current position in the signature Blob. * Move to the next byte. */ public int readByte() { return (buf.get() + 0x100) & 0xff; } /** Skip the current byte if equal to the given value. */ public void skipByte(int b) { if (b == getByte()) buf.get(); } /** Decodes an integer from the signature Blob. * @return the decoded integer */ public int decodeInt() { int res = readByte(); if ((res & 0x80) != 0) { res = ((res & 0x7f) << 8) | readByte(); if ((res & 0x4000) != 0) res = ((res & 0x3fff)<<16) | (readByte()<<8) | readByte(); } return res; } /** @return - the type encoded at the current position in the signature * according to 23.2.12 */ public Type decodeType() { try { return decodeType0(); } catch (RuntimeException e) { System.out.println("" + pos() + "@" + this); throw e; } } public Type decodeType0() { Type type = null; int desc = readByte(); switch (desc) { case ELEMENT_TYPE_BOOLEAN:type = Type.GetType("System.Boolean"); break; case ELEMENT_TYPE_CHAR: type = Type.GetType("System.Char"); break; case ELEMENT_TYPE_I1: type = Type.GetType("System.SByte"); break; case ELEMENT_TYPE_U1: type = Type.GetType("System.Byte"); break; case ELEMENT_TYPE_I2: type = Type.GetType("System.Int16"); break; case ELEMENT_TYPE_U2: type = Type.GetType("System.UInt16"); break; case ELEMENT_TYPE_I4: type = Type.GetType("System.Int32"); break; case ELEMENT_TYPE_U4: type = Type.GetType("System.UInt32"); break; case ELEMENT_TYPE_I8: type = Type.GetType("System.Int64"); break; case ELEMENT_TYPE_U8: type = Type.GetType("System.UInt64"); break; case ELEMENT_TYPE_R4: type = Type.GetType("System.Single"); break; case ELEMENT_TYPE_R8: type = Type.GetType("System.Double"); break; case ELEMENT_TYPE_OBJECT: type = Type.GetType("System.Object"); break; case ELEMENT_TYPE_STRING: type = Type.GetType("System.String"); break; case ELEMENT_TYPE_I: type = Type.GetType("System.IntPtr"); break; case ELEMENT_TYPE_U: type = Type.GetType("System.UIntPtr"); break; case ELEMENT_TYPE_PTR: // Followed by <type> token. if (getByte() == ELEMENT_TYPE_VOID) { readByte(); type = Type.mkPtr(Type.GetType("System.Void")); } else type = Type.mkPtr(decodeType()); break; case ELEMENT_TYPE_BYREF: /* although BYREF is not listed in 23.2.12. as possible alternative, this method is also called when parsing the signatures of a method param and a method return, which do allow for BYREF */ type = Type.mkByRef(decodeType()); break; case ELEMENT_TYPE_VALUETYPE: // Followed by TypeDefOrRefEncoded assert true; case ELEMENT_TYPE_CLASS: // Followed by <type> token type = pemodule.getTypeDefOrRef(decodeInt()); if (type == null) throw new RuntimeException(); break; case ELEMENT_TYPE_SZARRAY: // Single-dim array with 0 lower bound. skipCustomMods(); type = Type.mkArray(decodeType(), 1); break; case ELEMENT_TYPE_ARRAY: // <type> Other Scala examples (source code examples)Here is a short list of links related to this Scala PEFile.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.