2017-01-06 11:17:35 +01:00
|
|
|
|
/**
|
2023-05-28 11:14:43 +02:00
|
|
|
|
* Steamless - Copyright (c) 2015 - 2023 atom0s [atom0s@live.com]
|
2017-01-06 11:17:35 +01:00
|
|
|
|
*
|
|
|
|
|
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
|
|
|
|
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
|
|
|
|
|
* Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
|
|
|
|
*
|
|
|
|
|
* By using Steamless, you agree to the above license and its terms.
|
|
|
|
|
*
|
|
|
|
|
* Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
|
|
|
|
|
* made. You must do so in any reasonable manner, but not in any way that suggests the licensor
|
|
|
|
|
* endorses you or your use.
|
|
|
|
|
*
|
|
|
|
|
* Non-Commercial - You may not use the material (Steamless) for commercial purposes.
|
|
|
|
|
*
|
|
|
|
|
* No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
|
|
|
|
|
* modified material. You are, however, allowed to submit the modified works back to the original
|
|
|
|
|
* Steamless project in attempt to have it added to the original project.
|
|
|
|
|
*
|
|
|
|
|
* You may not apply legal terms or technological measures that legally restrict others
|
|
|
|
|
* from doing anything the license permits.
|
|
|
|
|
*
|
|
|
|
|
* No warranties are given.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace Steamless.API.PE32
|
|
|
|
|
{
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2022-03-26 10:23:03 +01:00
|
|
|
|
using System.IO;
|
2017-01-06 11:17:35 +01:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
|
|
|
|
|
public class Pe32Helpers
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Converts a byte array to the given structure type.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
|
|
|
|
/// <param name="data"></param>
|
|
|
|
|
/// <param name="offset"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static T GetStructure<T>(byte[] data, int offset = 0)
|
|
|
|
|
{
|
2020-08-17 10:52:21 +02:00
|
|
|
|
var size = Marshal.SizeOf(typeof(T));
|
|
|
|
|
var ptr = Marshal.AllocHGlobal(size);
|
2020-12-18 08:10:04 +01:00
|
|
|
|
|
|
|
|
|
// Size can land up being bigger than our buffer..
|
|
|
|
|
if (size > data.Length)
|
|
|
|
|
size = Math.Min(data.Length, Math.Max(0, size));
|
|
|
|
|
|
2020-08-17 10:52:21 +02:00
|
|
|
|
Marshal.Copy(data, offset, ptr, size);
|
2017-01-06 11:17:35 +01:00
|
|
|
|
var obj = (T)Marshal.PtrToStructure(ptr, typeof(T));
|
|
|
|
|
Marshal.FreeHGlobal(ptr);
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Converts the given object back to a byte array.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
|
|
|
|
/// <param name="obj"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static byte[] GetStructureBytes<T>(T obj)
|
|
|
|
|
{
|
|
|
|
|
var size = Marshal.SizeOf(obj);
|
|
|
|
|
var data = new byte[size];
|
|
|
|
|
var ptr = Marshal.AllocHGlobal(size);
|
|
|
|
|
Marshal.StructureToPtr(obj, ptr, true);
|
|
|
|
|
Marshal.Copy(ptr, data, 0, size);
|
|
|
|
|
Marshal.FreeHGlobal(ptr);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Obtains a section from the given file information.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="rawData"></param>
|
|
|
|
|
/// <param name="index"></param>
|
|
|
|
|
/// <param name="dosHeader"></param>
|
|
|
|
|
/// <param name="ntHeaders"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static NativeApi32.ImageSectionHeader32 GetSection(byte[] rawData, int index, NativeApi32.ImageDosHeader32 dosHeader, NativeApi32.ImageNtHeaders32 ntHeaders)
|
|
|
|
|
{
|
|
|
|
|
var sectionSize = Marshal.SizeOf(typeof(NativeApi32.ImageSectionHeader32));
|
|
|
|
|
var optionalHeaderOffset = Marshal.OffsetOf(typeof(NativeApi32.ImageNtHeaders32), "OptionalHeader").ToInt32();
|
|
|
|
|
var dataOffset = dosHeader.e_lfanew + optionalHeaderOffset + ntHeaders.FileHeader.SizeOfOptionalHeader;
|
|
|
|
|
|
|
|
|
|
return GetStructure<NativeApi32.ImageSectionHeader32>(rawData, dataOffset + (index * sectionSize));
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-26 10:23:03 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Updates the given files PE checksum value. (Path is assumed to be a 32bit PE file.)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="path"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static bool UpdateFileChecksum(string path)
|
|
|
|
|
{
|
2022-09-24 00:57:55 +02:00
|
|
|
|
// Obtain the proper checksum for the file..
|
|
|
|
|
var ret = NativeApi32.MapFileAndCheckSum(path, out uint HeaderSum, out uint Checksum);
|
|
|
|
|
if (ret != 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
2022-03-26 10:23:03 +01:00
|
|
|
|
FileStream fStream = null;
|
|
|
|
|
var data = new byte[4];
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Open the file for reading/writing..
|
|
|
|
|
fStream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
|
|
|
|
|
|
|
|
|
|
// Read the starting offset to the files NT headers..
|
|
|
|
|
fStream.Position = (int)Marshal.OffsetOf(typeof(NativeApi32.ImageDosHeader32), "e_lfanew");
|
|
|
|
|
fStream.Read(data, 0, 4);
|
|
|
|
|
|
|
|
|
|
var offset = BitConverter.ToUInt32(data, 0);
|
|
|
|
|
|
|
|
|
|
// Move to the files CheckSum position..
|
|
|
|
|
offset += 4 + (uint)Marshal.SizeOf(typeof(NativeApi32.ImageFileHeader32)) + (uint)Marshal.OffsetOf(typeof(NativeApi32.ImageOptionalHeader32), "CheckSum").ToInt32();
|
|
|
|
|
fStream.Position = offset;
|
|
|
|
|
|
2022-09-24 00:57:55 +02:00
|
|
|
|
// Overwrite the file checksum..
|
|
|
|
|
data = BitConverter.GetBytes(Checksum);
|
2022-03-26 10:23:03 +01:00
|
|
|
|
fStream.Write(data, 0, 4);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
fStream?.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-06 11:17:35 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Scans the given data for the given pattern.
|
|
|
|
|
///
|
|
|
|
|
/// Notes:
|
|
|
|
|
/// Patterns are assumed to be 2 byte hex values with spaces.
|
|
|
|
|
/// Wildcards are represented by ??.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data"></param>
|
|
|
|
|
/// <param name="pattern"></param>
|
|
|
|
|
/// <returns></returns>
|
2022-03-26 02:49:50 +01:00
|
|
|
|
public static long FindPattern(byte[] data, string pattern)
|
2017-01-06 11:17:35 +01:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Trim the pattern from extra whitespace..
|
|
|
|
|
var trimPattern = pattern.Replace(" ", "").Trim();
|
|
|
|
|
|
|
|
|
|
// Convert the pattern to a byte array..
|
|
|
|
|
var patternMask = new List<bool>();
|
|
|
|
|
var patternData = Enumerable.Range(0, trimPattern.Length).Where(x => x % 2 == 0)
|
|
|
|
|
.Select(x =>
|
|
|
|
|
{
|
|
|
|
|
var bt = trimPattern.Substring(x, 2);
|
|
|
|
|
patternMask.Add(!bt.Contains('?'));
|
|
|
|
|
return bt.Contains('?') ? (byte)0 : Convert.ToByte(bt, 16);
|
|
|
|
|
}).ToArray();
|
|
|
|
|
|
|
|
|
|
// Scan the given data for our pattern..
|
|
|
|
|
for (var x = 0; x < data.Length; x++)
|
|
|
|
|
{
|
|
|
|
|
if (!patternData.Where((t, y) => patternMask[y] && t != data[x + y]).Any())
|
|
|
|
|
return (uint)x;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-26 02:49:50 +01:00
|
|
|
|
return -1;
|
2017-01-06 11:17:35 +01:00
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
2022-03-26 02:49:50 +01:00
|
|
|
|
return -1;
|
2017-01-06 11:17:35 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|