2012-11-18 01:57:36 +08:00
|
|
|
|
using System;
|
2012-11-21 18:14:20 +08:00
|
|
|
|
using System.Collections.Generic;
|
2012-12-20 09:06:09 +08:00
|
|
|
|
using dnlib.IO;
|
|
|
|
|
using dnlib.PE;
|
|
|
|
|
using dnlib.DotNet.MD;
|
2012-11-21 18:14:20 +08:00
|
|
|
|
using de4dot.blocks;
|
2012-11-18 01:57:36 +08:00
|
|
|
|
|
2012-11-21 18:14:20 +08:00
|
|
|
|
namespace de4dot.code.deobfuscators {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
sealed class MyPEImage : IDisposable {
|
|
|
|
|
IPEImage peImage;
|
|
|
|
|
byte[] peImageData;
|
|
|
|
|
IImageStream peStream;
|
2014-05-23 22:19:25 +08:00
|
|
|
|
IMetaData metaData;
|
2012-11-21 18:14:20 +08:00
|
|
|
|
bool dnFileInitialized;
|
2012-11-18 01:57:36 +08:00
|
|
|
|
ImageSectionHeader dotNetSection;
|
|
|
|
|
bool ownPeImage;
|
|
|
|
|
|
2014-05-23 22:19:25 +08:00
|
|
|
|
public IMetaData MetaData {
|
2012-11-21 18:14:20 +08:00
|
|
|
|
get {
|
|
|
|
|
if (dnFileInitialized)
|
2014-05-23 22:19:25 +08:00
|
|
|
|
return metaData;
|
2012-11-21 18:14:20 +08:00
|
|
|
|
dnFileInitialized = true;
|
|
|
|
|
|
|
|
|
|
var dotNetDir = peImage.ImageNTHeaders.OptionalHeader.DataDirectories[14];
|
|
|
|
|
if (dotNetDir.VirtualAddress != 0 && dotNetDir.Size >= 0x48) {
|
2014-05-23 22:19:25 +08:00
|
|
|
|
metaData = MetaDataCreator.CreateMetaData(peImage, false);
|
2013-01-19 20:03:57 +08:00
|
|
|
|
dotNetSection = FindSection(dotNetDir.VirtualAddress);
|
2012-11-21 18:14:20 +08:00
|
|
|
|
}
|
2014-05-23 22:19:25 +08:00
|
|
|
|
return metaData;
|
2012-11-21 18:14:20 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ImageCor20Header Cor20Header {
|
2014-05-23 22:19:25 +08:00
|
|
|
|
get { return MetaData.ImageCor20Header; }
|
2012-11-21 18:14:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IBinaryReader Reader {
|
|
|
|
|
get { return peStream; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-18 01:57:36 +08:00
|
|
|
|
public IPEImage PEImage {
|
|
|
|
|
get { return peImage; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-01 04:04:05 +08:00
|
|
|
|
public ImageFileHeader FileHeader {
|
|
|
|
|
get { return peImage.ImageNTHeaders.FileHeader; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IImageOptionalHeader OptionalHeader {
|
|
|
|
|
get { return peImage.ImageNTHeaders.OptionalHeader; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-21 18:14:20 +08:00
|
|
|
|
public IList<ImageSectionHeader> Sections {
|
|
|
|
|
get { return peImage.ImageSectionHeaders; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-18 01:57:36 +08:00
|
|
|
|
public uint Length {
|
|
|
|
|
get { return (uint)peStream.Length; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public MyPEImage(IPEImage peImage) {
|
2013-01-19 20:03:57 +08:00
|
|
|
|
Initialize(peImage);
|
2012-11-18 01:57:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public MyPEImage(byte[] peImageData) {
|
|
|
|
|
this.ownPeImage = true;
|
|
|
|
|
this.peImageData = peImageData;
|
2013-01-19 20:03:57 +08:00
|
|
|
|
Initialize(new PEImage(peImageData));
|
2012-11-18 01:57:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
void Initialize(IPEImage peImage) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
this.peImage = peImage;
|
|
|
|
|
this.peStream = peImage.CreateFullStream();
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-20 16:25:51 +08:00
|
|
|
|
public ImageSectionHeader FindSection(RVA rva) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
foreach (var section in peImage.ImageSectionHeaders) {
|
|
|
|
|
if (section.VirtualAddress <= rva && rva < section.VirtualAddress + Math.Max(section.VirtualSize, section.SizeOfRawData))
|
|
|
|
|
return section;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public ImageSectionHeader FindSection(string name) {
|
2012-11-21 18:14:20 +08:00
|
|
|
|
foreach (var section in peImage.ImageSectionHeaders) {
|
|
|
|
|
if (section.DisplayName == name)
|
|
|
|
|
return section;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public void ReadMethodTableRowTo(DumpedMethod dm, uint rid) {
|
2012-11-21 18:14:20 +08:00
|
|
|
|
dm.token = 0x06000000 + rid;
|
2014-05-23 22:19:25 +08:00
|
|
|
|
var row = MetaData.TablesStream.ReadMethodRow(rid);
|
2012-11-21 18:14:20 +08:00
|
|
|
|
if (row == null)
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public void UpdateMethodHeaderInfo(DumpedMethod dm, MethodBodyHeader mbHeader) {
|
2012-11-21 18:14:20 +08:00
|
|
|
|
dm.mhFlags = mbHeader.flags;
|
|
|
|
|
dm.mhMaxStack = mbHeader.maxStack;
|
|
|
|
|
dm.mhCodeSize = dm.code == null ? 0 : (uint)dm.code.Length;
|
|
|
|
|
dm.mhLocalVarSigTok = mbHeader.localVarSigTok;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public uint RvaToOffset(uint rva) {
|
2012-11-21 18:14:20 +08:00
|
|
|
|
return (uint)peImage.ToFileOffset((RVA)rva);
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
static bool IsInside(ImageSectionHeader section, uint offset, uint length) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
return offset >= section.PointerToRawData && offset + length <= section.PointerToRawData + section.SizeOfRawData;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public void WriteUInt32(uint rva, uint data) {
|
|
|
|
|
OffsetWriteUInt32(RvaToOffset(rva), data);
|
2012-11-21 18:14:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public void WriteUInt16(uint rva, ushort data) {
|
|
|
|
|
OffsetWriteUInt16(RvaToOffset(rva), data);
|
2012-11-21 18:14:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public byte ReadByte(uint rva) {
|
|
|
|
|
return OffsetReadByte(RvaToOffset(rva));
|
2012-11-21 18:14:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public int ReadInt32(uint rva) {
|
|
|
|
|
return (int)OffsetReadUInt32(RvaToOffset(rva));
|
2012-11-21 18:14:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public ushort ReadUInt16(uint rva) {
|
|
|
|
|
return OffsetReadUInt16(RvaToOffset(rva));
|
2012-11-21 18:14:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public byte[] ReadBytes(uint rva, int size) {
|
|
|
|
|
return OffsetReadBytes(RvaToOffset(rva), size);
|
2012-11-21 18:14:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public void OffsetWriteUInt32(uint offset, uint val) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
peImageData[offset + 0] = (byte)val;
|
|
|
|
|
peImageData[offset + 1] = (byte)(val >> 8);
|
|
|
|
|
peImageData[offset + 2] = (byte)(val >> 16);
|
|
|
|
|
peImageData[offset + 3] = (byte)(val >> 24);
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public void OffsetWriteUInt16(uint offset, ushort val) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
peImageData[offset + 0] = (byte)val;
|
|
|
|
|
peImageData[offset + 1] = (byte)(val >> 8);
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public uint OffsetReadUInt32(uint offset) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
peStream.Position = offset;
|
|
|
|
|
return peStream.ReadUInt32();
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public ushort OffsetReadUInt16(uint offset) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
peStream.Position = offset;
|
|
|
|
|
return peStream.ReadUInt16();
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public byte OffsetReadByte(uint offset) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
peStream.Position = offset;
|
|
|
|
|
return peStream.ReadByte();
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public byte[] OffsetReadBytes(uint offset, int size) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
peStream.Position = offset;
|
|
|
|
|
return peStream.ReadBytes(size);
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public void OffsetWrite(uint offset, byte[] data) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
Array.Copy(data, 0, peImageData, offset, data.Length);
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
bool Intersect(uint offset1, uint length1, uint offset2, uint length2) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
return !(offset1 + length1 <= offset2 || offset2 + length2 <= offset1);
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
bool Intersect(uint offset, uint length, IFileSection location) {
|
|
|
|
|
return Intersect(offset, length, (uint)location.StartOffset, (uint)(location.EndOffset - location.StartOffset));
|
2012-11-18 01:57:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public bool DotNetSafeWriteOffset(uint offset, byte[] data) {
|
2014-05-23 22:19:25 +08:00
|
|
|
|
if (MetaData != null) {
|
2012-11-18 01:57:36 +08:00
|
|
|
|
uint length = (uint)data.Length;
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
if (!IsInside(dotNetSection, offset, length))
|
2012-11-18 01:57:36 +08:00
|
|
|
|
return false;
|
2014-05-23 22:19:25 +08:00
|
|
|
|
if (Intersect(offset, length, MetaData.ImageCor20Header))
|
2012-11-18 01:57:36 +08:00
|
|
|
|
return false;
|
2014-05-23 22:19:25 +08:00
|
|
|
|
if (Intersect(offset, length, MetaData.MetaDataHeader))
|
2012-11-18 01:57:36 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
OffsetWrite(offset, data);
|
2012-11-18 01:57:36 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public bool DotNetSafeWrite(uint rva, byte[] data) {
|
|
|
|
|
return DotNetSafeWriteOffset((uint)peImage.ToFileOffset((RVA)rva), data);
|
2012-11-18 01:57:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose() {
|
|
|
|
|
if (ownPeImage) {
|
2014-05-23 22:19:25 +08:00
|
|
|
|
if (metaData != null)
|
|
|
|
|
metaData.Dispose();
|
2012-11-18 01:57:36 +08:00
|
|
|
|
if (peImage != null)
|
|
|
|
|
peImage.Dispose();
|
|
|
|
|
}
|
|
|
|
|
if (peStream != null)
|
|
|
|
|
peStream.Dispose();
|
|
|
|
|
|
2014-05-23 22:19:25 +08:00
|
|
|
|
metaData = null;
|
2012-11-18 01:57:36 +08:00
|
|
|
|
peImage = null;
|
|
|
|
|
peStream = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|