From a95ee6eb678b4fb8740d4d1404ba11c6b06bc820 Mon Sep 17 00:00:00 2001
From: swismer <47538304+swismer@users.noreply.github.com>
Date: Mon, 26 Jun 2023 17:54:38 +0200
Subject: [PATCH] Parser and Assembler refactoring (#31)
* Update minimal Java version to 8
* Move read and write functionality to corresponding data structures
* Add read-write test for whole PE file
* Move read and write functionality for resources to corresponding data structures
* Add write support for more resource structures
---
README.md | 4 +-
pom.xml | 7 +-
.../pecoff4j/AttributeCertificateTable.java | 16 +
.../java/com/kichik/pecoff4j/BoundImport.java | 17 +
.../pecoff4j/BoundImportDirectoryTable.java | 81 ++
.../com/kichik/pecoff4j/CLRRuntimeHeader.java | 29 +
.../java/com/kichik/pecoff4j/COFFHeader.java | 27 +
.../java/com/kichik/pecoff4j/DOSHeader.java | 74 ++
.../java/com/kichik/pecoff4j/DOSStub.java | 20 +
.../com/kichik/pecoff4j/DebugDirectory.java | 18 +
.../com/kichik/pecoff4j/ExportDirectory.java | 21 +
.../java/com/kichik/pecoff4j/ImageData.java | 154 ++++
.../kichik/pecoff4j/ImageDataDirectory.java | 19 +
.../com/kichik/pecoff4j/ImportDirectory.java | 25 +
.../kichik/pecoff4j/ImportDirectoryEntry.java | 20 +
.../kichik/pecoff4j/ImportDirectoryTable.java | 23 +
.../java/com/kichik/pecoff4j/ImportEntry.java | 14 +
.../kichik/pecoff4j/LoadConfigDirectory.java | 34 +
.../com/kichik/pecoff4j/OptionalHeader.java | 111 +++
src/main/java/com/kichik/pecoff4j/PE.java | 266 ++++++
.../java/com/kichik/pecoff4j/PESignature.java | 16 +
.../kichik/pecoff4j/ResourceDirectory.java | 71 ++
.../pecoff4j/ResourceDirectoryTable.java | 26 +
.../com/kichik/pecoff4j/ResourceEntry.java | 60 ++
.../java/com/kichik/pecoff4j/SectionData.java | 68 ++
.../com/kichik/pecoff4j/SectionHeader.java | 33 +
.../com/kichik/pecoff4j/SectionTable.java | 29 +
.../com/kichik/pecoff4j/io/DataWriter.java | 32 +
.../com/kichik/pecoff4j/io/IDataReader.java | 37 +
.../com/kichik/pecoff4j/io/IDataWriter.java | 14 +-
.../com/kichik/pecoff4j/io/PEAssembler.java | 329 +-------
.../java/com/kichik/pecoff4j/io/PEParser.java | 772 +++---------------
.../kichik/pecoff4j/io/ResourceAssembler.java | 87 +-
.../kichik/pecoff4j/io/ResourceParser.java | 330 +++-----
.../kichik/pecoff4j/io/SectionAssembler.java | 14 -
.../com/kichik/pecoff4j/resources/Bitmap.java | 18 +
.../pecoff4j/resources/BitmapFileHeader.java | 13 +-
.../pecoff4j/resources/BitmapInfoHeader.java | 36 +
.../pecoff4j/resources/FixedFileInfo.java | 39 +
.../pecoff4j/resources/IconDirectory.java | 25 +
.../resources/IconDirectoryEntry.java | 30 +
.../kichik/pecoff4j/resources/IconImage.java | 67 ++
.../kichik/pecoff4j/resources/Manifest.java | 16 +
.../kichik/pecoff4j/resources/RGBQuad.java | 21 +
.../pecoff4j/resources/StringFileInfo.java | 49 ++
.../kichik/pecoff4j/resources/StringPair.java | 50 ++
.../pecoff4j/resources/StringTable.java | 39 +
.../com/kichik/pecoff4j/resources/Var.java | 29 +
.../pecoff4j/resources/VarFileInfo.java | 29 +
.../pecoff4j/resources/VersionInfo.java | 59 ++
.../kichik/pecoff4j/util/IconExtractor.java | 5 +-
.../com/kichik/pecoff4j/util/IconFile.java | 10 +-
.../com/kichik/pecoff4j/ReadWriteTest.java | 100 +++
.../kichik/pecoff4j/VersionStringsTest.java | 4 +-
.../kichik/pecoff4j/io/ValidatingWriter.java | 107 +++
55 files changed, 2328 insertions(+), 1316 deletions(-)
delete mode 100644 src/main/java/com/kichik/pecoff4j/io/SectionAssembler.java
create mode 100644 src/test/java/com/kichik/pecoff4j/ReadWriteTest.java
create mode 100644 src/test/java/com/kichik/pecoff4j/io/ValidatingWriter.java
diff --git a/README.md b/README.md
index a9dac13..4d4f208 100644
--- a/README.md
+++ b/README.md
@@ -45,8 +45,8 @@ import com.kichik.pecoff4j.PE;
import com.kichik.pecoff4j.ResourceDirectory;
import com.kichik.pecoff4j.ResourceEntry;
import com.kichik.pecoff4j.constant.ResourceType;
+import com.kichik.pecoff4j.io.DataReader;
import com.kichik.pecoff4j.io.PEParser;
-import com.kichik.pecoff4j.io.ResourceParser;
import com.kichik.pecoff4j.resources.StringFileInfo;
import com.kichik.pecoff4j.resources.StringTable;
import com.kichik.pecoff4j.resources.VersionInfo;
@@ -61,7 +61,7 @@ public class Main {
ResourceEntry[] entries = ResourceHelper.findResources(rd, ResourceType.VERSION_INFO);
for (int i = 0; i < entries.length; i++) {
byte[] data = entries[i].getData();
- VersionInfo version = ResourceParser.readVersionInfo(data);
+ VersionInfo version = VersionInfo.read(new DataReader(data));
StringFileInfo strings = version.getStringFileInfo();
StringTable table = strings.getTable(0);
diff --git a/pom.xml b/pom.xml
index c0cc492..2be7e02 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,8 +29,7 @@
UTF-8
-
- 7
+ 8
@@ -114,9 +113,9 @@
9
-
+
- java-7-compile
+ java-8-compile
compile
diff --git a/src/main/java/com/kichik/pecoff4j/AttributeCertificateTable.java b/src/main/java/com/kichik/pecoff4j/AttributeCertificateTable.java
index 9947614..3178880 100644
--- a/src/main/java/com/kichik/pecoff4j/AttributeCertificateTable.java
+++ b/src/main/java/com/kichik/pecoff4j/AttributeCertificateTable.java
@@ -9,8 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.DataReader;
import com.kichik.pecoff4j.util.DataObject;
+import java.io.IOException;
+
/**
* Encapsulates the Attribute Certificate Table (Image Only). Section 5.7 of the PE/COFF
* spec Rev10.
@@ -21,6 +24,19 @@ public class AttributeCertificateTable extends DataObject {
private int certificateType;
private byte[] certificate;
+ public static AttributeCertificateTable read(byte[] b) throws IOException {
+ AttributeCertificateTable dd = new AttributeCertificateTable();
+ dd.set(b);
+ DataReader dr = new DataReader(b);
+ dd.setLength(dr.readDoubleWord());
+ dd.setRevision(dr.readWord());
+ dd.setCertificateType(dr.readWord());
+ byte[] certificate = new byte[dd.getLength() - 8];
+ dr.read(certificate);
+ dd.setCertificate(certificate);
+ return dd;
+ }
+
public int getLength() {
return length;
}
diff --git a/src/main/java/com/kichik/pecoff4j/BoundImport.java b/src/main/java/com/kichik/pecoff4j/BoundImport.java
index eda258c..4644695 100644
--- a/src/main/java/com/kichik/pecoff4j/BoundImport.java
+++ b/src/main/java/com/kichik/pecoff4j/BoundImport.java
@@ -9,12 +9,29 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+
+import java.io.IOException;
+
public class BoundImport {
private long timestamp;
private int offsetToModuleName;
private String moduleName;
private int numModuleForwarderRefs;
+ public static BoundImport read(IDataReader dr) throws IOException {
+ BoundImport bi = new BoundImport();
+ bi.setTimestamp(dr.readDoubleWord());
+ bi.setOffsetToModuleName(dr.readWord());
+ bi.setNumberOfModuleForwarderRefs(dr.readWord());
+
+ if (bi.getTimestamp() == 0 && bi.getOffsetToModuleName() == 0
+ && bi.getNumberOfModuleForwarderRefs() == 0)
+ return null;
+
+ return bi;
+ }
+
public long getTimestamp() {
return timestamp;
}
diff --git a/src/main/java/com/kichik/pecoff4j/BoundImportDirectoryTable.java b/src/main/java/com/kichik/pecoff4j/BoundImportDirectoryTable.java
index 89af24b..32d7da0 100644
--- a/src/main/java/com/kichik/pecoff4j/BoundImportDirectoryTable.java
+++ b/src/main/java/com/kichik/pecoff4j/BoundImportDirectoryTable.java
@@ -9,12 +9,93 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.constant.ImageDataDirectoryType;
+import com.kichik.pecoff4j.io.DataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+import com.kichik.pecoff4j.util.IntMap;
+
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
public class BoundImportDirectoryTable {
private List imports = new ArrayList();
+ public static BoundImportDirectoryTable read(DataReader dr) throws IOException {
+ BoundImportDirectoryTable bidt = new BoundImportDirectoryTable();
+ List imports = new ArrayList();
+ BoundImport bi = null;
+ while ((bi = BoundImport.read(dr)) != null) {
+ bidt.add(bi);
+ imports.add(bi);
+ }
+ Collections.sort(imports, new Comparator() {
+ @Override
+ public int compare(BoundImport o1, BoundImport o2) {
+ return o1.getOffsetToModuleName() - o2.getOffsetToModuleName();
+ }
+ });
+ IntMap names = new IntMap();
+ for (int i = 0; i < imports.size(); i++) {
+ bi = imports.get(i);
+ int offset = bi.getOffsetToModuleName();
+ String n = (String) names.get(offset);
+ if (n == null) {
+ dr.jumpTo(offset);
+ n = dr.readUtf();
+ names.put(offset, n);
+ }
+ bi.setModuleName(n);
+ }
+ return bidt;
+ }
+
+ public void write(PE pe, IDataWriter dw) throws IOException {
+ int pos = dw.getPosition();
+ List bil = new ArrayList();
+
+ for (int i = 0; i < size(); i++) {
+ BoundImport bi = get(i);
+ bil.add(bi);
+ dw.writeDoubleWord((int) bi.getTimestamp());
+ dw.writeWord(bi.getOffsetToModuleName());
+ dw.writeWord(bi.getNumberOfModuleForwarderRefs());
+ }
+
+ Collections.sort(bil, new Comparator() {
+ @Override
+ public int compare(BoundImport o1, BoundImport o2) {
+ return o1.getOffsetToModuleName() - o2.getOffsetToModuleName();
+ }
+ });
+
+ // Now write out empty block
+ dw.writeDoubleWord(0);
+ dw.writeDoubleWord(0);
+
+ // Now write out module names
+ Set names = new HashSet();
+ for (int i = 0; i < bil.size(); i++) {
+ String s = bil.get(i).getModuleName();
+ if (!names.contains(s))
+ dw.writeUtf(s);
+ names.add(s);
+ }
+
+ // Check for empty block at end - padding for alignment
+ int dpos = dw.getPosition() - pos;
+ int bis = pe.getOptionalHeader()
+ .getDataDirectory(ImageDataDirectoryType.BOUND_IMPORT)
+ .getSize();
+ if (bis > dpos) {
+ dw.writeByte(0, bis - dpos);
+ }
+ }
+
public void add(BoundImport bi) {
imports.add(bi);
}
diff --git a/src/main/java/com/kichik/pecoff4j/CLRRuntimeHeader.java b/src/main/java/com/kichik/pecoff4j/CLRRuntimeHeader.java
index 7bc4e5a..575b38c 100644
--- a/src/main/java/com/kichik/pecoff4j/CLRRuntimeHeader.java
+++ b/src/main/java/com/kichik/pecoff4j/CLRRuntimeHeader.java
@@ -1,7 +1,10 @@
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.DataReader;
import com.kichik.pecoff4j.util.DataObject;
+import java.io.IOException;
+
public class CLRRuntimeHeader extends DataObject {
private int headerSize;
private int majorRuntimeVersion;
@@ -23,6 +26,32 @@ public class CLRRuntimeHeader extends DataObject {
private int managedNativeHeaderAddress;
private int managedNativeHeaderSize;
+ public static CLRRuntimeHeader read(byte[] b) throws IOException {
+ DataReader dr = new DataReader(b);
+ CLRRuntimeHeader clrrh = new CLRRuntimeHeader();
+ clrrh.set(b);
+ clrrh.setHeaderSize(dr.readDoubleWord());
+ clrrh.setMajorRuntimeVersion(dr.readWord());
+ clrrh.setMinorRuntimeVersion(dr.readWord());
+ clrrh.setMetaDataDirectoryAddress(dr.readDoubleWord());
+ clrrh.setMetaDataDirectorySize(dr.readDoubleWord());
+ clrrh.setFlags(dr.readDoubleWord());
+ clrrh.setEntryPointToken(dr.readDoubleWord());
+ clrrh.setResourcesDirectoryAddress(dr.readDoubleWord());
+ clrrh.setResourcesDirectorySize(dr.readDoubleWord());
+ clrrh.setStrongNameSignatureAddress(dr.readDoubleWord());
+ clrrh.setStrongNameSignatureSize(dr.readDoubleWord());
+ clrrh.setCodeManagerTableAddress(dr.readDoubleWord());
+ clrrh.setCodeManagerTableSize(dr.readDoubleWord());
+ clrrh.setvTableFixupsAddress(dr.readDoubleWord());
+ clrrh.setvTableFixupsSize(dr.readDoubleWord());
+ clrrh.setExportAddressTableJumpsAddress(dr.readDoubleWord());
+ clrrh.setExportAddressTableJumpsSize(dr.readDoubleWord());
+ clrrh.setManagedNativeHeaderAddress(dr.readDoubleWord());
+ clrrh.setManagedNativeHeaderSize(dr.readDoubleWord());
+ return clrrh;
+ }
+
public int getHeaderSize() {
return headerSize;
}
diff --git a/src/main/java/com/kichik/pecoff4j/COFFHeader.java b/src/main/java/com/kichik/pecoff4j/COFFHeader.java
index d25e489..53f7d63 100644
--- a/src/main/java/com/kichik/pecoff4j/COFFHeader.java
+++ b/src/main/java/com/kichik/pecoff4j/COFFHeader.java
@@ -9,6 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class COFFHeader {
private int machine;
private int numberOfSections;
@@ -18,6 +23,28 @@ public class COFFHeader {
private int sizeOfOptionalHeader;
private int characteristics;
+ public static COFFHeader read(IDataReader dr) throws IOException {
+ COFFHeader h = new COFFHeader();
+ h.setMachine(dr.readWord());
+ h.setNumberOfSections(dr.readWord());
+ h.setTimeDateStamp(dr.readDoubleWord());
+ h.setPointerToSymbolTable(dr.readDoubleWord());
+ h.setNumberOfSymbols(dr.readDoubleWord());
+ h.setSizeOfOptionalHeader(dr.readWord());
+ h.setCharacteristics(dr.readWord());
+ return h;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeWord(getMachine());
+ dw.writeWord(getNumberOfSections());
+ dw.writeDoubleWord(getTimeDateStamp());
+ dw.writeDoubleWord(getPointerToSymbolTable());
+ dw.writeDoubleWord(getNumberOfSymbols());
+ dw.writeWord(getSizeOfOptionalHeader());
+ dw.writeWord(getCharacteristics());
+ }
+
public int getMachine() {
return machine;
}
diff --git a/src/main/java/com/kichik/pecoff4j/DOSHeader.java b/src/main/java/com/kichik/pecoff4j/DOSHeader.java
index 69cd241..392658e 100644
--- a/src/main/java/com/kichik/pecoff4j/DOSHeader.java
+++ b/src/main/java/com/kichik/pecoff4j/DOSHeader.java
@@ -9,6 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class DOSHeader {
public static final int DOS_MAGIC = 0;
@@ -33,6 +38,75 @@ public class DOSHeader {
private int addressOfNewExeHeader;
private int stubSize;
+ public static DOSHeader read(IDataReader dr) throws IOException {
+ DOSHeader dh = new DOSHeader();
+ dh.setMagic(dr.readWord());
+ dh.setUsedBytesInLastPage(dr.readWord());
+ dh.setFileSizeInPages(dr.readWord());
+ dh.setNumRelocationItems(dr.readWord());
+ dh.setHeaderSizeInParagraphs(dr.readWord());
+ dh.setMinExtraParagraphs(dr.readWord());
+ dh.setMaxExtraParagraphs(dr.readWord());
+ dh.setInitialSS(dr.readWord());
+ dh.setInitialSP(dr.readWord());
+ dh.setChecksum(dr.readWord());
+ dh.setInitialIP(dr.readWord());
+ dh.setInitialRelativeCS(dr.readWord());
+ dh.setAddressOfRelocationTable(dr.readWord());
+ dh.setOverlayNumber(dr.readWord());
+ int[] reserved = new int[4];
+ for (int i = 0; i < reserved.length; i++) {
+ reserved[i] = dr.readWord();
+ }
+ dh.setReserved(reserved);
+ dh.setOemId(dr.readWord());
+ dh.setOemInfo(dr.readWord());
+ int[] reserved2 = new int[10];
+ for (int i = 0; i < reserved2.length; i++) {
+ reserved2[i] = dr.readWord();
+ }
+ dh.setReserved2(reserved2);
+ dh.setAddressOfNewExeHeader(dr.readDoubleWord());
+
+ // calc stub size
+ int stubSize = dh.getFileSizeInPages() * 512
+ - (512 - dh.getUsedBytesInLastPage());
+ if (stubSize > dh.getAddressOfNewExeHeader())
+ stubSize = dh.getAddressOfNewExeHeader();
+ stubSize -= dh.getHeaderSizeInParagraphs() * 16;
+ dh.setStubSize(stubSize);
+
+ return dh;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeWord(getMagic());
+ dw.writeWord(getUsedBytesInLastPage());
+ dw.writeWord(getFileSizeInPages());
+ dw.writeWord(getNumRelocationItems());
+ dw.writeWord(getHeaderSizeInParagraphs());
+ dw.writeWord(getMinExtraParagraphs());
+ dw.writeWord(getMaxExtraParagraphs());
+ dw.writeWord(getInitialSS());
+ dw.writeWord(getInitialSP());
+ dw.writeWord(getChecksum());
+ dw.writeWord(getInitialIP());
+ dw.writeWord(getInitialRelativeCS());
+ dw.writeWord(getAddressOfRelocationTable());
+ dw.writeWord(getOverlayNumber());
+ int[] res = getReserved();
+ for (int i = 0; i < res.length; i++) {
+ dw.writeWord(res[i]);
+ }
+ dw.writeWord(getOemId());
+ dw.writeWord(getOemInfo());
+ int[] res2 = getReserved2();
+ for (int i = 0; i < res2.length; i++) {
+ dw.writeWord(res2[i]);
+ }
+ dw.writeDoubleWord(getAddressOfNewExeHeader());
+ }
+
public int getMagic() {
return magic;
}
diff --git a/src/main/java/com/kichik/pecoff4j/DOSStub.java b/src/main/java/com/kichik/pecoff4j/DOSStub.java
index 6d9e84a..87c0632 100644
--- a/src/main/java/com/kichik/pecoff4j/DOSStub.java
+++ b/src/main/java/com/kichik/pecoff4j/DOSStub.java
@@ -9,12 +9,32 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
/**
* Used to store the stub program.
*/
public class DOSStub {
private byte[] stub;
+ public static DOSStub read(DOSHeader header, IDataReader dr)
+ throws IOException {
+ DOSStub ds = new DOSStub();
+ int pos = dr.getPosition();
+ int add = header.getAddressOfNewExeHeader();
+ byte[] stub = new byte[add - pos];
+ dr.read(stub);
+ ds.setStub(stub);
+ return ds;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeBytes(getStub());
+ }
+
public byte[] getStub() {
return stub;
}
diff --git a/src/main/java/com/kichik/pecoff4j/DebugDirectory.java b/src/main/java/com/kichik/pecoff4j/DebugDirectory.java
index 2ebfaba..c4c9ca5 100644
--- a/src/main/java/com/kichik/pecoff4j/DebugDirectory.java
+++ b/src/main/java/com/kichik/pecoff4j/DebugDirectory.java
@@ -9,8 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.DataReader;
import com.kichik.pecoff4j.util.DataObject;
+import java.io.IOException;
+
/**
* Encapsulates the Debug Directory (Image Only). Section 6.1.1 of the PE/COFF
* spec v8.
@@ -24,6 +27,21 @@ public class DebugDirectory extends DataObject {
private int addressOfRawData;
private int pointerToRawData;
+ public static DebugDirectory read(byte[] b) throws IOException {
+ DebugDirectory dd = new DebugDirectory();
+ dd.set(b);
+ DataReader dr = new DataReader(b);
+ dd.setCharacteristics(dr.readDoubleWord());
+ dd.setTimeDateStamp(dr.readDoubleWord());
+ dd.setMajorVersion(dr.readWord());
+ dd.setMajorVersion(dr.readWord());
+ dd.setType(dr.readDoubleWord());
+ dd.setSizeOfData(dr.readDoubleWord());
+ dd.setAddressOfRawData(dr.readDoubleWord());
+ dd.setPointerToRawData(dr.readDoubleWord());
+ return dd;
+ }
+
public int getCharacteristics() {
return characteristics;
}
diff --git a/src/main/java/com/kichik/pecoff4j/ExportDirectory.java b/src/main/java/com/kichik/pecoff4j/ExportDirectory.java
index 74224df..868844d 100644
--- a/src/main/java/com/kichik/pecoff4j/ExportDirectory.java
+++ b/src/main/java/com/kichik/pecoff4j/ExportDirectory.java
@@ -9,9 +9,12 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.DataReader;
import com.kichik.pecoff4j.util.DataObject;
import com.kichik.pecoff4j.util.Reflection;
+import java.io.IOException;
+
/**
* The export directory table. See section 6.3.1 of the PE/COFF specification
* v8.
@@ -29,6 +32,24 @@ public class ExportDirectory extends DataObject {
private long namePointerRVA;
private long ordinalTableRVA;
+ public static ExportDirectory read(byte[] b) throws IOException {
+ DataReader dr = new DataReader(b);
+ ExportDirectory edt = new ExportDirectory();
+ edt.set(b);
+ edt.setExportFlags(dr.readDoubleWord());
+ edt.setTimeDateStamp(dr.readDoubleWord());
+ edt.setMajorVersion(dr.readWord());
+ edt.setMinorVersion(dr.readWord());
+ edt.setNameRVA(dr.readDoubleWord());
+ edt.setOrdinalBase(dr.readDoubleWord());
+ edt.setAddressTableEntries(dr.readDoubleWord());
+ edt.setNumberOfNamePointers(dr.readDoubleWord());
+ edt.setExportAddressTableRVA(dr.readDoubleWord());
+ edt.setNamePointerRVA(dr.readDoubleWord());
+ edt.setOrdinalTableRVA(dr.readDoubleWord());
+ return edt;
+ }
+
public long getExportFlags() {
return exportFlags;
}
diff --git a/src/main/java/com/kichik/pecoff4j/ImageData.java b/src/main/java/com/kichik/pecoff4j/ImageData.java
index 514c763..7a5b963 100644
--- a/src/main/java/com/kichik/pecoff4j/ImageData.java
+++ b/src/main/java/com/kichik/pecoff4j/ImageData.java
@@ -9,8 +9,16 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.constant.ImageDataDirectoryType;
+import com.kichik.pecoff4j.io.ByteArrayDataReader;
+import com.kichik.pecoff4j.io.DataEntry;
+import com.kichik.pecoff4j.io.DataReader;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
import com.kichik.pecoff4j.util.IntMap;
+import java.io.IOException;
+
public class ImageData {
private byte[] headerPadding; // TODO find out what this is
@@ -42,6 +50,152 @@ public class ImageData {
// Any trailing data
private byte[] trailingData;
+ public void read(PE pe, DataEntry entry, IDataReader dr)
+ throws IOException {
+
+ // Read any preamble data
+ byte[] pa = dr.readNonZeroOrNull(entry.pointer);
+ if (pa != null)
+ put(entry.index, pa);
+
+ // Read the image data
+ ImageDataDirectory idd = pe.getOptionalHeader().getDataDirectory(
+ entry.index);
+ byte[] b = new byte[idd.getSize()];
+ dr.read(b);
+
+ switch (entry.index) {
+ case ImageDataDirectoryType.EXPORT_TABLE:
+ setExportTable(ExportDirectory.read(b));
+ break;
+ case ImageDataDirectoryType.IMPORT_TABLE:
+ setImportTable(ImportDirectory.read(b, entry.baseAddress));
+ break;
+ case ImageDataDirectoryType.RESOURCE_TABLE:
+ setResourceTable(ResourceDirectory.read(new ByteArrayDataReader(b), entry.baseAddress));
+ break;
+ case ImageDataDirectoryType.EXCEPTION_TABLE:
+ setExceptionTable(b);
+ break;
+ case ImageDataDirectoryType.CERTIFICATE_TABLE:
+ setCertificateTable(AttributeCertificateTable.read(b));
+ break;
+ case ImageDataDirectoryType.BASE_RELOCATION_TABLE:
+ setBaseRelocationTable(b);
+ break;
+ case ImageDataDirectoryType.DEBUG:
+ setDebug(DebugDirectory.read(b));
+ break;
+ case ImageDataDirectoryType.ARCHITECTURE:
+ setArchitecture(b);
+ break;
+ case ImageDataDirectoryType.GLOBAL_PTR:
+ setGlobalPtr(b);
+ break;
+ case ImageDataDirectoryType.TLS_TABLE:
+ setTlsTable(b);
+ break;
+ case ImageDataDirectoryType.LOAD_CONFIG_TABLE:
+ setLoadConfigTable(LoadConfigDirectory.read(pe, b));
+ break;
+ case ImageDataDirectoryType.BOUND_IMPORT:
+ setBoundImports(BoundImportDirectoryTable.read(new DataReader(b)));
+ break;
+ case ImageDataDirectoryType.IAT:
+ setIat(b);
+ break;
+ case ImageDataDirectoryType.DELAY_IMPORT_DESCRIPTOR:
+ setDelayImportDescriptor(b);
+ break;
+ case ImageDataDirectoryType.CLR_RUNTIME_HEADER:
+ setClrRuntimeHeader(CLRRuntimeHeader.read(b));
+ break;
+ case ImageDataDirectoryType.RESERVED:
+ setReserved(b);
+ break;
+ }
+ }
+
+ public void write(PE pe, DataEntry entry, IDataWriter dw)
+ throws IOException {
+ ImageDataDirectory idd = pe.getOptionalHeader().getDataDirectory(
+ entry.index);
+ RVAConverter rvc = pe.getSectionTable().getRVAConverter();
+ int prd = idd.getVirtualAddress();
+ if (entry.index != ImageDataDirectoryType.CERTIFICATE_TABLE)
+ prd = rvc.convertVirtualAddressToRawDataPointer(idd
+ .getVirtualAddress());
+ if (prd > dw.getPosition()) {
+ byte[] pa = pe.getImageData().getPreamble(entry.index);
+ if (pa != null)
+ dw.writeBytes(pa);
+ else
+ dw.writeByte(0, prd - dw.getPosition());
+ }
+
+ switch (entry.index) {
+ case ImageDataDirectoryType.EXPORT_TABLE:
+ dw.writeBytes(getExportTable().get());
+ break;
+ case ImageDataDirectoryType.IMPORT_TABLE:
+ dw.writeBytes(getImportTable().get());
+ break;
+ case ImageDataDirectoryType.RESOURCE_TABLE:
+ dw.writeBytes(getResourceTable().get());
+ break;
+ case ImageDataDirectoryType.EXCEPTION_TABLE:
+ dw.writeBytes(getExceptionTable());
+ break;
+ case ImageDataDirectoryType.CERTIFICATE_TABLE:
+ dw.writeBytes(getCertificateTable().get());
+ break;
+ case ImageDataDirectoryType.BASE_RELOCATION_TABLE:
+ dw.writeBytes(getBaseRelocationTable());
+ break;
+ case ImageDataDirectoryType.DEBUG:
+ dw.writeBytes(getDebug().get());
+ break;
+ case ImageDataDirectoryType.ARCHITECTURE:
+ dw.writeBytes(getArchitecture());
+ break;
+ case ImageDataDirectoryType.GLOBAL_PTR:
+ dw.writeBytes(getGlobalPtr());
+ break;
+ case ImageDataDirectoryType.TLS_TABLE:
+ dw.writeBytes(getTlsTable());
+ break;
+ case ImageDataDirectoryType.LOAD_CONFIG_TABLE:
+ break;
+ case ImageDataDirectoryType.BOUND_IMPORT:
+ getBoundImports().write(pe, dw);
+ break;
+ case ImageDataDirectoryType.IAT:
+ dw.writeBytes(getIat());
+ break;
+ case ImageDataDirectoryType.DELAY_IMPORT_DESCRIPTOR:
+ dw.writeBytes(getDelayImportDescriptor());
+ break;
+ case ImageDataDirectoryType.CLR_RUNTIME_HEADER:
+ dw.writeBytes(getClrRuntimeHeader().get());
+ break;
+ case ImageDataDirectoryType.RESERVED:
+ dw.writeBytes(getReserved());
+ break;
+ }
+ }
+
+ public void writeDebugRawData(DataEntry entry, IDataWriter dw)
+ throws IOException {
+ if (entry.pointer > dw.getPosition()) {
+ byte[] pa = getDebugRawDataPreamble();
+ if (pa != null)
+ dw.writeBytes(pa);
+ else
+ dw.writeByte(0, entry.pointer - dw.getPosition());
+ }
+ dw.writeBytes(getDebugRawData());
+ }
+
public byte[] getHeaderPadding() {
return headerPadding;
}
diff --git a/src/main/java/com/kichik/pecoff4j/ImageDataDirectory.java b/src/main/java/com/kichik/pecoff4j/ImageDataDirectory.java
index d97e1ad..0131962 100644
--- a/src/main/java/com/kichik/pecoff4j/ImageDataDirectory.java
+++ b/src/main/java/com/kichik/pecoff4j/ImageDataDirectory.java
@@ -9,10 +9,29 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class ImageDataDirectory {
private int virtualAddress;
private int size;
+ public static ImageDataDirectory read(IDataReader dr)
+ throws IOException {
+ ImageDataDirectory idd = new ImageDataDirectory();
+ idd.setVirtualAddress(dr.readDoubleWord());
+ idd.setSize(dr.readDoubleWord());
+ return idd;
+ }
+
+ public void write(IDataWriter dw)
+ throws IOException {
+ dw.writeDoubleWord(getVirtualAddress());
+ dw.writeDoubleWord(getSize());
+ }
+
public int getVirtualAddress() {
return virtualAddress;
}
diff --git a/src/main/java/com/kichik/pecoff4j/ImportDirectory.java b/src/main/java/com/kichik/pecoff4j/ImportDirectory.java
index d7db740..6343915 100644
--- a/src/main/java/com/kichik/pecoff4j/ImportDirectory.java
+++ b/src/main/java/com/kichik/pecoff4j/ImportDirectory.java
@@ -9,9 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import com.kichik.pecoff4j.io.DataReader;
import com.kichik.pecoff4j.util.DataObject;
public class ImportDirectory extends DataObject {
@@ -20,6 +22,29 @@ public class ImportDirectory extends DataObject {
private List nameTables = new ArrayList();
private List addressTables = new ArrayList();
+ public static ImportDirectory read(byte[] b, int baseAddress)
+ throws IOException {
+ DataReader dr = new DataReader(b);
+ ImportDirectory id = new ImportDirectory();
+ ImportDirectoryEntry ide = null;
+ while ((ide = ImportDirectoryEntry.read(dr)) != null) {
+ id.add(ide);
+ }
+
+ /*
+ * FIXME - name table refer to data outside image directory for (int i =
+ * 0; i < id.size(); i++) { ImportDirectoryEntry e = id.getEntry(i);
+ * dr.jumpTo(e.getNameRVA() - baseAddress); String name = dr.readUtf();
+ * dr.jumpTo(e.getImportLookupTableRVA() - baseAddress);
+ * ImportDirectoryTable nt = readImportDirectoryTable(dr, baseAddress);
+ * dr.jumpTo(e.getImportAddressTableRVA() - baseAddress);
+ * ImportDirectoryTable at = null; // readImportDirectoryTable(dr, //
+ * baseAddress); id.add(name, nt, at); }
+ */
+
+ return id;
+ }
+
public void add(ImportDirectoryEntry entry) {
entries.add(entry);
}
diff --git a/src/main/java/com/kichik/pecoff4j/ImportDirectoryEntry.java b/src/main/java/com/kichik/pecoff4j/ImportDirectoryEntry.java
index ec2e4f7..4f31bee 100644
--- a/src/main/java/com/kichik/pecoff4j/ImportDirectoryEntry.java
+++ b/src/main/java/com/kichik/pecoff4j/ImportDirectoryEntry.java
@@ -9,6 +9,10 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+
+import java.io.IOException;
+
public class ImportDirectoryEntry {
private int importLookupTableRVA;
private int timeDateStamp;
@@ -16,6 +20,22 @@ public class ImportDirectoryEntry {
private int nameRVA;
private int importAddressTableRVA;
+ public static ImportDirectoryEntry read(IDataReader dr) throws IOException {
+ ImportDirectoryEntry id = new ImportDirectoryEntry();
+ id.setImportLookupTableRVA(dr.readDoubleWord());
+ id.setTimeDateStamp(dr.readDoubleWord());
+ id.setForwarderChain(dr.readDoubleWord());
+ id.setNameRVA(dr.readDoubleWord());
+ id.setImportAddressTableRVA(dr.readDoubleWord());
+
+ // The last entry is null
+ if (id.getImportLookupTableRVA() == 0) {
+ return null;
+ }
+
+ return id;
+ }
+
public int getImportLookupTableRVA() {
return importLookupTableRVA;
}
diff --git a/src/main/java/com/kichik/pecoff4j/ImportDirectoryTable.java b/src/main/java/com/kichik/pecoff4j/ImportDirectoryTable.java
index eb5062f..3cabbcf 100644
--- a/src/main/java/com/kichik/pecoff4j/ImportDirectoryTable.java
+++ b/src/main/java/com/kichik/pecoff4j/ImportDirectoryTable.java
@@ -9,11 +9,34 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+
+import java.io.IOException;
import java.util.ArrayList;
public class ImportDirectoryTable {
private ArrayList imports = new ArrayList();
+ public static ImportDirectoryTable read(IDataReader dr, int baseAddress) throws IOException {
+ ImportDirectoryTable idt = new ImportDirectoryTable();
+ ImportEntry ie = null;
+ while ((ie = ImportEntry.read(dr)) != null) {
+ idt.add(ie);
+ }
+
+ for (int i = 0; i < idt.size(); i++) {
+ ImportEntry iee = idt.getEntry(i);
+ if ((iee.getVal() & 0x80000000) != 0) {
+ iee.setOrdinal(iee.getVal() & 0x7fffffff);
+ } else {
+ dr.jumpTo(iee.getVal() - baseAddress);
+ dr.readWord(); // FIXME this is an index into the export table
+ iee.setName(dr.readUtf());
+ }
+ }
+ return idt;
+ }
+
public void add(ImportEntry entry) {
imports.add(entry);
}
diff --git a/src/main/java/com/kichik/pecoff4j/ImportEntry.java b/src/main/java/com/kichik/pecoff4j/ImportEntry.java
index aa8646f..74de62e 100644
--- a/src/main/java/com/kichik/pecoff4j/ImportEntry.java
+++ b/src/main/java/com/kichik/pecoff4j/ImportEntry.java
@@ -9,11 +9,25 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+
+import java.io.IOException;
+
public class ImportEntry {
private int val;
private int ordinal;
private String name;
+ public static ImportEntry read(IDataReader dr) throws IOException {
+ ImportEntry ie = new ImportEntry();
+ ie.setVal(dr.readDoubleWord());
+ if (ie.getVal() == 0) {
+ return null;
+ }
+
+ return ie;
+ }
+
public int getOrdinal() {
return ordinal;
}
diff --git a/src/main/java/com/kichik/pecoff4j/LoadConfigDirectory.java b/src/main/java/com/kichik/pecoff4j/LoadConfigDirectory.java
index a3c07d9..e778f9d 100644
--- a/src/main/java/com/kichik/pecoff4j/LoadConfigDirectory.java
+++ b/src/main/java/com/kichik/pecoff4j/LoadConfigDirectory.java
@@ -9,8 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.DataReader;
import com.kichik.pecoff4j.util.DataObject;
+import java.io.IOException;
+
public class LoadConfigDirectory extends DataObject {
private int size;
private int timeDateStamp;
@@ -33,6 +36,37 @@ public class LoadConfigDirectory extends DataObject {
private long seHandlerTable;
private long seHandlerCount;
+ public static LoadConfigDirectory read(PE pe, byte[] b) throws IOException {
+ DataReader dr = new DataReader(b);
+ LoadConfigDirectory lcd = new LoadConfigDirectory();
+ lcd.set(b);
+ lcd.setSize(dr.readDoubleWord());
+ lcd.setTimeDateStamp(dr.readDoubleWord());
+ lcd.setMajorVersion(dr.readWord());
+ lcd.setMinorVersion(dr.readWord());
+ lcd.setGlobalFlagsClear(dr.readDoubleWord());
+ lcd.setGlobalFlagsSet(dr.readDoubleWord());
+ lcd.setCriticalSectionDefaultTimeout(dr.readDoubleWord());
+ lcd.setDeCommitFreeBlockThreshold(pe.is64() ? dr.readLong() : dr.readDoubleWord());
+ lcd.setDeCommitTotalFreeThreshold(pe.is64() ? dr.readLong() : dr.readDoubleWord());
+ lcd.setLockPrefixTable(pe.is64() ? dr.readLong() : dr.readDoubleWord());
+ lcd.setMaximumAllocationSize(pe.is64() ? dr.readLong() : dr.readDoubleWord());
+ lcd.setVirtualMemoryThreshold(pe.is64() ? dr.readLong() : dr.readDoubleWord());
+ lcd.setProcessAffinityMask(pe.is64() ? dr.readLong() : dr.readDoubleWord());
+ lcd.setProcessHeapFlags(dr.readDoubleWord());
+ lcd.setCsdVersion(dr.readWord());
+ lcd.setReserved(dr.readWord());
+ lcd.setEditList(pe.is64() ? dr.readLong() : dr.readDoubleWord());
+ if (dr.hasMore()) // optional
+ lcd.setSecurityCookie(pe.is64() ? dr.readLong() : dr.readDoubleWord());
+ if (dr.hasMore()) // optional
+ lcd.setSeHandlerTable(pe.is64() ? dr.readLong() : dr.readDoubleWord());
+ if (dr.hasMore()) // optional
+ lcd.setSeHandlerCount(pe.is64() ? dr.readLong() : dr.readDoubleWord());
+
+ return lcd;
+ }
+
public int getSize() {
return size;
}
diff --git a/src/main/java/com/kichik/pecoff4j/OptionalHeader.java b/src/main/java/com/kichik/pecoff4j/OptionalHeader.java
index 6916c00..b68d442 100644
--- a/src/main/java/com/kichik/pecoff4j/OptionalHeader.java
+++ b/src/main/java/com/kichik/pecoff4j/OptionalHeader.java
@@ -9,6 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class OptionalHeader {
public static final int MAGIC_PE32 = 0x10b;
public static final int MAGIC_PE32plus = 0x20b;
@@ -48,6 +53,112 @@ public class OptionalHeader {
// The data directories
private ImageDataDirectory[] dataDirectories;
+ public static OptionalHeader read(IDataReader dr)
+ throws IOException {
+ OptionalHeader oh = new OptionalHeader();
+ oh.setMagic(dr.readWord());
+ boolean is64 = oh.isPE32plus();
+ oh.setMajorLinkerVersion(dr.readByte());
+ oh.setMinorLinkerVersion(dr.readByte());
+ oh.setSizeOfCode(dr.readDoubleWord());
+ oh.setSizeOfInitializedData(dr.readDoubleWord());
+ oh.setSizeOfUninitializedData(dr.readDoubleWord());
+ oh.setAddressOfEntryPoint(dr.readDoubleWord());
+ oh.setBaseOfCode(dr.readDoubleWord());
+
+ if (!is64)
+ oh.setBaseOfData(dr.readDoubleWord());
+
+ // NT additional fields.
+ oh.setImageBase(is64 ? dr.readLong() : dr.readDoubleWord());
+ oh.setSectionAlignment(dr.readDoubleWord());
+ oh.setFileAlignment(dr.readDoubleWord());
+ oh.setMajorOperatingSystemVersion(dr.readWord());
+ oh.setMinorOperatingSystemVersion(dr.readWord());
+ oh.setMajorImageVersion(dr.readWord());
+ oh.setMinorImageVersion(dr.readWord());
+ oh.setMajorSubsystemVersion(dr.readWord());
+ oh.setMinorSubsystemVersion(dr.readWord());
+ oh.setWin32VersionValue(dr.readDoubleWord());
+ oh.setSizeOfImage(dr.readDoubleWord());
+ oh.setSizeOfHeaders(dr.readDoubleWord());
+ oh.setCheckSum(dr.readDoubleWord());
+ oh.setSubsystem(dr.readWord());
+ oh.setDllCharacteristics(dr.readWord());
+ oh.setSizeOfStackReserve(is64 ? dr.readLong() : dr.readDoubleWord());
+ oh.setSizeOfStackCommit(is64 ? dr.readLong() : dr.readDoubleWord());
+ oh.setSizeOfHeapReserve(is64 ? dr.readLong() : dr.readDoubleWord());
+ oh.setSizeOfHeapCommit(is64 ? dr.readLong() : dr.readDoubleWord());
+ oh.setLoaderFlags(dr.readDoubleWord());
+ oh.setNumberOfRvaAndSizes(dr.readDoubleWord());
+
+ // Data directories
+ ImageDataDirectory[] dds = new ImageDataDirectory[16];
+ for (int i = 0; i < dds.length; i++) {
+ dds[i] = ImageDataDirectory.read(dr);
+ }
+ oh.setDataDirectories(dds);
+
+ return oh;
+ }
+
+ public void write(IDataWriter dw)
+ throws IOException {
+ boolean is64 = isPE32plus();
+
+ dw.writeWord(getMagic());
+ dw.writeByte(getMajorLinkerVersion());
+ dw.writeByte(getMinorLinkerVersion());
+ dw.writeDoubleWord(getSizeOfCode());
+ dw.writeDoubleWord(getSizeOfInitializedData());
+ dw.writeDoubleWord(getSizeOfUninitializedData());
+ dw.writeDoubleWord(getAddressOfEntryPoint());
+ dw.writeDoubleWord(getBaseOfCode());
+ if (!is64)
+ dw.writeDoubleWord(getBaseOfData());
+
+ // NT additional fields.
+ if (is64)
+ dw.writeLong(getImageBase());
+ else
+ dw.writeDoubleWord((int) getImageBase());
+
+ dw.writeDoubleWord(getSectionAlignment());
+ dw.writeDoubleWord(getFileAlignment());
+ dw.writeWord(getMajorOperatingSystemVersion());
+ dw.writeWord(getMinorOperatingSystemVersion());
+ dw.writeWord(getMajorImageVersion());
+ dw.writeWord(getMinorImageVersion());
+ dw.writeWord(getMajorSubsystemVersion());
+ dw.writeWord(getMinorSubsystemVersion());
+ dw.writeDoubleWord(getWin32VersionValue());
+ dw.writeDoubleWord(getSizeOfImage());
+ dw.writeDoubleWord(getSizeOfHeaders());
+ dw.writeDoubleWord(getCheckSum());
+ dw.writeWord(getSubsystem());
+ dw.writeWord(getDllCharacteristics());
+ if (is64) {
+ dw.writeLong(getSizeOfStackReserve());
+ dw.writeLong(getSizeOfStackCommit());
+ dw.writeLong(getSizeOfHeapReserve());
+ dw.writeLong(getSizeOfHeapCommit());
+ } else {
+ dw.writeDoubleWord((int) getSizeOfStackReserve());
+ dw.writeDoubleWord((int) getSizeOfStackCommit());
+ dw.writeDoubleWord((int) getSizeOfHeapReserve());
+ dw.writeDoubleWord((int) getSizeOfHeapCommit());
+ }
+
+ dw.writeDoubleWord(getLoaderFlags());
+ dw.writeDoubleWord(getNumberOfRvaAndSizes());
+
+ // Data directories
+ int ddc = getDataDirectoryCount();
+ for (int i = 0; i < ddc; i++) {
+ getDataDirectory(i).write(dw);
+ }
+ }
+
public int getMagic() {
return magic;
}
diff --git a/src/main/java/com/kichik/pecoff4j/PE.java b/src/main/java/com/kichik/pecoff4j/PE.java
index 92108ae..333f59c 100644
--- a/src/main/java/com/kichik/pecoff4j/PE.java
+++ b/src/main/java/com/kichik/pecoff4j/PE.java
@@ -9,6 +9,13 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.constant.ImageDataDirectoryType;
+import com.kichik.pecoff4j.io.DataEntry;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class PE {
private DOSHeader dosHeader;
private DOSStub stub;
@@ -19,6 +26,265 @@ public class PE {
private SectionTable sectionTable;
private boolean is64bit;
+ public static PE read(IDataReader dr) throws IOException {
+ PE pe = new PE();
+ pe.setDosHeader(DOSHeader.read(dr));
+
+ // Check if we have an old file type
+ if (pe.getDosHeader().getAddressOfNewExeHeader() == 0
+ || pe.getDosHeader().getAddressOfNewExeHeader() > 8192) {
+ return pe;
+ }
+
+ pe.setStub(DOSStub.read(pe.getDosHeader(), dr));
+ pe.setSignature(PESignature.read(dr));
+
+ // Check signature to ensure we have a pe/coff file
+ if (!pe.getSignature().isValid()) {
+ return pe;
+ }
+
+ pe.setCoffHeader(COFFHeader.read(dr));
+ pe.setOptionalHeader(OptionalHeader.read(dr));
+ pe.setSectionTable(SectionTable.read(pe, dr));
+
+ pe.set64(pe.getOptionalHeader().isPE32plus());
+
+ // Now read the rest of the file
+ DataEntry entry = null;
+ while ((entry = pe.findNextEntry(dr.getPosition())) != null) {
+ if (entry.isSection) {
+ SectionData.read(pe, entry, dr);
+ } else if (entry.isDebugRawData) {
+ readDebugRawData(pe, entry, dr);
+ } else {
+ pe.getImageData().read(pe, entry, dr);
+ }
+ }
+
+ // Read any trailing data
+ byte[] tb = dr.readAll();
+ if (tb.length > 0) {
+ pe.getImageData().setTrailingData(tb);
+ }
+
+ return pe;
+ }
+
+ public DataEntry findNextEntry(int pos) {
+ DataEntry de = new DataEntry();
+
+ // Check sections first
+ int ns = getCoffHeader().getNumberOfSections();
+ for (int i = 0; i < ns; i++) {
+ SectionHeader sh = getSectionTable().getHeader(i);
+ if (sh.getSizeOfRawData() > 0
+ && sh.getPointerToRawData() >= pos
+ && (de.pointer == 0 || sh.getPointerToRawData() < de.pointer)) {
+ de.pointer = sh.getPointerToRawData();
+ de.index = i;
+ de.isSection = true;
+ }
+ }
+
+ // Now check image data directories
+ RVAConverter rvc = getSectionTable().getRVAConverter();
+ int dc = getOptionalHeader().getDataDirectoryCount();
+ for (int i = 0; i < dc; i++) {
+ ImageDataDirectory idd = getOptionalHeader().getDataDirectory(i);
+ if (idd.getSize() > 0) {
+ int prd = idd.getVirtualAddress();
+ // Assume certificate live outside section ?
+ if (i != ImageDataDirectoryType.CERTIFICATE_TABLE
+ && isInsideSection(idd)) {
+ prd = rvc.convertVirtualAddressToRawDataPointer(idd
+ .getVirtualAddress());
+ }
+ if (prd >= pos && (de.pointer == 0 || prd < de.pointer)) {
+ de.pointer = prd;
+ de.index = i;
+ de.isSection = false;
+ }
+ }
+ }
+
+ // Check debug
+ ImageData id = getImageData();
+ DebugDirectory dd = null;
+ if (id != null)
+ dd = id.getDebug();
+ if (dd != null) {
+ int prd = dd.getPointerToRawData();
+ if (prd >= pos && (de.pointer == 0 || prd < de.pointer)) {
+ de.pointer = prd;
+ de.index = -1;
+ de.isDebugRawData = true;
+ de.isSection = false;
+ de.baseAddress = prd;
+ }
+ }
+
+ if (de.pointer == 0)
+ return null;
+
+ return de;
+ }
+
+ private boolean isInsideSection(ImageDataDirectory idd) {
+ int prd = idd.getVirtualAddress();
+ int pex = prd + idd.getSize();
+ SectionTable st = getSectionTable();
+ int ns = st.getNumberOfSections();
+ for (int i = 0; i < ns; i++) {
+ SectionHeader sh = st.getHeader(i);
+ int vad = sh.getVirtualAddress();
+ int vex = vad + sh.getVirtualSize();
+ if (prd >= vad && prd < vex && pex <= vex)
+ return true;
+ }
+ return false;
+ }
+
+ private static void readDebugRawData(PE pe, DataEntry entry, IDataReader dr)
+ throws IOException {
+ // Read any preamble data
+ ImageData id = pe.getImageData();
+ byte[] pa = dr.readNonZeroOrNull(entry.pointer);
+ if (pa != null)
+ id.setDebugRawDataPreamble(pa);
+ DebugDirectory dd = id.getDebug();
+ byte[] b = new byte[dd.getSizeOfData()];
+ dr.read(b);
+ id.setDebugRawData(b);
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ getDosHeader().write(dw);
+ getStub().write(dw);
+ getSignature().write(dw);
+ getCoffHeader().write(dw);
+ getOptionalHeader().write(dw);
+ getSectionTable().write(dw);
+
+ // Now write out the rest
+ DataEntry entry = null;
+ while ((entry = findNextEntry(dw.getPosition())) != null) {
+ if (entry.isSection) {
+ writeSection(entry, dw);
+ } else if (entry.isDebugRawData) {
+ writeDebugRawData(entry, dw);
+ } else {
+ writeImageData(entry, dw);
+ }
+ }
+
+ // Dump out any trailing data - TODO find out what this is
+ byte[] tb = getImageData().getTrailingData();
+ if (tb != null)
+ dw.writeBytes(tb);
+ }
+
+ private void writeImageData(DataEntry entry, IDataWriter dw)
+ throws IOException {
+ ImageDataDirectory idd = getOptionalHeader().getDataDirectory(
+ entry.index);
+ RVAConverter rvc = getSectionTable().getRVAConverter();
+ int prd = idd.getVirtualAddress();
+ if (entry.index != ImageDataDirectoryType.CERTIFICATE_TABLE)
+ prd = rvc.convertVirtualAddressToRawDataPointer(idd
+ .getVirtualAddress());
+ if (prd > dw.getPosition()) {
+ byte[] pa = getImageData().getPreamble(entry.index);
+ if (pa != null)
+ dw.writeBytes(pa);
+ else
+ dw.writeByte(0, prd - dw.getPosition());
+ }
+
+ ImageData id = getImageData();
+
+ switch (entry.index) {
+ case ImageDataDirectoryType.EXPORT_TABLE:
+ dw.writeBytes(id.getExportTable().get());
+ break;
+ case ImageDataDirectoryType.IMPORT_TABLE:
+ dw.writeBytes(id.getImportTable().get());
+ break;
+ case ImageDataDirectoryType.RESOURCE_TABLE:
+ dw.writeBytes(id.getResourceTable().get());
+ break;
+ case ImageDataDirectoryType.EXCEPTION_TABLE:
+ dw.writeBytes(id.getExceptionTable());
+ break;
+ case ImageDataDirectoryType.CERTIFICATE_TABLE:
+ dw.writeBytes(id.getCertificateTable().get());
+ break;
+ case ImageDataDirectoryType.BASE_RELOCATION_TABLE:
+ dw.writeBytes(id.getBaseRelocationTable());
+ break;
+ case ImageDataDirectoryType.DEBUG:
+ dw.writeBytes(id.getDebug().get());
+ break;
+ case ImageDataDirectoryType.ARCHITECTURE:
+ dw.writeBytes(id.getArchitecture());
+ break;
+ case ImageDataDirectoryType.GLOBAL_PTR:
+ dw.writeBytes(id.getGlobalPtr());
+ break;
+ case ImageDataDirectoryType.TLS_TABLE:
+ dw.writeBytes(id.getTlsTable());
+ break;
+ case ImageDataDirectoryType.LOAD_CONFIG_TABLE:
+ break;
+ case ImageDataDirectoryType.BOUND_IMPORT:
+ id.getBoundImports().write(this, dw);
+ break;
+ case ImageDataDirectoryType.IAT:
+ dw.writeBytes(id.getIat());
+ break;
+ case ImageDataDirectoryType.DELAY_IMPORT_DESCRIPTOR:
+ dw.writeBytes(id.getDelayImportDescriptor());
+ break;
+ case ImageDataDirectoryType.CLR_RUNTIME_HEADER:
+ dw.writeBytes(id.getClrRuntimeHeader().get());
+ break;
+ case ImageDataDirectoryType.RESERVED:
+ dw.writeBytes(id.getReserved());
+ break;
+ }
+ }
+
+ private void writeDebugRawData(DataEntry entry, IDataWriter dw)
+ throws IOException {
+ if (entry.pointer > dw.getPosition()) {
+ byte[] pa = getImageData().getDebugRawDataPreamble();
+ if (pa != null)
+ dw.writeBytes(pa);
+ else
+ dw.writeByte(0, entry.pointer - dw.getPosition());
+ }
+ dw.writeBytes(getImageData().getDebugRawData());
+ }
+
+ private void writeSection(DataEntry entry, IDataWriter dw)
+ throws IOException {
+ SectionTable st = getSectionTable();
+ SectionHeader sh = st.getHeader(entry.index);
+ SectionData sd = st.getSection(entry.index);
+ int prd = sh.getPointerToRawData();
+ if (prd > dw.getPosition()) {
+ byte[] pa = sd.getPreamble();
+ if (pa != null) {
+ dw.writeBytes(pa);
+ } else {
+ dw.writeByte(0, prd - dw.getPosition());
+ }
+ }
+
+ byte[] b = sd.getData();
+ dw.writeBytes(b);
+ }
+
public DOSHeader getDosHeader() {
return dosHeader;
}
diff --git a/src/main/java/com/kichik/pecoff4j/PESignature.java b/src/main/java/com/kichik/pecoff4j/PESignature.java
index ab86851..3dfede8 100644
--- a/src/main/java/com/kichik/pecoff4j/PESignature.java
+++ b/src/main/java/com/kichik/pecoff4j/PESignature.java
@@ -9,6 +9,10 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
import java.util.Arrays;
public class PESignature {
@@ -16,6 +20,18 @@ public class PESignature {
private static byte[] expected2 = new byte[] { 0x50, 0x69, 0x00, 0x00 };
private byte[] signature;
+ public static PESignature read(IDataReader dr) throws IOException {
+ PESignature ps = new PESignature();
+ byte[] signature = new byte[4];
+ dr.read(signature);
+ ps.setSignature(signature);
+ return ps;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeBytes(getSignature());
+ }
+
public byte[] getSignature() {
return signature;
}
diff --git a/src/main/java/com/kichik/pecoff4j/ResourceDirectory.java b/src/main/java/com/kichik/pecoff4j/ResourceDirectory.java
index a2acb6c..662a1c2 100644
--- a/src/main/java/com/kichik/pecoff4j/ResourceDirectory.java
+++ b/src/main/java/com/kichik/pecoff4j/ResourceDirectory.java
@@ -9,15 +9,86 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import java.io.IOException;
+import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
+import java.util.Queue;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
import com.kichik.pecoff4j.util.DataObject;
public class ResourceDirectory extends DataObject {
private ResourceDirectoryTable table;
private List entries = new ArrayList();
+ public static ResourceDirectory read(IDataReader dr, int baseAddress) throws IOException {
+ ResourceDirectory d = new ResourceDirectory();
+ d.setTable(ResourceDirectoryTable.read(dr));
+ int ne = d.getTable().getNumNameEntries()
+ + d.getTable().getNumIdEntries();
+ for (int i = 0; i < ne; i++) {
+ d.add(ResourceEntry.read(dr, baseAddress));
+ }
+
+ return d;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ List dirs = new ArrayList<>();
+ List entries = new ArrayList<>();
+ flattenInto(dirs, entries);
+
+ for (ResourceDirectory dir : dirs) {
+ dir.getTable().write(dw);
+ for (int i = 0; i < dir.size(); i++) {
+ dir.get(i).writeNonLeaf(dw);
+ }
+ }
+ for (ResourceEntry re : entries) {
+ re.writeLeaf(dw);
+ }
+ Collections.sort(entries, Comparator.comparing(ResourceEntry::getDataRVA));
+ for (ResourceDirectory dir : dirs) {
+ for (int i = 0; i < dir.size(); i++) {
+ dir.get(i).writeName(dw);
+ }
+ }
+ for (ResourceEntry re : entries) {
+ re.writeName(dw);
+ }
+ dw.align(4);
+ for (ResourceEntry re : entries) {
+ re.writeData(dw);
+ dw.align(4);
+ }
+ }
+
+ /**
+ * Traverse tree in breath-first order and fill directories and entries into given lists.
+ */
+ private void flattenInto(List dirs, List entries) {
+ Queue toProcess = new ArrayDeque<>();
+ toProcess.add(this);
+ dirs.add(this);
+
+ while (!toProcess.isEmpty()) {
+ ResourceDirectory dir = toProcess.poll();
+ for (int i = 0; i < dir.size(); i++) {
+ ResourceEntry entry = dir.get(i);
+ if (entry.getDirectory() != null) {
+ toProcess.add(entry.getDirectory());
+ dirs.add(entry.getDirectory());
+ } else {
+ entries.add(entry);
+ }
+ }
+ }
+ }
+
public ResourceDirectoryTable getTable() {
return table;
}
diff --git a/src/main/java/com/kichik/pecoff4j/ResourceDirectoryTable.java b/src/main/java/com/kichik/pecoff4j/ResourceDirectoryTable.java
index 366d9b2..12b3419 100644
--- a/src/main/java/com/kichik/pecoff4j/ResourceDirectoryTable.java
+++ b/src/main/java/com/kichik/pecoff4j/ResourceDirectoryTable.java
@@ -9,6 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class ResourceDirectoryTable {
private int characteristics;
private int timeDateStamp;
@@ -17,6 +22,27 @@ public class ResourceDirectoryTable {
private int numNameEntries;
private int numIdEntries;
+ public static ResourceDirectoryTable read(IDataReader dr) throws IOException {
+ ResourceDirectoryTable t = new ResourceDirectoryTable();
+ t.setCharacteristics(dr.readDoubleWord());
+ t.setTimeDateStamp(dr.readDoubleWord());
+ t.setMajorVersion(dr.readWord());
+ t.setMinVersion(dr.readWord());
+ t.setNumNameEntries(dr.readWord());
+ t.setNumIdEntries(dr.readWord());
+
+ return t;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeDoubleWord(getCharacteristics());
+ dw.writeDoubleWord(getTimeDateStamp());
+ dw.writeWord(getMajorVersion());
+ dw.writeWord(getMinVersion());
+ dw.writeWord(getNumNameEntries());
+ dw.writeWord(getNumIdEntries());
+ }
+
public int getCharacteristics() {
return characteristics;
}
diff --git a/src/main/java/com/kichik/pecoff4j/ResourceEntry.java b/src/main/java/com/kichik/pecoff4j/ResourceEntry.java
index 2021cb6..8c5dd7e 100644
--- a/src/main/java/com/kichik/pecoff4j/ResourceEntry.java
+++ b/src/main/java/com/kichik/pecoff4j/ResourceEntry.java
@@ -9,6 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class ResourceEntry {
private int id;
private String name;
@@ -19,6 +24,61 @@ public class ResourceEntry {
private int codePage;
private int reserved;
+ public static ResourceEntry read(IDataReader dr, int baseAddress) throws IOException {
+ ResourceEntry re = new ResourceEntry();
+ int id = dr.readDoubleWord();
+ re.setId(id);
+ int offset = dr.readDoubleWord();
+ re.setOffset(offset);
+ int pos = dr.getPosition();
+ if ((id & 0x80000000) != 0) {
+ dr.jumpTo(id & 0x7fffffff);
+ re.setName(dr.readUnicode(dr.readWord()));
+ }
+ if ((offset & 0x80000000) != 0) {
+ dr.jumpTo(offset & 0x7fffffff);
+ re.setDirectory(ResourceDirectory.read(dr, baseAddress));
+ } else {
+ dr.jumpTo(offset);
+ int rva = dr.readDoubleWord();
+ int size = dr.readDoubleWord();
+ int cp = dr.readDoubleWord();
+ int res = dr.readDoubleWord();
+ re.setDataRVA(rva);
+ re.setCodePage(cp);
+ re.setReserved(res);
+ dr.jumpTo(rva - baseAddress);
+ byte[] b = new byte[size];
+ dr.read(b);
+ re.setData(b);
+ }
+ dr.jumpTo(pos);
+ return re;
+ }
+
+ public void writeNonLeaf(IDataWriter dw) throws IOException {
+ dw.writeDoubleWord(getId());
+ dw.writeDoubleWord(getOffset());
+ }
+
+ public void writeLeaf(IDataWriter dw) throws IOException {
+ dw.writeDoubleWord(getDataRVA());
+ dw.writeDoubleWord(getData().length);
+ dw.writeDoubleWord(getCodePage());
+ dw.writeDoubleWord(getReserved());
+ }
+
+ public void writeName(IDataWriter dw) throws IOException {
+ if (name != null) {
+ dw.writeWord(name.length());
+ dw.writeUnicode(name, name.length());
+ }
+ }
+
+ public void writeData(IDataWriter dw) throws IOException {
+ dw.writeBytes(getData());
+ }
+
public int getId() {
return id;
}
diff --git a/src/main/java/com/kichik/pecoff4j/SectionData.java b/src/main/java/com/kichik/pecoff4j/SectionData.java
index b109141..3f9b78e 100644
--- a/src/main/java/com/kichik/pecoff4j/SectionData.java
+++ b/src/main/java/com/kichik/pecoff4j/SectionData.java
@@ -9,10 +9,78 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.constant.ImageDataDirectoryType;
+import com.kichik.pecoff4j.io.ByteArrayDataReader;
+import com.kichik.pecoff4j.io.DataEntry;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class SectionData {
private byte[] data;
private byte[] preamble;
+ public static SectionData read(PE pe, DataEntry entry, IDataReader dr)
+ throws IOException {
+ SectionTable st = pe.getSectionTable();
+ SectionHeader sh = st.getHeader(entry.index);
+ SectionData sd = new SectionData();
+
+ // Read any preamble - store if non-zero
+ byte[] pa = dr.readNonZeroOrNull(sh.getPointerToRawData());
+ if (pa != null)
+ sd.setPreamble(pa);
+
+ // Read in the raw data block
+ dr.jumpTo(sh.getPointerToRawData());
+ byte[] b = new byte[sh.getSizeOfRawData()];
+ dr.read(b);
+ sd.setData(b);
+ st.put(entry.index, sd);
+
+ // Check for an image directory within this section
+ int ddc = pe.getOptionalHeader().getDataDirectoryCount();
+ for (int i = 0; i < ddc; i++) {
+ if (i == ImageDataDirectoryType.CERTIFICATE_TABLE)
+ continue;
+ ImageDataDirectory idd = pe.getOptionalHeader().getDataDirectory(i);
+ if (idd.getSize() > 0) {
+ int vad = sh.getVirtualAddress();
+ int vex = vad + sh.getVirtualSize();
+ int dad = idd.getVirtualAddress();
+ if (dad >= vad && dad < vex) {
+ int off = dad - vad;
+ IDataReader idr = new ByteArrayDataReader(b, off,
+ idd.getSize());
+ DataEntry de = new DataEntry(i, 0);
+ de.baseAddress = sh.getVirtualAddress();
+ pe.getImageData().read(pe, de, idr);
+ }
+ }
+ }
+ return sd;
+ }
+
+ public void write(PE pe, DataEntry entry, IDataWriter dw)
+ throws IOException {
+ SectionTable st = pe.getSectionTable();
+ SectionHeader sh = st.getHeader(entry.index);
+ SectionData sd = st.getSection(entry.index);
+ int prd = sh.getPointerToRawData();
+ if (prd > dw.getPosition()) {
+ byte[] pa = sd.getPreamble();
+ if (pa != null) {
+ dw.writeBytes(pa);
+ } else {
+ dw.writeByte(0, prd - dw.getPosition());
+ }
+ }
+
+ byte[] b = sd.getData();
+ dw.writeBytes(b);
+ }
+
public byte[] getPreamble() {
return preamble;
}
diff --git a/src/main/java/com/kichik/pecoff4j/SectionHeader.java b/src/main/java/com/kichik/pecoff4j/SectionHeader.java
index 908598a..f677b10 100644
--- a/src/main/java/com/kichik/pecoff4j/SectionHeader.java
+++ b/src/main/java/com/kichik/pecoff4j/SectionHeader.java
@@ -9,6 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class SectionHeader {
private String name;
private int virtualSize;
@@ -21,6 +26,34 @@ public class SectionHeader {
private int numberOfLineNumbers;
private int characteristics;
+ public static SectionHeader read(IDataReader dr) throws IOException {
+ SectionHeader sh = new SectionHeader();
+ sh.setName(dr.readUtf(8));
+ sh.setVirtualSize(dr.readDoubleWord());
+ sh.setVirtualAddress(dr.readDoubleWord());
+ sh.setSizeOfRawData(dr.readDoubleWord());
+ sh.setPointerToRawData(dr.readDoubleWord());
+ sh.setPointerToRelocations(dr.readDoubleWord());
+ sh.setPointerToLineNumbers(dr.readDoubleWord());
+ sh.setNumberOfRelocations(dr.readWord());
+ sh.setNumberOfLineNumbers(dr.readWord());
+ sh.setCharacteristics(dr.readDoubleWord());
+ return sh;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeUtf(getName(), 8);
+ dw.writeDoubleWord(getVirtualSize());
+ dw.writeDoubleWord(getVirtualAddress());
+ dw.writeDoubleWord(getSizeOfRawData());
+ dw.writeDoubleWord(getPointerToRawData());
+ dw.writeDoubleWord(getPointerToRelocations());
+ dw.writeDoubleWord(getPointerToLineNumbers());
+ dw.writeWord(getNumberOfRelocations());
+ dw.writeWord(getNumberOfLineNumbers());
+ dw.writeDoubleWord(getCharacteristics());
+ }
+
public String getName() {
return name;
}
diff --git a/src/main/java/com/kichik/pecoff4j/SectionTable.java b/src/main/java/com/kichik/pecoff4j/SectionTable.java
index 6cc0631..8336f29 100644
--- a/src/main/java/com/kichik/pecoff4j/SectionTable.java
+++ b/src/main/java/com/kichik/pecoff4j/SectionTable.java
@@ -9,11 +9,14 @@
*******************************************************************************/
package com.kichik.pecoff4j;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
import com.kichik.pecoff4j.util.IntMap;
public class SectionTable {
@@ -28,6 +31,32 @@ public class SectionTable {
private IntMap sections = new IntMap();
private RVAConverter rvaConverter;
+ public static SectionTable read(PE pe, IDataReader dr)
+ throws IOException {
+ SectionTable st = new SectionTable();
+ int ns = pe.getCoffHeader().getNumberOfSections();
+ for (int i = 0; i < ns; i++) {
+ st.add(SectionHeader.read(dr));
+ }
+
+ SectionHeader[] sorted = st.getHeadersPointerSorted();
+ int[] virtualAddress = new int[sorted.length];
+ int[] pointerToRawData = new int[sorted.length];
+ for (int i = 0; i < sorted.length; i++) {
+ virtualAddress[i] = sorted[i].getVirtualAddress();
+ pointerToRawData[i] = sorted[i].getPointerToRawData();
+ }
+
+ st.setRvaConverter(new RVAConverter(virtualAddress, pointerToRawData));
+ return st;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ for (SectionHeader header : headers) {
+ header.write(dw);
+ }
+ }
+
public void add(SectionHeader header) {
headers.add(header);
}
diff --git a/src/main/java/com/kichik/pecoff4j/io/DataWriter.java b/src/main/java/com/kichik/pecoff4j/io/DataWriter.java
index 0f99621..de8ba6e 100644
--- a/src/main/java/com/kichik/pecoff4j/io/DataWriter.java
+++ b/src/main/java/com/kichik/pecoff4j/io/DataWriter.java
@@ -10,6 +10,7 @@
package com.kichik.pecoff4j.io;
import java.io.BufferedOutputStream;
+import java.io.EOFException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -103,4 +104,35 @@ public void writeUtf(String s) throws IOException {
out.write(0);
position += b.length + 1;
}
+
+ @Override
+ public void writeUnicode(String s) throws IOException {
+ for (char c : s.toCharArray()) {
+ writeWord(c);
+ }
+ writeWord(0);
+ }
+
+ @Override
+ public void writeUnicode(String s, int len) throws IOException {
+ char[] c = s.toCharArray();
+ int i = 0;
+ for (; i < c.length && i < len; i++) {
+ writeWord(c[i]);
+ }
+ for (; i < len; i++) {
+ writeWord(0);
+ }
+ }
+
+ @Override
+ public int align(int alignment) throws IOException {
+ int off = (alignment - (getPosition() % alignment)) % alignment;
+ try {
+ writeByte(0, off);
+ } catch (EOFException ignored) {
+ // no need to align when it's at the end of its data
+ }
+ return off;
+ }
}
diff --git a/src/main/java/com/kichik/pecoff4j/io/IDataReader.java b/src/main/java/com/kichik/pecoff4j/io/IDataReader.java
index 03326cb..29c104f 100644
--- a/src/main/java/com/kichik/pecoff4j/io/IDataReader.java
+++ b/src/main/java/com/kichik/pecoff4j/io/IDataReader.java
@@ -9,6 +9,7 @@
*******************************************************************************/
package com.kichik.pecoff4j.io;
+import java.io.EOFException;
import java.io.IOException;
public interface IDataReader extends AutoCloseable {
@@ -41,4 +42,40 @@ public interface IDataReader extends AutoCloseable {
public abstract String readUnicode(int size) throws IOException;
public abstract byte[] readAll() throws IOException;
+
+ /**
+ * Align the reader's position
+ * @param alignment the alignment in bytes
+ * @return the number of bytes that have been skipped
+ */
+ default int align(int alignment) throws IOException {
+ int off = (alignment - (getPosition() % alignment)) % alignment;
+ try {
+ skipBytes(off);
+ } catch (EOFException ignored) {
+ // no need to align when it's at the end of its data
+ }
+ return off;
+ }
+
+ /**
+ * Read all bytes until the given position is reached. If all these bytes are zero, null is returned instead.
+ */
+ default byte[] readNonZeroOrNull(int pointer) throws IOException {
+ if (pointer > getPosition()) {
+ byte[] pa = new byte[pointer - getPosition()];
+ read(pa);
+ boolean zeroes = true;
+ for (int i = 0; i < pa.length; i++) {
+ if (pa[i] != 0) {
+ zeroes = false;
+ break;
+ }
+ }
+ if (!zeroes)
+ return pa;
+ }
+
+ return null;
+ }
}
diff --git a/src/main/java/com/kichik/pecoff4j/io/IDataWriter.java b/src/main/java/com/kichik/pecoff4j/io/IDataWriter.java
index b043e06..78dc5e2 100644
--- a/src/main/java/com/kichik/pecoff4j/io/IDataWriter.java
+++ b/src/main/java/com/kichik/pecoff4j/io/IDataWriter.java
@@ -9,6 +9,7 @@
*******************************************************************************/
package com.kichik.pecoff4j.io;
+import java.io.EOFException;
import java.io.IOException;
public interface IDataWriter {
@@ -28,5 +29,16 @@ public interface IDataWriter {
void writeUtf(String s, int len) throws IOException;
- public abstract int getPosition();
+ void writeUnicode(String s) throws IOException;
+
+ void writeUnicode(String s, int len) throws IOException;
+
+ int getPosition();
+
+ /**
+ * Align the writer's position by writing zeros
+ * @param alignment the alignment in bytes
+ * @return the number of bytes that have been written
+ */
+ int align(int alignment) throws IOException;
}
diff --git a/src/main/java/com/kichik/pecoff4j/io/PEAssembler.java b/src/main/java/com/kichik/pecoff4j/io/PEAssembler.java
index 73e9997..69fb442 100644
--- a/src/main/java/com/kichik/pecoff4j/io/PEAssembler.java
+++ b/src/main/java/com/kichik/pecoff4j/io/PEAssembler.java
@@ -9,33 +9,13 @@
*******************************************************************************/
package com.kichik.pecoff4j.io;
+import com.kichik.pecoff4j.PE;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import com.kichik.pecoff4j.BoundImport;
-import com.kichik.pecoff4j.BoundImportDirectoryTable;
-import com.kichik.pecoff4j.COFFHeader;
-import com.kichik.pecoff4j.DOSHeader;
-import com.kichik.pecoff4j.DOSStub;
-import com.kichik.pecoff4j.ImageData;
-import com.kichik.pecoff4j.ImageDataDirectory;
-import com.kichik.pecoff4j.OptionalHeader;
-import com.kichik.pecoff4j.PE;
-import com.kichik.pecoff4j.PESignature;
-import com.kichik.pecoff4j.RVAConverter;
-import com.kichik.pecoff4j.SectionData;
-import com.kichik.pecoff4j.SectionHeader;
-import com.kichik.pecoff4j.SectionTable;
-import com.kichik.pecoff4j.constant.ImageDataDirectoryType;
public class PEAssembler {
public static byte[] toBytes(PE pe) throws IOException {
@@ -58,306 +38,11 @@ public static void write(PE pe, OutputStream os) throws IOException {
dw.flush();
}
+ /**
+ * @deprecated use {@link PE#write(IDataWriter)} instead
+ */
+ @Deprecated
public static void write(PE pe, IDataWriter dw) throws IOException {
- write(pe.getDosHeader(), dw);
- write(pe.getStub(), dw);
- write(pe.getSignature(), dw);
- write(pe.getCoffHeader(), dw);
- write(pe.getOptionalHeader(), dw);
- writeSectionHeaders(pe, dw);
-
- // Now write out the rest
- DataEntry entry = null;
- while ((entry = PEParser.findNextEntry(pe, dw.getPosition())) != null) {
- if (entry.isSection) {
- writeSection(pe, entry, dw);
- } else if (entry.isDebugRawData) {
- writeDebugRawData(pe, entry, dw);
- } else {
- writeImageData(pe, entry, dw);
- }
- }
-
- // Dump out any trailing data - TODO find out what this is
- byte[] tb = pe.getImageData().getTrailingData();
- if (tb != null)
- dw.writeBytes(tb);
- }
-
- private static void write(DOSHeader dh, IDataWriter dw) throws IOException {
- dw.writeWord(dh.getMagic());
- dw.writeWord(dh.getUsedBytesInLastPage());
- dw.writeWord(dh.getFileSizeInPages());
- dw.writeWord(dh.getNumRelocationItems());
- dw.writeWord(dh.getHeaderSizeInParagraphs());
- dw.writeWord(dh.getMinExtraParagraphs());
- dw.writeWord(dh.getMaxExtraParagraphs());
- dw.writeWord(dh.getInitialSS());
- dw.writeWord(dh.getInitialSP());
- dw.writeWord(dh.getChecksum());
- dw.writeWord(dh.getInitialIP());
- dw.writeWord(dh.getInitialRelativeCS());
- dw.writeWord(dh.getAddressOfRelocationTable());
- dw.writeWord(dh.getOverlayNumber());
- int[] res = dh.getReserved();
- for (int i = 0; i < res.length; i++) {
- dw.writeWord(res[i]);
- }
- dw.writeWord(dh.getOemId());
- dw.writeWord(dh.getOemInfo());
- int[] res2 = dh.getReserved2();
- for (int i = 0; i < res2.length; i++) {
- dw.writeWord(res2[i]);
- }
- dw.writeDoubleWord(dh.getAddressOfNewExeHeader());
- }
-
- private static void write(DOSStub stub, IDataWriter dw) throws IOException {
- dw.writeBytes(stub.getStub());
- }
-
- private static void write(PESignature s, IDataWriter dw) throws IOException {
- dw.writeBytes(s.getSignature());
- }
-
- private static void write(COFFHeader ch, IDataWriter dw) throws IOException {
- dw.writeWord(ch.getMachine());
- dw.writeWord(ch.getNumberOfSections());
- dw.writeDoubleWord(ch.getTimeDateStamp());
- dw.writeDoubleWord(ch.getPointerToSymbolTable());
- dw.writeDoubleWord(ch.getNumberOfSymbols());
- dw.writeWord(ch.getSizeOfOptionalHeader());
- dw.writeWord(ch.getCharacteristics());
- }
-
- private static void write(OptionalHeader oh, IDataWriter dw)
- throws IOException {
- boolean is64 = oh.isPE32plus();
-
- dw.writeWord(oh.getMagic());
- dw.writeByte(oh.getMajorLinkerVersion());
- dw.writeByte(oh.getMinorLinkerVersion());
- dw.writeDoubleWord(oh.getSizeOfCode());
- dw.writeDoubleWord(oh.getSizeOfInitializedData());
- dw.writeDoubleWord(oh.getSizeOfUninitializedData());
- dw.writeDoubleWord(oh.getAddressOfEntryPoint());
- dw.writeDoubleWord(oh.getBaseOfCode());
- if (!is64)
- dw.writeDoubleWord(oh.getBaseOfData());
-
- // NT additional fields.
- if (is64)
- dw.writeLong(oh.getImageBase());
- else
- dw.writeDoubleWord((int) oh.getImageBase());
-
- dw.writeDoubleWord(oh.getSectionAlignment());
- dw.writeDoubleWord(oh.getFileAlignment());
- dw.writeWord(oh.getMajorOperatingSystemVersion());
- dw.writeWord(oh.getMinorOperatingSystemVersion());
- dw.writeWord(oh.getMajorImageVersion());
- dw.writeWord(oh.getMinorImageVersion());
- dw.writeWord(oh.getMajorSubsystemVersion());
- dw.writeWord(oh.getMinorSubsystemVersion());
- dw.writeDoubleWord(oh.getWin32VersionValue());
- dw.writeDoubleWord(oh.getSizeOfImage());
- dw.writeDoubleWord(oh.getSizeOfHeaders());
- dw.writeDoubleWord(oh.getCheckSum());
- dw.writeWord(oh.getSubsystem());
- dw.writeWord(oh.getDllCharacteristics());
- if (is64) {
- dw.writeLong(oh.getSizeOfStackReserve());
- dw.writeLong(oh.getSizeOfStackCommit());
- dw.writeLong(oh.getSizeOfHeapReserve());
- dw.writeLong(oh.getSizeOfHeapCommit());
- } else {
- dw.writeDoubleWord((int) oh.getSizeOfStackReserve());
- dw.writeDoubleWord((int) oh.getSizeOfStackCommit());
- dw.writeDoubleWord((int) oh.getSizeOfHeapReserve());
- dw.writeDoubleWord((int) oh.getSizeOfHeapCommit());
- }
-
- dw.writeDoubleWord(oh.getLoaderFlags());
- dw.writeDoubleWord(oh.getNumberOfRvaAndSizes());
-
- // Data directories
- int ddc = oh.getDataDirectoryCount();
- for (int i = 0; i < ddc; i++) {
- write(oh.getDataDirectory(i), dw);
- }
- }
-
- private static void write(ImageDataDirectory idd, IDataWriter dw)
- throws IOException {
- dw.writeDoubleWord(idd.getVirtualAddress());
- dw.writeDoubleWord(idd.getSize());
- }
-
- private static void writeSectionHeaders(PE pe, IDataWriter dw)
- throws IOException {
- SectionTable st = pe.getSectionTable();
- int ns = st.getNumberOfSections();
- for (int i = 0; i < ns; i++) {
- SectionHeader sh = st.getHeader(i);
- writeSectionHeader(sh, dw);
- }
- }
-
- private static void writeSectionHeader(SectionHeader sh, IDataWriter dw)
- throws IOException {
- dw.writeUtf(sh.getName(), 8);
- dw.writeDoubleWord(sh.getVirtualSize());
- dw.writeDoubleWord(sh.getVirtualAddress());
- dw.writeDoubleWord(sh.getSizeOfRawData());
- dw.writeDoubleWord(sh.getPointerToRawData());
- dw.writeDoubleWord(sh.getPointerToRelocations());
- dw.writeDoubleWord(sh.getPointerToLineNumbers());
- dw.writeWord(sh.getNumberOfRelocations());
- dw.writeWord(sh.getNumberOfLineNumbers());
- dw.writeDoubleWord(sh.getCharacteristics());
- }
-
- private static void writeImageData(PE pe, DataEntry entry, IDataWriter dw)
- throws IOException {
- ImageDataDirectory idd = pe.getOptionalHeader().getDataDirectory(
- entry.index);
- RVAConverter rvc = pe.getSectionTable().getRVAConverter();
- int prd = idd.getVirtualAddress();
- if (entry.index != ImageDataDirectoryType.CERTIFICATE_TABLE)
- prd = rvc.convertVirtualAddressToRawDataPointer(idd
- .getVirtualAddress());
- if (prd > dw.getPosition()) {
- byte[] pa = pe.getImageData().getPreamble(entry.index);
- if (pa != null)
- dw.writeBytes(pa);
- else
- dw.writeByte(0, prd - dw.getPosition());
- }
-
- ImageData id = pe.getImageData();
-
- switch (entry.index) {
- case ImageDataDirectoryType.EXPORT_TABLE:
- dw.writeBytes(id.getExportTable().get());
- break;
- case ImageDataDirectoryType.IMPORT_TABLE:
- dw.writeBytes(id.getImportTable().get());
- break;
- case ImageDataDirectoryType.RESOURCE_TABLE:
- dw.writeBytes(id.getResourceTable().get());
- break;
- case ImageDataDirectoryType.EXCEPTION_TABLE:
- dw.writeBytes(id.getExceptionTable());
- break;
- case ImageDataDirectoryType.CERTIFICATE_TABLE:
- dw.writeBytes(id.getCertificateTable().get());
- break;
- case ImageDataDirectoryType.BASE_RELOCATION_TABLE:
- dw.writeBytes(id.getBaseRelocationTable());
- break;
- case ImageDataDirectoryType.DEBUG:
- dw.writeBytes(id.getDebug().get());
- break;
- case ImageDataDirectoryType.ARCHITECTURE:
- dw.writeBytes(id.getArchitecture());
- break;
- case ImageDataDirectoryType.GLOBAL_PTR:
- dw.writeBytes(id.getGlobalPtr());
- break;
- case ImageDataDirectoryType.TLS_TABLE:
- dw.writeBytes(id.getTlsTable());
- break;
- case ImageDataDirectoryType.LOAD_CONFIG_TABLE:
- break;
- case ImageDataDirectoryType.BOUND_IMPORT:
- write(pe, id.getBoundImports(), dw);
- break;
- case ImageDataDirectoryType.IAT:
- dw.writeBytes(id.getIat());
- break;
- case ImageDataDirectoryType.DELAY_IMPORT_DESCRIPTOR:
- dw.writeBytes(id.getDelayImportDescriptor());
- break;
- case ImageDataDirectoryType.CLR_RUNTIME_HEADER:
- dw.writeBytes(id.getClrRuntimeHeader().get());
- break;
- case ImageDataDirectoryType.RESERVED:
- dw.writeBytes(id.getReserved());
- break;
- }
- }
-
- private static void writeDebugRawData(PE pe, DataEntry entry, IDataWriter dw)
- throws IOException {
- if (entry.pointer > dw.getPosition()) {
- byte[] pa = pe.getImageData().getDebugRawDataPreamble();
- if (pa != null)
- dw.writeBytes(pa);
- else
- dw.writeByte(0, entry.pointer - dw.getPosition());
- }
- dw.writeBytes(pe.getImageData().getDebugRawData());
- }
-
- private static void writeSection(PE pe, DataEntry entry, IDataWriter dw)
- throws IOException {
- SectionTable st = pe.getSectionTable();
- SectionHeader sh = st.getHeader(entry.index);
- SectionData sd = st.getSection(entry.index);
- int prd = sh.getPointerToRawData();
- if (prd > dw.getPosition()) {
- byte[] pa = sd.getPreamble();
- if (pa != null) {
- dw.writeBytes(pa);
- } else {
- dw.writeByte(0, prd - dw.getPosition());
- }
- }
-
- byte[] b = sd.getData();
- dw.writeBytes(b);
- }
-
- private static void write(PE pe, BoundImportDirectoryTable bidt,
- IDataWriter dw) throws IOException {
- int pos = dw.getPosition();
- List bil = new ArrayList();
-
- for (int i = 0; i < bidt.size(); i++) {
- BoundImport bi = bidt.get(i);
- bil.add(bi);
- dw.writeDoubleWord((int) bi.getTimestamp());
- dw.writeWord(bi.getOffsetToModuleName());
- dw.writeWord(bi.getNumberOfModuleForwarderRefs());
- }
-
- Collections.sort(bil, new Comparator() {
- @Override
- public int compare(BoundImport o1, BoundImport o2) {
- return o1.getOffsetToModuleName() - o2.getOffsetToModuleName();
- }
- });
-
- // Now write out empty block
- dw.writeDoubleWord(0);
- dw.writeDoubleWord(0);
-
- // Now write out module names
- Set names = new HashSet();
- for (int i = 0; i < bil.size(); i++) {
- String s = bil.get(i).getModuleName();
- if (!names.contains(s))
- dw.writeUtf(s);
- names.add(s);
- }
-
- // Check for empty block at end - padding for alignment
- int dpos = dw.getPosition() - pos;
- int bis = pe.getOptionalHeader()
- .getDataDirectory(ImageDataDirectoryType.BOUND_IMPORT)
- .getSize();
- if (bis > dpos) {
- dw.writeByte(0, bis - dpos);
- }
+ pe.write(dw);
}
}
diff --git a/src/main/java/com/kichik/pecoff4j/io/PEParser.java b/src/main/java/com/kichik/pecoff4j/io/PEParser.java
index d9317ea..d0665b9 100644
--- a/src/main/java/com/kichik/pecoff4j/io/PEParser.java
+++ b/src/main/java/com/kichik/pecoff4j/io/PEParser.java
@@ -9,27 +9,12 @@
*******************************************************************************/
package com.kichik.pecoff4j.io;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
import com.kichik.pecoff4j.AttributeCertificateTable;
-import com.kichik.pecoff4j.BoundImport;
-import com.kichik.pecoff4j.BoundImportDirectoryTable;
-import com.kichik.pecoff4j.CLRRuntimeHeader;
import com.kichik.pecoff4j.COFFHeader;
import com.kichik.pecoff4j.DOSHeader;
import com.kichik.pecoff4j.DOSStub;
import com.kichik.pecoff4j.DebugDirectory;
import com.kichik.pecoff4j.ExportDirectory;
-import com.kichik.pecoff4j.ImageData;
import com.kichik.pecoff4j.ImageDataDirectory;
import com.kichik.pecoff4j.ImportDirectory;
import com.kichik.pecoff4j.ImportDirectoryEntry;
@@ -39,15 +24,15 @@
import com.kichik.pecoff4j.OptionalHeader;
import com.kichik.pecoff4j.PE;
import com.kichik.pecoff4j.PESignature;
-import com.kichik.pecoff4j.RVAConverter;
-import com.kichik.pecoff4j.ResourceDirectory;
-import com.kichik.pecoff4j.ResourceDirectoryTable;
-import com.kichik.pecoff4j.ResourceEntry;
-import com.kichik.pecoff4j.SectionData;
import com.kichik.pecoff4j.SectionHeader;
import com.kichik.pecoff4j.SectionTable;
-import com.kichik.pecoff4j.constant.ImageDataDirectoryType;
-import com.kichik.pecoff4j.util.IntMap;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
public class PEParser {
public static PE parse(InputStream is) throws IOException {
@@ -74,726 +59,179 @@ public static PE parse(Path path) throws IOException {
}
}
+ /**
+ * @deprecated use {@link PE#read(IDataReader)} instead
+ */
+ @Deprecated
public static PE read(IDataReader dr) throws IOException {
- PE pe = new PE();
- pe.setDosHeader(readDos(dr));
-
- // Check if we have an old file type
- if (pe.getDosHeader().getAddressOfNewExeHeader() == 0
- || pe.getDosHeader().getAddressOfNewExeHeader() > 8192) {
- return pe;
- }
-
- pe.setStub(readStub(pe.getDosHeader(), dr));
- pe.setSignature(readSignature(dr));
-
- // Check signature to ensure we have a pe/coff file
- if (!pe.getSignature().isValid()) {
- return pe;
- }
-
- pe.setCoffHeader(readCOFF(dr));
- pe.setOptionalHeader(readOptional(dr));
- pe.setSectionTable(readSectionHeaders(pe, dr));
-
- pe.set64(pe.getOptionalHeader().isPE32plus());
-
- // Now read the rest of the file
- DataEntry entry = null;
- while ((entry = findNextEntry(pe, dr.getPosition())) != null) {
- if (entry.isSection) {
- readSection(pe, entry, dr);
- } else if (entry.isDebugRawData) {
- readDebugRawData(pe, entry, dr);
- } else {
- readImageData(pe, entry, dr);
- }
- }
-
- // Read any trailing data
- byte[] tb = dr.readAll();
- if (tb.length > 0) {
- pe.getImageData().setTrailingData(tb);
- }
-
- return pe;
+ return PE.read(dr);
}
+ /**
+ * @deprecated use {@link DOSHeader#read(IDataReader)} instead
+ */
+ @Deprecated
public static DOSHeader readDos(IDataReader dr) throws IOException {
- DOSHeader dh = new DOSHeader();
- dh.setMagic(dr.readWord());
- dh.setUsedBytesInLastPage(dr.readWord());
- dh.setFileSizeInPages(dr.readWord());
- dh.setNumRelocationItems(dr.readWord());
- dh.setHeaderSizeInParagraphs(dr.readWord());
- dh.setMinExtraParagraphs(dr.readWord());
- dh.setMaxExtraParagraphs(dr.readWord());
- dh.setInitialSS(dr.readWord());
- dh.setInitialSP(dr.readWord());
- dh.setChecksum(dr.readWord());
- dh.setInitialIP(dr.readWord());
- dh.setInitialRelativeCS(dr.readWord());
- dh.setAddressOfRelocationTable(dr.readWord());
- dh.setOverlayNumber(dr.readWord());
- int[] reserved = new int[4];
- for (int i = 0; i < reserved.length; i++) {
- reserved[i] = dr.readWord();
- }
- dh.setReserved(reserved);
- dh.setOemId(dr.readWord());
- dh.setOemInfo(dr.readWord());
- int[] reserved2 = new int[10];
- for (int i = 0; i < reserved2.length; i++) {
- reserved2[i] = dr.readWord();
- }
- dh.setReserved2(reserved2);
- dh.setAddressOfNewExeHeader(dr.readDoubleWord());
-
- // calc stub size
- int stubSize = dh.getFileSizeInPages() * 512
- - (512 - dh.getUsedBytesInLastPage());
- if (stubSize > dh.getAddressOfNewExeHeader())
- stubSize = dh.getAddressOfNewExeHeader();
- stubSize -= dh.getHeaderSizeInParagraphs() * 16;
- dh.setStubSize(stubSize);
-
- return dh;
+ return DOSHeader.read(dr);
}
+ /**
+ * @deprecated use {@link DOSStub#read(DOSHeader, IDataReader)} instead
+ */
+ @Deprecated
public static DOSStub readStub(DOSHeader header, IDataReader dr)
throws IOException {
- DOSStub ds = new DOSStub();
- int pos = dr.getPosition();
- int add = header.getAddressOfNewExeHeader();
- byte[] stub = new byte[add - pos];
- dr.read(stub);
- ds.setStub(stub);
- return ds;
+ return DOSStub.read(header, dr);
}
+ /**
+ * @deprecated use {@link PESignature#read(IDataReader)} instead
+ */
+ @Deprecated
public static PESignature readSignature(IDataReader dr) throws IOException {
- PESignature ps = new PESignature();
- byte[] signature = new byte[4];
- dr.read(signature);
- ps.setSignature(signature);
- return ps;
+ return PESignature.read(dr);
}
+ /**
+ * @deprecated use {@link COFFHeader#read(IDataReader)} instead
+ */
+ @Deprecated
public static COFFHeader readCOFF(IDataReader dr) throws IOException {
- COFFHeader h = new COFFHeader();
- h.setMachine(dr.readWord());
- h.setNumberOfSections(dr.readWord());
- h.setTimeDateStamp(dr.readDoubleWord());
- h.setPointerToSymbolTable(dr.readDoubleWord());
- h.setNumberOfSymbols(dr.readDoubleWord());
- h.setSizeOfOptionalHeader(dr.readWord());
- h.setCharacteristics(dr.readWord());
- return h;
+ return COFFHeader.read(dr);
}
+ /**
+ * @deprecated use {@link OptionalHeader#read(IDataReader)} instead
+ */
+ @Deprecated
public static OptionalHeader readOptional(IDataReader dr)
throws IOException {
- OptionalHeader oh = new OptionalHeader();
- oh.setMagic(dr.readWord());
- boolean is64 = oh.isPE32plus();
- oh.setMajorLinkerVersion(dr.readByte());
- oh.setMinorLinkerVersion(dr.readByte());
- oh.setSizeOfCode(dr.readDoubleWord());
- oh.setSizeOfInitializedData(dr.readDoubleWord());
- oh.setSizeOfUninitializedData(dr.readDoubleWord());
- oh.setAddressOfEntryPoint(dr.readDoubleWord());
- oh.setBaseOfCode(dr.readDoubleWord());
-
- if (!is64)
- oh.setBaseOfData(dr.readDoubleWord());
-
- // NT additional fields.
- oh.setImageBase(is64 ? dr.readLong() : dr.readDoubleWord());
- oh.setSectionAlignment(dr.readDoubleWord());
- oh.setFileAlignment(dr.readDoubleWord());
- oh.setMajorOperatingSystemVersion(dr.readWord());
- oh.setMinorOperatingSystemVersion(dr.readWord());
- oh.setMajorImageVersion(dr.readWord());
- oh.setMinorImageVersion(dr.readWord());
- oh.setMajorSubsystemVersion(dr.readWord());
- oh.setMinorSubsystemVersion(dr.readWord());
- oh.setWin32VersionValue(dr.readDoubleWord());
- oh.setSizeOfImage(dr.readDoubleWord());
- oh.setSizeOfHeaders(dr.readDoubleWord());
- oh.setCheckSum(dr.readDoubleWord());
- oh.setSubsystem(dr.readWord());
- oh.setDllCharacteristics(dr.readWord());
- oh.setSizeOfStackReserve(is64 ? dr.readLong() : dr.readDoubleWord());
- oh.setSizeOfStackCommit(is64 ? dr.readLong() : dr.readDoubleWord());
- oh.setSizeOfHeapReserve(is64 ? dr.readLong() : dr.readDoubleWord());
- oh.setSizeOfHeapCommit(is64 ? dr.readLong() : dr.readDoubleWord());
- oh.setLoaderFlags(dr.readDoubleWord());
- oh.setNumberOfRvaAndSizes(dr.readDoubleWord());
-
- // Data directories
- ImageDataDirectory[] dds = new ImageDataDirectory[16];
- for (int i = 0; i < dds.length; i++) {
- dds[i] = readImageDD(dr);
- }
- oh.setDataDirectories(dds);
-
- return oh;
+ return OptionalHeader.read(dr);
}
+ /**
+ * @deprecated use {@link ImageDataDirectory#read(IDataReader)} instead
+ */
+ @Deprecated
public static ImageDataDirectory readImageDD(IDataReader dr)
throws IOException {
- ImageDataDirectory idd = new ImageDataDirectory();
- idd.setVirtualAddress(dr.readDoubleWord());
- idd.setSize(dr.readDoubleWord());
- return idd;
+ return ImageDataDirectory.read(dr);
}
+ /**
+ * @deprecated use {@link SectionTable#read(PE, IDataReader)} instead
+ */
+ @Deprecated
public static SectionTable readSectionHeaders(PE pe, IDataReader dr)
throws IOException {
- SectionTable st = new SectionTable();
- int ns = pe.getCoffHeader().getNumberOfSections();
- for (int i = 0; i < ns; i++) {
- st.add(readSectionHeader(dr));
- }
-
- SectionHeader[] sorted = st.getHeadersPointerSorted();
- int[] virtualAddress = new int[sorted.length];
- int[] pointerToRawData = new int[sorted.length];
- for (int i = 0; i < sorted.length; i++) {
- virtualAddress[i] = sorted[i].getVirtualAddress();
- pointerToRawData[i] = sorted[i].getPointerToRawData();
- }
-
- st.setRvaConverter(new RVAConverter(virtualAddress, pointerToRawData));
- return st;
+ return SectionTable.read(pe, dr);
}
+ /**
+ * @deprecated use {@link SectionHeader#read(IDataReader)} instead
+ */
+ @Deprecated
public static SectionHeader readSectionHeader(IDataReader dr)
throws IOException {
- SectionHeader sh = new SectionHeader();
- sh.setName(dr.readUtf(8));
- sh.setVirtualSize(dr.readDoubleWord());
- sh.setVirtualAddress(dr.readDoubleWord());
- sh.setSizeOfRawData(dr.readDoubleWord());
- sh.setPointerToRawData(dr.readDoubleWord());
- sh.setPointerToRelocations(dr.readDoubleWord());
- sh.setPointerToLineNumbers(dr.readDoubleWord());
- sh.setNumberOfRelocations(dr.readWord());
- sh.setNumberOfLineNumbers(dr.readWord());
- sh.setCharacteristics(dr.readDoubleWord());
- return sh;
+ return SectionHeader.read(dr);
}
+ /**
+ * @deprecated use {@link PE#findNextEntry(int)} instead
+ */
+ @Deprecated
public static DataEntry findNextEntry(PE pe, int pos) {
- DataEntry de = new DataEntry();
-
- // Check sections first
- int ns = pe.getCoffHeader().getNumberOfSections();
- for (int i = 0; i < ns; i++) {
- SectionHeader sh = pe.getSectionTable().getHeader(i);
- if (sh.getSizeOfRawData() > 0
- && sh.getPointerToRawData() >= pos
- && (de.pointer == 0 || sh.getPointerToRawData() < de.pointer)) {
- de.pointer = sh.getPointerToRawData();
- de.index = i;
- de.isSection = true;
- }
- }
-
- // Now check image data directories
- RVAConverter rvc = pe.getSectionTable().getRVAConverter();
- int dc = pe.getOptionalHeader().getDataDirectoryCount();
- for (int i = 0; i < dc; i++) {
- ImageDataDirectory idd = pe.getOptionalHeader().getDataDirectory(i);
- if (idd.getSize() > 0) {
- int prd = idd.getVirtualAddress();
- // Assume certificate live outside section ?
- if (i != ImageDataDirectoryType.CERTIFICATE_TABLE
- && isInsideSection(pe, idd)) {
- prd = rvc.convertVirtualAddressToRawDataPointer(idd
- .getVirtualAddress());
- }
- if (prd >= pos && (de.pointer == 0 || prd < de.pointer)) {
- de.pointer = prd;
- de.index = i;
- de.isSection = false;
- }
- }
- }
-
- // Check debug
- ImageData id = pe.getImageData();
- DebugDirectory dd = null;
- if (id != null)
- dd = id.getDebug();
- if (dd != null) {
- int prd = dd.getPointerToRawData();
- if (prd >= pos && (de.pointer == 0 || prd < de.pointer)) {
- de.pointer = prd;
- de.index = -1;
- de.isDebugRawData = true;
- de.isSection = false;
- de.baseAddress = prd;
- }
- }
-
- if (de.pointer == 0)
- return null;
-
- return de;
- }
-
- private static boolean isInsideSection(PE pe, ImageDataDirectory idd) {
- int prd = idd.getVirtualAddress();
- int pex = prd + idd.getSize();
- SectionTable st = pe.getSectionTable();
- int ns = st.getNumberOfSections();
- for (int i = 0; i < ns; i++) {
- SectionHeader sh = st.getHeader(i);
- int vad = sh.getVirtualAddress();
- int vex = vad + sh.getVirtualSize();
- if (prd >= vad && prd < vex && pex <= vex)
- return true;
- }
- return false;
- }
-
- private static void readImageData(PE pe, DataEntry entry, IDataReader dr)
- throws IOException {
-
- // Read any preamble data
- ImageData id = pe.getImageData();
- byte[] pa = readPreambleData(entry.pointer, dr);
- if (pa != null)
- id.put(entry.index, pa);
-
- // Read the image data
- ImageDataDirectory idd = pe.getOptionalHeader().getDataDirectory(
- entry.index);
- byte[] b = new byte[idd.getSize()];
- dr.read(b);
-
- switch (entry.index) {
- case ImageDataDirectoryType.EXPORT_TABLE:
- id.setExportTable(readExportDirectory(b));
- break;
- case ImageDataDirectoryType.IMPORT_TABLE:
- id.setImportTable(readImportDirectory(b, entry.baseAddress));
- break;
- case ImageDataDirectoryType.RESOURCE_TABLE:
- id.setResourceTable(readResourceDirectory(b, entry.baseAddress));
- break;
- case ImageDataDirectoryType.EXCEPTION_TABLE:
- id.setExceptionTable(b);
- break;
- case ImageDataDirectoryType.CERTIFICATE_TABLE:
- id.setCertificateTable(readAttributeCertificateTable(b));
- break;
- case ImageDataDirectoryType.BASE_RELOCATION_TABLE:
- id.setBaseRelocationTable(b);
- break;
- case ImageDataDirectoryType.DEBUG:
- id.setDebug(readDebugDirectory(b));
- break;
- case ImageDataDirectoryType.ARCHITECTURE:
- id.setArchitecture(b);
- break;
- case ImageDataDirectoryType.GLOBAL_PTR:
- id.setGlobalPtr(b);
- break;
- case ImageDataDirectoryType.TLS_TABLE:
- id.setTlsTable(b);
- break;
- case ImageDataDirectoryType.LOAD_CONFIG_TABLE:
- id.setLoadConfigTable(readLoadConfigDirectory(pe, b));
- break;
- case ImageDataDirectoryType.BOUND_IMPORT:
- id.setBoundImports(readBoundImportDirectoryTable(b));
- break;
- case ImageDataDirectoryType.IAT:
- id.setIat(b);
- break;
- case ImageDataDirectoryType.DELAY_IMPORT_DESCRIPTOR:
- id.setDelayImportDescriptor(b);
- break;
- case ImageDataDirectoryType.CLR_RUNTIME_HEADER:
- id.setClrRuntimeHeader(readClrRuntimeHeader(b));
- break;
- case ImageDataDirectoryType.RESERVED:
- id.setReserved(b);
- break;
- }
- }
-
- private static byte[] readPreambleData(int pointer, IDataReader dr)
- throws IOException {
- if (pointer > dr.getPosition()) {
- byte[] pa = new byte[pointer - dr.getPosition()];
- dr.read(pa);
- boolean zeroes = true;
- for (int i = 0; i < pa.length; i++) {
- if (pa[i] != 0) {
- zeroes = false;
- break;
- }
- }
- if (!zeroes)
- return pa;
- }
-
- return null;
- }
-
- private static void readDebugRawData(PE pe, DataEntry entry, IDataReader dr)
- throws IOException {
- // Read any preamble data
- ImageData id = pe.getImageData();
- byte[] pa = readPreambleData(entry.pointer, dr);
- if (pa != null)
- id.setDebugRawDataPreamble(pa);
- DebugDirectory dd = id.getDebug();
- byte[] b = new byte[dd.getSizeOfData()];
- dr.read(b);
- id.setDebugRawData(b);
- }
-
- private static void readSection(PE pe, DataEntry entry, IDataReader dr)
- throws IOException {
- SectionTable st = pe.getSectionTable();
- SectionHeader sh = st.getHeader(entry.index);
- SectionData sd = new SectionData();
-
- // Read any preamble - store if non-zero
- byte[] pa = readPreambleData(sh.getPointerToRawData(), dr);
- if (pa != null)
- sd.setPreamble(pa);
-
- // Read in the raw data block
- dr.jumpTo(sh.getPointerToRawData());
- byte[] b = new byte[sh.getSizeOfRawData()];
- dr.read(b);
- sd.setData(b);
- st.put(entry.index, sd);
-
- // Check for an image directory within this section
- int ddc = pe.getOptionalHeader().getDataDirectoryCount();
- for (int i = 0; i < ddc; i++) {
- if (i == ImageDataDirectoryType.CERTIFICATE_TABLE)
- continue;
- ImageDataDirectory idd = pe.getOptionalHeader().getDataDirectory(i);
- if (idd.getSize() > 0) {
- int vad = sh.getVirtualAddress();
- int vex = vad + sh.getVirtualSize();
- int dad = idd.getVirtualAddress();
- if (dad >= vad && dad < vex) {
- int off = dad - vad;
- IDataReader idr = new ByteArrayDataReader(b, off,
- idd.getSize());
- DataEntry de = new DataEntry(i, 0);
- de.baseAddress = sh.getVirtualAddress();
- readImageData(pe, de, idr);
- }
- }
- }
- }
-
- private static CLRRuntimeHeader readClrRuntimeHeader(
- byte[] b) throws IOException {
- DataReader dr = new DataReader(b);
- CLRRuntimeHeader clrrh = new CLRRuntimeHeader();
- clrrh.set(b);
- clrrh.setHeaderSize(dr.readDoubleWord());
- clrrh.setMajorRuntimeVersion(dr.readWord());
- clrrh.setMinorRuntimeVersion(dr.readWord());
- clrrh.setMetaDataDirectoryAddress(dr.readDoubleWord());
- clrrh.setMetaDataDirectorySize(dr.readDoubleWord());
- clrrh.setFlags(dr.readDoubleWord());
- clrrh.setEntryPointToken(dr.readDoubleWord());
- clrrh.setResourcesDirectoryAddress(dr.readDoubleWord());
- clrrh.setResourcesDirectorySize(dr.readDoubleWord());
- clrrh.setStrongNameSignatureAddress(dr.readDoubleWord());
- clrrh.setStrongNameSignatureSize(dr.readDoubleWord());
- clrrh.setCodeManagerTableAddress(dr.readDoubleWord());
- clrrh.setCodeManagerTableSize(dr.readDoubleWord());
- clrrh.setvTableFixupsAddress(dr.readDoubleWord());
- clrrh.setvTableFixupsSize(dr.readDoubleWord());
- clrrh.setExportAddressTableJumpsAddress(dr.readDoubleWord());
- clrrh.setExportAddressTableJumpsSize(dr.readDoubleWord());
- clrrh.setManagedNativeHeaderAddress(dr.readDoubleWord());
- clrrh.setManagedNativeHeaderSize(dr.readDoubleWord());
- return clrrh;
- }
-
- private static BoundImportDirectoryTable readBoundImportDirectoryTable(
- byte[] b) throws IOException {
- DataReader dr = new DataReader(b);
- BoundImportDirectoryTable bidt = new BoundImportDirectoryTable();
- List imports = new ArrayList();
- BoundImport bi = null;
- while ((bi = readBoundImport(dr)) != null) {
- bidt.add(bi);
- imports.add(bi);
- }
- Collections.sort(imports, new Comparator() {
- @Override
- public int compare(BoundImport o1, BoundImport o2) {
- return o1.getOffsetToModuleName() - o2.getOffsetToModuleName();
- }
- });
- IntMap names = new IntMap();
- for (int i = 0; i < imports.size(); i++) {
- bi = imports.get(i);
- int offset = bi.getOffsetToModuleName();
- String n = (String) names.get(offset);
- if (n == null) {
- dr.jumpTo(offset);
- n = dr.readUtf();
- names.put(offset, n);
- }
- bi.setModuleName(n);
- }
- return bidt;
- }
-
- private static BoundImport readBoundImport(IDataReader dr)
- throws IOException {
- BoundImport bi = new BoundImport();
- bi.setTimestamp(dr.readDoubleWord());
- bi.setOffsetToModuleName(dr.readWord());
- bi.setNumberOfModuleForwarderRefs(dr.readWord());
-
- if (bi.getTimestamp() == 0 && bi.getOffsetToModuleName() == 0
- && bi.getNumberOfModuleForwarderRefs() == 0)
- return null;
-
- return bi;
+ return pe.findNextEntry(pos);
}
+ /**
+ * @deprecated use {@link ImportDirectory#read(byte[], int)} instead
+ */
+ @Deprecated
public static ImportDirectory readImportDirectory(byte[] b, int baseAddress)
throws IOException {
- DataReader dr = new DataReader(b);
- ImportDirectory id = new ImportDirectory();
- ImportDirectoryEntry ide = null;
- while ((ide = readImportDirectoryEntry(dr)) != null) {
- id.add(ide);
- }
-
- /*
- * FIXME - name table refer to data outside image directory for (int i =
- * 0; i < id.size(); i++) { ImportDirectoryEntry e = id.getEntry(i);
- * dr.jumpTo(e.getNameRVA() - baseAddress); String name = dr.readUtf();
- * dr.jumpTo(e.getImportLookupTableRVA() - baseAddress);
- * ImportDirectoryTable nt = readImportDirectoryTable(dr, baseAddress);
- * dr.jumpTo(e.getImportAddressTableRVA() - baseAddress);
- * ImportDirectoryTable at = null; // readImportDirectoryTable(dr, //
- * baseAddress); id.add(name, nt, at); }
- */
-
- return id;
+ return ImportDirectory.read(b, baseAddress);
}
+ /**
+ * @deprecated use {@link ImportDirectoryEntry#read(IDataReader)} instead
+ */
+ @Deprecated
public static ImportDirectoryEntry readImportDirectoryEntry(IDataReader dr)
throws IOException {
- ImportDirectoryEntry id = new ImportDirectoryEntry();
- id.setImportLookupTableRVA(dr.readDoubleWord());
- id.setTimeDateStamp(dr.readDoubleWord());
- id.setForwarderChain(dr.readDoubleWord());
- id.setNameRVA(dr.readDoubleWord());
- id.setImportAddressTableRVA(dr.readDoubleWord());
-
- // The last entry is null
- if (id.getImportLookupTableRVA() == 0) {
- return null;
- }
-
- return id;
+ return ImportDirectoryEntry.read(dr);
}
+ /**
+ * @deprecated use {@link ImportDirectoryTable#read(IDataReader, int)} instead
+ */
+ @Deprecated
public static ImportDirectoryTable readImportDirectoryTable(IDataReader dr,
int baseAddress) throws IOException {
- ImportDirectoryTable idt = new ImportDirectoryTable();
- ImportEntry ie = null;
- while ((ie = readImportEntry(dr)) != null) {
- idt.add(ie);
- }
-
- for (int i = 0; i < idt.size(); i++) {
- ImportEntry iee = idt.getEntry(i);
- if ((iee.getVal() & 0x80000000) != 0) {
- iee.setOrdinal(iee.getVal() & 0x7fffffff);
- } else {
- dr.jumpTo(iee.getVal() - baseAddress);
- dr.readWord(); // FIXME this is an index into the export table
- iee.setName(dr.readUtf());
- }
- }
- return idt;
+ return ImportDirectoryTable.read(dr, baseAddress);
}
+ /**
+ * @deprecated use {@link ImportEntry#read(IDataReader)} instead
+ */
+ @Deprecated
public static ImportEntry readImportEntry(IDataReader dr)
throws IOException {
- ImportEntry ie = new ImportEntry();
- ie.setVal(dr.readDoubleWord());
- if (ie.getVal() == 0) {
- return null;
- }
-
- return ie;
+ return ImportEntry.read(dr);
}
+ /**
+ * @deprecated use {@link ExportDirectory#read(byte[])} instead
+ */
+ @Deprecated
public static ExportDirectory readExportDirectory(byte[] b)
throws IOException {
- DataReader dr = new DataReader(b);
- ExportDirectory edt = new ExportDirectory();
- edt.set(b);
- edt.setExportFlags(dr.readDoubleWord());
- edt.setTimeDateStamp(dr.readDoubleWord());
- edt.setMajorVersion(dr.readWord());
- edt.setMinorVersion(dr.readWord());
- edt.setNameRVA(dr.readDoubleWord());
- edt.setOrdinalBase(dr.readDoubleWord());
- edt.setAddressTableEntries(dr.readDoubleWord());
- edt.setNumberOfNamePointers(dr.readDoubleWord());
- edt.setExportAddressTableRVA(dr.readDoubleWord());
- edt.setNamePointerRVA(dr.readDoubleWord());
- edt.setOrdinalTableRVA(dr.readDoubleWord());
- return edt;
+ return ExportDirectory.read(b);
}
+ /**
+ * @deprecated use {@link LoadConfigDirectory#read(PE, byte[])} instead
+ */
+ @Deprecated
public static LoadConfigDirectory readLoadConfigDirectory(PE pe, byte[] b)
throws IOException {
- DataReader dr = new DataReader(b);
- LoadConfigDirectory lcd = new LoadConfigDirectory();
- lcd.set(b);
- lcd.setSize(dr.readDoubleWord());
- lcd.setTimeDateStamp(dr.readDoubleWord());
- lcd.setMajorVersion(dr.readWord());
- lcd.setMinorVersion(dr.readWord());
- lcd.setGlobalFlagsClear(dr.readDoubleWord());
- lcd.setGlobalFlagsSet(dr.readDoubleWord());
- lcd.setCriticalSectionDefaultTimeout(dr.readDoubleWord());
- lcd.setDeCommitFreeBlockThreshold(pe.is64() ? dr.readLong() : dr.readDoubleWord());
- lcd.setDeCommitTotalFreeThreshold(pe.is64() ? dr.readLong() : dr.readDoubleWord());
- lcd.setLockPrefixTable(pe.is64() ? dr.readLong() : dr.readDoubleWord());
- lcd.setMaximumAllocationSize(pe.is64() ? dr.readLong() : dr.readDoubleWord());
- lcd.setVirtualMemoryThreshold(pe.is64() ? dr.readLong() : dr.readDoubleWord());
- lcd.setProcessAffinityMask(pe.is64() ? dr.readLong() : dr.readDoubleWord());
- lcd.setProcessHeapFlags(dr.readDoubleWord());
- lcd.setCsdVersion(dr.readWord());
- lcd.setReserved(dr.readWord());
- lcd.setEditList(pe.is64() ? dr.readLong() : dr.readDoubleWord());
- if (dr.hasMore()) // optional
- lcd.setSecurityCookie(pe.is64() ? dr.readLong() : dr.readDoubleWord());
- if (dr.hasMore()) // optional
- lcd.setSeHandlerTable(pe.is64() ? dr.readLong() : dr.readDoubleWord());
- if (dr.hasMore()) // optional
- lcd.setSeHandlerCount(pe.is64() ? dr.readLong() : dr.readDoubleWord());
-
- return lcd;
+ return LoadConfigDirectory.read(pe, b);
}
+ /**
+ * @deprecated use {@link DebugDirectory#read(byte[])} instead
+ */
+ @Deprecated
public static DebugDirectory readDebugDirectory(byte[] b)
throws IOException {
return readDebugDirectory(b, new DataReader(b));
}
+ /**
+ * @deprecated use {@link DebugDirectory#read(byte[])} instead
+ */
+ @Deprecated
public static DebugDirectory readDebugDirectory(byte[] b, IDataReader dr)
throws IOException {
- DebugDirectory dd = new DebugDirectory();
- dd.set(b);
- dd.setCharacteristics(dr.readDoubleWord());
- dd.setTimeDateStamp(dr.readDoubleWord());
- dd.setMajorVersion(dr.readWord());
- dd.setMajorVersion(dr.readWord());
- dd.setType(dr.readDoubleWord());
- dd.setSizeOfData(dr.readDoubleWord());
- dd.setAddressOfRawData(dr.readDoubleWord());
- dd.setPointerToRawData(dr.readDoubleWord());
- return dd;
- }
-
- private static ResourceDirectory readResourceDirectory(byte[] b,
- int baseAddress) throws IOException {
- IDataReader dr = new ByteArrayDataReader(b);
- return readResourceDirectory(dr, baseAddress);
- }
-
- private static ResourceDirectory readResourceDirectory(IDataReader dr,
- int baseAddress) throws IOException {
- ResourceDirectory d = new ResourceDirectory();
- d.setTable(readResourceDirectoryTable(dr));
- int ne = d.getTable().getNumNameEntries()
- + d.getTable().getNumIdEntries();
- for (int i = 0; i < ne; i++) {
- d.add(readResourceEntry(dr, baseAddress));
- }
-
- return d;
- }
-
- private static ResourceEntry readResourceEntry(IDataReader dr,
- int baseAddress) throws IOException {
- ResourceEntry re = new ResourceEntry();
- int id = dr.readDoubleWord();
- int offset = dr.readDoubleWord();
- re.setOffset(offset);
- int pos = dr.getPosition();
- if ((id & 0x80000000) != 0) {
- dr.jumpTo(id & 0x7fffffff);
- re.setName(dr.readUnicode(dr.readWord()));
- } else {
- re.setId(id);
- }
- if ((offset & 0x80000000) != 0) {
- dr.jumpTo(offset & 0x7fffffff);
- re.setDirectory(readResourceDirectory(dr, baseAddress));
- } else {
- dr.jumpTo(offset);
- int rva = dr.readDoubleWord();
- int size = dr.readDoubleWord();
- int cp = dr.readDoubleWord();
- int res = dr.readDoubleWord();
- re.setDataRVA(rva);
- re.setCodePage(cp);
- re.setReserved(res);
- dr.jumpTo(rva - baseAddress);
- byte[] b = new byte[size];
- dr.read(b);
- re.setData(b);
- }
- dr.jumpTo(pos);
- return re;
- }
-
- private static ResourceDirectoryTable readResourceDirectoryTable(
- IDataReader dr) throws IOException {
- ResourceDirectoryTable t = new ResourceDirectoryTable();
- t.setCharacteristics(dr.readDoubleWord());
- t.setTimeDateStamp(dr.readDoubleWord());
- t.setMajorVersion(dr.readWord());
- t.setMinVersion(dr.readWord());
- t.setNumNameEntries(dr.readWord());
- t.setNumIdEntries(dr.readWord());
-
- return t;
+ return DebugDirectory.read(b);
}
+ /**
+ * @deprecated use {@link AttributeCertificateTable#read(byte[])} instead
+ */
+ @Deprecated
public static AttributeCertificateTable readAttributeCertificateTable(byte[] b)
throws IOException {
return readAttributeCertificateTable(b, new DataReader(b));
}
+ /**
+ * @deprecated use {@link AttributeCertificateTable#read(byte[])} instead
+ */
+ @Deprecated
public static AttributeCertificateTable readAttributeCertificateTable(byte[] b, IDataReader dr)
throws IOException {
- AttributeCertificateTable dd = new AttributeCertificateTable();
- dd.set(b);
- dd.setLength(dr.readDoubleWord());
- dd.setRevision(dr.readWord());
- dd.setCertificateType(dr.readWord());
- byte[] certificate = new byte[dd.getLength() - 8];
- dr.read(certificate);
- dd.setCertificate(certificate);
- return dd;
+ return AttributeCertificateTable.read(b);
}
}
diff --git a/src/main/java/com/kichik/pecoff4j/io/ResourceAssembler.java b/src/main/java/com/kichik/pecoff4j/io/ResourceAssembler.java
index f1426e2..c943e4c 100644
--- a/src/main/java/com/kichik/pecoff4j/io/ResourceAssembler.java
+++ b/src/main/java/com/kichik/pecoff4j/io/ResourceAssembler.java
@@ -11,6 +11,7 @@
import java.io.IOException;
+import com.kichik.pecoff4j.resources.Bitmap;
import com.kichik.pecoff4j.resources.BitmapInfoHeader;
import com.kichik.pecoff4j.resources.FixedFileInfo;
import com.kichik.pecoff4j.resources.IconDirectory;
@@ -18,81 +19,57 @@
import com.kichik.pecoff4j.resources.IconImage;
import com.kichik.pecoff4j.resources.RGBQuad;
+@Deprecated
public class ResourceAssembler {
+ /**
+ * @deprecated use {@link FixedFileInfo#write(IDataWriter)} instead
+ */
+ @Deprecated
public static void write(FixedFileInfo info, IDataWriter dw)
throws IOException {
- dw.writeDoubleWord(info.getSignature());
- dw.writeDoubleWord(info.getStrucVersion());
- dw.writeDoubleWord(info.getFileVersionMS());
- dw.writeDoubleWord(info.getFileVersionLS());
- dw.writeDoubleWord(info.getProductVersionMS());
- dw.writeDoubleWord(info.getProductVersionLS());
- dw.writeDoubleWord(info.getFileFlagMask());
- dw.writeDoubleWord(info.getFileFlags());
- dw.writeDoubleWord(info.getFileOS());
- dw.writeDoubleWord(info.getFileType());
- dw.writeDoubleWord(info.getFileSubtype());
- dw.writeDoubleWord(info.getFileDateMS());
- dw.writeDoubleWord(info.getFileDateLS());
+ info.write(dw);
}
+ /**
+ * @deprecated use {@link RGBQuad#write(IDataWriter)} instead
+ */
+ @Deprecated
public static void write(RGBQuad rgb, IDataWriter dw) throws IOException {
- dw.writeByte(rgb.getBlue());
- dw.writeByte(rgb.getGreen());
- dw.writeByte(rgb.getRed());
- dw.writeByte(rgb.getReserved());
+ rgb.write(dw);
}
+ /**
+ * @deprecated use {@link IconImage#write(IDataWriter)} instead
+ */
+ @Deprecated
public static void write(IconImage ii, IDataWriter dw) throws IOException {
- if (ii.getHeader() != null) {
- write(ii.getHeader(), dw);
- RGBQuad[] colors = ii.getColors();
- if (colors != null) {
- for (int i = 0; i < colors.length; i++) {
- write(colors[i], dw);
- }
- }
- dw.writeBytes(ii.getXorMask());
- dw.writeBytes(ii.getAndMask());
- } else {
- dw.writeBytes(ii.getPNG());
- }
+ ii.write(dw);
}
+ /**
+ * @deprecated use {@link BitmapInfoHeader#write(IDataWriter)} instead
+ */
+ @Deprecated
public static void write(BitmapInfoHeader bih, IDataWriter dw)
throws IOException {
- dw.writeDoubleWord(bih.getSize());
- dw.writeDoubleWord(bih.getWidth());
- dw.writeDoubleWord(bih.getHeight());
- dw.writeWord(bih.getPlanes());
- dw.writeWord(bih.getBitCount());
- dw.writeDoubleWord(bih.getCompression());
- dw.writeDoubleWord(bih.getSizeImage());
- dw.writeDoubleWord(bih.getXpelsPerMeter());
- dw.writeDoubleWord(bih.getYpelsPerMeter());
- dw.writeDoubleWord(bih.getClrUsed());
- dw.writeDoubleWord(bih.getClrImportant());
+ bih.write(dw);
}
+ /**
+ * @deprecated use {@link IconDirectoryEntry#write(IDataWriter)} instead
+ */
+ @Deprecated
public static void write(IconDirectoryEntry ide, IDataWriter dw)
throws IOException {
- dw.writeByte(ide.getWidth());
- dw.writeByte(ide.getHeight());
- dw.writeByte(ide.getColorCount());
- dw.writeByte(ide.getReserved());
- dw.writeWord(ide.getPlanes());
- dw.writeWord(ide.getBitCount());
- dw.writeDoubleWord(ide.getBytesInRes());
- dw.writeDoubleWord(ide.getOffset());
+ ide.write(dw);
}
+ /**
+ * @deprecated use {@link IconDirectory#write(IDataWriter)} instead
+ */
+ @Deprecated
public static void write(IconDirectory id, IDataWriter dw)
throws IOException {
- dw.writeWord(id.getReserved());
- dw.writeWord(id.getType());
- dw.writeWord(id.getCount());
- for (int i = 0; i < id.getCount(); i++) {
- write(id.getEntry(i), dw);
- }
+ id.write(dw);
}
}
diff --git a/src/main/java/com/kichik/pecoff4j/io/ResourceParser.java b/src/main/java/com/kichik/pecoff4j/io/ResourceParser.java
index 9016499..6a60a0f 100644
--- a/src/main/java/com/kichik/pecoff4j/io/ResourceParser.java
+++ b/src/main/java/com/kichik/pecoff4j/io/ResourceParser.java
@@ -10,7 +10,6 @@
*******************************************************************************/
package com.kichik.pecoff4j.io;
-import java.io.EOFException;
import java.io.IOException;
import com.kichik.pecoff4j.resources.Bitmap;
@@ -29,304 +28,159 @@
import com.kichik.pecoff4j.resources.VarFileInfo;
import com.kichik.pecoff4j.resources.VersionInfo;
+@Deprecated
public class ResourceParser {
+ /**
+ * @deprecated use {@link Bitmap#read(IDataReader)} instead
+ */
+ @Deprecated
public static Bitmap readBitmap(IDataReader dr) throws IOException {
- Bitmap bm = new Bitmap();
- bm.setFileHeader(readBitmapFileHeader(dr));
- bm.setInfoHeader(readBitmapInfoHeader(dr));
-
- return bm;
+ return Bitmap.read(dr);
}
+ /**
+ * @deprecated use {@link BitmapFileHeader#read(IDataReader)} instead
+ */
+ @Deprecated
public static BitmapFileHeader readBitmapFileHeader(IDataReader dr)
throws IOException {
- BitmapFileHeader bfh = new BitmapFileHeader();
- bfh.setType(dr.readWord());
- bfh.setSize(dr.readDoubleWord());
- bfh.setReserved1(dr.readWord());
- bfh.setReserved2(dr.readWord());
- bfh.setOffBits(dr.readDoubleWord());
-
- return bfh;
+ return BitmapFileHeader.read(dr);
}
+ /**
+ * @deprecated use {@link BitmapInfoHeader#read(IDataReader)} instead
+ */
+ @Deprecated
public static BitmapInfoHeader readBitmapInfoHeader(IDataReader dr)
throws IOException {
- BitmapInfoHeader bh = new BitmapInfoHeader();
- bh.setSize(dr.readDoubleWord());
- bh.setWidth(dr.readDoubleWord());
- bh.setHeight(dr.readDoubleWord());
- bh.setPlanes(dr.readWord());
- bh.setBitCount(dr.readWord());
- bh.setCompression(dr.readDoubleWord());
- bh.setSizeImage(dr.readDoubleWord());
- bh.setXpelsPerMeter(dr.readDoubleWord());
- bh.setYpelsPerMeter(dr.readDoubleWord());
- bh.setClrUsed(dr.readDoubleWord());
- bh.setClrImportant(dr.readDoubleWord());
-
- return bh;
+ return BitmapInfoHeader.read(dr);
}
+ /**
+ * @deprecated use {@link FixedFileInfo#read(IDataReader)} instead
+ */
+ @Deprecated
public static FixedFileInfo readFixedFileInfo(IDataReader dr)
throws IOException {
- FixedFileInfo ffi = new FixedFileInfo();
- ffi.setSignature(dr.readDoubleWord());
- ffi.setStrucVersion(dr.readDoubleWord());
- ffi.setFileVersionMS(dr.readDoubleWord());
- ffi.setFileVersionLS(dr.readDoubleWord());
- ffi.setProductVersionMS(dr.readDoubleWord());
- ffi.setProductVersionLS(dr.readDoubleWord());
- ffi.setFileFlagMask(dr.readDoubleWord());
- ffi.setFileFlags(dr.readDoubleWord());
- ffi.setFileOS(dr.readDoubleWord());
- ffi.setFileType(dr.readDoubleWord());
- ffi.setFileSubtype(dr.readDoubleWord());
- ffi.setFileDateMS(dr.readDoubleWord());
- ffi.setFileDateLS(dr.readDoubleWord());
- return ffi;
+ return FixedFileInfo.read(dr);
}
+ /**
+ * @deprecated use {@link IconImage#readIcon(IDataReader, int)} instead
+ */
+ @Deprecated
public static IconImage readIconImage(IDataReader dr, int bytesInRes)
throws IOException {
- IconImage ii = new IconImage();
- int quadSize = 0;
- ii.setHeader(readBitmapInfoHeader(dr));
- if (ii.getHeader().getClrUsed() != 0) {
- quadSize = ii.getHeader().getClrUsed();
- } else {
- if (ii.getHeader().getBitCount() <= 8) {
- quadSize = 1 << ii.getHeader().getBitCount();
- } else {
- quadSize = 0;
- }
- }
-
- int numBytesPerLine = ((((ii.getHeader().getWidth()
- * ii.getHeader().getPlanes() * ii.getHeader().getBitCount()) + 31) >> 5) << 2);
- int xorSize = numBytesPerLine * ii.getHeader().getHeight() / 2;
- int andSize = bytesInRes - (quadSize * 4) - ii.getHeader().getSize()
- - xorSize;
-
- if (quadSize > 0) {
- RGBQuad[] colors = new RGBQuad[quadSize];
- for (int i = 0; i < quadSize; i++) {
- colors[i] = readRGB(dr);
- }
- ii.setColors(colors);
- }
-
- byte[] xorMask = new byte[xorSize];
- dr.read(xorMask);
- ii.setXorMask(xorMask);
-
- byte[] andMask = new byte[andSize];
- dr.read(andMask);
- ii.setAndMask(andMask);
-
- return ii;
+ return IconImage.readIcon(dr, bytesInRes);
}
+ /**
+ * @deprecated use {@link IconImage#readPNG(byte[])} instead
+ */
+ @Deprecated
public static IconImage readPNG(byte[] data) {
- IconImage ii = new IconImage();
- ii.setPngData(data);
- return ii;
+ return IconImage.readPNG(data);
}
+ /**
+ * @deprecated use {@link VersionInfo#read(IDataReader)} instead
+ */
+ @Deprecated
public static VersionInfo readVersionInfo(byte[] data) throws IOException {
return readVersionInfo(new DataReader(data));
}
+ /**
+ * @deprecated use {@link VersionInfo#read(IDataReader)} instead
+ */
+ @Deprecated
public static VersionInfo readVersionInfo(IDataReader dr)
throws IOException {
- int versionInfoPos = dr.getPosition();
- VersionInfo vi = new VersionInfo();
- vi.setLength(dr.readWord());
- vi.setValueLength(dr.readWord());
- vi.setType(dr.readWord());
- vi.setKey(dr.readUnicode());
- alignDataReader(dr);
- vi.setFixedFileInfo(ResourceParser.readFixedFileInfo(dr));
- alignDataReader(dr);
-
- while (dr.getPosition() < versionInfoPos + vi.getLength()) {
- int initialPos = dr.getPosition();
-
- int length = dr.readWord();
- if (length == 0) {
- break;
- }
- int valueLength = dr.readWord();
- int type = dr.readWord();
- String key = dr.readUnicode();
- if ("VarFileInfo".equals(key)) {
- vi.setVarFileInfo(readVarFileInfo(dr, initialPos, length, valueLength, type, key));
- } else if ("StringFileInfo".equals(key)) {
- vi.setStringFileInfo(readStringFileInfo(dr, initialPos, length, valueLength, type, key));
- } else {
- dr.jumpTo(initialPos + length);
- break;
- }
- }
-
- return vi;
+ return VersionInfo.read(dr);
}
-
- public static VarFileInfo readVarFileInfo(IDataReader dr, int initialPos, int length, int valueLength, int type, String key) throws IOException {
- VarFileInfo vfi = new VarFileInfo();
- vfi.setLength(length);
- vfi.setValueLength(valueLength);
- vfi.setType(type);
- vfi.setKey(key);
- alignDataReader(dr);
- while (dr.getPosition() < initialPos + length) {
- vfi.addVar(readVar(dr));
- }
- return vfi;
+ /**
+ * @deprecated use {@link VarFileInfo#readPartial(IDataReader, int, int, int, int, String)} instead
+ */
+ @Deprecated
+ public static VarFileInfo readVarFileInfo(IDataReader dr, int initialPos, int length, int valueLength, int type, String key) throws IOException {
+ return VarFileInfo.readPartial(dr, initialPos, length, valueLength, type, key);
}
+ /**
+ * @deprecated use {@link Var#read(IDataReader)} instead
+ */
+ @Deprecated
public static Var readVar(IDataReader dr) throws IOException {
- Var v = new Var();
- int initialPos = dr.getPosition();
- v.setLength(dr.readWord());
- v.setValueLength(dr.readWord());
- v.setType(dr.readWord());
- v.setKey(dr.readUnicode());
- alignDataReader(dr);
- while (dr.getPosition() < initialPos + v.getLength()) {
- v.addValue(dr.readDoubleWord());
- }
- return v;
+ return Var.read(dr);
}
+ /**
+ * @deprecated use {@link StringTable#read(IDataReader)} instead
+ */
+ @Deprecated
public static StringTable readStringTable(IDataReader dr)
throws IOException {
- int initialPos = dr.getPosition();
-
- StringTable vfi = new StringTable();
- vfi.setLength(dr.readWord());
- if (vfi.getLength() == 0) {
- return null;
- }
- vfi.setValueLength(dr.readWord());
- vfi.setType(dr.readWord());
- vfi.setKey(dr.readUnicode());
- vfi.setPadding(alignDataReader(dr));
-
- while (dr.getPosition() - initialPos < vfi.getLength())
- vfi.add(readStringPair(dr));
-
- return vfi;
+ return StringTable.read(dr);
}
+ /**
+ * @deprecated use {@link StringPair#read(IDataReader)} instead
+ */
+ @Deprecated
public static StringPair readStringPair(IDataReader dr) throws IOException {
- int initialPos = dr.getPosition();
-
- StringPair sp = new StringPair();
- sp.setLength(dr.readWord());
- sp.setValueLength(dr.readWord());
- sp.setType(dr.readWord());
- sp.setKey(dr.readUnicode());
- sp.setPadding(alignDataReader(dr));
-
- int remainingWords = (sp.getLength() - (dr.getPosition() - initialPos)) / 2;
- int valueLength = sp.getValueLength();
- if (sp.getType() == 0) // wType == 0 => binary; wLength is in bytes
- valueLength /= 2;
- if (valueLength > remainingWords)
- valueLength = remainingWords;
- sp.setValue(dr.readUnicode(valueLength).trim());
-
- int remainingBytes = (sp.getLength() - (dr.getPosition() - initialPos));
- dr.skipBytes(remainingBytes);
- alignDataReader(dr);
- return sp;
+ return StringPair.read(dr);
}
+ /**
+ * @deprecated use {@link Manifest#read(IDataReader, int)} instead
+ */
+ @Deprecated
public static Manifest readManifest(IDataReader dr, int length)
throws IOException {
- Manifest mf = new Manifest();
- mf.set(dr.readUtf(length));
- return mf;
+ return Manifest.read(dr, length);
}
+ /**
+ * @deprecated use {@link RGBQuad#read(IDataReader)} instead
+ */
+ @Deprecated
public static RGBQuad readRGB(IDataReader dr) throws IOException {
- RGBQuad r = new RGBQuad();
- r.setBlue(dr.readByte());
- r.setGreen(dr.readByte());
- r.setRed(dr.readByte());
- r.setReserved(dr.readByte());
- return r;
+ return RGBQuad.read(dr);
}
-
- public static StringFileInfo readStringFileInfo(IDataReader dr, int initialPos, int length, int valueLength, int type, String key) throws IOException {
- StringFileInfo sfi = new StringFileInfo();
- sfi.setLength(length);
- sfi.setValueLength(valueLength);
- sfi.setType(type);
- sfi.setKey(key);
- sfi.setPadding(alignDataReader(dr));
- while (dr.getPosition() - initialPos < sfi.getLength()) {
- sfi.add(readStringTable(dr));
- }
- return sfi;
+ /**
+ * @deprecated use {@link StringFileInfo#readPartial(IDataReader, int, int, int, int, String)} instead
+ */
+ @Deprecated
+ public static StringFileInfo readStringFileInfo(IDataReader dr, int initialPos, int length, int valueLength, int type, String key) throws IOException {
+ return StringFileInfo.readPartial(dr, initialPos, length, valueLength, type, key);
}
+ /**
+ * @deprecated use {@link StringFileInfo#read(IDataReader)} instead
+ */
+ @Deprecated
public static StringFileInfo readStringFileInfo(IDataReader dr)
throws IOException {
- int initialPos = dr.getPosition();
-
- StringFileInfo sfi = new StringFileInfo();
-
- sfi.setLength(dr.readWord());
- sfi.setValueLength(dr.readWord());
- sfi.setType(dr.readWord());
- sfi.setKey(dr.readUnicode());
- sfi.setPadding(alignDataReader(dr));
-
- while (dr.getPosition() - initialPos < sfi.getLength())
- sfi.add(readStringTable(dr));
-
- return sfi;
+ return StringFileInfo.read(dr);
}
+ /**
+ * @deprecated use {@link IconDirectoryEntry#read(IDataReader)} instead
+ */
+ @Deprecated
public static IconDirectoryEntry readIconDirectoryEntry(IDataReader dr)
throws IOException {
- IconDirectoryEntry ge = new IconDirectoryEntry();
- ge.setWidth(dr.readByte());
- ge.setHeight(dr.readByte());
- ge.setColorCount(dr.readByte());
- ge.setReserved(dr.readByte());
- ge.setPlanes(dr.readWord());
- ge.setBitCount(dr.readWord());
- ge.setBytesInRes(dr.readDoubleWord());
- ge.setOffset(dr.readDoubleWord());
-
- return ge;
+ return IconDirectoryEntry.read(dr);
}
+ /**
+ * @deprecated use {@link IconDirectory#read(IDataReader)} instead
+ */
+ @Deprecated
public static IconDirectory readIconDirectory(IDataReader dr)
throws IOException {
- IconDirectory gi = new IconDirectory();
- gi.setReserved(dr.readWord());
- gi.setType(dr.readWord());
- int count = dr.readWord();
- for (int i = 0; i < count; i++) {
- gi.add(readIconDirectoryEntry(dr));
- }
-
- return gi;
- }
-
- private static int alignDataReader(IDataReader dr) throws IOException {
- int off = (4 - (dr.getPosition() % 4)) % 4;
- try {
- dr.skipBytes(off);
- } catch (EOFException ignored) {
- // no need to align when it's at the end of its data
- }
- return off;
+ return IconDirectory.read(dr);
}
}
diff --git a/src/main/java/com/kichik/pecoff4j/io/SectionAssembler.java b/src/main/java/com/kichik/pecoff4j/io/SectionAssembler.java
deleted file mode 100644
index 086ffa9..0000000
--- a/src/main/java/com/kichik/pecoff4j/io/SectionAssembler.java
+++ /dev/null
@@ -1,14 +0,0 @@
-/*******************************************************************************
- * This program and the accompanying materials
- * are made available under the terms of the Common Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v10.html
- *
- * Contributors:
- * Peter Smith
- *******************************************************************************/
-package com.kichik.pecoff4j.io;
-
-public class SectionAssembler {
-
-}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/Bitmap.java b/src/main/java/com/kichik/pecoff4j/resources/Bitmap.java
index abc3c71..3725579 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/Bitmap.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/Bitmap.java
@@ -9,12 +9,30 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class Bitmap {
private BitmapFileHeader fileHeader;
private BitmapInfoHeader infoHeader;
private byte[] colors;
private byte[] bitmapBits;
+ public static Bitmap read(IDataReader dr) throws IOException {
+ Bitmap bm = new Bitmap();
+ bm.setFileHeader(BitmapFileHeader.read(dr));
+ bm.setInfoHeader(BitmapInfoHeader.read(dr));
+
+ return bm;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ getFileHeader().write(dw);
+ getInfoHeader().write(dw);
+ }
+
public BitmapFileHeader getFileHeader() {
return fileHeader;
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/BitmapFileHeader.java b/src/main/java/com/kichik/pecoff4j/resources/BitmapFileHeader.java
index 0c28363..960d20a 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/BitmapFileHeader.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/BitmapFileHeader.java
@@ -11,7 +11,8 @@
import java.io.IOException;
-import com.kichik.pecoff4j.io.DataReader;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
public class BitmapFileHeader {
private int type;
@@ -20,7 +21,7 @@ public class BitmapFileHeader {
private int reserved2;
private int offBits;
- public static BitmapFileHeader read(DataReader dr) throws IOException {
+ public static BitmapFileHeader read(IDataReader dr) throws IOException {
BitmapFileHeader bfh = new BitmapFileHeader();
bfh.type = dr.readWord();
bfh.size = dr.readDoubleWord();
@@ -31,6 +32,14 @@ public static BitmapFileHeader read(DataReader dr) throws IOException {
return bfh;
}
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeWord(getType());
+ dw.writeDoubleWord(getSize());
+ dw.writeWord(getReserved1());
+ dw.writeWord(getReserved2());
+ dw.writeDoubleWord(getOffBits());
+ }
+
public int getType() {
return type;
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/BitmapInfoHeader.java b/src/main/java/com/kichik/pecoff4j/resources/BitmapInfoHeader.java
index 0c8243a..dd36330 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/BitmapInfoHeader.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/BitmapInfoHeader.java
@@ -9,6 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class BitmapInfoHeader {
private int size;
private int width;
@@ -22,6 +27,37 @@ public class BitmapInfoHeader {
private int clrUsed;
private int clrImportant;
+ public static BitmapInfoHeader read(IDataReader dr) throws IOException {
+ BitmapInfoHeader bh = new BitmapInfoHeader();
+ bh.setSize(dr.readDoubleWord());
+ bh.setWidth(dr.readDoubleWord());
+ bh.setHeight(dr.readDoubleWord());
+ bh.setPlanes(dr.readWord());
+ bh.setBitCount(dr.readWord());
+ bh.setCompression(dr.readDoubleWord());
+ bh.setSizeImage(dr.readDoubleWord());
+ bh.setXpelsPerMeter(dr.readDoubleWord());
+ bh.setYpelsPerMeter(dr.readDoubleWord());
+ bh.setClrUsed(dr.readDoubleWord());
+ bh.setClrImportant(dr.readDoubleWord());
+
+ return bh;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeDoubleWord(getSize());
+ dw.writeDoubleWord(getWidth());
+ dw.writeDoubleWord(getHeight());
+ dw.writeWord(getPlanes());
+ dw.writeWord(getBitCount());
+ dw.writeDoubleWord(getCompression());
+ dw.writeDoubleWord(getSizeImage());
+ dw.writeDoubleWord(getXpelsPerMeter());
+ dw.writeDoubleWord(getYpelsPerMeter());
+ dw.writeDoubleWord(getClrUsed());
+ dw.writeDoubleWord(getClrImportant());
+ }
+
public int getSize() {
return size;
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/FixedFileInfo.java b/src/main/java/com/kichik/pecoff4j/resources/FixedFileInfo.java
index b6c2049..2aa43cc 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/FixedFileInfo.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/FixedFileInfo.java
@@ -9,6 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class FixedFileInfo {
private int signature;
private int strucVersion;
@@ -24,6 +29,40 @@ public class FixedFileInfo {
private int fileDateMS;
private int fileDateLS;
+ public static FixedFileInfo read(IDataReader dr) throws IOException {
+ FixedFileInfo ffi = new FixedFileInfo();
+ ffi.setSignature(dr.readDoubleWord());
+ ffi.setStrucVersion(dr.readDoubleWord());
+ ffi.setFileVersionMS(dr.readDoubleWord());
+ ffi.setFileVersionLS(dr.readDoubleWord());
+ ffi.setProductVersionMS(dr.readDoubleWord());
+ ffi.setProductVersionLS(dr.readDoubleWord());
+ ffi.setFileFlagMask(dr.readDoubleWord());
+ ffi.setFileFlags(dr.readDoubleWord());
+ ffi.setFileOS(dr.readDoubleWord());
+ ffi.setFileType(dr.readDoubleWord());
+ ffi.setFileSubtype(dr.readDoubleWord());
+ ffi.setFileDateMS(dr.readDoubleWord());
+ ffi.setFileDateLS(dr.readDoubleWord());
+ return ffi;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeDoubleWord(getSignature());
+ dw.writeDoubleWord(getStrucVersion());
+ dw.writeDoubleWord(getFileVersionMS());
+ dw.writeDoubleWord(getFileVersionLS());
+ dw.writeDoubleWord(getProductVersionMS());
+ dw.writeDoubleWord(getProductVersionLS());
+ dw.writeDoubleWord(getFileFlagMask());
+ dw.writeDoubleWord(getFileFlags());
+ dw.writeDoubleWord(getFileOS());
+ dw.writeDoubleWord(getFileType());
+ dw.writeDoubleWord(getFileSubtype());
+ dw.writeDoubleWord(getFileDateMS());
+ dw.writeDoubleWord(getFileDateLS());
+ }
+
public int getSignature() {
return signature;
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/IconDirectory.java b/src/main/java/com/kichik/pecoff4j/resources/IconDirectory.java
index c892136..f4c4375 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/IconDirectory.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/IconDirectory.java
@@ -9,6 +9,10 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
import java.util.ArrayList;
public class IconDirectory {
@@ -16,6 +20,27 @@ public class IconDirectory {
private int type;
private ArrayList entries = new ArrayList();
+ public static IconDirectory read(IDataReader dr) throws IOException {
+ IconDirectory gi = new IconDirectory();
+ gi.setReserved(dr.readWord());
+ gi.setType(dr.readWord());
+ int count = dr.readWord();
+ for (int i = 0; i < count; i++) {
+ gi.add(IconDirectoryEntry.read(dr));
+ }
+
+ return gi;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeWord(getReserved());
+ dw.writeWord(getType());
+ dw.writeWord(getCount());
+ for (int i = 0; i < getCount(); i++) {
+ getEntry(i).write(dw);
+ }
+ }
+
public void add(IconDirectoryEntry entry) {
entries.add(entry);
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/IconDirectoryEntry.java b/src/main/java/com/kichik/pecoff4j/resources/IconDirectoryEntry.java
index 9ee859c..deb1164 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/IconDirectoryEntry.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/IconDirectoryEntry.java
@@ -9,6 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class IconDirectoryEntry {
private int width;
private int height;
@@ -19,6 +24,31 @@ public class IconDirectoryEntry {
private int bytesInRes;
private int offset;
+ public static IconDirectoryEntry read(IDataReader dr) throws IOException {
+ IconDirectoryEntry ge = new IconDirectoryEntry();
+ ge.setWidth(dr.readByte());
+ ge.setHeight(dr.readByte());
+ ge.setColorCount(dr.readByte());
+ ge.setReserved(dr.readByte());
+ ge.setPlanes(dr.readWord());
+ ge.setBitCount(dr.readWord());
+ ge.setBytesInRes(dr.readDoubleWord());
+ ge.setOffset(dr.readDoubleWord());
+
+ return ge;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeByte(getWidth());
+ dw.writeByte(getHeight());
+ dw.writeByte(getColorCount());
+ dw.writeByte(getReserved());
+ dw.writeWord(getPlanes());
+ dw.writeWord(getBitCount());
+ dw.writeDoubleWord(getBytesInRes());
+ dw.writeDoubleWord(getOffset());
+ }
+
public int getWidth() {
return width;
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/IconImage.java b/src/main/java/com/kichik/pecoff4j/resources/IconImage.java
index 2e834a5..8ddcfa7 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/IconImage.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/IconImage.java
@@ -9,6 +9,11 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class IconImage {
private BitmapInfoHeader header;
private RGBQuad[] colors;
@@ -16,6 +21,68 @@ public class IconImage {
private byte[] andMask;
private byte[] pngData;
+ public static IconImage readIcon(IDataReader dr, int bytesInRes)
+ throws IOException {
+ IconImage ii = new IconImage();
+ int quadSize = 0;
+ ii.setHeader(BitmapInfoHeader.read(dr));
+ if (ii.getHeader().getClrUsed() != 0) {
+ quadSize = ii.getHeader().getClrUsed();
+ } else {
+ if (ii.getHeader().getBitCount() <= 8) {
+ quadSize = 1 << ii.getHeader().getBitCount();
+ } else {
+ quadSize = 0;
+ }
+ }
+
+ int numBytesPerLine = ((((ii.getHeader().getWidth()
+ * ii.getHeader().getPlanes() * ii.getHeader().getBitCount()) + 31) >> 5) << 2);
+ int xorSize = numBytesPerLine * ii.getHeader().getHeight() / 2;
+ int andSize = bytesInRes - (quadSize * 4) - ii.getHeader().getSize()
+ - xorSize;
+
+ if (quadSize > 0) {
+ RGBQuad[] colors = new RGBQuad[quadSize];
+ for (int i = 0; i < quadSize; i++) {
+ colors[i] = RGBQuad.read(dr);
+ }
+ ii.setColors(colors);
+ }
+
+ byte[] xorMask = new byte[xorSize];
+ dr.read(xorMask);
+ ii.setXorMask(xorMask);
+
+ byte[] andMask = new byte[andSize];
+ dr.read(andMask);
+ ii.setAndMask(andMask);
+
+ return ii;
+ }
+
+ public static IconImage readPNG(byte[] data) {
+ IconImage ii = new IconImage();
+ ii.setPngData(data);
+ return ii;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ if (getHeader() != null) {
+ getHeader().write(dw);
+ RGBQuad[] colors = getColors();
+ if (colors != null) {
+ for (int i = 0; i < colors.length; i++) {
+ colors[i].write(dw);
+ }
+ }
+ dw.writeBytes(getXorMask());
+ dw.writeBytes(getAndMask());
+ } else {
+ dw.writeBytes(getPNG());
+ }
+ }
+
public BitmapInfoHeader getHeader() {
return header;
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/Manifest.java b/src/main/java/com/kichik/pecoff4j/resources/Manifest.java
index 6399b8a..f85e8df 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/Manifest.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/Manifest.java
@@ -9,9 +9,25 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class Manifest {
private String str;
+ public static Manifest read(IDataReader dr, int length)
+ throws IOException {
+ Manifest mf = new Manifest();
+ mf.set(dr.readUtf(length));
+ return mf;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeUtf(get(), get().length());
+ }
+
public String get() {
return str;
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/RGBQuad.java b/src/main/java/com/kichik/pecoff4j/resources/RGBQuad.java
index 68bcd60..1420741 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/RGBQuad.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/RGBQuad.java
@@ -9,12 +9,33 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
+
public class RGBQuad {
private int blue;
private int green;
private int red;
private int reserved;
+ public static RGBQuad read(IDataReader dr) throws IOException {
+ RGBQuad r = new RGBQuad();
+ r.setBlue(dr.readByte());
+ r.setGreen(dr.readByte());
+ r.setRed(dr.readByte());
+ r.setReserved(dr.readByte());
+ return r;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeByte(getBlue());
+ dw.writeByte(getGreen());
+ dw.writeByte(getRed());
+ dw.writeByte(getReserved());
+ }
+
public int getBlue() {
return blue;
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/StringFileInfo.java b/src/main/java/com/kichik/pecoff4j/resources/StringFileInfo.java
index 8d9c3a1..5578186 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/StringFileInfo.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/StringFileInfo.java
@@ -10,9 +10,12 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
import com.kichik.pecoff4j.util.Strings;
public class StringFileInfo {
@@ -23,6 +26,52 @@ public class StringFileInfo {
private int padding;
private List tables = new ArrayList();
+ public static StringFileInfo read(IDataReader dr) throws IOException {
+ int initialPos = dr.getPosition();
+
+ StringFileInfo sfi = new StringFileInfo();
+
+ sfi.setLength(dr.readWord());
+ sfi.setValueLength(dr.readWord());
+ sfi.setType(dr.readWord());
+ sfi.setKey(dr.readUnicode());
+ sfi.setPadding(dr.align(4));
+
+ while (dr.getPosition() - initialPos < sfi.getLength())
+ sfi.add(StringTable.read(dr));
+
+ return sfi;
+ }
+
+ public static StringFileInfo readPartial(IDataReader dr, int initialPos, int length, int valueLength, int type, String key) throws IOException {
+ StringFileInfo sfi = new StringFileInfo();
+
+ sfi.setLength(length);
+ sfi.setValueLength(valueLength);
+ sfi.setType(type);
+ sfi.setKey(key);
+ sfi.setPadding(dr.align(4));
+ while (dr.getPosition() - initialPos < sfi.getLength()) {
+ sfi.add(StringTable.read(dr));
+ }
+ return sfi;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeWord(getLength());
+ if (getLength() == 0) {
+ return;
+ }
+ dw.writeWord(getValueLength());
+ dw.writeWord(getType());
+ dw.writeUnicode(getKey());
+ dw.align(4);
+ for (int i = 0; i < getCount(); i++) {
+ StringTable table = getTable(i);
+ table.write(dw);
+ }
+ }
+
public void add(StringTable table) {
tables.add(table);
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/StringPair.java b/src/main/java/com/kichik/pecoff4j/resources/StringPair.java
index dcba31f..30886ac 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/StringPair.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/StringPair.java
@@ -10,9 +10,13 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
import com.kichik.pecoff4j.util.Reflection;
import com.kichik.pecoff4j.util.Strings;
+import java.io.IOException;
+
public class StringPair {
private int length;
private int valueLength;
@@ -21,6 +25,52 @@ public class StringPair {
private String value;
private int padding;
+ public static StringPair read(IDataReader dr) throws IOException {
+ int initialPos = dr.getPosition();
+
+ StringPair sp = new StringPair();
+ sp.setLength(dr.readWord());
+ sp.setValueLength(dr.readWord());
+ sp.setType(dr.readWord());
+ sp.setKey(dr.readUnicode());
+ sp.setPadding(dr.align(4));
+
+ int remainingWords = (sp.getLength() - (dr.getPosition() - initialPos)) / 2;
+ int valueLength = sp.getValueLength();
+ if (sp.getType() == 0) // wType == 0 => binary; wLength is in bytes
+ valueLength /= 2;
+ if (valueLength > remainingWords)
+ valueLength = remainingWords;
+ sp.setValue(dr.readUnicode(valueLength).trim());
+
+ int remainingBytes = (sp.getLength() - (dr.getPosition() - initialPos));
+ dr.skipBytes(remainingBytes);
+ dr.align(4);
+ return sp;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ int initialPos = dw.getPosition();
+
+ dw.writeWord(getLength());
+ dw.writeWord(getValueLength());
+ dw.writeWord(getType());
+ dw.writeUnicode(getKey());
+ dw.align(4);
+
+ int remainingWords = (getLength() - (dw.getPosition() - initialPos)) / 2;
+ int valueLength = getValueLength();
+ if (getType() == 0) // wType == 0 => binary; wLength is in bytes
+ valueLength /= 2;
+ if (valueLength > remainingWords)
+ valueLength = remainingWords;
+ dw.writeUnicode(getValue(), valueLength);
+
+ int remainingBytes = (getLength() - (dw.getPosition() - initialPos));
+ dw.writeByte(0, remainingBytes);
+ dw.align(4);
+ }
+
public int getLength() {
return length;
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/StringTable.java b/src/main/java/com/kichik/pecoff4j/resources/StringTable.java
index 2a645b2..af12a67 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/StringTable.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/StringTable.java
@@ -10,9 +10,12 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
import com.kichik.pecoff4j.util.Strings;
public class StringTable {
@@ -23,6 +26,42 @@ public class StringTable {
private int padding;
private List strings = new ArrayList();
+ public static StringTable read(IDataReader dr) throws IOException {
+ int initialPos = dr.getPosition();
+
+ StringTable vfi = new StringTable();
+ vfi.setLength(dr.readWord());
+ if (vfi.getLength() == 0) {
+ return null;
+ }
+ vfi.setValueLength(dr.readWord());
+ vfi.setType(dr.readWord());
+ vfi.setKey(dr.readUnicode());
+ vfi.setPadding(dr.align(4));
+
+ while (dr.getPosition() - initialPos < vfi.getLength())
+ vfi.add(StringPair.read(dr));
+
+ return vfi;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeWord(getLength());
+ if (getLength() == 0) {
+ return;
+ }
+
+ dw.writeWord(getValueLength());
+ dw.writeWord(getType());
+ dw.writeUnicode(getKey());
+ dw.align(4);
+
+ for (int i = 0; i < getCount(); i++) {
+ StringPair pair = getString(i);
+ pair.write(dw);
+ }
+ }
+
public void add(StringPair string) {
strings.add(string);
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/Var.java b/src/main/java/com/kichik/pecoff4j/resources/Var.java
index 95e950c..e2b2c2e 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/Var.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/Var.java
@@ -1,5 +1,9 @@
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -15,6 +19,31 @@ public class Var {
private String key;
private final List values = new ArrayList<>();
+ public static Var read(IDataReader dr) throws IOException {
+ Var v = new Var();
+ int initialPos = dr.getPosition();
+ v.setLength(dr.readWord());
+ v.setValueLength(dr.readWord());
+ v.setType(dr.readWord());
+ v.setKey(dr.readUnicode());
+ dr.align(4);
+ while (dr.getPosition() < initialPos + v.getLength()) {
+ v.addValue(dr.readDoubleWord());
+ }
+ return v;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeWord(getLength());
+ dw.writeWord(getValueLength());
+ dw.writeWord(getType());
+ dw.writeUnicode(getKey());
+ dw.align(4);
+ for (Integer value : getValues()) {
+ dw.writeDoubleWord(value);
+ }
+ }
+
public int getLength() {
return length;
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/VarFileInfo.java b/src/main/java/com/kichik/pecoff4j/resources/VarFileInfo.java
index 7679848..5f2b210 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/VarFileInfo.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/VarFileInfo.java
@@ -9,6 +9,10 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -19,6 +23,31 @@ public class VarFileInfo {
private String key;
private final List vars = new ArrayList<>();
+ public static VarFileInfo readPartial(IDataReader dr, int initialPos, int length, int valueLength, int type, String key) throws IOException {
+ VarFileInfo vfi = new VarFileInfo();
+ vfi.setLength(length);
+ vfi.setValueLength(valueLength);
+ vfi.setType(type);
+ vfi.setKey(key);
+ dr.align(4);
+
+ while (dr.getPosition() < initialPos + length) {
+ vfi.addVar(Var.read(dr));
+ }
+ return vfi;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeWord(getLength());
+ dw.writeWord(getValueLength());
+ dw.writeWord(getType());
+ dw.writeUnicode(getKey());
+ dw.align(4);
+ for (Var v : getVars()) {
+ v.write(dw);
+ }
+ }
+
public void setLength(int length) {
this.length = length;
}
diff --git a/src/main/java/com/kichik/pecoff4j/resources/VersionInfo.java b/src/main/java/com/kichik/pecoff4j/resources/VersionInfo.java
index f853c73..c641502 100644
--- a/src/main/java/com/kichik/pecoff4j/resources/VersionInfo.java
+++ b/src/main/java/com/kichik/pecoff4j/resources/VersionInfo.java
@@ -9,6 +9,12 @@
*******************************************************************************/
package com.kichik.pecoff4j.resources;
+import com.kichik.pecoff4j.io.IDataReader;
+import com.kichik.pecoff4j.io.IDataWriter;
+import com.kichik.pecoff4j.io.ResourceAssembler;
+
+import java.io.IOException;
+
public class VersionInfo {
private int length;
private int valueLength;
@@ -18,6 +24,59 @@ public class VersionInfo {
private StringFileInfo stringFileInfo;
private VarFileInfo varFileInfo;
+ public static VersionInfo read(IDataReader dr)
+ throws IOException {
+ int versionInfoPos = dr.getPosition();
+ VersionInfo vi = new VersionInfo();
+ vi.setLength(dr.readWord());
+ vi.setValueLength(dr.readWord());
+ vi.setType(dr.readWord());
+ vi.setKey(dr.readUnicode());
+ dr.align(4);
+ vi.setFixedFileInfo(FixedFileInfo.read(dr));
+ dr.align(4);
+
+ while (dr.getPosition() < versionInfoPos + vi.getLength()) {
+ int initialPos = dr.getPosition();
+
+ int length = dr.readWord();
+ if (length == 0) {
+ break;
+ }
+ int valueLength = dr.readWord();
+ int type = dr.readWord();
+ String key = dr.readUnicode();
+ if ("VarFileInfo".equals(key)) {
+ vi.setVarFileInfo(VarFileInfo.readPartial(dr, initialPos, length, valueLength, type, key));
+ } else if ("StringFileInfo".equals(key)) {
+ vi.setStringFileInfo(StringFileInfo.readPartial(dr, initialPos, length, valueLength, type, key));
+ } else {
+ dr.jumpTo(initialPos + length);
+ break;
+ }
+ }
+
+ return vi;
+ }
+
+ public void write(IDataWriter dw) throws IOException {
+ dw.writeWord(getLength());
+ dw.writeWord(getValueLength());
+ dw.writeWord(getType());
+ dw.writeUnicode(getKey());
+ dw.align(4);
+ ResourceAssembler.write(getFixedFileInfo(), dw);
+
+ StringFileInfo stringFileInfo = getStringFileInfo();
+ if (stringFileInfo != null) {
+ stringFileInfo.write(dw);
+ }
+ VarFileInfo varFileInfo = getVarFileInfo();
+ if (varFileInfo != null) {
+ varFileInfo.write(dw);
+ }
+ }
+
public int getLength() {
return length;
}
diff --git a/src/main/java/com/kichik/pecoff4j/util/IconExtractor.java b/src/main/java/com/kichik/pecoff4j/util/IconExtractor.java
index febc2b8..1833e17 100644
--- a/src/main/java/com/kichik/pecoff4j/util/IconExtractor.java
+++ b/src/main/java/com/kichik/pecoff4j/util/IconExtractor.java
@@ -20,7 +20,6 @@
import com.kichik.pecoff4j.io.DataReader;
import com.kichik.pecoff4j.io.DataWriter;
import com.kichik.pecoff4j.io.PEParser;
-import com.kichik.pecoff4j.io.ResourceParser;
import com.kichik.pecoff4j.resources.GroupIconDirectory;
import com.kichik.pecoff4j.resources.GroupIconDirectoryEntry;
import com.kichik.pecoff4j.resources.IconDirectory;
@@ -60,10 +59,10 @@ public static void extract(File pecoff, File outputDir) throws IOException {
ide.setBytesInRes(d.length);
// Check for PNG data
if (gide.getWidth() == 0 && gide.getHeight() == 0) {
- IconImage ii = ResourceParser.readPNG(d);
+ IconImage ii = IconImage.readPNG(d);
images[j] = ii;
} else {
- IconImage ii = ResourceParser.readIconImage(new DataReader(
+ IconImage ii = IconImage.readIcon(new DataReader(
d), gide.getBytesInRes());
images[j] = ii;
}
diff --git a/src/main/java/com/kichik/pecoff4j/util/IconFile.java b/src/main/java/com/kichik/pecoff4j/util/IconFile.java
index bc91dae..69cc0c4 100644
--- a/src/main/java/com/kichik/pecoff4j/util/IconFile.java
+++ b/src/main/java/com/kichik/pecoff4j/util/IconFile.java
@@ -16,8 +16,6 @@
import com.kichik.pecoff4j.io.DataReader;
import com.kichik.pecoff4j.io.IDataReader;
import com.kichik.pecoff4j.io.IDataWriter;
-import com.kichik.pecoff4j.io.ResourceAssembler;
-import com.kichik.pecoff4j.io.ResourceParser;
import com.kichik.pecoff4j.resources.IconDirectory;
import com.kichik.pecoff4j.resources.IconImage;
@@ -35,11 +33,11 @@ public static IconFile parse(File file) throws IOException {
public static IconFile read(IDataReader dr) throws IOException {
IconFile ic = new IconFile();
- ic.directory = ResourceParser.readIconDirectory(dr);
+ ic.directory = IconDirectory.read(dr);
ic.images = new IconImage[ic.directory.getCount()];
for (int i = 0; i < ic.directory.getCount(); i++) {
dr.jumpTo(ic.directory.getEntry(i).getOffset());
- ic.images[i] = ResourceParser.readIconImage(dr, ic.directory
+ ic.images[i] = IconImage.readIcon(dr, ic.directory
.getEntry(i).getBytesInRes());
}
return ic;
@@ -51,9 +49,9 @@ public void write(IDataWriter dw) throws IOException {
directory.getEntry(i).setOffset(offset);
offset += images[i].sizeOf();
}
- ResourceAssembler.write(directory, dw);
+ directory.write(dw);
for (int i = 0; i < images.length; i++) {
- ResourceAssembler.write(images[i], dw);
+ images[i].write(dw);
}
}
diff --git a/src/test/java/com/kichik/pecoff4j/ReadWriteTest.java b/src/test/java/com/kichik/pecoff4j/ReadWriteTest.java
new file mode 100644
index 0000000..06b258c
--- /dev/null
+++ b/src/test/java/com/kichik/pecoff4j/ReadWriteTest.java
@@ -0,0 +1,100 @@
+package com.kichik.pecoff4j;
+
+import com.kichik.pecoff4j.constant.ResourceType;
+import com.kichik.pecoff4j.io.DataReader;
+import com.kichik.pecoff4j.io.PEParser;
+import com.kichik.pecoff4j.io.ValidatingWriter;
+import com.kichik.pecoff4j.resources.GroupIconDirectory;
+import com.kichik.pecoff4j.resources.IconImage;
+import com.kichik.pecoff4j.resources.Manifest;
+import com.kichik.pecoff4j.resources.VersionInfo;
+import com.kichik.pecoff4j.util.ResourceHelper;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+public class ReadWriteTest {
+ @Test
+ public void testReadWriteExe() throws IOException {
+ PE pe = PEParser.parse(getClass().getResourceAsStream("/WinRun4J.exe"));
+ ValidatingWriter writer = new ValidatingWriter(new DataReader(getClass().getResourceAsStream("/WinRun4J.exe")));
+
+ pe.write(writer);
+ writer.assertEndOfStream();
+ }
+
+ @Test
+ public void testReadWriteDll() throws IOException {
+ PE pe = PEParser.parse(getClass().getResourceAsStream("/clr/ClassLibrary.dll"));
+ ValidatingWriter writer = new ValidatingWriter(new DataReader(getClass().getResourceAsStream("/clr/ClassLibrary.dll")));
+
+ pe.write(writer);
+ writer.assertEndOfStream();
+ }
+
+ @Test
+ public void testReadWriteResources() throws IOException {
+ PE pe = PEParser.parse(getClass().getResourceAsStream("/WinRun4J.exe"));
+ ValidatingWriter writer = new ValidatingWriter(new DataReader(pe.getSectionTable().findSection(".rsrc").getData()));
+
+ pe.getImageData().getResourceTable().write(writer);
+ writer.align(pe.getOptionalHeader().getFileAlignment());
+ writer.assertEndOfStream();
+ }
+
+ @Test
+ public void testReadWriteVersionInfo() throws IOException {
+ PE pe = PEParser.parse(getClass().getResourceAsStream("/WinRun4J.exe"));
+
+ ResourceDirectory rd = pe.getImageData().getResourceTable();
+ ResourceEntry[] entries = ResourceHelper.findResources(rd, ResourceType.VERSION_INFO);
+ for (ResourceEntry entry : entries) {
+ VersionInfo versionInfo = VersionInfo.read(new DataReader(entry.getData()));
+ ValidatingWriter writer = new ValidatingWriter(new DataReader(entry.getData()));
+ versionInfo.write(writer);
+ writer.assertEndOfStream();
+ }
+ }
+
+ @Test
+ public void testReadWriteManifest() throws IOException {
+ PE pe = PEParser.parse(getClass().getResourceAsStream("/WinRun4J.exe"));
+
+ ResourceDirectory rd = pe.getImageData().getResourceTable();
+ ResourceEntry[] entries = ResourceHelper.findResources(rd, ResourceType.MANIFEST);
+ for (ResourceEntry entry : entries) {
+ Manifest manifest = Manifest.read(new DataReader(entry.getData()), entry.getData().length);
+ ValidatingWriter writer = new ValidatingWriter(new DataReader(entry.getData()));
+ manifest.write(writer);
+ writer.assertEndOfStream();
+ }
+ }
+
+ @Test
+ public void testReadWriteIconGroups() throws IOException {
+ PE pe = PEParser.parse(getClass().getResourceAsStream("/WinRun4J.exe"));
+
+ ResourceDirectory rd = pe.getImageData().getResourceTable();
+ ResourceEntry[] entries = ResourceHelper.findResources(rd, ResourceType.GROUP_ICON);
+ for (ResourceEntry entry : entries) {
+ GroupIconDirectory dir = GroupIconDirectory.read(new DataReader(entry.getData()));
+ ValidatingWriter writer = new ValidatingWriter(new DataReader(entry.getData()));
+ dir.write(writer);
+ writer.assertEndOfStream();
+ }
+ }
+
+ @Test
+ public void testReadWriteIcons() throws IOException {
+ PE pe = PEParser.parse(getClass().getResourceAsStream("/WinRun4J.exe"));
+
+ ResourceDirectory rd = pe.getImageData().getResourceTable();
+ ResourceEntry[] entries = ResourceHelper.findResources(rd, ResourceType.ICON);
+ for (ResourceEntry entry : entries) {
+ IconImage image = IconImage.readIcon(new DataReader(entry.getData()), entry.getData().length);
+ ValidatingWriter writer = new ValidatingWriter(new DataReader(entry.getData()));
+ image.write(writer);
+ writer.assertEndOfStream();
+ }
+ }
+}
diff --git a/src/test/java/com/kichik/pecoff4j/VersionStringsTest.java b/src/test/java/com/kichik/pecoff4j/VersionStringsTest.java
index 84c4b97..7e3ed28 100644
--- a/src/test/java/com/kichik/pecoff4j/VersionStringsTest.java
+++ b/src/test/java/com/kichik/pecoff4j/VersionStringsTest.java
@@ -12,8 +12,8 @@
import java.io.IOException;
import com.kichik.pecoff4j.constant.ResourceType;
+import com.kichik.pecoff4j.io.DataReader;
import com.kichik.pecoff4j.io.PEParser;
-import com.kichik.pecoff4j.io.ResourceParser;
import com.kichik.pecoff4j.resources.StringFileInfo;
import com.kichik.pecoff4j.resources.StringPair;
import com.kichik.pecoff4j.resources.StringTable;
@@ -36,7 +36,7 @@ public void testVersionStrings() throws IOException {
ResourceEntry[] entries = ResourceHelper.findResources(rd, ResourceType.VERSION_INFO);
assertEquals(1, entries.length);
- VersionInfo version = ResourceParser.readVersionInfo(entries[0].getData());
+ VersionInfo version = VersionInfo.read(new DataReader(entries[0].getData()));
// check StringFileInfo structure
StringFileInfo strings = version.getStringFileInfo();
diff --git a/src/test/java/com/kichik/pecoff4j/io/ValidatingWriter.java b/src/test/java/com/kichik/pecoff4j/io/ValidatingWriter.java
new file mode 100644
index 0000000..2c3f247
--- /dev/null
+++ b/src/test/java/com/kichik/pecoff4j/io/ValidatingWriter.java
@@ -0,0 +1,107 @@
+package com.kichik.pecoff4j.io;
+
+import org.junit.jupiter.api.Assertions;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * A {@link IDataWriter} that validates the data to write by comparing them
+ * to the data provided by a {@link IDataReader}. Compared to a diff of
+ * expected and actual byte array, this approach provides immediate feedback
+ * when a value is written that is not expected.
+ */
+public class ValidatingWriter implements IDataWriter {
+
+ private static final byte[] PADDING = "PADDINGXXPADDING".getBytes(StandardCharsets.US_ASCII);
+
+ private final IDataReader expected;
+
+ public ValidatingWriter(IDataReader expected) {
+ this.expected = expected;
+ }
+
+ @Override
+ public void writeByte(int b) throws IOException {
+ Assertions.assertEquals(expected.readByte(), b);
+ }
+
+ @Override
+ public void writeByte(int b, int count) throws IOException {
+ for (int i = 0; i < count; i++) {
+ Assertions.assertEquals(expected.readByte(), b);
+ }
+ }
+
+ @Override
+ public void writeBytes(byte[] b) throws IOException {
+ byte[] expectedBytes = new byte[b.length];
+ expected.read(expectedBytes);
+ Assertions.assertArrayEquals(expectedBytes, b);
+ }
+
+ @Override
+ public void writeDoubleWord(int dw) throws IOException {
+ Assertions.assertEquals(expected.readDoubleWord(), dw);
+ }
+
+ @Override
+ public void writeWord(int w) throws IOException {
+ Assertions.assertEquals(expected.readWord(), w);
+ }
+
+ @Override
+ public void writeLong(long l) throws IOException {
+ Assertions.assertEquals(expected.readLong(), l);
+ }
+
+ @Override
+ public int getPosition() {
+ return expected.getPosition();
+ }
+
+ @Override
+ public void writeUtf(String s, int len) throws IOException {
+ int position = expected.getPosition();
+ Assertions.assertEquals(expected.readUtf(len), s);
+ Assertions.assertEquals(position + len, expected.getPosition());
+ }
+
+ @Override
+ public void writeUtf(String s) throws IOException {
+ Assertions.assertEquals(expected.readUtf(s.length()), s);
+ }
+
+ @Override
+ public void writeUnicode(String s) throws IOException {
+ Assertions.assertEquals(expected.readUnicode(), s);
+ }
+
+ @Override
+ public void writeUnicode(String s, int len) throws IOException {
+ Assertions.assertEquals(expected.readUnicode(len).trim(), s);
+ }
+
+ @Override
+ public int align(int alignment) throws IOException {
+ int off = (alignment - (getPosition() % alignment)) % alignment;
+ if (off != 0) {
+ for (int i = 0; i < off; i++) {
+ int value = expected.readByte();
+ if (value != 0 && value != PADDING[i % 16]) {
+ Assertions.fail("Padding unexpected");
+ }
+ }
+ }
+ return off;
+ }
+
+ public void assertEndOfStream() throws IOException {
+ Assertions.assertFalse(expected.hasMore());
+ }
+
+ @Override
+ public String toString() {
+ return "ValidatingWriter @ " + getPosition();
+ }
+}