diff --git a/README.md b/README.md index 1f65759a..192f0b57 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,8 @@ See https://ebourg.github.io/jsign for more information. * The APPX/MSIX bundles are now signed with the correct Authenticode UUID * The error message displayed when the password of a PKCS#12 keystore is missing has been fixed * The log4j configuration warning displayed when signing a MSI file has been fixed (contributed by Pascal Davoust) +* API changes: + * The PEFile class has been refactored to keep only the methods related to signing #### Version 6.0 (2024-01-17) diff --git a/jsign-core/src/main/java/net/jsign/pe/CertificateTableEntry.java b/jsign-core/src/main/java/net/jsign/pe/CertificateTableEntry.java index cedf1372..d47ac18d 100644 --- a/jsign-core/src/main/java/net/jsign/pe/CertificateTableEntry.java +++ b/jsign-core/src/main/java/net/jsign/pe/CertificateTableEntry.java @@ -32,7 +32,7 @@ * @author Emmanuel Bourg * @since 1.3 */ -public class CertificateTableEntry { +class CertificateTableEntry { private int size; private int revision; diff --git a/jsign-core/src/main/java/net/jsign/pe/CertificateType.java b/jsign-core/src/main/java/net/jsign/pe/CertificateType.java index fa5a294a..46fb72c5 100644 --- a/jsign-core/src/main/java/net/jsign/pe/CertificateType.java +++ b/jsign-core/src/main/java/net/jsign/pe/CertificateType.java @@ -22,7 +22,7 @@ * @author Emmanuel Bourg * @since 1.3 */ -public enum CertificateType { +enum CertificateType { /** X.509 Certificate (not supported) */ X509(0x0001), diff --git a/jsign-core/src/main/java/net/jsign/pe/DataDirectory.java b/jsign-core/src/main/java/net/jsign/pe/DataDirectory.java index 99eeca3a..9ec81fe1 100644 --- a/jsign-core/src/main/java/net/jsign/pe/DataDirectory.java +++ b/jsign-core/src/main/java/net/jsign/pe/DataDirectory.java @@ -26,7 +26,7 @@ * @author Emmanuel Bourg * @since 1.0 */ -public class DataDirectory { +class DataDirectory { private final PEFile peFile; private final int index; diff --git a/jsign-core/src/main/java/net/jsign/pe/DataDirectoryType.java b/jsign-core/src/main/java/net/jsign/pe/DataDirectoryType.java index 3b31c443..bf18e167 100644 --- a/jsign-core/src/main/java/net/jsign/pe/DataDirectoryType.java +++ b/jsign-core/src/main/java/net/jsign/pe/DataDirectoryType.java @@ -22,7 +22,7 @@ * @author Emmanuel Bourg * @since 1.0 */ -public enum DataDirectoryType { +enum DataDirectoryType { /** The export table */ EXPORT_TABLE, diff --git a/jsign-core/src/main/java/net/jsign/pe/MachineType.java b/jsign-core/src/main/java/net/jsign/pe/MachineType.java deleted file mode 100644 index 1ddfdd5e..00000000 --- a/jsign-core/src/main/java/net/jsign/pe/MachineType.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright 2012 Emmanuel Bourg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http:/**www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.jsign.pe; - -/** - * Target architecture of an executable file. - * - * @author Emmanuel Bourg - * @since 1.0 - */ -public enum MachineType { - - /** Executable assumed to be applicable to any machine type */ - UNKNOWN(0x0), - - /** Matsushita AM33 */ - AM33(0x1d3), - - /** x64 */ - AMD64(0x8664), - - /** ARM little endian */ - ARM(0x1c0), - - /** ARMv7 (or higher) Thumb mode only */ - ARMV7(0x1c4), - - /** ARMv8 in 64-bit mode */ - ARM64(0xaa64), - - /** EFI byte code */ - EBC(0xebc), - - /** Intel 386 or later processors and compatible processors */ - I386(0x14c), - - /** Intel Itanium processor family */ - IA64(0x200), - - /** Mitsubishi M32R little endian */ - M32R(0x9041), - - /** MIPS16 */ - MIPS16(0x266), - - /** MIPS with FPU */ - MIPSFPU(0x366), - - /** MIPS16 with FPU */ - MIPSFPU16(0x466), - - /** Power PC little endian */ - POWERPC(0x1f0), - - /** Power PC with floating point support */ - POWERPCFP(0x1f1), - - /** MIPS little endian */ - R4000(0x166), - - /** Hitachi SH3 */ - SH3(0x1a2), - - /** Hitachi SH3 DSP */ - SH3DSP(0x1a3), - - /** Hitachi SH4 */ - SH4(0x1a6), - - /** Hitachi SH5 */ - SH5(0x1a8), - - /** ARM or Thumb (interworking) */ - THUMB(0x1c2), - - /** MIPS little-endian WCE v2 */ - WCEMIPSV2(0x169); - - private final int value; - - MachineType(int value) { - this.value = value; - } - - static MachineType valueOf(int value) { - for (MachineType format : values()) { - if (format.value == value) { - return format; - } - } - - return null; - } -} diff --git a/jsign-core/src/main/java/net/jsign/pe/PEFile.java b/jsign-core/src/main/java/net/jsign/pe/PEFile.java index 1c57cc8a..6af8c9f2 100644 --- a/jsign-core/src/main/java/net/jsign/pe/PEFile.java +++ b/jsign-core/src/main/java/net/jsign/pe/PEFile.java @@ -18,8 +18,6 @@ import java.io.File; import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.SeekableByteChannel; @@ -27,7 +25,6 @@ import java.nio.file.StandardOpenOption; import java.security.MessageDigest; import java.util.ArrayList; -import java.util.Date; import java.util.List; import org.bouncycastle.asn1.ASN1Encodable; @@ -36,11 +33,8 @@ import org.bouncycastle.asn1.cms.Attribute; import org.bouncycastle.asn1.cms.AttributeTable; import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DigestInfo; -import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; -import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cms.CMSProcessable; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.SignerInformation; @@ -69,7 +63,6 @@ public class PEFile implements Signable { /** The position of the PE header in the file */ private final long peHeaderOffset; - private File file; final SeekableByteChannel channel; /** Reusable buffer for reading bytes, words, dwords and qwords from the file */ @@ -112,7 +105,6 @@ public static boolean isPEFile(File file) throws IOException { */ public PEFile(File file) throws IOException { this(Files.newByteChannel(file.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE)); - this.file = file; } /** @@ -179,11 +171,6 @@ private void read(long base, int offset, int length) { } } - synchronized int read(long base, int offset) { - read(base, offset, 1); - return valueBuffer.get(); - } - synchronized int readWord(long base, int offset) { read(base, offset, 2); return valueBuffer.getShort() & 0xFFFF; @@ -194,11 +181,6 @@ synchronized long readDWord(long base, int offset) { return valueBuffer.getInt() & 0xFFFFFFFFL; } - synchronized long readQWord(long base, int offset) { - read(base, offset, 8); - return valueBuffer.getLong(); - } - synchronized void write(long base, byte[] data) throws IOException { write(base, ByteBuffer.wrap(data)); } @@ -210,290 +192,16 @@ synchronized void write(long base, ByteBuffer data) throws IOException { } } - public MachineType getMachineType() { - return MachineType.valueOf(readWord(peHeaderOffset, 4)); - } - - /** - * The number of sections. This indicates the size of the section table, - * which immediately follows the headers. - * - * @return the number of sections - */ - public int getNumberOfSections() { - return readWord(peHeaderOffset, 6); - } - - /** - * The low 32 bits of the number of seconds since 00:00 January 1, 1970 - * (a C runtime time_t value), that indicates when the file was created. - * - * @return the PE file creation date - */ - public Date getTimeDateStamp() { - return new Date(1000 * readDWord(peHeaderOffset, 8)); - } - - /** - * The file offset of the COFF symbol table, or zero if no COFF symbol table - * is present. This value should be zero for an image because COFF debugging - * information is deprecated. - * - * @return the offset of the COFF symbol table - */ - public long getPointerToSymbolTable() { - return readDWord(peHeaderOffset, 12); - } - - /** - * The number of entries in the symbol table. This data can be used to - * locate the string table, which immediately follows the symbol table. - * This value should be zero for an image because COFF debugging - * information is deprecated. - * - * @return the number of entries in the symbol table - */ - public long getNumberOfSymbols() { - return readDWord(peHeaderOffset, 16); - } - - /** - * The size of the optional header, which is required for executable files - * but not for object files. This value should be zero for an object file. - * - * @return the size of the optional header - */ - public int getSizeOfOptionalHeader() { - return readWord(peHeaderOffset, 20); - } - - /** - * The flags that indicate the attributes of the file. - * - * @return the characteristics flag - */ - public int getCharacteristics() { - return readWord(peHeaderOffset, 22); - } - - public PEFormat getFormat() { + PEFormat getFormat() { return PEFormat.valueOf(readWord(peHeaderOffset, 24)); } - /** - * The linker major version number. - * - * @return the linker major version number - */ - public int getMajorLinkerVersion() { - return read(peHeaderOffset, 26); - } - - /** - * The linker minor version number. - * - * @return the linker minor version number - */ - public int getMinorLinkerVersion() { - return read(peHeaderOffset, 27); - } - - /** - * The size of the code (text) section, or the sum of all code sections - * if there are multiple sections. - * - * @return the size of the code (text) section - */ - public long getSizeOfCode() { - return readDWord(peHeaderOffset, 28); - } - - /** - * The size of the initialized data section, or the sum of all such - * sections if there are multiple data sections. - * - * @return the size of the initialized data section - */ - public long getSizeOfInitializedData() { - return readDWord(peHeaderOffset, 32); - } - - /** - * The size of the uninitialized data section (BSS), or the sum of all such - * sections if there are multiple BSS sections. - * - * @return the size of the uninitialized data section (BSS) - */ - public long getSizeOfUninitializedData() { - return readDWord(peHeaderOffset, 36); - } - - /** - * The address of the entry point relative to the image base when the - * executable file is loaded into memory. For program images, this is the - * starting address. For device drivers, this is the address of the - * initialization function. An entry point is optional for DLLs. When no - * entry point is present, this field must be zero. - * - * @return the address of the entry point - */ - public long getAddressOfEntryPoint() { - return readDWord(peHeaderOffset, 40); - } - - /** - * The address that is relative to the image base of the beginning-of-code - * section when it is loaded into memory. - * - * @return the code base address - */ - public long getBaseOfCode() { - return readDWord(peHeaderOffset, 44); - } - - /** - * The address that is relative to the image base of the beginning-of-data - * section when it is loaded into memory (PE32 only). - * - * @return the data base address - */ - public long getBaseOfData() { - if (PEFormat.PE32.equals(getFormat())) { - return readDWord(peHeaderOffset, 48); - } else { - return 0; - } - } - - /** - * The preferred address of the first byte of image when loaded into memory; - * must be a multiple of 64 K. The default for DLLs is 0x10000000. The default - * for Windows CE EXEs is 0x00010000. The default for Windows NT, Windows 2000, - * Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000. - * - * @return the image base address - */ - public long getImageBase() { - if (PEFormat.PE32.equals(getFormat())) { - return readDWord(peHeaderOffset, 52); - } else { - return readQWord(peHeaderOffset, 48); - } - } - - /** - * The alignment (in bytes) of sections when they are loaded into memory. - * It must be greater than or equal to FileAlignment. The default is the - * page size for the architecture. - * - * @return the size of the sections memory alignment (in bytes) - */ - public long getSectionAlignment() { - return readDWord(peHeaderOffset, 56); - } - - /** - * The alignment factor (in bytes) that is used to align the raw data of - * sections in the image file. The value should be a power of 2 between - * 512 and 64 K, inclusive. The default is 512. If the SectionAlignment - * is less than the architecture?s page size, then FileAlignment must - * match SectionAlignment. - * - * @return the alignment factor (in bytes) - */ - public long getFileAlignment() { - return readDWord(peHeaderOffset, 60); - } - - /** - * The major version number of the required operating system. - * - * @return the major version number of the required operating system - */ - public int getMajorOperatingSystemVersion() { - return readWord(peHeaderOffset, 64); - } - - /** - * The minor version number of the required operating system. - * - * @return the minor version number of the required operating system - */ - public int getMinorOperatingSystemVersion() { - return readWord(peHeaderOffset, 66); - } - - /** - * The major version number of the image. - * - * @return the major version number of the image - */ - public int getMajorImageVersion() { - return readWord(peHeaderOffset, 68); - } - - /** - * The minor version number of the image. - * - * @return the minor version number of the image - */ - public int getMinorImageVersion() { - return readWord(peHeaderOffset, 70); - } - - /** - * The major version number of the subsystem. - * - * @return the major version number of the subsystem - */ - public int getMajorSubsystemVersion() { - return readWord(peHeaderOffset, 72); - } - - /** - * The minor version number of the subsystem. - * - * @return the minor version number of the subsystem - */ - public int getMinorSubsystemVersion() { - return readWord(peHeaderOffset, 74); - } - - /** - * Reserved, must be zero. - * - * @return zero - */ - public long getWin32VersionValue() { - return readDWord(peHeaderOffset, 76); - } - - /** - * The size (in bytes) of the image, including all headers, as the image - * is loaded in memory. It must be a multiple of SectionAlignment. - * - * @return the size of the image (in bytes) - */ - public long getSizeOfImage() { - return readDWord(peHeaderOffset, 80); - } - - /** - * The combined size of an MS DOS stub, PE header, and section headers - * rounded up to a multiple of FileAlignment. - * - * @return the combined size of the headers - */ - public long getSizeOfHeaders() { - return readDWord(peHeaderOffset, 84); - } - /** * The image file checksum. * * @return the checksum of the image */ - public long getCheckSum() { + long getCheckSum() { return readDWord(peHeaderOffset, 88); } @@ -503,7 +211,7 @@ public long getCheckSum() { * * @return the checksum of the image */ - public synchronized long computeChecksum() { + synchronized long computeChecksum() { PEImageChecksum checksum = new PEImageChecksum(peHeaderOffset + 88); ByteBuffer b = ByteBuffer.allocate(64 * 1024); @@ -523,7 +231,7 @@ public synchronized long computeChecksum() { return checksum.getValue(); } - public synchronized void updateChecksum() { + synchronized void updateChecksum() { ByteBuffer buffer = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN); buffer.putInt((int) computeChecksum()); buffer.flip(); @@ -535,90 +243,13 @@ public synchronized void updateChecksum() { } } - /** - * The subsystem that is required to run this image. - * - * @return the required subsystem - */ - public Subsystem getSubsystem() { - return Subsystem.valueOf(readWord(peHeaderOffset, 92)); - } - - public int getDllCharacteristics() { - return readWord(peHeaderOffset, 94); - } - - /** - * The size of the stack to reserve. Only SizeOfStackCommit is committed; - * the rest is made available one page at a time until the reserve size is reached. - * - * @return the size of the stack to reserve - */ - public long getSizeOfStackReserve() { - if (PEFormat.PE32.equals(getFormat())) { - return readDWord(peHeaderOffset, 96); - } else { - return readQWord(peHeaderOffset, 96); - } - } - - /** - * The size of the stack to commit. - * - * @return the size of the stack to commit - */ - public long getSizeOfStackCommit() { - if (PEFormat.PE32.equals(getFormat())) { - return readDWord(peHeaderOffset, 100); - } else { - return readQWord(peHeaderOffset, 104); - } - } - - /** - * The size of the local heap space to reserve. Only SizeOfHeapCommit is - * committed; the rest is made available one page at a time until the - * reserve size is reached. - * - * @return the size of the local heap space to reserve - */ - public long getSizeOfHeapReserve() { - if (PEFormat.PE32.equals(getFormat())) { - return readDWord(peHeaderOffset, 104); - } else { - return readQWord(peHeaderOffset, 112); - } - } - - /** - * The size of the local heap space to commit. - * - * @return the size of the local heap space to commit - */ - public long getSizeOfHeapCommit() { - if (PEFormat.PE32.equals(getFormat())) { - return readDWord(peHeaderOffset, 108); - } else { - return readQWord(peHeaderOffset, 120); - } - } - - /** - * Reserved, must be zero. - * - * @return zero - */ - public long getLoaderFlags() { - return readDWord(peHeaderOffset, PEFormat.PE32.equals(getFormat()) ? 112 : 128); - } - /** * The number of data-directory entries in the remainder of the optional * header. Each describes a location and size. * * @return the number of data-directory entries */ - public int getNumberOfRvaAndSizes() { + int getNumberOfRvaAndSizes() { return (int) readDWord(peHeaderOffset, PEFormat.PE32.equals(getFormat()) ? 116 : 132); } @@ -632,7 +263,7 @@ int getDataDirectoryOffset() { * @param type the type of data directory * @return the data directory of the specified type */ - public DataDirectory getDataDirectory(DataDirectoryType type) { + DataDirectory getDataDirectory(DataDirectoryType type) { if (type.ordinal() >= getNumberOfRvaAndSizes()) { return null; } else { @@ -742,118 +373,6 @@ private synchronized List getCertificateTable() { return entries; } - public synchronized List
getSections() { - List
sections = new ArrayList<>(); - int sectionTableOffset = getDataDirectoryOffset() + 8 * getNumberOfRvaAndSizes(); - - for (int i = 0; i < getNumberOfSections(); i++) { - sections.add(new Section(this, sectionTableOffset + 40 * i)); - } - - return sections; - } - - /** - * Print detailed informations about the PE file. - * - * @param out the output stream where the info is printed - */ - public void printInfo(OutputStream out) { - printInfo(new PrintWriter(out, true)); - } - - /** - * Print detailed informations about the PE file. - * - * @param out the output writer where the info is printed - */ - public void printInfo(PrintWriter out) { - if (file != null) { - out.println("PE File"); - out.println(" Name: " + file.getName()); - out.println(" Size: " + file.length()); - out.println(" Last Modified: " + new Date(file.lastModified())); - out.println(); - } - - out.println("PE Header"); - out.println(" Machine: " + getMachineType()); - out.println(" Number of sections: " + getNumberOfSections()); - out.println(" Timestamp: " + getTimeDateStamp()); - out.println(" Pointer to symbol table: 0x" + Long.toHexString(getPointerToSymbolTable())); - out.println(" Number of symbols: " + getNumberOfSymbols()); - out.println(" Size of optional header: " + getSizeOfOptionalHeader()); - out.println(" Characteristics: 0x" + Long.toBinaryString(getCharacteristics())); - out.println(); - - out.println("Optional Header"); - PEFormat format = getFormat(); - out.println(" PE Format: 0x" + Integer.toHexString(format.value) + " (" + format.label + ")"); - out.println(" Linker version: " + getMajorLinkerVersion() + "." + getMinorLinkerVersion()); - out.println(" Size of code: " + getSizeOfCode()); - out.println(" Size of initialized data: " + getSizeOfInitializedData()); - out.println(" Size of uninitialized data: " + getSizeOfUninitializedData()); - out.println(" Address of entry point: 0x" + Long.toHexString(getAddressOfEntryPoint())); - out.println(" Base of code: 0x" + Long.toHexString(getBaseOfCode())); - if (PEFormat.PE32.equals(getFormat())) { - out.println(" Base of data: 0x" + Long.toHexString(getBaseOfData())); - } - out.println(" Image base: 0x" + Long.toHexString(getImageBase())); - out.println(" Section alignment: " + getSectionAlignment()); - out.println(" File alignment: " + getFileAlignment()); - out.println(" Operating system version: " + getMajorOperatingSystemVersion() + "." + getMinorOperatingSystemVersion()); - out.println(" Image version: " + getMajorImageVersion() + "." + getMinorImageVersion()); - out.println(" Subsystem version: " + getMajorSubsystemVersion() + "." + getMinorSubsystemVersion()); - out.println(" Size of image: " + getSizeOfImage()); - out.println(" Size of headers: " + getSizeOfHeaders()); - out.println(" Checksum: 0x" + Long.toHexString(getCheckSum())); - out.println(" Checksum (computed): 0x" + Long.toHexString(computeChecksum())); - out.println(" Subsystem: " + getSubsystem()); - out.println(" DLL characteristics: 0x" + Long.toBinaryString(getDllCharacteristics())); - out.println(" Size of stack reserve: " + getSizeOfStackReserve()); - out.println(" Size of stack commit: " + getSizeOfStackCommit()); - out.println(" Size of heap reserve: " + getSizeOfHeapReserve()); - out.println(" Size of heap commit: " + getSizeOfHeapCommit()); - out.println(" Number of RVA and sizes: " + getNumberOfRvaAndSizes()); - out.println(); - - out.println("Data Directory"); - for (DataDirectoryType type : DataDirectoryType.values()) { - DataDirectory entry = getDataDirectory(type); - if (entry != null && entry.exists()) { - out.printf(" %-30s 0x%08x %8d bytes%n", type, entry.getVirtualAddress(), entry.getSize()); - } - } - out.println(); - - out.println("Sections"); - out.println(" Name Virtual Size Virtual Address Raw Data Size Raw Data Ptr Characteristics"); - List
sections = getSections(); - for (int i = 0; i < sections.size(); i++) { - Section section = sections.get(i); - out.printf(" #%d %-8s %8d 0x%08x %8d 0x%08x %s%n", i + 1, section.getName(), section.getVirtualSize(), section.getVirtualAddress(), section.getSizeOfRawData(), section.getPointerToRawData(), section.getCharacteristics()); - } - out.println(); - - List signatures = getSignatures(); - if (!signatures.isEmpty()) { - out.println("Signatures"); - for (CMSSignedData signedData : signatures) { - SignerInformation signerInformation = signedData.getSignerInfos().getSigners().iterator().next(); - X509CertificateHolder certificate = (X509CertificateHolder) signedData.getCertificates().getMatches(signerInformation.getSID()).iterator().next(); - - String commonName = certificate.getSubject().getRDNs(X509ObjectIdentifiers.commonName)[0].getFirst().getValue().toString(); - - AttributeTable unsignedAttributes = signerInformation.getUnsignedAttributes(); - boolean timestamped = unsignedAttributes != null && - (unsignedAttributes.get(PKCSObjectIdentifiers.pkcs_9_at_counterSignature) != null - || unsignedAttributes.get(AuthenticodeObjectIdentifiers.SPC_RFC3161_OBJID) != null); - DigestAlgorithm algorithm = DigestAlgorithm.of(signerInformation.getDigestAlgorithmID().getAlgorithm()); - out.println(" " + commonName + " " + (algorithm != null ? "[" + algorithm.id + "] " : "") + (timestamped ? "(timestamped)" : "")); - } - } - } - /** * Compute the digest of the file. The checksum field, the certificate * directory table entry and the certificate table are excluded from @@ -884,8 +403,6 @@ public synchronized byte[] computeDigest(DigestAlgorithm digestAlgorithm) throws // skip the certificate entry position = certificateTableOffset + 8; - // todo digest the sections in ascending address order - // digest from the end of the certificate table entry to the beginning of the certificate table if (certificateTable != null && certificateTable.exists()) { certificateTable.check(); @@ -913,15 +430,4 @@ public ASN1Object createIndirectData(DigestAlgorithm digestAlgorithm) throws IOE return new SpcIndirectDataContent(data, digestInfo); } - - /** - * Increase the size of the file up to a size that is a multiple of the specified value. - * - * @param multiple the size of the byte alignment - * @throws IOException if an I/O error occurs - */ - public synchronized void pad(int multiple) throws IOException { - long padding = (multiple - channel.size() % multiple) % multiple; - write(channel.size(), ByteBuffer.allocate((int) padding)); - } } diff --git a/jsign-core/src/main/java/net/jsign/pe/PEFormat.java b/jsign-core/src/main/java/net/jsign/pe/PEFormat.java index a8a50aa9..8910de53 100644 --- a/jsign-core/src/main/java/net/jsign/pe/PEFormat.java +++ b/jsign-core/src/main/java/net/jsign/pe/PEFormat.java @@ -22,7 +22,7 @@ * @author Emmanuel Bourg * @since 1.0 */ -public enum PEFormat { +enum PEFormat { PE32(0x10b, "PE32"), PE32plus(0x20b, "PE32+"), diff --git a/jsign-core/src/main/java/net/jsign/pe/Section.java b/jsign-core/src/main/java/net/jsign/pe/Section.java deleted file mode 100644 index 76f003f3..00000000 --- a/jsign-core/src/main/java/net/jsign/pe/Section.java +++ /dev/null @@ -1,162 +0,0 @@ -/** - * Copyright 2012 Emmanuel Bourg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.jsign.pe; - -import java.nio.charset.StandardCharsets; -import java.util.List; - -/** - * Section of an executable file. - * - * @author Emmanuel Bourg - * @since 1.0 - */ -public class Section { - - private final PEFile peFile; - private final int baseOffset; - - Section(PEFile peFile, int baseOffset) { - this.peFile = peFile; - this.baseOffset = baseOffset; - } - - /** - * An 8-byte, null-padded UTF-8 encoded string. If the string is exactly - * 8 characters long, there is no terminating null. For longer names, this - * field contains a slash (/) that is followed by an ASCII representation - * of a decimal number that is an offset into the string table. Executable - * images do not use a string table and do not support section names longer - * than 8 characters. Long names in object files are truncated if they are - * emitted to an executable file. - * - * @return the name of the section - */ - public String getName() { - byte[] buffer = new byte[8]; - peFile.read(buffer, baseOffset, 0); - String name = new String(buffer, StandardCharsets.UTF_8); - if (name.indexOf(0) != -1) { - name = name.substring(0, name.indexOf(0)); - } - - return name; - } - - /** - * The total size of the section when loaded into memory. If this value is - * greater than SizeOfRawData, the section is zero-padded. This field is - * valid only for executable images and should be set to zero for object files. - * - * @return the virtual size - */ - public long getVirtualSize() { - return peFile.readDWord(baseOffset, 8); - } - - /** - * For executable images, the address of the first byte of the section - * relative to the image base when the section is loaded into memory. - * For object files, this field is the address of the first byte before - * relocation is applied; for simplicity, compilers should set this to zero. - * Otherwise, it is an arbitrary value that is subtracted from offsets - * during relocation. - * - * @return the section address relative to the image base address - */ - public long getVirtualAddress() { - return peFile.readDWord(baseOffset, 12); - } - - /** - * The size of the section (for object files) or the size of the initialized - * data on disk (for image files). For executable images, this must be a - * multiple of FileAlignment from the optional header. If this is less than - * VirtualSize, the remainder of the section is zero-filled. Because the - * SizeOfRawData field is rounded but the VirtualSize field is not, it is - * possible for SizeOfRawData to be greater than VirtualSize as well. When - * a section contains only uninitialized data, this field should be zero. - * - * @return the size of the section - */ - public long getSizeOfRawData() { - return peFile.readDWord(baseOffset, 16); - } - - /** - * The file pointer to the first page of the section within the COFF file. - * For executable images, this must be a multiple of FileAlignment from the - * optional header. For object files, the value should be aligned on a 4 byte - * boundary for best performance. When a section contains only uninitialized - * data, this field should be zero. - * - * @return the file pointer to the first page - */ - public long getPointerToRawData() { - return peFile.readDWord(baseOffset, 20); - } - - /** - * The file pointer to the beginning of relocation entries for the section. - * This is set to zero for executable images or if there are no relocations. - * - * @return the file pointer to the beginning of relocation entries - */ - public long getPointerToRelocations() { - return peFile.readDWord(baseOffset, 24); - } - - /** - * The file pointer to the beginning of line-number entries for the section. - * This is set to zero if there are no COFF line numbers. This value should - * be zero for an image because COFF debugging information is deprecated. - * - * @return the file pointer to the beginning of line-number entries - */ - public long getPointerToLineNumbers() { - return peFile.readDWord(baseOffset, 28); - } - - /** - * The number of relocation entries for the section. This is set to zero - * for executable images. - * - * @return the number of relocation entries - */ - public int getNumberOfRelocations() { - return peFile.readWord(baseOffset, 32); - } - - /** - * The number of line-number entries for the section. This value should - * be zero for an image because COFF debugging information is deprecated. - * - * @return the number of line-number entries - */ - public int getNumberOfLineNumbers() { - return peFile.readWord(baseOffset, 34); - } - - /** - * The flags that describe the characteristics of the section. - * - * @return the characteristics flags - */ - public List getCharacteristics() { - return SectionFlag.getFlags((int) peFile.readDWord(baseOffset, 36)); - } -} diff --git a/jsign-core/src/main/java/net/jsign/pe/SectionFlag.java b/jsign-core/src/main/java/net/jsign/pe/SectionFlag.java deleted file mode 100644 index 7cbd54a0..00000000 --- a/jsign-core/src/main/java/net/jsign/pe/SectionFlag.java +++ /dev/null @@ -1,152 +0,0 @@ -/** - * Copyright 2012 Emmanuel Bourg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http:/**www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.jsign.pe; - -import java.util.ArrayList; -import java.util.List; - -/** - * Characteristics of the section of an executable file. - * - * @author Emmanuel Bourg - * @since 1.0 - */ -public enum SectionFlag { - - /** The section should not be padded to the next boundary. This flag is obsolete and is replaced by ALIGN_1BYTES. This is valid only for object files.. */ - TYPE_NO_PAD (0x00000008), - - /** The section contains executable code. */ - CODE (0x00000020), - - /** The section contains initialized data. */ - INITIALIZED_DATA (0x00000040), - - /** The section contains uninitialized data. */ - UNINITIALIZED_DATA (0x00000080), - - /** Reserved for future use. */ - LNK_OTHER (0x00000100), - - /** The section contains comments or other information. The .drectve section has this type. This is valid for object files only. */ - LNK_INFO (0x00000200), - - /** The section will not become part of the image. This is valid only for object files. */ - LNK_REMOVE (0x00000800), - - /** The section contains COMDAT data. This is valid only for object files. */ - LNK_COMDAT (0x00001000), - - /** The section contains data referenced through the global pointer (GP). */ - GPREL (0x00008000), - - /** Reserved for future use. */ - MEM_PURGEABLE (0x00020000), - - /** For ARM machine types, the section contains Thumb code. Reserved for future use with other machine types. */ - MEM_16BIT (0x00020000), - - /** Reserved for future use. */ - MEM_LOCKED (0x00040000), - - /** Reserved for future use. */ - MEM_PRELOAD (0x00080000), - - /** Align data on a 1-byte boundary. Valid only for object files. */ - ALIGN_1BYTES (0x00100000), - - /** Align data on a 2-byte boundary. Valid only for object files. */ - ALIGN_2BYTES (0x00200000), - - /** Align data on a 4-byte boundary. Valid only for object files. */ - ALIGN_4BYTES (0x00300000), - - /** Align data on an 8-byte boundary. Valid only for object files. */ - ALIGN_8BYTES (0x00400000), - - /** Align data on a 16-byte boundary. Valid only for object files. */ - ALIGN_16BYTES (0x00500000), - - /** Align data on a 32-byte boundary. Valid only for object files. */ - ALIGN_32BYTES (0x00600000), - - /** Align data on a 64-byte boundary. Valid only for object files. */ - ALIGN_64BYTES (0x00700000), - - /** Align data on a 128-byte boundary. Valid only for object files. */ - ALIGN_128BYTES (0x00800000), - - /** Align data on a 256-byte boundary. Valid only for object files. */ - ALIGN_256BYTES (0x00900000), - - /** Align data on a 512-byte boundary. Valid only for object files. */ - ALIGN_512BYTES (0x00A00000), - - /** Align data on a 1024-byte boundary. Valid only for object files. */ - ALIGN_1024BYTES (0x00B00000), - - /** Align data on a 2048-byte boundary. Valid only for object files. */ - ALIGN_2048BYTES (0x00C00000), - - /** Align data on a 4096-byte boundary. Valid only for object files. */ - ALIGN_4096BYTES (0x00D00000), - - /** Align data on an 8192-byte boundary. Valid only for object files. */ - ALIGN_8192BYTES (0x00E00000), - - /** The section contains extended relocations. */ - LNK_NRELOC_OVFL (0x01000000), - - /** The section can be discarded as needed. */ - MEM_DISCARDABLE (0x02000000), - - /** The section cannot be cached. */ - MEM_NOT_CACHED (0x04000000), - - /** The section is not pageable. */ - MEM_NOT_PAGED (0x08000000), - - /** The section can be shared in memory. */ - MEM_SHARED (0x10000000), - - /** The section can be executed as code. */ - EXECUTE (0x20000000), - - /** The section can be read. */ - READ (0x40000000), - - /** The section can be written to. */ - WRITE (0x80000000); - - private final int mask; - - SectionFlag(int mask) { - this.mask = mask; - } - - static List getFlags(int flags) { - List result = new ArrayList<>(); - - for (SectionFlag flag : values()) { - if ((flag.mask & flags) != 0) { - result.add(flag); - } - } - - return result; - } -} diff --git a/jsign-core/src/main/java/net/jsign/pe/Subsystem.java b/jsign-core/src/main/java/net/jsign/pe/Subsystem.java deleted file mode 100644 index 890ba82b..00000000 --- a/jsign-core/src/main/java/net/jsign/pe/Subsystem.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright 2012 Emmanuel Bourg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http:/**www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.jsign.pe; - -/** - * The subsystem of an executable file. - * - * @author Emmanuel Bourg - * @since 1.0 - */ -public enum Subsystem { - - /** An unknown subsystem */ - UNKNOWN(0), - /** Device drivers and native Windows processes */ - NATIVE(1), - /** The Windows graphical user interface (GUI) subsystem */ - WINDOWS_GUI(2), - /** The Windows character subsystem */ - WINDOWS_CUI(3), - /** The Posix character subsystem */ - POSIX_CUI(7), - /** Windows CE */ - WINDOWS_CE_GUI(9), - /** An Extensible Firmware Interface (EFI) application */ - EFI_APPLICATION(10), - /** An EFI driver with boot services */ - EFI_BOOT_SERVICE_DRIVER(11), - /** An EFI driver with run-time services */ - EFI_RUNTIME_DRIVER(12), - /** An EFI ROM image */ - EFI_ROM(13), - /** XBOX */ - XBOX(14); - - final int value; - - Subsystem(int value) { - this.value = value; - } - - static Subsystem valueOf(int value) { - for (Subsystem format : values()) { - if (format.value == value) { - return format; - } - } - - return null; - } -} diff --git a/jsign-core/src/test/java/net/jsign/PESignerTest.java b/jsign-core/src/test/java/net/jsign/PESignerTest.java index a30c71c9..e543b459 100644 --- a/jsign-core/src/test/java/net/jsign/PESignerTest.java +++ b/jsign-core/src/test/java/net/jsign/PESignerTest.java @@ -84,8 +84,6 @@ public void testSign() throws Exception { assertNotNull(signature); assertNull(signature.getSignerInfos().iterator().next().getSignedAttributes().get(CMSAttributes.signingTime)); - - peFile.printInfo(System.out); } } @@ -226,8 +224,6 @@ public void testTimestamp(TimestampingMode mode, DigestAlgorithm alg) throws Exc SignatureAssert.assertSigned(peFile, alg); SignatureAssert.assertTimestamped("Invalid timestamp", peFile.getSignatures().get(0)); - - peFile.printInfo(System.out); } } diff --git a/jsign-core/src/test/java/net/jsign/pe/MachineTypeTest.java b/jsign-core/src/test/java/net/jsign/pe/MachineTypeTest.java deleted file mode 100644 index df42270d..00000000 --- a/jsign-core/src/test/java/net/jsign/pe/MachineTypeTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright 2016 Emmanuel Bourg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.jsign.pe; - -import org.junit.Test; - -import static org.junit.Assert.*; - -public class MachineTypeTest { - - @Test - public void testValueOf() { - assertEquals(MachineType.ARM64, MachineType.valueOf(0xaa64)); - assertNull(MachineType.valueOf(0xbb8)); - } -} diff --git a/jsign-core/src/test/java/net/jsign/pe/PEFileTest.java b/jsign-core/src/test/java/net/jsign/pe/PEFileTest.java index 0223aeae..43acef9c 100644 --- a/jsign-core/src/test/java/net/jsign/pe/PEFileTest.java +++ b/jsign-core/src/test/java/net/jsign/pe/PEFileTest.java @@ -16,14 +16,12 @@ package net.jsign.pe; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.KeyStore; -import java.util.List; import org.apache.commons.io.FileUtils; import org.bouncycastle.util.encoders.Hex; @@ -49,27 +47,7 @@ public void testIsMSCabinetFile() throws Exception { @Test public void testLoad() throws Exception { try (PEFile file = new PEFile(new File("target/test-classes/wineyes.exe"))) { - assertEquals(MachineType.I386, file.getMachineType()); - assertEquals(4, file.getNumberOfSections()); - assertEquals(0, file.getPointerToSymbolTable()); - assertEquals(0, file.getNumberOfSymbols()); - assertEquals(224, file.getSizeOfOptionalHeader()); assertEquals(PEFormat.PE32, file.getFormat()); - assertEquals(24576, file.getSizeOfCode()); - assertEquals(20480, file.getSizeOfInitializedData()); - assertEquals(0, file.getSizeOfUninitializedData()); - assertEquals(0x400000, file.getImageBase()); - assertEquals(4096, file.getSectionAlignment()); - assertEquals(4096, file.getFileAlignment()); - assertEquals(4, file.getMajorOperatingSystemVersion()); - assertEquals(0, file.getMinorOperatingSystemVersion()); - assertEquals(4, file.getMajorSubsystemVersion()); - assertEquals(0, file.getMinorSubsystemVersion()); - assertEquals(0, file.getWin32VersionValue()); - assertEquals(49152, file.getSizeOfImage()); - assertEquals(4096, file.getSizeOfHeaders()); - assertEquals(Subsystem.WINDOWS_GUI, file.getSubsystem()); - assertEquals(0, file.getLoaderFlags()); assertEquals(16, file.getNumberOfRvaAndSizes()); } } @@ -99,62 +77,6 @@ public void testDosExecutable() throws Exception { } } - @Test - public void testGetSections() throws Exception { - try (PEFile file = new PEFile(new File("target/test-classes/wineyes.exe"))) { - List
sections = file.getSections(); - assertNotNull(sections); - assertFalse("No section found", sections.isEmpty()); - for (Section section : file.getSections()) { - assertNotNull("null section found", section); - assertEquals(0, section.getPointerToRelocations()); - assertEquals(0, section.getPointerToLineNumbers()); - assertEquals(0, section.getNumberOfRelocations()); - assertEquals(0, section.getNumberOfLineNumbers()); - } - } - } - - @Test - public void testPrintInfo() throws Exception { - ByteArrayOutputStream out; - try (PEFile file = new PEFile(new File("target/test-classes/wineyes.exe"))) { - out = new ByteArrayOutputStream(); - file.printInfo(out); - } - - assertNotNull(out.toString()); - assertFalse(out.toString().isEmpty()); - - System.out.println(out); - } - - @Test - public void testPadNoOp() throws Exception { - File testFile = new File("target/test-classes/wineyes.exe"); - File testFilePadded = new File("target/test-classes/wineyes-padded.exe"); - FileUtils.copyFile(testFile, testFilePadded); - - PEFile file = new PEFile(testFilePadded); - file.pad(8); - file.close(); - - assertEquals("Padded file size", testFile.length(), testFilePadded.length()); - } - - @Test - public void testPad() throws Exception { - File testFile = new File("target/test-classes/wineyes.exe"); - File testFilePadded = new File("target/test-classes/wineyes-padded.exe"); - FileUtils.copyFile(testFile, testFilePadded); - - PEFile file = new PEFile(testFilePadded); - file.pad(7); - file.close(); - - assertEquals("Padded file size", testFile.length() + 4, testFilePadded.length()); - } - @Test public void testComputeChecksum() throws Exception { try (PEFile file = new PEFile(new File("target/test-classes/wineyes.exe"))) { diff --git a/jsign-core/src/test/java/net/jsign/pe/SubsystemTest.java b/jsign-core/src/test/java/net/jsign/pe/SubsystemTest.java deleted file mode 100644 index 7c193d6f..00000000 --- a/jsign-core/src/test/java/net/jsign/pe/SubsystemTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright 2016 Emmanuel Bourg - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.jsign.pe; - -import org.junit.Test; - -import static org.junit.Assert.*; - -public class SubsystemTest { - - @Test - public void testValueOf() { - assertEquals(Subsystem.XBOX, Subsystem.valueOf(14)); - assertNull(Subsystem.valueOf(0xcafe)); - } -}