Skip to content

Commit

Permalink
Improve VarFileInfo parsing support (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
swismer committed May 8, 2023
1 parent cf339ed commit 90f3a2c
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 72 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M3</version>
<version>3.3.0</version>
<executions>
<execution>
<id>enforce-jdk-paths</id>
Expand Down
56 changes: 28 additions & 28 deletions src/main/java/com/kichik/pecoff4j/io/ResourceParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.kichik.pecoff4j.resources.StringFileInfo;
import com.kichik.pecoff4j.resources.StringPair;
import com.kichik.pecoff4j.resources.StringTable;
import com.kichik.pecoff4j.resources.Var;
import com.kichik.pecoff4j.resources.VarFileInfo;
import com.kichik.pecoff4j.resources.VersionInfo;

Expand Down Expand Up @@ -138,17 +139,17 @@ public static VersionInfo readVersionInfo(byte[] data) throws IOException {

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));


while (true) {
int padding = alignDataReader(dr);
alignDataReader(dr);

while (dr.getPosition() < versionInfoPos + vi.getLength()) {
int initialPos = dr.getPosition();

int length = dr.readWord();
Expand All @@ -159,11 +160,9 @@ public static VersionInfo readVersionInfo(IDataReader dr)
int type = dr.readWord();
String key = dr.readUnicode();
if ("VarFileInfo".equals(key)) {
//We may or may not find the varFileInfo...
vi.setVarFileInfo(readVarFileInfo(dr, initialPos, length, valueLength, type, key, padding));
vi.setVarFileInfo(readVarFileInfo(dr, initialPos, length, valueLength, type, key));
} else if ("StringFileInfo".equals(key)) {
vi.setStringFileInfo(readStringFileInfo(dr, initialPos, length, valueLength, type, key, padding));
break;
vi.setStringFileInfo(readStringFileInfo(dr, initialPos, length, valueLength, type, key));
} else {
dr.jumpTo(initialPos + length);
break;
Expand All @@ -173,31 +172,32 @@ public static VersionInfo readVersionInfo(IDataReader dr)
return vi;
}

public static VarFileInfo readVarFileInfo(IDataReader dr, int initialPos, int length, int valueLength, int type, String key, int padding) throws IOException {
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);
String name = null;
while ((name = dr.readUnicode()) != null) {
if (name.length() == 2) {
name = dr.readUnicode();
}
vfi.add(name, dr.readUnicode());
alignDataReader(dr);

while (dr.getPosition() < initialPos + length) {
vfi.addVar(readVar(dr));
}
dr.jumpTo(initialPos + length - 2);
return vfi;
}

public static VarFileInfo readVarFileInfo(IDataReader dr)
throws IOException {
VarFileInfo vfi = new VarFileInfo();
vfi.setKey(dr.readUnicode());
String name = null;
while ((name = dr.readUnicode()) != null) {
if (name.length() % 2 == 1)
dr.readWord();
vfi.add(name, dr.readUnicode());
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 vfi;
return v;
}

public static StringTable readStringTable(IDataReader dr)
Expand Down Expand Up @@ -260,14 +260,14 @@ public static RGBQuad readRGB(IDataReader dr) throws IOException {
return r;
}

public static StringFileInfo readStringFileInfo(IDataReader dr, int initialPos, int length, int valueLength, int type, String key, int padding) throws IOException {
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(padding);
sfi.setPadding(alignDataReader(dr));
while (dr.getPosition() - initialPos < sfi.getLength()) {
sfi.add(readStringTable(dr));
}
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/com/kichik/pecoff4j/resources/Var.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.kichik.pecoff4j.resources;

import java.util.ArrayList;
import java.util.List;

/**
* A list of language and code page identifier pairs.
*
* See <a href="https://learn.microsoft.com/en-us/windows/win32/menurc/var-str">Var structure</a> for details.
*/
public class Var {
private int length;
private int valueLength;
private int type;
private String key;
private final List<Integer> values = new ArrayList<>();

public int getLength() {
return length;
}

public void setLength(int length) {
this.length = length;
}

public int getValueLength() {
return valueLength;
}

public void setValueLength(int valueLength) {
this.valueLength = valueLength;
}

public int getType() {
return type;
}

public void setType(int type) {
this.type = type;
}

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}

public List<Integer> getValues() {
return values;
}

public void addValue(int value) {
values.add(value);
}
}
49 changes: 31 additions & 18 deletions src/main/java/com/kichik/pecoff4j/resources/VarFileInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,50 @@
import java.util.List;

public class VarFileInfo {
private int length;
private int valueLength;
private int type;
private String key;
private List<String> names = new ArrayList();
private List<String> values = new ArrayList();
private final List<Var> vars = new ArrayList<>();

public String getKey() {
return key;
public void setLength(int length) {
this.length = length;
}

public void setKey(String key) {
this.key = key;
public int getLength() {
return length;
}

public int size() {
return names.size();
public void setValueLength(int valueLength) {
this.valueLength = valueLength;
}

public String getName(int index) {
return names.get(index);
public int getValueLength() {
return valueLength;
}

public String getValue(int index) {
return values.get(index);
public void setType(int type) {
this.type = type;
}

public void add(String name, String value) {
names.add(name);
values.add(value);
public int getType() {
return type;
}

public void clear() {
names.clear();
values.clear();
public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}

public void addVar(Var v) {
vars.add(v);
}

public List<Var> getVars() {
return vars;
}

}
69 changes: 44 additions & 25 deletions src/test/java/com/kichik/pecoff4j/VersionStringsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,62 @@

import java.io.IOException;

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.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;
import com.kichik.pecoff4j.resources.Var;
import com.kichik.pecoff4j.resources.VarFileInfo;
import com.kichik.pecoff4j.resources.VersionInfo;
import com.kichik.pecoff4j.util.ResourceHelper;

public class VersionStringsTest {
import org.junit.jupiter.api.Test;

public static void main(String[] args) throws IOException {
testVersionStrings("C:/windows/system32/notepad.exe");
testVersionStrings("C:/windows/system32/ieframe.dll");
testVersionStrings("C:/windows/system32/igfxtray.exe");
}
import static org.junit.jupiter.api.Assertions.assertEquals;

public class VersionStringsTest {

public static void testVersionStrings(String path) throws IOException {
PE pe = PEParser.parse(path);
@Test
public void testVersionStrings() throws IOException {
PE pe = PEParser.parse(getClass().getResourceAsStream("/WinRun4J.exe"));
ResourceDirectory rd = pe.getImageData().getResourceTable();

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);

StringFileInfo strings = version.getStringFileInfo();
StringTable table = strings.getTable(0);
for (int j = 0; j < table.getCount(); j++) {
String key = table.getString(j).getKey();
String value = table.getString(j).getValue();
System.out.println(key + " = " + value);
}
}
ResourceEntry[] entries = ResourceHelper.findResources(rd, ResourceType.VERSION_INFO);
assertEquals(1, entries.length);

VersionInfo version = ResourceParser.readVersionInfo(entries[0].getData());

// check StringFileInfo structure
StringFileInfo strings = version.getStringFileInfo();
assertEquals("StringFileInfo", strings.getKey());
assertEquals(1, strings.getCount());
StringTable table = strings.getTable(0);

assertEquals(4, table.getCount());
assertKeyValue("FileDescription", "WinRun4J Application Launcher", table.getString(0));
assertKeyValue("FileVersion", "0, 0, 2, 0", table.getString(1));
assertKeyValue("OriginalFilename", "WinRun4J.exe", table.getString(2));
assertKeyValue("ProductVersion", "0, 0, 2, 0", table.getString(3));

// check VarFileInfo structure
VarFileInfo varFileInfo = version.getVarFileInfo();
assertEquals("VarFileInfo", varFileInfo.getKey());

assertEquals(1, varFileInfo.getVars().size());
Var var1 = varFileInfo.getVars().get(0);
assertEquals("Translation", var1.getKey());
assertEquals(1, var1.getValues().size());
// code page 1200 is "utf-16"
assertEquals(1200, var1.getValues().get(0) >> 16);
// Microsoft language identifier 1033 is "English - United States"
assertEquals(1033, var1.getValues().get(0) & 0xFFFF);
}

private void assertKeyValue(String key, String value, StringPair actual) {
assertEquals(key, actual.getKey());
assertEquals(value, actual.getValue());
}

}

0 comments on commit 90f3a2c

Please sign in to comment.