Dnspy/Extensions/dnSpy.AsmEditor/SaveModule/SaveModuleOptionsVM.cs
2021-09-20 18:20:01 +02:00

1136 lines
39 KiB
C#

/*
Copyright (C) 2014-2019 de4dot@gmail.com
This file is part of dnSpy
dnSpy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
dnSpy is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with dnSpy. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Text;
using System.Windows.Input;
using dnlib.DotNet;
using dnlib.DotNet.MD;
using dnlib.DotNet.Writer;
using dnlib.PE;
using dnlib.W32Resources;
using dnSpy.AsmEditor.Properties;
using dnSpy.Contracts.Documents;
using dnSpy.Contracts.MVVM;
namespace dnSpy.AsmEditor.SaveModule {
sealed class SaveModuleOptionsVM : SaveOptionsVM {
public override SaveOptionsType Type => SaveOptionsType.Module;
public ModuleDef Module { get; }
public override object UndoDocument => document;
readonly IDsDocument document;
public ICommand ReinitializeCommand => new RelayCommand(a => Reinitialize());
public bool CanSaveMixedModeModule => Module is ModuleDefMD;
public bool IsMixedModeModule => CanSaveMixedModeModule && !Module.IsILOnly;
public bool CanPreserveOtherMetadataStreams => Module is ModuleDefMD;
public bool UseMixedMode {
get => useMixedMode;
set {
if (useMixedMode != value) {
useMixedMode = value;
OnPropertyChanged(nameof(UseMixedMode));
ReinitializeModuleWriterOptions();
}
}
}
bool useMixedMode;
public bool CanWritePdb => Module.PdbState is not null;
public bool WritePdb {
get => writePdb;
set {
if (writePdb != value) {
writePdb = value;
OnPropertyChanged(nameof(WritePdb));
}
}
}
bool writePdb;
public bool ShareMethodBodies {
get => shareMethodBodies;
set {
if (value != shareMethodBodies) {
shareMethodBodies = value;
OnPropertyChanged(nameof(ShareMethodBodies));
}
}
}
bool shareMethodBodies;
public bool AddCheckSum {
get => addCheckSum;
set {
if (value != addCheckSum) {
addCheckSum = value;
OnPropertyChanged(nameof(AddCheckSum));
}
}
}
bool addCheckSum;
public Win32Resources? Win32Resources {
get => win32Resources;
set {
if (win32Resources != value) {
win32Resources = value;
OnPropertyChanged(nameof(Win32Resources));
}
}
}
Win32Resources? win32Resources;
public bool KeepExtraPEData {
get => keepExtraPEData;
set {
if (keepExtraPEData != value) {
keepExtraPEData = value;
OnPropertyChanged(nameof(KeepExtraPEData));
}
}
}
bool keepExtraPEData;
public bool KeepWin32Resources {
get => keepWin32Resources;
set {
if (keepWin32Resources != value) {
keepWin32Resources = value;
OnPropertyChanged(nameof(KeepWin32Resources));
}
}
}
bool keepWin32Resources;
internal static readonly EnumVM[] moduleKindList = EnumVM.Create(typeof(ModuleKind));
public EnumListVM ModuleKind { get; }
public string Extension {
get {
switch ((ModuleKind)ModuleKind.SelectedItem!) {
case dnlib.DotNet.ModuleKind.Console:
case dnlib.DotNet.ModuleKind.Windows:
default:
return "exe";
case dnlib.DotNet.ModuleKind.Dll:
return "dll";
case dnlib.DotNet.ModuleKind.NetModule:
return "netmodule";
}
}
}
public PEHeadersOptionsVM PEHeadersOptions { get; }
public Cor20HeaderOptionsVM Cor20HeaderOptions { get; }
public MetadataOptionsVM MetadataOptions { get; }
public SaveModuleOptionsVM(IDsDocument document) {
this.document = document;
Module = document.ModuleDef!;
PEHeadersOptions = new PEHeadersOptionsVM(Module.Machine, GetSubsystem(Module.Kind));
Cor20HeaderOptions = new Cor20HeaderOptionsVM();
MetadataOptions = new MetadataOptionsVM(Module);
PEHeadersOptions.PropertyChanged += (s, e) => HasErrorUpdated();
Cor20HeaderOptions.PropertyChanged += (s, e) => HasErrorUpdated();
MetadataOptions.PropertyChanged += (s, e) => HasErrorUpdated();
ModuleKind = new EnumListVM(moduleKindList, (a, b) => {
OnPropertyChanged(nameof(Extension));
PEHeadersOptions.Subsystem.SelectedItem = GetSubsystem((ModuleKind)ModuleKind!.SelectedItem!);
PEHeadersOptions.Characteristics = CharacteristicsHelper.GetCharacteristics(PEHeadersOptions.Characteristics ?? 0, (ModuleKind)ModuleKind.SelectedItem!);
});
Reinitialize();
}
static Subsystem GetSubsystem(ModuleKind moduleKind) {
if (moduleKind == dnlib.DotNet.ModuleKind.Windows)
return Subsystem.WindowsGui;
return Subsystem.WindowsCui;
}
void Reinitialize() {
FileName = Module.Location;
OriginalFileName = Module.Location;
if (UseMixedMode == IsMixedModeModule)
ReinitializeModuleWriterOptions();
else
UseMixedMode = IsMixedModeModule;
}
void ReinitializeModuleWriterOptions() {
if (UseMixedMode)
InitializeFrom(new NativeModuleWriterOptions((ModuleDefMD)Module, optimizeImageSize: true));
else
InitializeFrom(new ModuleWriterOptions(Module));
WritePdb = CanWritePdb;
}
public ModuleWriterOptionsBase CreateWriterOptions() {
if (UseMixedMode) {
var options = new NativeModuleWriterOptions((ModuleDefMD)Module, optimizeImageSize: true);
CopyTo(options);
options.KeepExtraPEData = KeepExtraPEData;
options.KeepWin32Resources = KeepWin32Resources;
return AddOtherOptions(options);
}
else {
var options = new ModuleWriterOptions(Module);
CopyTo(options);
if (Module.ManagedEntryPoint is not null || Module.NativeEntryPoint == 0)
options.Cor20HeaderOptions.Flags &= ~ComImageFlags.NativeEntryPoint;
return AddOtherOptions(options);
}
}
ModuleWriterOptionsBase AddOtherOptions(ModuleWriterOptionsBase options) {
if (MetadataOptions.PreserveOtherMetadataStreams)
options.MetadataOptions.PreserveHeapOrder(Module, addCustomHeaps: true);
return options;
}
void CopyTo(ModuleWriterOptionsBase options) {
PEHeadersOptions.CopyTo(options.PEHeadersOptions);
Cor20HeaderOptions.CopyTo(options.Cor20HeaderOptions);
MetadataOptions.CopyTo(options.MetadataOptions);
options.WritePdb = WritePdb;
options.ShareMethodBodies = ShareMethodBodies;
options.AddCheckSum = AddCheckSum;
options.Win32Resources = Win32Resources;
options.ModuleKind = (ModuleKind)ModuleKind.SelectedItem!;
}
public SaveModuleOptionsVM Clone() => CopyTo(new SaveModuleOptionsVM(document));
public SaveModuleOptionsVM CopyTo(SaveModuleOptionsVM other) {
other.FileName = FileName;
other.OriginalFileName = OriginalFileName;
other.UseMixedMode = UseMixedMode;
other.MetadataOptions.PreserveOtherMetadataStreams = MetadataOptions.PreserveOtherMetadataStreams;
other.InitializeFrom(CreateWriterOptions());
return other;
}
public void InitializeFrom(ModuleWriterOptionsBase options) {
if (options is ModuleWriterOptions)
InitializeFrom((ModuleWriterOptions)options);
else
InitializeFrom((NativeModuleWriterOptions)options);
}
public void InitializeFrom(ModuleWriterOptions options) {
InitializeFromInternal((ModuleWriterOptionsBase)options);
KeepExtraPEData = false;
KeepWin32Resources = false;
}
public void InitializeFrom(NativeModuleWriterOptions options) {
InitializeFromInternal((ModuleWriterOptionsBase)options);
KeepExtraPEData = options.KeepExtraPEData;
KeepWin32Resources = options.KeepWin32Resources;
}
void InitializeFromInternal(ModuleWriterOptionsBase options) {
// Writing to it triggers a write to Subsystem so write it first
ModuleKind.SelectedItem = options.ModuleKind;
PEHeadersOptions.InitializeFrom(options.PEHeadersOptions);
Cor20HeaderOptions.InitializeFrom(options.Cor20HeaderOptions);
MetadataOptions.InitializeFrom(options.MetadataOptions);
WritePdb = options.WritePdb;
ShareMethodBodies = options.ShareMethodBodies;
AddCheckSum = options.AddCheckSum;
Win32Resources = options.Win32Resources;
// Writing to Machine and ModuleKind triggers code that updates Characteristics
PEHeadersOptions.Characteristics = options.PEHeadersOptions.Characteristics;
}
protected override string GetExtension(string filename) => Extension;
public override bool HasError {
get {
return base.HasError ||
PEHeadersOptions.HasError ||
Cor20HeaderOptions.HasError ||
MetadataOptions.HasError;
}
}
}
sealed class PEHeadersOptionsVM : ViewModelBase {
readonly Machine defaultMachine;
readonly Subsystem defaultSubsystem;
public PEHeadersOptionsVM(Machine defaultMachine, Subsystem defaultSubsystem) {
this.defaultMachine = defaultMachine;
this.defaultSubsystem = defaultSubsystem;
Machine = new EnumListVM(machineList, (a, b) => {
Characteristics = CharacteristicsHelper.GetCharacteristics(Characteristics ?? 0, (dnlib.PE.Machine)Machine!.SelectedItem!);
});
TimeDateStamp = new NullableUInt32VM(a => HasErrorUpdated());
PointerToSymbolTable = new NullableUInt32VM(a => HasErrorUpdated());
NumberOfSymbols = new NullableUInt32VM(a => HasErrorUpdated());
MajorLinkerVersion = new NullableByteVM(a => HasErrorUpdated());
MinorLinkerVersion = new NullableByteVM(a => HasErrorUpdated());
ImageBase = new NullableUInt64VM(a => HasErrorUpdated());
SectionAlignment = new NullableUInt32VM(a => HasErrorUpdated());
FileAlignment = new NullableUInt32VM(a => HasErrorUpdated());
MajorOperatingSystemVersion = new NullableUInt16VM(a => HasErrorUpdated());
MinorOperatingSystemVersion = new NullableUInt16VM(a => HasErrorUpdated());
MajorImageVersion = new NullableUInt16VM(a => HasErrorUpdated());
MinorImageVersion = new NullableUInt16VM(a => HasErrorUpdated());
MajorSubsystemVersion = new NullableUInt16VM(a => HasErrorUpdated());
MinorSubsystemVersion = new NullableUInt16VM(a => HasErrorUpdated());
Win32VersionValue = new NullableUInt32VM(a => HasErrorUpdated());
SizeOfStackReserve = new NullableUInt64VM(a => HasErrorUpdated());
SizeOfStackCommit = new NullableUInt64VM(a => HasErrorUpdated());
SizeOfHeapReserve = new NullableUInt64VM(a => HasErrorUpdated());
SizeOfHeapCommit = new NullableUInt64VM(a => HasErrorUpdated());
LoaderFlags = new NullableUInt32VM(a => HasErrorUpdated());
NumberOfRvaAndSizes = new NullableUInt32VM(a => HasErrorUpdated());
}
internal static readonly EnumVM[] machineList = EnumVM.Create(typeof(dnlib.PE.Machine), dnlib.PE.Machine.I386, dnlib.PE.Machine.AMD64, dnlib.PE.Machine.IA64, dnlib.PE.Machine.ARMNT, dnlib.PE.Machine.ARM64);
public EnumListVM Machine { get; }
public NullableUInt32VM TimeDateStamp { get; }
public NullableUInt32VM PointerToSymbolTable { get; }
public NullableUInt32VM NumberOfSymbols { get; }
public Characteristics? Characteristics {
get => characteristics;
set {
if (characteristics != value) {
characteristics = value;
OnPropertyChanged(nameof(Characteristics));
OnPropertyChanged(nameof(RelocsStripped));
OnPropertyChanged(nameof(ExecutableImage));
OnPropertyChanged(nameof(LineNumsStripped));
OnPropertyChanged(nameof(LocalSymsStripped));
OnPropertyChanged(nameof(AggressiveWsTrim));
OnPropertyChanged(nameof(LargeAddressAware));
OnPropertyChanged(nameof(CharacteristicsReserved1));
OnPropertyChanged(nameof(BytesReversedLo));
OnPropertyChanged(nameof(Bit32Machine));
OnPropertyChanged(nameof(DebugStripped));
OnPropertyChanged(nameof(RemovableRunFromSwap));
OnPropertyChanged(nameof(NetRunFromSwap));
OnPropertyChanged(nameof(System));
OnPropertyChanged(nameof(Dll));
OnPropertyChanged(nameof(UpSystemOnly));
OnPropertyChanged(nameof(BytesReversedHi));
}
}
}
Characteristics? characteristics;
public bool? RelocsStripped {
get => GetFlagValue(dnlib.PE.Characteristics.RelocsStripped);
set => SetFlagValue(dnlib.PE.Characteristics.RelocsStripped, value);
}
public bool? ExecutableImage {
get => GetFlagValue(dnlib.PE.Characteristics.ExecutableImage);
set => SetFlagValue(dnlib.PE.Characteristics.ExecutableImage, value);
}
public bool? LineNumsStripped {
get => GetFlagValue(dnlib.PE.Characteristics.LineNumsStripped);
set => SetFlagValue(dnlib.PE.Characteristics.LineNumsStripped, value);
}
public bool? LocalSymsStripped {
get => GetFlagValue(dnlib.PE.Characteristics.LocalSymsStripped);
set => SetFlagValue(dnlib.PE.Characteristics.LocalSymsStripped, value);
}
public bool? AggressiveWsTrim {
get => GetFlagValue(dnlib.PE.Characteristics.AggressiveWsTrim);
set => SetFlagValue(dnlib.PE.Characteristics.AggressiveWsTrim, value);
}
public bool? LargeAddressAware {
get => GetFlagValue(dnlib.PE.Characteristics.LargeAddressAware);
set => SetFlagValue(dnlib.PE.Characteristics.LargeAddressAware, value);
}
public bool? CharacteristicsReserved1 {
get => GetFlagValue(dnlib.PE.Characteristics.Reserved1);
set => SetFlagValue(dnlib.PE.Characteristics.Reserved1, value);
}
public bool? BytesReversedLo {
get => GetFlagValue(dnlib.PE.Characteristics.BytesReversedLo);
set => SetFlagValue(dnlib.PE.Characteristics.BytesReversedLo, value);
}
public bool? Bit32Machine {
get => GetFlagValue(dnlib.PE.Characteristics.Bit32Machine);
set => SetFlagValue(dnlib.PE.Characteristics.Bit32Machine, value);
}
public bool? DebugStripped {
get => GetFlagValue(dnlib.PE.Characteristics.DebugStripped);
set => SetFlagValue(dnlib.PE.Characteristics.DebugStripped, value);
}
public bool? RemovableRunFromSwap {
get => GetFlagValue(dnlib.PE.Characteristics.RemovableRunFromSwap);
set => SetFlagValue(dnlib.PE.Characteristics.RemovableRunFromSwap, value);
}
public bool? NetRunFromSwap {
get => GetFlagValue(dnlib.PE.Characteristics.NetRunFromSwap);
set => SetFlagValue(dnlib.PE.Characteristics.NetRunFromSwap, value);
}
public bool? System {
get => GetFlagValue(dnlib.PE.Characteristics.System);
set => SetFlagValue(dnlib.PE.Characteristics.System, value);
}
public bool? Dll {
get => GetFlagValue(dnlib.PE.Characteristics.Dll);
set => SetFlagValue(dnlib.PE.Characteristics.Dll, value);
}
public bool? UpSystemOnly {
get => GetFlagValue(dnlib.PE.Characteristics.UpSystemOnly);
set => SetFlagValue(dnlib.PE.Characteristics.UpSystemOnly, value);
}
public bool? BytesReversedHi {
get => GetFlagValue(dnlib.PE.Characteristics.BytesReversedHi);
set => SetFlagValue(dnlib.PE.Characteristics.BytesReversedHi, value);
}
bool? GetFlagValue(Characteristics flag) => Characteristics is null ? (bool?)null : (Characteristics.Value & flag) != 0;
void SetFlagValue(Characteristics flag, bool? value) {
if (Characteristics is null)
Characteristics = 0;
if (value ?? false)
Characteristics |= flag;
else
Characteristics &= ~flag;
}
public NullableByteVM MajorLinkerVersion { get; }
public NullableByteVM MinorLinkerVersion { get; }
public NullableUInt64VM ImageBase { get; }
public NullableUInt32VM SectionAlignment { get; }
public NullableUInt32VM FileAlignment { get; }
public NullableUInt16VM MajorOperatingSystemVersion { get; }
public NullableUInt16VM MinorOperatingSystemVersion { get; }
public NullableUInt16VM MajorImageVersion { get; }
public NullableUInt16VM MinorImageVersion { get; }
public NullableUInt16VM MajorSubsystemVersion { get; }
public NullableUInt16VM MinorSubsystemVersion { get; }
public NullableUInt32VM Win32VersionValue { get; }
static readonly EnumVM[] subsystemList = EnumVM.Create(typeof(dnlib.PE.Subsystem), dnlib.PE.Subsystem.WindowsGui, dnlib.PE.Subsystem.WindowsCui);
public EnumListVM Subsystem { get; } = new EnumListVM(subsystemList);
public DllCharacteristics? DllCharacteristics {
get => dllCharacteristics;
set {
if (dllCharacteristics != value) {
dllCharacteristics = value;
OnPropertyChanged(nameof(DllCharacteristics));
OnPropertyChanged(nameof(DllCharacteristicsReserved1));
OnPropertyChanged(nameof(DllCharacteristicsReserved2));
OnPropertyChanged(nameof(DllCharacteristicsReserved3));
OnPropertyChanged(nameof(DllCharacteristicsReserved4));
OnPropertyChanged(nameof(DllCharacteristicsReserved5));
OnPropertyChanged(nameof(HighEntropyVA));
OnPropertyChanged(nameof(DynamicBase));
OnPropertyChanged(nameof(ForceIntegrity));
OnPropertyChanged(nameof(NxCompat));
OnPropertyChanged(nameof(NoIsolation));
OnPropertyChanged(nameof(NoSeh));
OnPropertyChanged(nameof(NoBind));
OnPropertyChanged(nameof(AppContainer));
OnPropertyChanged(nameof(WdmDriver));
OnPropertyChanged(nameof(GuardCf));
OnPropertyChanged(nameof(TerminalServerAware));
}
}
}
DllCharacteristics? dllCharacteristics;
public bool? DllCharacteristicsReserved1 {
get => GetFlagValue(dnlib.PE.DllCharacteristics.Reserved1);
set => SetFlagValue(dnlib.PE.DllCharacteristics.Reserved1, value);
}
public bool? DllCharacteristicsReserved2 {
get => GetFlagValue(dnlib.PE.DllCharacteristics.Reserved2);
set => SetFlagValue(dnlib.PE.DllCharacteristics.Reserved2, value);
}
public bool? DllCharacteristicsReserved3 {
get => GetFlagValue(dnlib.PE.DllCharacteristics.Reserved3);
set => SetFlagValue(dnlib.PE.DllCharacteristics.Reserved3, value);
}
public bool? DllCharacteristicsReserved4 {
get => GetFlagValue(dnlib.PE.DllCharacteristics.Reserved4);
set => SetFlagValue(dnlib.PE.DllCharacteristics.Reserved4, value);
}
public bool? DllCharacteristicsReserved5 {
get => GetFlagValue(dnlib.PE.DllCharacteristics.Reserved5);
set => SetFlagValue(dnlib.PE.DllCharacteristics.Reserved5, value);
}
public bool? HighEntropyVA {
get => GetFlagValue(dnlib.PE.DllCharacteristics.HighEntropyVA);
set => SetFlagValue(dnlib.PE.DllCharacteristics.HighEntropyVA, value);
}
public bool? DynamicBase {
get => GetFlagValue(dnlib.PE.DllCharacteristics.DynamicBase);
set => SetFlagValue(dnlib.PE.DllCharacteristics.DynamicBase, value);
}
public bool? ForceIntegrity {
get => GetFlagValue(dnlib.PE.DllCharacteristics.ForceIntegrity);
set => SetFlagValue(dnlib.PE.DllCharacteristics.ForceIntegrity, value);
}
public bool? NxCompat {
get => GetFlagValue(dnlib.PE.DllCharacteristics.NxCompat);
set => SetFlagValue(dnlib.PE.DllCharacteristics.NxCompat, value);
}
public bool? NoIsolation {
get => GetFlagValue(dnlib.PE.DllCharacteristics.NoIsolation);
set => SetFlagValue(dnlib.PE.DllCharacteristics.NoIsolation, value);
}
public bool? NoSeh {
get => GetFlagValue(dnlib.PE.DllCharacteristics.NoSeh);
set => SetFlagValue(dnlib.PE.DllCharacteristics.NoSeh, value);
}
public bool? NoBind {
get => GetFlagValue(dnlib.PE.DllCharacteristics.NoBind);
set => SetFlagValue(dnlib.PE.DllCharacteristics.NoBind, value);
}
public bool? AppContainer {
get => GetFlagValue(dnlib.PE.DllCharacteristics.AppContainer);
set => SetFlagValue(dnlib.PE.DllCharacteristics.AppContainer, value);
}
public bool? WdmDriver {
get => GetFlagValue(dnlib.PE.DllCharacteristics.WdmDriver);
set => SetFlagValue(dnlib.PE.DllCharacteristics.WdmDriver, value);
}
public bool? GuardCf {
get => GetFlagValue(dnlib.PE.DllCharacteristics.GuardCf);
set => SetFlagValue(dnlib.PE.DllCharacteristics.GuardCf, value);
}
public bool? TerminalServerAware {
get => GetFlagValue(dnlib.PE.DllCharacteristics.TerminalServerAware);
set => SetFlagValue(dnlib.PE.DllCharacteristics.TerminalServerAware, value);
}
bool? GetFlagValue(DllCharacteristics flag) => DllCharacteristics is null ? (bool?)null : (DllCharacteristics.Value & flag) != 0;
void SetFlagValue(DllCharacteristics flag, bool? value) {
if (DllCharacteristics is null)
DllCharacteristics = 0;
if (value ?? false)
DllCharacteristics |= flag;
else
DllCharacteristics &= ~flag;
}
public NullableUInt64VM SizeOfStackReserve { get; }
public NullableUInt64VM SizeOfStackCommit { get; }
public NullableUInt64VM SizeOfHeapReserve { get; }
public NullableUInt64VM SizeOfHeapCommit { get; }
public NullableUInt32VM LoaderFlags { get; }
public NullableUInt32VM NumberOfRvaAndSizes { get; }
public void CopyTo(PEHeadersOptions options) {
options.Machine = (dnlib.PE.Machine)Machine.SelectedItem!;
options.TimeDateStamp = TimeDateStamp.Value;
options.PointerToSymbolTable = PointerToSymbolTable.Value;
options.NumberOfSymbols = NumberOfSymbols.Value;
options.Characteristics = Characteristics;
options.MajorLinkerVersion = MajorLinkerVersion.Value;
options.MinorLinkerVersion = MinorLinkerVersion.Value;
options.ImageBase = ImageBase.Value;
options.SectionAlignment = SectionAlignment.Value;
options.FileAlignment = FileAlignment.Value;
options.MajorOperatingSystemVersion = MajorOperatingSystemVersion.Value;
options.MinorOperatingSystemVersion = MinorOperatingSystemVersion.Value;
options.MajorImageVersion = MajorImageVersion.Value;
options.MinorImageVersion = MinorImageVersion.Value;
options.MajorSubsystemVersion = MajorSubsystemVersion.Value;
options.MinorSubsystemVersion = MinorSubsystemVersion.Value;
options.Win32VersionValue = Win32VersionValue.Value;
options.Subsystem = (dnlib.PE.Subsystem)Subsystem.SelectedItem!;
options.DllCharacteristics = DllCharacteristics;
options.SizeOfStackReserve = SizeOfStackReserve.Value;
options.SizeOfStackCommit = SizeOfStackCommit.Value;
options.SizeOfHeapReserve = SizeOfHeapReserve.Value;
options.SizeOfHeapCommit = SizeOfHeapCommit.Value;
options.LoaderFlags = LoaderFlags.Value;
options.NumberOfRvaAndSizes = NumberOfRvaAndSizes.Value;
}
public void InitializeFrom(PEHeadersOptions options) {
Machine.SelectedItem = options.Machine ?? defaultMachine;
TimeDateStamp.Value = options.TimeDateStamp;
PointerToSymbolTable.Value = options.PointerToSymbolTable;
NumberOfSymbols.Value = options.NumberOfSymbols;
Characteristics = options.Characteristics;
MajorLinkerVersion.Value = options.MajorLinkerVersion;
MinorLinkerVersion.Value = options.MinorLinkerVersion;
ImageBase.Value = options.ImageBase;
SectionAlignment.Value = options.SectionAlignment;
FileAlignment.Value = options.FileAlignment;
MajorOperatingSystemVersion.Value = options.MajorOperatingSystemVersion;
MinorOperatingSystemVersion.Value = options.MinorOperatingSystemVersion;
MajorImageVersion.Value = options.MajorImageVersion;
MinorImageVersion.Value = options.MinorImageVersion;
MajorSubsystemVersion.Value = options.MajorSubsystemVersion;
MinorSubsystemVersion.Value = options.MinorSubsystemVersion;
Win32VersionValue.Value = options.Win32VersionValue;
Subsystem.SelectedItem = options.Subsystem ?? defaultSubsystem;
DllCharacteristics = options.DllCharacteristics;
SizeOfStackReserve.Value = options.SizeOfStackReserve;
SizeOfStackCommit.Value = options.SizeOfStackCommit;
SizeOfHeapReserve.Value = options.SizeOfHeapReserve;
SizeOfHeapCommit.Value = options.SizeOfHeapCommit;
LoaderFlags.Value = options.LoaderFlags;
NumberOfRvaAndSizes.Value = options.NumberOfRvaAndSizes;
}
public override bool HasError {
get {
return TimeDateStamp.HasError ||
PointerToSymbolTable.HasError ||
NumberOfSymbols.HasError ||
MajorLinkerVersion.HasError ||
MinorLinkerVersion.HasError ||
ImageBase.HasError ||
SectionAlignment.HasError ||
FileAlignment.HasError ||
MajorOperatingSystemVersion.HasError ||
MinorOperatingSystemVersion.HasError ||
MajorImageVersion.HasError ||
MinorImageVersion.HasError ||
MajorSubsystemVersion.HasError ||
MinorSubsystemVersion.HasError ||
Win32VersionValue.HasError ||
SizeOfStackReserve.HasError ||
SizeOfStackCommit.HasError ||
SizeOfHeapReserve.HasError ||
SizeOfHeapCommit.HasError ||
LoaderFlags.HasError ||
NumberOfRvaAndSizes.HasError;
}
}
}
sealed class Cor20HeaderOptionsVM : ViewModelBase {
public Cor20HeaderOptionsVM() {
MajorRuntimeVersion = new NullableUInt16VM(a => HasErrorUpdated());
MinorRuntimeVersion = new NullableUInt16VM(a => HasErrorUpdated());
EntryPoint = new NullableUInt32VM(a => HasErrorUpdated());
}
public NullableUInt16VM MajorRuntimeVersion { get; }
public NullableUInt16VM MinorRuntimeVersion { get; }
public ComImageFlags? Flags {
get => flags;
set {
if (flags != value) {
flags = value;
OnPropertyChanged(nameof(Flags));
OnPropertyChanged(nameof(ILOnly));
OnPropertyChanged(nameof(Bit32Required));
OnPropertyChanged(nameof(ILLibrary));
OnPropertyChanged(nameof(StrongNameSigned));
OnPropertyChanged(nameof(TrackDebugData));
OnPropertyChanged(nameof(Bit32Preferred));
}
}
}
ComImageFlags? flags;
public bool? ILOnly {
get => GetFlagValue(ComImageFlags.ILOnly);
set => SetFlagValue(ComImageFlags.ILOnly, value);
}
public bool? Bit32Required {
get => GetFlagValue(ComImageFlags.Bit32Required);
set => SetFlagValue(ComImageFlags.Bit32Required, value);
}
public bool? ILLibrary {
get => GetFlagValue(ComImageFlags.ILLibrary);
set => SetFlagValue(ComImageFlags.ILLibrary, value);
}
public bool? StrongNameSigned {
get => GetFlagValue(ComImageFlags.StrongNameSigned);
set => SetFlagValue(ComImageFlags.StrongNameSigned, value);
}
public bool? TrackDebugData {
get => GetFlagValue(ComImageFlags.TrackDebugData);
set => SetFlagValue(ComImageFlags.TrackDebugData, value);
}
public bool? Bit32Preferred {
get => GetFlagValue(ComImageFlags.Bit32Preferred);
set => SetFlagValue(ComImageFlags.Bit32Preferred, value);
}
bool? GetFlagValue(ComImageFlags flag) => Flags is null ? (bool?)null : (Flags.Value & flag) != 0;
void SetFlagValue(ComImageFlags flag, bool? value) {
if (Flags is null)
Flags = 0;
if (value ?? false)
Flags |= flag;
else
Flags &= ~flag;
}
public NullableUInt32VM EntryPoint { get; }
public void CopyTo(Cor20HeaderOptions options) {
options.MajorRuntimeVersion = MajorRuntimeVersion.Value;
options.MinorRuntimeVersion = MinorRuntimeVersion.Value;
options.Flags = Flags;
options.EntryPoint = EntryPoint.Value;
}
public void InitializeFrom(Cor20HeaderOptions options) {
MajorRuntimeVersion.Value = options.MajorRuntimeVersion;
MinorRuntimeVersion.Value = options.MinorRuntimeVersion;
Flags = options.Flags;
EntryPoint.Value = options.EntryPoint;
}
public override bool HasError {
get {
return MajorRuntimeVersion.HasError ||
MinorRuntimeVersion.HasError ||
EntryPoint.HasError;
}
}
}
sealed class MetadataOptionsVM : ViewModelBase {
readonly ModuleDef module;
public MetadataOptionsVM(ModuleDef module) {
this.module = module;
MetadataHeaderOptions = new MetadataHeaderOptionsVM();
TablesHeapOptions = new TablesHeapOptionsVM();
MetadataHeaderOptions.PropertyChanged += (s, e) => HasErrorUpdated();
TablesHeapOptions.PropertyChanged += (s, e) => HasErrorUpdated();
}
public MetadataHeaderOptionsVM MetadataHeaderOptions { get; }
public TablesHeapOptionsVM TablesHeapOptions { get; }
public MetadataFlags Flags {
get => flags;
set {
if (flags != value) {
flags = value;
OnPropertyChanged(nameof(Flags));
}
}
}
MetadataFlags flags;
public bool PreserveTypeRefRids {
get => GetFlagValue(MetadataFlags.PreserveTypeRefRids);
set => SetFlagValue(MetadataFlags.PreserveTypeRefRids, value, nameof(PreserveRids), nameof(PreserveTypeRefRids));
}
public bool PreserveTypeDefRids {
get => GetFlagValue(MetadataFlags.PreserveTypeDefRids);
set => SetFlagValue(MetadataFlags.PreserveTypeDefRids, value, nameof(PreserveRids), nameof(PreserveTypeDefRids));
}
public bool PreserveFieldRids {
get => GetFlagValue(MetadataFlags.PreserveFieldRids);
set => SetFlagValue(MetadataFlags.PreserveFieldRids, value, nameof(PreserveRids), nameof(PreserveFieldRids));
}
public bool PreserveMethodRids {
get => GetFlagValue(MetadataFlags.PreserveMethodRids);
set => SetFlagValue(MetadataFlags.PreserveMethodRids, value, nameof(PreserveRids), nameof(PreserveMethodRids));
}
public bool PreserveParamRids {
get => GetFlagValue(MetadataFlags.PreserveParamRids);
set => SetFlagValue(MetadataFlags.PreserveParamRids, value, nameof(PreserveRids), nameof(PreserveParamRids));
}
public bool PreserveMemberRefRids {
get => GetFlagValue(MetadataFlags.PreserveMemberRefRids);
set => SetFlagValue(MetadataFlags.PreserveMemberRefRids, value, nameof(PreserveRids), nameof(PreserveMemberRefRids));
}
public bool PreserveStandAloneSigRids {
get => GetFlagValue(MetadataFlags.PreserveStandAloneSigRids);
set => SetFlagValue(MetadataFlags.PreserveStandAloneSigRids, value, nameof(PreserveRids), nameof(PreserveStandAloneSigRids));
}
public bool PreserveEventRids {
get => GetFlagValue(MetadataFlags.PreserveEventRids);
set => SetFlagValue(MetadataFlags.PreserveEventRids, value, nameof(PreserveRids), nameof(PreserveEventRids));
}
public bool PreservePropertyRids {
get => GetFlagValue(MetadataFlags.PreservePropertyRids);
set => SetFlagValue(MetadataFlags.PreservePropertyRids, value, nameof(PreserveRids), nameof(PreservePropertyRids));
}
public bool PreserveTypeSpecRids {
get => GetFlagValue(MetadataFlags.PreserveTypeSpecRids);
set => SetFlagValue(MetadataFlags.PreserveTypeSpecRids, value, nameof(PreserveRids), nameof(PreserveTypeSpecRids));
}
public bool PreserveMethodSpecRids {
get => GetFlagValue(MetadataFlags.PreserveMethodSpecRids);
set => SetFlagValue(MetadataFlags.PreserveMethodSpecRids, value, nameof(PreserveRids), nameof(PreserveMethodSpecRids));
}
public bool? PreserveRids {
get {
var val = Flags & MetadataFlags.PreserveRids;
if (val == MetadataFlags.PreserveRids)
return true;
if (val == 0)
return false;
return null;
}
set {
if (value is not null && value != PreserveRids) {
if (value.Value)
Flags |= MetadataFlags.PreserveRids;
else
Flags &= ~MetadataFlags.PreserveRids;
OnPropertyChanged(nameof(PreserveRids));
OnPropertyChanged(nameof(PreserveTypeRefRids));
OnPropertyChanged(nameof(PreserveTypeDefRids));
OnPropertyChanged(nameof(PreserveFieldRids));
OnPropertyChanged(nameof(PreserveMethodRids));
OnPropertyChanged(nameof(PreserveParamRids));
OnPropertyChanged(nameof(PreserveMemberRefRids));
OnPropertyChanged(nameof(PreserveStandAloneSigRids));
OnPropertyChanged(nameof(PreserveEventRids));
OnPropertyChanged(nameof(PreservePropertyRids));
OnPropertyChanged(nameof(PreserveTypeSpecRids));
OnPropertyChanged(nameof(PreserveMethodSpecRids));
}
}
}
public bool PreserveStringsOffsets {
get => GetFlagValue(MetadataFlags.PreserveStringsOffsets);
set => SetFlagValue(MetadataFlags.PreserveStringsOffsets, value, nameof(PreserveStringsOffsets));
}
public bool PreserveUSOffsets {
get => GetFlagValue(MetadataFlags.PreserveUSOffsets);
set => SetFlagValue(MetadataFlags.PreserveUSOffsets, value, nameof(PreserveUSOffsets));
}
public bool PreserveBlobOffsets {
get => GetFlagValue(MetadataFlags.PreserveBlobOffsets);
set => SetFlagValue(MetadataFlags.PreserveBlobOffsets, value, nameof(PreserveBlobOffsets));
}
public bool PreserveExtraSignatureData {
get => GetFlagValue(MetadataFlags.PreserveExtraSignatureData);
set => SetFlagValue(MetadataFlags.PreserveExtraSignatureData, value, nameof(PreserveExtraSignatureData));
}
public bool KeepOldMaxStack {
get => GetFlagValue(MetadataFlags.KeepOldMaxStack);
set => SetFlagValue(MetadataFlags.KeepOldMaxStack, value, nameof(KeepOldMaxStack));
}
public bool AlwaysCreateGuidHeap {
get => GetFlagValue(MetadataFlags.AlwaysCreateGuidHeap);
set => SetFlagValue(MetadataFlags.AlwaysCreateGuidHeap, value, nameof(AlwaysCreateGuidHeap));
}
public bool AlwaysCreateStringsHeap {
get => GetFlagValue(MetadataFlags.AlwaysCreateStringsHeap);
set => SetFlagValue(MetadataFlags.AlwaysCreateStringsHeap, value, nameof(AlwaysCreateStringsHeap));
}
public bool AlwaysCreateUSHeap {
get => GetFlagValue(MetadataFlags.AlwaysCreateUSHeap);
set => SetFlagValue(MetadataFlags.AlwaysCreateUSHeap, value, nameof(AlwaysCreateUSHeap));
}
public bool AlwaysCreateBlobHeap {
get => GetFlagValue(MetadataFlags.AlwaysCreateBlobHeap);
set => SetFlagValue(MetadataFlags.AlwaysCreateBlobHeap, value, nameof(AlwaysCreateBlobHeap));
}
public bool PreserveOtherMetadataStreams {
get => preserveOtherMetadataStreams;
set {
if (preserveOtherMetadataStreams != value) {
preserveOtherMetadataStreams = value;
OnPropertyChanged(nameof(PreserveOtherMetadataStreams));
if (preserveOtherMetadataStreams && module is ModuleDefMD mod) {
if (mod.Metadata.GuidStream.StartOffset != 0)
AlwaysCreateGuidHeap = true;
if (mod.Metadata.StringsStream.StartOffset != 0)
AlwaysCreateStringsHeap = true;
if (mod.Metadata.USStream.StartOffset != 0)
AlwaysCreateUSHeap = true;
if (mod.Metadata.BlobStream.StartOffset != 0)
AlwaysCreateBlobHeap = true;
}
}
}
}
bool preserveOtherMetadataStreams;
bool GetFlagValue(MetadataFlags flag) => (Flags & flag) != 0;
void SetFlagValue(MetadataFlags flag, bool value, string prop1, string? prop2 = null) {
bool origValue = (Flags & flag) != 0;
if (origValue == value)
return;
if (value)
Flags |= flag;
else
Flags &= ~flag;
OnPropertyChanged(prop1);
if (prop2 is not null)
OnPropertyChanged(prop2);
}
public void CopyTo(MetadataOptions options) {
MetadataHeaderOptions.CopyTo(options.MetadataHeaderOptions);
TablesHeapOptions.CopyTo(options.TablesHeapOptions);
options.Flags = Flags;
}
public void InitializeFrom(MetadataOptions options) {
MetadataHeaderOptions.InitializeFrom(options.MetadataHeaderOptions);
TablesHeapOptions.InitializeFrom(options.TablesHeapOptions);
Flags = options.Flags;
PreserveOtherMetadataStreams = false;
OnFlagsChanged();
}
void OnFlagsChanged() {
OnPropertyChanged(nameof(PreserveTypeRefRids));
OnPropertyChanged(nameof(PreserveTypeDefRids));
OnPropertyChanged(nameof(PreserveFieldRids));
OnPropertyChanged(nameof(PreserveMethodRids));
OnPropertyChanged(nameof(PreserveParamRids));
OnPropertyChanged(nameof(PreserveMemberRefRids));
OnPropertyChanged(nameof(PreserveStandAloneSigRids));
OnPropertyChanged(nameof(PreserveEventRids));
OnPropertyChanged(nameof(PreservePropertyRids));
OnPropertyChanged(nameof(PreserveTypeSpecRids));
OnPropertyChanged(nameof(PreserveMethodSpecRids));
OnPropertyChanged(nameof(PreserveRids));
OnPropertyChanged(nameof(PreserveStringsOffsets));
OnPropertyChanged(nameof(PreserveUSOffsets));
OnPropertyChanged(nameof(PreserveBlobOffsets));
OnPropertyChanged(nameof(PreserveExtraSignatureData));
OnPropertyChanged(nameof(KeepOldMaxStack));
OnPropertyChanged(nameof(AlwaysCreateGuidHeap));
OnPropertyChanged(nameof(AlwaysCreateStringsHeap));
OnPropertyChanged(nameof(AlwaysCreateUSHeap));
OnPropertyChanged(nameof(AlwaysCreateBlobHeap));
}
public override bool HasError {
get {
return MetadataHeaderOptions.HasError ||
TablesHeapOptions.HasError;
}
}
}
sealed class MetadataHeaderOptionsVM : ViewModelBase {
public MetadataHeaderOptionsVM() {
Signature = new NullableUInt32VM(a => HasErrorUpdated());
MajorVersion = new NullableUInt16VM(a => HasErrorUpdated());
MinorVersion = new NullableUInt16VM(a => HasErrorUpdated());
Reserved1 = new NullableUInt32VM(a => HasErrorUpdated());
StorageFlags = new NullableByteVM(a => HasErrorUpdated());
Reserved2 = new NullableByteVM(a => HasErrorUpdated());
}
public NullableUInt32VM Signature { get; }
public NullableUInt16VM MajorVersion { get; }
public NullableUInt16VM MinorVersion { get; }
public NullableUInt32VM Reserved1 { get; }
public string? VersionString {
get => versionString;
set {
versionString = value;
OnPropertyChanged(nameof(VersionString));
HasErrorUpdated();
}
}
string? versionString;
public NullableByteVM StorageFlags { get; }
public NullableByteVM Reserved2 { get; }
public void CopyTo(MetadataHeaderOptions options) {
options.Signature = Signature.Value;
options.MajorVersion = MajorVersion.Value;
options.MinorVersion = MinorVersion.Value;
options.Reserved1 = Reserved1.Value;
options.VersionString = string.IsNullOrEmpty(VersionString) ? null : VersionString;
options.StorageFlags = (StorageFlags?)StorageFlags.Value;
options.Reserved2 = Reserved2.Value;
}
public void InitializeFrom(MetadataHeaderOptions options) {
Signature.Value = options.Signature;
MajorVersion.Value = options.MajorVersion;
MinorVersion.Value = options.MinorVersion;
Reserved1.Value = options.Reserved1;
VersionString = options.VersionString;
StorageFlags.Value = (byte?)options.StorageFlags;
Reserved2.Value = options.Reserved2;
}
protected override string? Verify(string columnName) {
if (columnName == nameof(VersionString))
return ValidateVersionString(versionString);
return string.Empty;
}
public override bool HasError {
get {
if (!string.IsNullOrEmpty(Verify(nameof(VersionString))))
return true;
return Signature.HasError ||
MajorVersion.HasError ||
MinorVersion.HasError ||
Reserved1.HasError ||
StorageFlags.HasError ||
Reserved2.HasError;
}
}
internal static string ValidateVersionString(string? versionString) {
var bytes = Encoding.UTF8.GetBytes(versionString + "\0");
if (bytes.Length > 256)
return dnSpy_AsmEditor_Resources.Error_VersionStringTooLong;
return string.Empty;
}
}
sealed class TablesHeapOptionsVM : ViewModelBase {
public TablesHeapOptionsVM() {
Reserved1 = new NullableUInt32VM(a => HasErrorUpdated());
MajorVersion = new NullableByteVM(a => HasErrorUpdated());
MinorVersion = new NullableByteVM(a => HasErrorUpdated());
ExtraData = new NullableUInt32VM(a => HasErrorUpdated());
}
public NullableUInt32VM Reserved1 { get; }
public NullableByteVM MajorVersion { get; }
public NullableByteVM MinorVersion { get; }
public bool? UseENC {
get => useENC;
set {
useENC = value;
OnPropertyChanged(nameof(UseENC));
}
}
bool? useENC;
public NullableUInt32VM ExtraData { get; }
public bool? HasDeletedRows {
get => hasDeletedRows;
set {
hasDeletedRows = value;
OnPropertyChanged(nameof(HasDeletedRows));
}
}
bool? hasDeletedRows;
public void CopyTo(TablesHeapOptions options) {
options.Reserved1 = Reserved1.Value;
options.MajorVersion = MajorVersion.Value;
options.MinorVersion = MinorVersion.Value;
options.UseENC = UseENC;
options.ExtraData = ExtraData.Value;
options.HasDeletedRows = HasDeletedRows;
}
public void InitializeFrom(TablesHeapOptions options) {
Reserved1.Value = options.Reserved1;
MajorVersion.Value = options.MajorVersion;
MinorVersion.Value = options.MinorVersion;
UseENC = options.UseENC;
ExtraData.Value = options.ExtraData;
HasDeletedRows = options.HasDeletedRows;
}
public override bool HasError {
get {
return Reserved1.HasError ||
MajorVersion.HasError ||
MinorVersion.HasError ||
ExtraData.HasError;
}
}
}
}