mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-07-30 07:18:37 -09:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
@@ -18,12 +18,13 @@ public final class GFileUtilityMethods {
|
||||
public final static File writeTemporaryFile( InputStream inputStream, int maxBytesToWrite ) throws IOException {
|
||||
File tempOutputFile = File.createTempFile( GHIDRA_FILE_SYSTEM_PREFIX, GHIDRA_FILE_SYSTEM_SUFFIX );
|
||||
tempOutputFile.deleteOnExit();
|
||||
OutputStream outputStream = new FileOutputStream( tempOutputFile );
|
||||
try {
|
||||
|
||||
try (OutputStream outputStream = new FileOutputStream(tempOutputFile)) {
|
||||
int nWritten = 0;
|
||||
byte [] buffer = new byte[ 8192 ];
|
||||
byte[] buffer = new byte[8192];
|
||||
while ( true ) {
|
||||
int nRead = inputStream.read( buffer );
|
||||
int limit = Math.min(maxBytesToWrite - nWritten, buffer.length);
|
||||
int nRead = inputStream.read(buffer, 0, limit);
|
||||
if ( nRead == -1 ) {
|
||||
break;
|
||||
}
|
||||
@@ -34,13 +35,10 @@ public final class GFileUtilityMethods {
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
outputStream.close();
|
||||
}
|
||||
return tempOutputFile;
|
||||
}
|
||||
|
||||
public final static File writeTemporaryFile( byte [] bytes, String prefix ) throws IOException {
|
||||
public final static File writeTemporaryFile(byte[] bytes, String prefix) throws IOException {
|
||||
if ( prefix == null ) {
|
||||
prefix = GHIDRA_FILE_SYSTEM_PREFIX;
|
||||
}
|
||||
@@ -51,13 +49,11 @@ public final class GFileUtilityMethods {
|
||||
}
|
||||
File tempFile = File.createTempFile( prefix , GHIDRA_FILE_SYSTEM_SUFFIX );
|
||||
tempFile.deleteOnExit();
|
||||
OutputStream tempFileOut = new FileOutputStream( tempFile );
|
||||
try {
|
||||
|
||||
try (OutputStream tempFileOut = new FileOutputStream(tempFile)) {
|
||||
tempFileOut.write( bytes );
|
||||
}
|
||||
finally {
|
||||
tempFileOut.close();
|
||||
}
|
||||
|
||||
return tempFile;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package mobiledevices.dmg.reader;
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import org.catacombae.dmgextractor.encodings.encrypted.ReadableCEncryptedEncodingStream;
|
||||
import org.catacombae.hfsexplorer.FileSystemRecognizer;
|
||||
@@ -27,7 +28,6 @@ import mobiledevices.dmg.decmpfs.DecmpfsCompressionTypes;
|
||||
import mobiledevices.dmg.decmpfs.DecmpfsHeader;
|
||||
import mobiledevices.dmg.ghidra.*;
|
||||
import mobiledevices.dmg.hfsplus.AttributesFileParser;
|
||||
import mobiledevices.dmg.zlib.ZLIB;
|
||||
|
||||
public class DmgFileReader implements Closeable {
|
||||
private final static GDataConverter ledc = new GDataConverterLE();
|
||||
@@ -191,24 +191,16 @@ public class DmgFileReader implements Closeable {
|
||||
if ( decmpfsHeader.getCompressionType() == DecmpfsCompressionTypes.CMP_Type3 ) {
|
||||
|
||||
if ( decmpfsHeader.getAttrBytes()[ 0 ] == -1 ) {
|
||||
return new ByteArrayInputStream( decmpfsHeader.getAttrBytes(), 1, decmpfsHeader.getAttrBytes().length - 1 );
|
||||
return new ByteArrayInputStream(decmpfsHeader.getAttrBytes(), 1,
|
||||
decmpfsHeader.getAttrBytes().length - 1);
|
||||
}
|
||||
|
||||
ZLIB zlib = new ZLIB();
|
||||
|
||||
InputStream inputStream =
|
||||
new ByteArrayInputStream(decmpfsHeader.getAttrBytes());
|
||||
|
||||
ByteArrayOutputStream uncompressedBytes =
|
||||
zlib.decompress(inputStream, (int) decmpfsHeader.getUncompressedSize());
|
||||
|
||||
File tempDecompressedFile = GFileUtilityMethods.writeTemporaryFile(
|
||||
uncompressedBytes.toByteArray(), entry.getName());
|
||||
return new FileInputStream(tempDecompressedFile);
|
||||
return new RestrictedInflaterInputStream(decmpfsHeader.getAttrBytes(),
|
||||
(int) decmpfsHeader.getUncompressedSize());
|
||||
}
|
||||
else if ( decmpfsHeader.getCompressionType() == DecmpfsCompressionTypes.CMP_Type4 ) {
|
||||
|
||||
return decompressResourceFork( entry, resourceForkStream, (int)decmpfsHeader.getUncompressedSize() );
|
||||
return decompressResourceFork(entry, resourceForkStream,
|
||||
(int) decmpfsHeader.getUncompressedSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,34 +215,102 @@ public class DmgFileReader implements Closeable {
|
||||
System.err.println(
|
||||
"dmg resource fork for " + entry.getName() + ": " + tempFile.getAbsolutePath());
|
||||
|
||||
InputStream input = new FileInputStream( tempFile );
|
||||
// Copy compressed portion of tempFile to tempCompressedFile
|
||||
File tempCompressedFile;
|
||||
try (InputStream input = new FileInputStream(tempFile)) {
|
||||
|
||||
for ( int i = 0 ; i < 0x100 ; ++i ) {
|
||||
input.read();
|
||||
for (int i = 0; i < 0x100; ++i) {
|
||||
input.read();
|
||||
}
|
||||
|
||||
byte[] sizeBytes = new byte[4];
|
||||
input.read(sizeBytes);
|
||||
int size = sizeBytes[0] == 0 ? bedc.getInt(sizeBytes) : ledc.getInt(sizeBytes);
|
||||
|
||||
byte[] flagsBytes = new byte[4];
|
||||
input.read(flagsBytes);
|
||||
|
||||
byte[] startDistanceBytes = new byte[4];
|
||||
input.read(startDistanceBytes);
|
||||
int startDistance = ledc.getInt(startDistanceBytes);
|
||||
|
||||
input.skip(startDistance - 8);//skip to the start of the zlib compressed file
|
||||
|
||||
tempCompressedFile =
|
||||
GFileUtilityMethods.writeTemporaryFile(input, size - startDistance);
|
||||
}
|
||||
finally {
|
||||
tempFile.delete();
|
||||
}
|
||||
|
||||
byte [] sizeBytes = new byte[ 4 ];
|
||||
input.read( sizeBytes );
|
||||
int size = sizeBytes[ 0 ] == 0 ?
|
||||
bedc.getInt( sizeBytes ) :
|
||||
ledc.getInt( sizeBytes );
|
||||
return new RestrictedInflaterInputStream(tempCompressedFile, expectedLength);
|
||||
}
|
||||
|
||||
byte [] flagsBytes = new byte[ 4 ];
|
||||
input.read( flagsBytes );
|
||||
private class RestrictedInflaterInputStream extends InflaterInputStream {
|
||||
|
||||
byte [] startDistanceBytes = new byte[ 4 ];
|
||||
input.read( startDistanceBytes );
|
||||
int startDistance = ledc.getInt( startDistanceBytes );
|
||||
private File tempCompressedFile;
|
||||
private int readLimit;
|
||||
private int readCount = 0;
|
||||
|
||||
input.skip( startDistance - 8 );//skip to the start of the zlib compressed file
|
||||
/**
|
||||
* Creates a new Inflater input stream with a default decompressor and buffer size.
|
||||
* NOTE: The default Inflater instance will be ended when this stream closes.
|
||||
* @param tempCompressedFile the temporary file containing compressed data. File will be
|
||||
* removed when this stream is closed.
|
||||
* @param readLimit maximum data read count. Exceeding this limit will result in an
|
||||
* IOException.
|
||||
* @throws FileNotFoundException if tempCompressedFile does not exist
|
||||
*/
|
||||
RestrictedInflaterInputStream(File tempCompressedFile, int readLimit)
|
||||
throws FileNotFoundException {
|
||||
super(new FileInputStream(tempCompressedFile));
|
||||
this.tempCompressedFile = tempCompressedFile;
|
||||
this.readLimit = readLimit;
|
||||
}
|
||||
|
||||
File tempCompressedFile = GFileUtilityMethods.writeTemporaryFile( input, size - startDistance );
|
||||
InputStream inputStream = new FileInputStream( tempCompressedFile );
|
||||
/**
|
||||
* Creates a new Inflater input stream with a default decompressor and buffer size.
|
||||
* NOTE: The default Inflater instance will be ended when this stream closes.
|
||||
* @param compressedData the byte array containing compressed data.
|
||||
* @param readLimit maximum data read count. Exceeding this limit will result in an
|
||||
* IOException.
|
||||
*/
|
||||
RestrictedInflaterInputStream(byte[] compressedData, int readLimit) {
|
||||
super(new ByteArrayInputStream(compressedData));
|
||||
this.tempCompressedFile = null;
|
||||
this.readLimit = readLimit;
|
||||
}
|
||||
|
||||
ZLIB zlib = new ZLIB( );
|
||||
ByteArrayOutputStream uncompressedByteStream = zlib.decompress( inputStream, expectedLength );
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
super.close();
|
||||
}
|
||||
finally {
|
||||
// Cleanup temporary file input stream and remove file
|
||||
in.close();
|
||||
if (tempCompressedFile != null) {
|
||||
tempCompressedFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ByteArrayInputStream( uncompressedByteStream.toByteArray() );
|
||||
@Override
|
||||
public int read(byte[] b, int off, int length) throws IOException {
|
||||
if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (readCount >= readLimit) {
|
||||
throw new IOException("Decompression limit exceeded: " + readLimit);
|
||||
}
|
||||
// Limit read length to avoid exceeding readLimit
|
||||
int limit = Math.min(readLimit - readCount, length);
|
||||
int count = super.read(b, off, limit);
|
||||
if (count > 0) {
|
||||
readCount += count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getInfo( String path ) {
|
||||
|
||||
@@ -128,6 +128,8 @@ public class DmgServer {
|
||||
|
||||
sendResponse(temporaryFile.getAbsolutePath());
|
||||
|
||||
// TODO: When can we remove temporaryFile
|
||||
|
||||
if (expectedFileLength != temporaryFile.length()) {
|
||||
log("file sizes do not match!");
|
||||
}
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/* ###
|
||||
* IP: Public Domain
|
||||
*/
|
||||
package mobiledevices.dmg.zlib;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* TODO make this more memory efficient!!
|
||||
*
|
||||
*/
|
||||
public class ZLIB {
|
||||
|
||||
public ZLIB() {
|
||||
}
|
||||
|
||||
public ByteArrayOutputStream decompress( InputStream compressedIn, int expectedDecompressedLength ) throws IOException {
|
||||
return decompress( compressedIn, expectedDecompressedLength, false );
|
||||
}
|
||||
|
||||
public ByteArrayOutputStream decompress( InputStream compressedIn, int expectedDecompressedLength, boolean noWrap ) throws IOException {
|
||||
|
||||
byte [] compressedBytes = convertInputStreamToByteArray( compressedIn );
|
||||
|
||||
ByteArrayOutputStream decompressedBOS = new ByteArrayOutputStream();
|
||||
|
||||
byte [] tempDecompressedBytes = new byte[ 0x10000 ];
|
||||
|
||||
int totalDecompressed = 0;
|
||||
int offset = 0;
|
||||
|
||||
try {
|
||||
while ( offset < compressedBytes.length && totalDecompressed < expectedDecompressedLength ) {
|
||||
|
||||
if ( !noWrap && compressedBytes [ offset ] != 0x78 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
Inflater inflater = new Inflater( noWrap );
|
||||
|
||||
inflater.setInput( compressedBytes, offset, compressedBytes.length - offset );
|
||||
|
||||
int nDecompressed = inflater.inflate( tempDecompressedBytes );
|
||||
|
||||
if ( nDecompressed == 0 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
totalDecompressed += nDecompressed;
|
||||
|
||||
decompressedBOS.write( tempDecompressedBytes, 0, nDecompressed );
|
||||
|
||||
offset += inflater.getTotalIn();//increment total compressed bytes consumed
|
||||
}
|
||||
}
|
||||
catch ( DataFormatException e ) {
|
||||
throw new IOException( e.getMessage() );
|
||||
}
|
||||
|
||||
return decompressedBOS;
|
||||
}
|
||||
|
||||
public ByteArrayOutputStream compress(byte[] decompressedBytes) {
|
||||
return compress( false, decompressedBytes );
|
||||
}
|
||||
|
||||
public ByteArrayOutputStream compress(boolean noWrap, byte[] decompressedBytes) {
|
||||
ByteArrayOutputStream compressedBOS = new ByteArrayOutputStream();
|
||||
|
||||
byte [] tempBuffer = new byte[ 0x10000 ];
|
||||
|
||||
int offset = 0;
|
||||
|
||||
while ( offset < decompressedBytes.length ) {
|
||||
|
||||
Deflater deflater = new Deflater( 0, noWrap );
|
||||
|
||||
deflater.setInput( decompressedBytes, offset, decompressedBytes.length - offset );
|
||||
|
||||
deflater.finish();
|
||||
|
||||
if ( deflater.needsInput() ) {
|
||||
System.err.println( "needs input??" );
|
||||
}
|
||||
|
||||
int nDeflated = deflater.deflate( tempBuffer );
|
||||
|
||||
if ( nDeflated == 0 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
compressedBOS.write( tempBuffer, 0, nDeflated );
|
||||
|
||||
offset += deflater.getTotalIn();
|
||||
}
|
||||
|
||||
return compressedBOS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the contents of an input stream to a byte array
|
||||
* @param compressedIn
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private byte [] convertInputStreamToByteArray( InputStream compressedIn ) throws IOException {
|
||||
byte [] bytes = new byte[ 8096 ];
|
||||
ByteArrayOutputStream compressedBOS = new ByteArrayOutputStream();
|
||||
while ( true ) {
|
||||
int nRead = compressedIn.read( bytes );
|
||||
if ( nRead == -1 ) {
|
||||
break;
|
||||
}
|
||||
compressedBOS.write( bytes, 0, nRead );
|
||||
}
|
||||
return compressedBOS.toByteArray();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user