I found a link: http://code.cheesydesign.com/?p=572 about reading PE Files. I am using this code but unfortunately, I get an error on ntHeadersSignature (on reader.ReadUint32). It says that it's unable to read beyond the stream. I wonder why and how to fix this error since I tried with peekchar and read it with readint32, converting it to uint doesn't work. Thank you for your sincere help!
public PeHeaderReader(string filePath)
{
// Read in the DLL or EXE and get the timestamp
using (FileStream stream = new FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
BinaryReader reader = new BinaryReader(stream);
dosHeader = FromBinaryReader<IMAGE_DOS_HEADER>(reader);
// Add 4 bytes to the offset
stream.Seek(dosHeader.e_lfanew, SeekOrigin.Begin);
UInt32 ntHeadersSignature = reader.ReadUInt32(); //HERE IS THE ERROR
fileHeader = FromBinaryReader<IMAGE_FILE_HEADER>(reader);
if (this.Is32BitHeader)
{
optionalHeader32 = FromBinaryReader<IMAGE_OPTIONAL_HEADER32>(reader);
}
else
{
optionalHeader64 = FromBinaryReader<IMAGE_OPTIONAL_HEADER64>(reader);
}
imageSectionHeaders = new IMAGE_SECTION_HEADER[fileHeader.NumberOfSections];
for(int headerNo = 0; headerNo < imageSectionHeaders.Length; ++headerNo)
{
imageSectionHeaders[headerNo] = FromBinaryReader<IMAGE_SECTION_HEADER>(reader);
}
}
}
Related
I am trying out following code in order to compress and save a bitmap of a screenshot but get this error. I haven't tried using CompressFiles as I have to do it using memory stream.
public void CompressAndSaveBitmap(Bitmap bitmap)
{
using (MemoryStream memStream = new MemoryStream())
{
using (FileStream file = new FileStream("XYZ", FileMode.Create, System.IO.FileAccess.Write))
{
bitmap.Save(memStream, System.Drawing.Imaging.ImageFormat.Bmp);
// tried these but they don't work.
//memStream.Seek(0, 0);
//memStream.Position = 0;
this.compressor.CompressStream(memStream, file); // throws error here
// also tried the following to see if Bitmap contains the problem
//UnicodeEncoding uniEncoding = new UnicodeEncoding();
//byte[] firstString = uniEncoding.GetBytes("Invalid file path characters are: ");
//int count = 0;
//while (count < firstString.Length)
//memStream.WriteByte(firstString[count++]);
//memStream.Flush();
////memStream.Seek(0, 0);
//memStream.Position = 0;
//this.compressor.CompressStream(memStream, file);
}
}
}
Compressor initialization code:
public Compressor()
{
SevenZipCompressor.SetLibraryPath(#"D:\7z.dll");
this.compressor = new SevenZip.SevenZipCompressor();
compressor.CompressionLevel = CompressionLevel.Ultra;
compressor.CompressionMethod = CompressionMethod.Ppmd;
}
It's crashes on this line in the library:
var lockObject = (object) _files ?? _streams;
lock (lockObject) // here in ArchiveUpdateCallback.cs
I see that the file is created but it's corrupt.
I was able to successfully compress file using following code:
public void CompressAndSaveBitmap(Bitmap bitmap)
{
using (MemoryStream memStream = new MemoryStream())
{
using (FileStream file = new FileStream("XYZ", FileMode.Create, System.IO.FileAccess.Write))
{
bitmap.Save(memStream, System.Drawing.Imaging.ImageFormat.Bmp);
// tried these but they don't work.
//memStream.Seek(0, 0);
//memStream.Position = 0;
SevenZipCompressor compressor =
new SevenZipCompressor
{
CompressionLevel = CompressionLevel.Ultra,
CompressionMethod = CompressionMethod.Lzma
};
compressor.CompressStream(memStream, file); // throws error here
}
}
}
Following was the bitmap file:
Executed code:
Bitmap bmp = new Bitmap("Test.bmp");
res.CompressAndSaveBitmap(bmp);
After execution got following output:
Opened the file with WinRar and extracted file:
In folder found the extracted image:
UPDATE:
I think the only problem with OP's code is this.compressor is not initialized.
I'm trying to use a FileStream with a relative path but it is not working.
var pic = ReadFile("~/Images/money.png");
It is working when I use something like:
var p = GetFilePath();
var pic = ReadFile(p);
the rest of the code(from SO):
public static byte[] ReadFile(string filePath)
{
byte[] buffer;
FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
try
{
int length = (int)fileStream.Length; // get file length
buffer = new byte[length]; // create buffer
int count; // actual number of bytes read
int sum = 0; // total number of bytes read
// read until Read method returns 0 (end of the stream has been reached)
while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
sum += count; // sum is a buffer offset for next reading
}
finally
{
fileStream.Close();
}
return buffer;
}
public string GetFilePath()
{
return HttpContext.Current.Server.MapPath("~/Images/money.png");
}
I don't get why it is not working because the FileStream constructor allow using relative path.
I'm assuming the folder in your program has the subfolder images, which contains your image file.
\folder\program.exe
\folder\Images\money.jpg
Try without the "~".
I also had the same issue but I solved it by using this code,
Try one of this code, hope it will solve your issue too.
#region GetImageStream
public static Stream GetImageStream(string Image64string)
{
Stream imageStream = new MemoryStream();
if (!string.IsNullOrEmpty(Image64string))
{
byte[] imageBytes = Convert.FromBase64String(Image64string.Substring(Image64string.IndexOf(',') + 1));
using (Image targetimage = BWS.AWS.S3.ResizeImage(System.Drawing.Image.FromStream(new MemoryStream(imageBytes, false)), new Size(1600, 1600), true))
{
targetimage.Save(imageStream, ImageFormat.Jpeg);
}
}
return imageStream;
}
#endregion
2nd one
#region GetImageStream
public static Stream GetImageStream(Stream stream)
{
Stream imageStream = new MemoryStream();
if (stream != null)
{
using (Image targetimage = BWS.AWS.S3.ResizeImage(System.Drawing.Image.FromStream(stream), new Size(1600, 1600), true))
{
targetimage.Save(imageStream, ImageFormat.Jpeg);
}
}
return imageStream;
}
#endregion
I've been playing around with C#'s SharpZip Library (version 0.86.0). I'm basically using it to package a number of files into one clean zip files. Here's what my function looks like to do generate the byte array of the zip file:
public static byte[] CompressToZip(List<Tuple<byte[], string>> fileItemList, int zipLevel = 3)
{
MemoryStream zipMemoryStream = new MemoryStream();
ZipOutputStream zOutput = new ZipOutputStream(zipMemoryStream);
zOutput.SetLevel(zipLevel);
ICSharpCode.SharpZipLib.Checksums.Crc32 crc = new ICSharpCode.SharpZipLib.Checksums.Crc32();
foreach (var file in fileItemList)
{
ZipEntry entry = new ZipEntry(file.Item2);
entry.DateTime = DateTime.Now;
entry.Size = file.Item1.Length;
crc.Reset();
crc.Update(file.Item1);
entry.Crc = crc.Value;
zOutput.PutNextEntry(entry);
zOutput.Write(file.Item1, 0, file.Item1.Length);
}
zOutput.IsStreamOwner = false;
zOutput.Finish();
zOutput.Close();
zipMemoryStream.Position = 0;
byte[] zipedFile = zipMemoryStream.ToArray();
return zipedFile;
}
The function works fine for files with one item in it. But for some reason when I have two or more I get errors when I go to extract/open it.
PeaZip says:
Archive is not readable
WinZip says:
The compressed size stored in the local header for this file is not the same as the compressed size stored in the central header
but here's the kicker. Windows 8 Archiving tool works just fine with the file. The WinZip error kind of makes me think I'm writing the files to the stream incorrectly. But it looks fine to me. Not sure what to make of this..
EDIT
Here's my changes from codemonkeys input. Looks better to me, but I'm still getting the same errors
public static byte[] CompressToZip(List<Tuple<byte[], string>> fileItemList, int zipLevel = 3)
{
MemoryStream zipMemoryStream = new MemoryStream();
ZipOutputStream zOutput = new ZipOutputStream(zipMemoryStream);
zOutput.SetLevel(zipLevel);
ICSharpCode.SharpZipLib.Checksums.Crc32 crc = new ICSharpCode.SharpZipLib.Checksums.Crc32();
foreach (var file in fileItemList)
{
ZipEntry entry = new ZipEntry(file.Item2);
entry.DateTime = DateTime.Now;
entry.Size = file.Item1.Length;
crc.Reset();
crc.Update(file.Item1);
entry.Crc = crc.Value;
zOutput.PutNextEntry(entry);
var memStreamCurrentfile = new MemoryStream(file.Item1);
StreamUtils.Copy(memStreamCurrentfile, zOutput, new byte[4096]);
zOutput.CloseEntry();
}
zOutput.IsStreamOwner = false;
zOutput.Finish();
zOutput.Close();
zipMemoryStream.Position = 0;
byte[] zipedFile = zipMemoryStream.ToArray();
return zipedFile;
}
Figured it out! It seems me setting the Crc and size of file entry was the issue. I assumed it would helped to define those. I guess I was wrong. Here's the final code for all to enjoy:
public static byte[] CompressToZip(List<Tuple<byte[], string>> fileItemList, int zipLevel = 3)
{
MemoryStream zipMemoryStream = new MemoryStream();
ZipOutputStream zOutput = new ZipOutputStream(zipMemoryStream);
zOutput.SetLevel(zipLevel);
ICSharpCode.SharpZipLib.Checksums.Crc32 crc = new ICSharpCode.SharpZipLib.Checksums.Crc32();
foreach (var file in fileItemList)
{
ZipEntry entry = new ZipEntry(file.Item2);
entry.DateTime = DateTime.Now;
zOutput.PutNextEntry(entry);
var memStreamCurrentfile = new MemoryStream(file.Item1);
StreamUtils.Copy(memStreamCurrentfile, zOutput, new byte[4096]);
zOutput.CloseEntry();
}
zOutput.IsStreamOwner = false;
zOutput.Finish();
zOutput.Close();
zipMemoryStream.Position = 0;
byte[] zipedFile = zipMemoryStream.ToArray();
return zipedFile;
}
I'm creating simple self-extracting archive using magic number to mark the beginning of the content.
For now it is a textfile:
MAGICNUMBER .... content of the text file
Next, textfile copied to the end of the executable:
copy programm.exe/b+textfile.txt/b sfx.exe
I'm trying to find the second occurrence of the magic number (the first one would be a hardcoded constant obviously) using the following code:
string my_filename = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
StreamReader file = new StreamReader(my_filename);
const int block_size = 1024;
const string magic = "MAGICNUMBER";
char[] buffer = new Char[block_size];
Int64 count = 0;
Int64 glob_pos = 0;
bool flag = false;
while (file.ReadBlock(buffer, 0, block_size) > 0)
{
var rel_pos = buffer.ToString().IndexOf(magic);
if ((rel_pos > -1) & (!flag))
{
flag = true;
continue;
}
if ((rel_pos > -1) & (flag == true))
{
glob_pos = block_size * count + rel_pos;
break;
}
count++;
}
using (FileStream fs = new FileStream(my_filename, FileMode.Open, FileAccess.Read))
{
byte[] b = new byte[fs.Length - glob_pos];
fs.Seek(glob_pos, SeekOrigin.Begin);
fs.Read(b, 0, (int)(fs.Length - glob_pos));
File.WriteAllBytes("c:/output.txt", b);
but for some reason I'm copying almost entire file, not the last few kilobytes. Is it because of the compiler optimization, inlining magic constant in while loop of something similar?
How should I do self-extraction archive properly?
Guessed I should read file backwards to avoid problems of compiler inlining magic constant multiply times.
So I've modified my code in the following way:
string my_filename = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
StreamReader file = new StreamReader(my_filename);
const int block_size = 1024;
const string magic = "MAGIC";
char[] buffer = new Char[block_size];
Int64 count = 0;
Int64 glob_pos = 0;
while (file.ReadBlock(buffer, 0, block_size) > 0)
{
var rel_pos = buffer.ToString().IndexOf(magic);
if (rel_pos > -1)
{
glob_pos = block_size * count + rel_pos;
}
count++;
}
using (FileStream fs = new FileStream(my_filename, FileMode.Open, FileAccess.Read))
{
byte[] b = new byte[fs.Length - glob_pos];
fs.Seek(glob_pos, SeekOrigin.Begin);
fs.Read(b, 0, (int)(fs.Length - glob_pos));
File.WriteAllBytes("c:/output.txt", b);
}
So I've scanned the all file once, found that I though would be the last occurrence of the magic number and copied from here to the end of it. While the file created by this procedure seems smaller than in previous attempt it in no way the same file I've attached to my "self-extracting" archive. Why?
My guess is that position calculation of the beginning of the attached file is wrong due to used conversion from binary to string. If so how should I modify my position calculation to make it correct?
Also how should I choose magic number then working with real files, pdfs for example? I wont be able to modify pdfs easily to include predefined magic number in it.
Try this out. Some C# Stream IO 101:
public static void Main()
{
String path = #"c:\here is your path";
// Method A: Read all information into a Byte Stream
Byte[] data = System.IO.File.ReadAllBytes(path);
String[] lines = System.IO.File.ReadAllLines(path);
// Method B: Use a stream to do essentially the same thing. (More powerful)
// Using block essentially means 'close when we're done'. See 'using block' or 'IDisposable'.
using (FileStream stream = File.OpenRead(path))
using (StreamReader reader = new StreamReader(stream))
{
// This will read all the data as a single string
String allData = reader.ReadToEnd();
}
String outputPath = #"C:\where I'm writing to";
// Copy from one file-stream to another
using (FileStream inputStream = File.OpenRead(path))
using (FileStream outputStream = File.Create(outputPath))
{
inputStream.CopyTo(outputStream);
// Again, this will close both streams when done.
}
// Copy to an in-memory stream
using (FileStream inputStream = File.OpenRead(path))
using (MemoryStream outputStream = new MemoryStream())
{
inputStream.CopyTo(outputStream);
// Again, this will close both streams when done.
// If you want to hold the data in memory, just don't wrap your
// memory stream in a using block.
}
// Use serialization to store data.
var serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
// We'll serialize a person to the memory stream.
MemoryStream memoryStream = new MemoryStream();
serializer.Serialize(memoryStream, new Person() { Name = "Sam", Age = 20 });
// Now the person is stored in the memory stream (just as easy to write to disk using a
// file stream as well.
// Now lets reset the stream to the beginning:
memoryStream.Seek(0, SeekOrigin.Begin);
// And deserialize the person
Person deserializedPerson = (Person)serializer.Deserialize(memoryStream);
Console.WriteLine(deserializedPerson.Name); // Should print Sam
}
// Mark Serializable stuff as serializable.
// This means that C# will automatically format this to be put in a stream
[Serializable]
class Person
{
public String Name { get; set; }
public Int32 Age { get; set; }
}
The easiest solution is to replace
const string magic = "MAGICNUMBER";
with
static string magic = "magicnumber".ToUpper();
But there are more problems with the whole magic string approach. What is the file contains the magic string? I think that the best solution is to put the file size after the file. The extraction is much easier that way: Read the length from the last bytes and read the required amount of bytes from the end of the file.
Update: This should work unless your files are very big. (You'd need to use a revolving pair of buffers in that case (to read the file in small blocks)):
string inputFilename = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
string outputFilename = inputFilename + ".secret";
string magic = "magic".ToUpper();
byte[] data = File.ReadAllBytes(inputFilename);
byte[] magicData = Encoding.ASCII.GetBytes(magic);
for (int idx = magicData.Length - 1; idx < data.Length; idx++) {
bool found = true;
for (int magicIdx = 0; magicIdx < magicData.Length; magicIdx++) {
if (data[idx - magicData.Length + 1 + magicIdx] != magicData[magicIdx]) {
found = false;
break;
}
}
if (found) {
using (FileStream output = new FileStream(outputFilename, FileMode.Create)) {
output.Write(data, idx + 1, data.Length - idx - 1);
}
}
}
Update2: This should be much faster, use little memory and work on files of all size, but the program your must be proper executable (with size being a multiple of 512 bytes):
string inputFilename = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
string outputFilename = inputFilename + ".secret";
string marker = "magic".ToUpper();
byte[] data = File.ReadAllBytes(inputFilename);
byte[] markerData = Encoding.ASCII.GetBytes(marker);
int markerLength = markerData.Length;
const int blockSize = 512; //important!
using(FileStream input = File.OpenRead(inputFilename)) {
long lastPosition = 0;
byte[] buffer = new byte[blockSize];
while (input.Read(buffer, 0, blockSize) >= markerLength) {
bool found = true;
for (int idx = 0; idx < markerLength; idx++) {
if (buffer[idx] != markerData[idx]) {
found = false;
break;
}
}
if (found) {
input.Position = lastPosition + markerLength;
using (FileStream output = File.OpenWrite(outputFilename)) {
input.CopyTo(output);
}
}
lastPosition = input.Position;
}
}
Read about some approaches here: http://www.strchr.com/creating_self-extracting_executables
You can add the compressed file as resource to the project itself:
Project > Properties
Set the property of this resource to Binary.
You can then retrieve the resource with
byte[] resource = Properties.Resources.NameOfYourResource;
Search backwards rather than forwards (assuming your file won't contain said magic number).
Or append your (text) file and then lastly its length (or the length of the original exe), so you only need read the last DWORD / few bytes to see how long the file is - then no magic number is required.
More robustly, store the file as an additional data section within the executable file. This is more fiddly without external tools as it requires knowledge of the PE file format used for NT executables, q.v. http://msdn.microsoft.com/en-us/library/ms809762.aspx
I have an application in ASP.NET where user can upload ZIP file. I'm trying to extract file using ICSharpZipLib (I also tried DotNetZip, but had same issue).
This zip file contains single xml document (9KB before compress).
When I open this file with other applications on my desktop (7zip, windows explorer) it seems to be ok.
My unzip method throws System.OutOfMemoryException and I have no idea why is that. When I debugged my unziping method I noticed that zipInputStreams' Length property throws Exception and is not available:
Stream UnZipSingleFile(Stream memoryStream)
{
var zipInputStream = new ZipInputStream(memoryStream);
memoryStream.Position = 0;
zipInputStream.GetNextEntry();
MemoryStream unzippedStream = new MemoryStream();
int len;
byte[] buf = new byte[4096];
while ((len = zipInputStream.Read(buf, 0, buf.Length)) > 0)
{
unzippedStream.Write(buf, 0, len);
}
unzippedStream.Position = 0;
memoryStream.Position = 0;
return unzippedStream;
}
and here's how I get string of unzippedStream:
string GetString()
{
var reader = new StreamReader(unzippedStream);
var result = reader.ReadToEnd();
unzippedStream.Position = 0;
return result;
}
From their wiki:
"Sharpzip supports Zip files using both stored and deflate compression methods and also supports old (PKZIP 2.0) style and AES encryption"
Are you sure the format of the uploaded zip file is acceptable for SharpZipLib?
While this post is quite old, I think it could be beneficial to illustrate how I did this for compression and decompression using ICSharpZipLib (C# package version 1.1.0). I put this together by looking into the examples shown here (see ie. these compression and decompression examples).
Assumption: The input to the compression and decompression below should be in bytes. If you have ie. an xml file you could load it to an XDocument, and convert it into an XmlDocument with .ToXmlDocument(). From there, you could access the string contents by calling .OuterXml, and converting the string to a byte array.
// Compression (inputBytes = ie. string-to-compress, as bytes)
using var dataStream = new MemoryStream(inputBytes);
var outputStream = new MemoryStream();
using (var zipStream = new ZipOutputStream(outputStream))
{
zipStream.SetLevel(3);
var newEntry = new ZipEntry("someFilename.someExtension");
newEntry.DateTime = DateTime.Now;
zipStream.PutNextEntry(newEntry);
StreamUtils.Copy(dataStream, zipStream, new byte[4096]);
zipStream.CloseEntry();
zipStream.IsStreamOwner = false;
}
outputStream.Position = 0;
var outputBytes = outputStream.ToArray();
// Decompression (inputBytes = ie. string-to-decompress, as bytes)
using var dataStream = new MemoryStream(inputBytes);
var outputStream = new MemoryStream();
using (var zipStream = new ZipInputStream(dataStream))
{
while (zipStream.GetNextEntry() is ZipEntry zipEntry)
{
var buffer = new byte[4096];
StreamUtils.Copy(zipStream, outputStream, buffer);
}
}
var outputBytes = outputStream.ToArray();