diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliBlobCustomAttrib.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliBlobCustomAttrib.java index 7f8d5d7a04..5d621c5f83 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliBlobCustomAttrib.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliBlobCustomAttrib.java @@ -52,6 +52,15 @@ public class CliBlobCustomAttrib extends CliBlob { private static final int CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_128 = 0x80; private static final int CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_192 = 0xC0; + private static final int CLIBLOBCUSTOMATTRIB_STRING_SIZE_ONE = 0x01; + private static final int CLIBLOBCUSTOMATTRIB_STRING_SIZE_TWO = 0x02; + private static final int CLIBLOBCUSTOMATTRIB_STRING_SIZE_TWO_BITMASK = 0x7F; + private static final int CLIBLOBCUSTOMATTRIB_STRING_SIZE_FOUR = 0x03; + private static final int CLIBLOBCUSTOMATTRIB_STRING_SIZE_FOUR_BITMASK = 0x3F; + + private static final int CLIBLOBCUSTOMATTRIB_STRING_SIZE_SHIFT = 0x06; + private static final int CLIBLOBCUSTOMATTRIB_STRING_SIZE_BITMASK = 0x03; + // UTF-8 boundaries that help detect the end of a string where // lengths aren't specified in FixedArg private static final int CLIBLOBCUSTOMATTRIB_UTF8_LOW = 0x1F; @@ -289,7 +298,8 @@ public class CliBlobCustomAttrib extends CliBlob { // based on the length of the string. This measures and decodes the Byte, Word, // or DWord length field and returns it. private int readSerStringLength(BinaryReader reader) throws IOException { - byte[] length; + byte[] lengthBytes; + int length = 0; ByteBuffer buf; // The first byte is either the size or an indicator that we have more @@ -297,50 +307,47 @@ public class CliBlobCustomAttrib extends CliBlob { // big-endian. byte firstByte = reader.readNextByte(); - if (firstByte < CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_128) { + // Shift the highest two bits to the bottom and mask off to detect the + // size of the field holding the size of the string (1, 2, or 4 bytes) + byte stringSizeIndicator = (byte) (firstByte >> CLIBLOBCUSTOMATTRIB_STRING_SIZE_SHIFT & + CLIBLOBCUSTOMATTRIB_STRING_SIZE_BITMASK); + + if (stringSizeIndicator <= CLIBLOBCUSTOMATTRIB_STRING_SIZE_ONE) { // A size less than 128 indicates this is the only size byte - return firstByte; + length = firstByte; } - else if (firstByte < CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_192) { + else if (stringSizeIndicator == CLIBLOBCUSTOMATTRIB_STRING_SIZE_TWO) { // A value in the first byte in range [128 - 191] indicates the size // is stored as a Word and the value in the highest bit must be unset - length = new byte[] { firstByte, reader.readNextByte() }; + lengthBytes = new byte[] { firstByte, reader.readNextByte() }; - // Unset the highest bit if it's set - if ((length[1] & - CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_128) == CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_128) { - length[1] ^= CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_128; - } + // Unset what will become the highest bit if it's set + lengthBytes[1] = (byte) (lengthBytes[1] & CLIBLOBCUSTOMATTRIB_STRING_SIZE_TWO_BITMASK); // Convert from big-endian - buf = ByteBuffer.wrap(length); + buf = ByteBuffer.wrap(lengthBytes); buf.order(ByteOrder.BIG_ENDIAN); - return buf.getShort(); + length = buf.getShort(); } - else { + else if (stringSizeIndicator == CLIBLOBCUSTOMATTRIB_STRING_SIZE_FOUR) { // A value in the first byte > 128 indicates the size is stored as // a DWord and the first two bits must be unset - length = new byte[4]; - length[0] = firstByte; - length[1] = reader.readNextByte(); - length[2] = reader.readNextByte(); - length[3] = reader.readNextByte(); + lengthBytes = new byte[Integer.BYTES]; + lengthBytes[0] = firstByte; + lengthBytes[1] = reader.readNextByte(); + lengthBytes[2] = reader.readNextByte(); + lengthBytes[3] = reader.readNextByte(); // Unset what will become the highest two bits if they're set - if ((length[3] & - CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_128) == CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_128) { - length[3] ^= CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_128; - } - if ((length[3] & - CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_64) == CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_64) { - length[3] ^= CLIBLOBCUSTOMATTRIB_STRING_BOUNDARY_64; - } + lengthBytes[3] = (byte) (lengthBytes[3] & CLIBLOBCUSTOMATTRIB_STRING_SIZE_FOUR_BITMASK); // Convert from big-endian - buf = ByteBuffer.wrap(length); + buf = ByteBuffer.wrap(lengthBytes); buf.order(ByteOrder.BIG_ENDIAN); - return buf.getInt(); + length = buf.getInt(); } + + return length; } private ArrayList processFixedArgs(BinaryReader reader, CliParam[] params) @@ -361,8 +368,10 @@ public class CliBlobCustomAttrib extends CliBlob { // end of the name StringBuilder sb = new StringBuilder(); - while ((reader.peekNextByte() > CLIBLOBCUSTOMATTRIB_UTF8_LOW) && - (reader.peekNextByte() < CLIBLOBCUSTOMATTRIB_UTF8_HIGH)) { + while (((reader.peekNextByte() & + CLIBLOBCUSTOMATTRIB_UTF8_HIGH) > CLIBLOBCUSTOMATTRIB_UTF8_LOW) && + ((reader.peekNextByte() & + CLIBLOBCUSTOMATTRIB_UTF8_HIGH) < CLIBLOBCUSTOMATTRIB_UTF8_HIGH)) { sb.append((char) reader.readNextByte()); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/streams/CliStreamBlob.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/streams/CliStreamBlob.java index a5f065511a..d658fa8d1e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/streams/CliStreamBlob.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/streams/CliStreamBlob.java @@ -4,9 +4,9 @@ * 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. @@ -16,12 +16,11 @@ package ghidra.app.util.bin.format.pe.cli.streams; import java.io.IOException; -import java.util.*; +import java.util.LinkedHashMap; +import java.util.Map; import ghidra.app.util.bin.BinaryReader; -import ghidra.app.util.bin.format.pe.PeUtils; import ghidra.app.util.bin.format.pe.cli.CliStreamHeader; -import ghidra.app.util.bin.format.pe.cli.blobs.CliAbstractSig.CliCustomAttrib; import ghidra.app.util.bin.format.pe.cli.blobs.CliBlob; import ghidra.program.model.address.Address; import ghidra.program.model.data.*; @@ -41,7 +40,7 @@ public class CliStreamBlob extends CliAbstractStream { /** * Gets the name of this stream. - * + * * @return The name of this stream. */ public static String getName() { @@ -50,9 +49,9 @@ public class CliStreamBlob extends CliAbstractStream { /** * Creates a new Blob stream. - * + * * @param header The stream header associated with this stream. - * @param offset The reader offset where this stream starts. + * @param offset The reader offset where this stream starts. * @param rva The relative virtual address where this stream starts. * @param reader A reader that is used to read the stream. * @throws IOException if there is a problem reading the stream. @@ -85,7 +84,7 @@ public class CliStreamBlob extends CliAbstractStream { /** * Gets the blob at the given index. - * + * * @param index The index of the blob to get. * @return The blob at the given index. Could be null if the index was invalid or * there was a problem reading the blob. @@ -96,7 +95,7 @@ public class CliStreamBlob extends CliAbstractStream { /** * Updates the blob at the given address with the new blob. - * + * * @param updatedBlob The updated blob. * @param addr The address of the blob to update. * @param program The program that will get the update. @@ -114,25 +113,28 @@ public class CliStreamBlob extends CliAbstractStream { // Make sure there is an old blob at the given address int structureOffset = (int) addr.subtract(containingData.getAddress()); - DataTypeComponent oldBlobDataComponent = containingStructure.getComponentAt(structureOffset); + DataTypeComponent oldBlobDataComponent = + containingStructure.getComponentAt(structureOffset); if (oldBlobDataComponent == null) { Msg.error(this, "Existing blob at address " + addr + " was not found."); return false; } - + // Make sure the old blob has the same size as the new blob DataType oldBlobDataType = oldBlobDataComponent.getDataType(); DataType newBlobDataType = updatedBlob.toDataType(); if (oldBlobDataType.getLength() != newBlobDataType.getLength()) { - Msg.error(this, "Cannot replace existing " + updatedBlob.getName() + " at address " + addr + " with " + - updatedBlob.getName() + " because they have different sizes (old: " + oldBlobDataType.getLength() + ", new: " + newBlobDataType.getLength() + ")."); + Msg.error(this, + "Cannot replace existing " + updatedBlob.getName() + " at address " + addr + + " with " + updatedBlob.getName() + " because they have different sizes (old: " + + oldBlobDataType.getLength() + ", new: " + newBlobDataType.getLength() + ")."); return false; } // Update the blob containingStructure.replaceAtOffset(structureOffset, newBlobDataType, updatedBlob.getSize(), updatedBlob.getName(), updatedBlob.getContentsComment()); - + return true; } @@ -149,4 +151,3 @@ public class CliStreamBlob extends CliAbstractStream { return struct; } } -