| /* |
| * Copyright 2006 ProductiveMe Inc. |
| * Copyright 2013 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.pme.exe; |
| |
| import com.pme.exe.res.ValuesAdd; |
| |
| import java.io.DataInput; |
| import java.io.DataOutput; |
| import java.io.IOException; |
| import java.io.OutputStreamWriter; |
| |
| /** |
| * Date: Mar 30, 2006 |
| * Time: 4:14:38 PM |
| */ |
| public class ExeReader extends Bin.Structure{ |
| private ArrayOfBins mySectionHeaders; |
| private SectionReader[] mySections; |
| private PeHeaderReader myPeHeader; |
| private ImageOptionalHeader myImageOptionalHeader; |
| private Bin.Bytes myBytes; |
| private Bin.Bytes myMsDosStub; |
| private MsDosHeader myMsDosHeader; |
| |
| public ExeReader(String name, ExeFormat exeFormat) { |
| super(name); |
| myMsDosHeader = new MsDosHeader(); |
| addMember( myMsDosHeader ); |
| Bin.Value member = myMsDosHeader.getValueMember("lfanew"); |
| ValuesAdd size = new ValuesAdd( member, new DWord("").setValue( myMsDosHeader.sizeInBytes() ) ); |
| myMsDosStub = new Bytes( "MsDos stub program", size ); |
| addMember( myMsDosStub ); |
| myPeHeader = new PeHeaderReader(member, exeFormat); |
| addMember( myPeHeader ); |
| if (exeFormat == ExeFormat.UNKNOWN) { |
| return; |
| } |
| myImageOptionalHeader = (ImageOptionalHeader) myPeHeader.getMember("Image Optional Header"); |
| mySectionHeaders = (ArrayOfBins)myPeHeader.getMember( "ImageSectionHeaders" ); |
| addSizeHolder( myImageOptionalHeader.getValueMember( "SizeOfImage" ) ); //b164 |
| } |
| |
| public long sizeOfHeaders(){ |
| return myPeHeader.sizeInBytes() + myMsDosStub.sizeInBytes() + myMsDosHeader.sizeInBytes(); |
| } |
| |
| public long sizeInBytes() { |
| long result = 0; |
| long va = 0; |
| for ( int i = 0; i < mySectionHeaders.size(); ++i){ |
| ImageSectionHeader header = (ImageSectionHeader)mySectionHeaders.get(i); |
| Value virtualAddress = header.getValueMember("VirtualAddress"); |
| if ( va < virtualAddress.getValue() ){ |
| result = mySections[i].sizeInBytes() + virtualAddress.getValue(); |
| } |
| } |
| long div = result / 0x1000; |
| long r = result % 0x1000; |
| if ( r != 0 ){ |
| div++; |
| } |
| result = div * 0x1000; |
| return result; |
| } |
| |
| public SectionReader[] getSections(){ |
| return mySections; |
| } |
| public ArrayOfBins getSectionHeaders(){ |
| return mySectionHeaders; |
| } |
| |
| public SectionReader getSectionReader( String sectionName ){ |
| for (SectionReader section : mySections) { |
| if (sectionName.equals(section.getSectionName())) { |
| return section; |
| } |
| } |
| return null; |
| } |
| |
| public void read(DataInput stream) throws IOException { |
| super.read(stream); |
| if (mySectionHeaders == null) { |
| return; |
| } |
| |
| long filePointer = getOffset() + sizeOfHeaders(); |
| |
| Bin.Value mainSectionsOffset; |
| mySections = new SectionReader[mySectionHeaders.size()]; |
| for ( int i = 0; i < mySectionHeaders.size(); ++i ){ |
| ImageSectionHeader sectionHeader = (ImageSectionHeader)mySectionHeaders.get(i); |
| Bin.Value startOffset = sectionHeader.getValueMember( "PointerToRawData" ); |
| Bin.Value rva = sectionHeader.getValueMember( "VirtualAddress" ); |
| |
| if ( i == 0 ){ |
| long size = startOffset.getValue() - filePointer; |
| if ( myBytes == null ){ |
| myBytes = new Bytes( "Aligment", size ); |
| addMemberToMapOnly( myBytes ); |
| } else { |
| myBytes = (Bytes)getMember( "Aligment" ); |
| myBytes.reset( (int)filePointer, (int)size ); |
| } |
| myBytes.read( stream ); |
| } |
| |
| mainSectionsOffset = new ValuesAdd( rva, startOffset ); |
| mySections[i] = new SectionReader( sectionHeader, startOffset, mainSectionsOffset, myImageOptionalHeader ); |
| mySections[i].read( stream ); |
| } |
| resetOffsets( 0 ); |
| } |
| |
| public void resetOffsets(long newOffset) { |
| super.resetOffsets(newOffset); |
| long mainOffset = myPeHeader.getOffset() + myPeHeader.sizeInBytes() + myBytes.sizeInBytes(); |
| long offset = 0; |
| for (SectionReader section : mySections) { |
| section.resetOffsets(mainOffset + offset); |
| offset += section.sizeInBytes(); |
| } |
| } |
| |
| public void write(DataOutput stream) throws IOException { |
| super.write(stream); |
| myBytes.write(stream); |
| for (SectionReader section : mySections) { |
| section.write(stream); |
| } |
| } |
| |
| public void report(OutputStreamWriter writer) throws IOException { |
| super.report(writer); |
| myBytes.report( writer ); |
| mySectionHeaders.report(writer); |
| for (SectionReader section : mySections) { |
| section.report(writer); |
| } |
| } |
| |
| public ExeFormat getExeFormat() { |
| long machine = myPeHeader.getImageFileHeader().getMachine(); |
| if (machine == 0x14c) { |
| return ExeFormat.X86; |
| } |
| if (machine == 0x8664) { |
| return ExeFormat.X64; |
| } |
| throw new UnsupportedOperationException("Unsupported machine code " + machine); |
| } |
| } |