0
0
mirror of https://github.com/sp-tarkov/assembly-tool.git synced 2025-02-13 09:50:44 -05:00

173 lines
5.4 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using dnlib.IO;
using dnlib.PE;
using dnlib.DotNet.MD;
using de4dot.blocks;
namespace de4dot.code.deobfuscators {
public sealed class MyPEImage : IDisposable {
IPEImage peImage;
byte[] peImageData;
Metadata metadata;
bool dnFileInitialized;
ImageSectionHeader dotNetSection;
bool ownPeImage;
public Metadata Metadata {
get {
if (dnFileInitialized)
return metadata;
dnFileInitialized = true;
var dotNetDir = peImage.ImageNTHeaders.OptionalHeader.DataDirectories[14];
if (dotNetDir.VirtualAddress != 0 && dotNetDir.Size >= 0x48) {
metadata = MetadataFactory.CreateMetadata(peImage, false);
dotNetSection = FindSection(dotNetDir.VirtualAddress);
}
return metadata;
}
}
public ImageCor20Header Cor20Header => Metadata.ImageCor20Header;
public DataReader Reader;
public IPEImage PEImage => peImage;
public ImageFileHeader FileHeader => peImage.ImageNTHeaders.FileHeader;
public IImageOptionalHeader OptionalHeader => peImage.ImageNTHeaders.OptionalHeader;
public IList<ImageSectionHeader> Sections => peImage.ImageSectionHeaders;
public uint Length => (uint)Reader.Length;
public MyPEImage(IPEImage peImage) => Initialize(peImage);
public MyPEImage(byte[] peImageData) {
ownPeImage = true;
this.peImageData = peImageData;
Initialize(new PEImage(peImageData));
}
void Initialize(IPEImage peImage) {
this.peImage = peImage;
Reader = peImage.CreateReader();
}
public ImageSectionHeader FindSection(RVA rva) {
foreach (var section in peImage.ImageSectionHeaders) {
if (section.VirtualAddress <= rva && rva < section.VirtualAddress + Math.Max(section.VirtualSize, section.SizeOfRawData))
return section;
}
return null;
}
public ImageSectionHeader FindSection(string name) {
foreach (var section in peImage.ImageSectionHeaders) {
if (section.DisplayName == name)
return section;
}
return null;
}
public void ReadMethodTableRowTo(DumpedMethod dm, uint rid) {
dm.token = 0x06000000 + rid;
if (!Metadata.TablesStream.TryReadMethodRow(rid, out var row))
throw new ArgumentException("Invalid Method rid");
dm.mdRVA = row.RVA;
dm.mdImplFlags = row.ImplFlags;
dm.mdFlags = row.Flags;
dm.mdName = row.Name;
dm.mdSignature = row.Signature;
dm.mdParamList = row.ParamList;
}
public void UpdateMethodHeaderInfo(DumpedMethod dm, MethodBodyHeader mbHeader) {
dm.mhFlags = mbHeader.flags;
dm.mhMaxStack = mbHeader.maxStack;
dm.mhCodeSize = dm.code == null ? 0 : (uint)dm.code.Length;
dm.mhLocalVarSigTok = mbHeader.localVarSigTok;
}
public uint RvaToOffset(uint rva) => (uint)peImage.ToFileOffset((RVA)rva);
static bool IsInside(ImageSectionHeader section, uint offset, uint length) =>
offset >= section.PointerToRawData && offset + length <= section.PointerToRawData + section.SizeOfRawData;
public void WriteUInt32(uint rva, uint data) => OffsetWriteUInt32(RvaToOffset(rva), data);
public void WriteUInt16(uint rva, ushort data) => OffsetWriteUInt16(RvaToOffset(rva), data);
public byte ReadByte(uint rva) => OffsetReadByte(RvaToOffset(rva));
public int ReadInt32(uint rva) => (int)OffsetReadUInt32(RvaToOffset(rva));
public ushort ReadUInt16(uint rva) => OffsetReadUInt16(RvaToOffset(rva));
public byte[] ReadBytes(uint rva, int size) => OffsetReadBytes(RvaToOffset(rva), size);
public void OffsetWriteUInt32(uint offset, uint val) {
peImageData[offset + 0] = (byte)val;
peImageData[offset + 1] = (byte)(val >> 8);
peImageData[offset + 2] = (byte)(val >> 16);
peImageData[offset + 3] = (byte)(val >> 24);
}
public void OffsetWriteUInt16(uint offset, ushort val) {
peImageData[offset + 0] = (byte)val;
peImageData[offset + 1] = (byte)(val >> 8);
}
public uint OffsetReadUInt32(uint offset) {
Reader.Position = offset;
return Reader.ReadUInt32();
}
public ushort OffsetReadUInt16(uint offset) {
Reader.Position = offset;
return Reader.ReadUInt16();
}
public byte OffsetReadByte(uint offset) {
Reader.Position = offset;
return Reader.ReadByte();
}
public byte[] OffsetReadBytes(uint offset, int size) {
Reader.Position = offset;
return Reader.ReadBytes(size);
}
public void OffsetWrite(uint offset, byte[] data) =>
Array.Copy(data, 0, peImageData, offset, data.Length);
bool Intersect(uint offset1, uint length1, uint offset2, uint length2) =>
!(offset1 + length1 <= offset2 || offset2 + length2 <= offset1);
bool Intersect(uint offset, uint length, IFileSection location) =>
Intersect(offset, length, (uint)location.StartOffset, (uint)(location.EndOffset - location.StartOffset));
public bool DotNetSafeWriteOffset(uint offset, byte[] data) {
if (Metadata != null) {
uint length = (uint)data.Length;
if (!IsInside(dotNetSection, offset, length))
return false;
if (Intersect(offset, length, Metadata.ImageCor20Header))
return false;
if (Intersect(offset, length, Metadata.MetadataHeader))
return false;
}
OffsetWrite(offset, data);
return true;
}
public bool DotNetSafeWrite(uint rva, byte[] data) =>
DotNetSafeWriteOffset((uint)peImage.ToFileOffset((RVA)rva), data);
public void Dispose() {
if (ownPeImage) {
if (metadata != null)
metadata.Dispose();
if (peImage != null)
peImage.Dispose();
}
metadata = null;
peImage = null;
Reader = default;
}
}
}