blob: 02b71c8631da649fc52ddd526ee9291a42de8bfc [file] [log] [blame]
/*
* 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);
}
}