mirror of
https://github.com/AdvDebug/Brovan
synced 2026-08-09 11:57:17 +00:00
Some optimizations and cleanups
Some optimizations and cleanups of the code. - BinaryFile.cs -- Avoiding allocations and unnecessary O(2) loop in the "ParseDotNetFunctions" - BinaryEmulator.cs -- Changing some fixed values to readonly and optimizing the sorting of memory region indexes. and also optimizing GetThreadsSnapshot by not using LINQ. - WindowsGuest.cs -- Avoiding LINQ in the rules path and caching ntdll module. also avoiding BitConverter.GetBytes and reusing the thread state. The rest of the commit are to ensure the state of the thread is cleared after it's death.
This commit is contained in:
+165
-170
@@ -102,6 +102,7 @@ namespace Brovan.Core
|
||||
/// <returns>The structure read from the supplied data.</returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T ReadStruct<T>(byte[] Data, int Offset) where T : unmanaged
|
||||
{
|
||||
if (Data == null || Data.Length == 0)
|
||||
@@ -133,6 +134,7 @@ namespace Brovan.Core
|
||||
/// <returns>The structure read from the supplied data.</returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T ReadStruct<T>(ReadOnlySpan<byte> Data, int Offset) where T : unmanaged
|
||||
{
|
||||
if (Data.IsEmpty || Data.Length == 0)
|
||||
@@ -787,14 +789,13 @@ namespace Brovan.Core
|
||||
MaxEnd = SectionEnd;
|
||||
|
||||
uint EndOffset = StartOffset;
|
||||
|
||||
byte[] ChunkData = GC.AllocateUninitializedArray<byte>(16);
|
||||
for (uint EndSearch = StartOffset; EndSearch < MaxEnd; EndSearch++)
|
||||
{
|
||||
if (EndSearch + 16 > (uint)Data.Length)
|
||||
break;
|
||||
|
||||
// Disassemble a chunk of code at the current position
|
||||
byte[] ChunkData = new byte[16];
|
||||
DataSpan.Slice((int)EndSearch, 16).CopyTo(ChunkData);
|
||||
|
||||
X86Instruction[] Instructions = Disassembler.Disassemble(ChunkData, EndSearch);
|
||||
@@ -1053,6 +1054,7 @@ namespace Brovan.Core
|
||||
/// <param name="Rva">The RVA to convert.</param>
|
||||
/// <param name="FileOffset">Receives the file offset when conversion succeeds.</param>
|
||||
/// <returns>True if the RVA could be converted; otherwise, false.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool TryRvaToFileOffset(uint Rva, out uint FileOffset)
|
||||
{
|
||||
if (RvaToFileOffsetCache != null &&
|
||||
@@ -1714,7 +1716,7 @@ namespace Brovan.Core
|
||||
/// <summary>
|
||||
/// Parse and read .NET Binary information.
|
||||
/// </summary>
|
||||
private void ParseDotNetFunctions()
|
||||
private unsafe void ParseDotNetFunctions()
|
||||
{
|
||||
List<DotNetFunction> DotNetFunctionList = new List<DotNetFunction>();
|
||||
List<DotNetProperty> DotNetPropertyList = new List<DotNetProperty>();
|
||||
@@ -1722,196 +1724,189 @@ namespace Brovan.Core
|
||||
List<DotNetType> DotNetTypeList = new List<DotNetType>();
|
||||
List<DotNetMember> DotNetMemberList = new List<DotNetMember>();
|
||||
MetadataReader MetadataReader = null;
|
||||
byte[] Data = this.Data.ToArray();
|
||||
try
|
||||
{
|
||||
using (MemoryStream Stream = new MemoryStream(Data))
|
||||
// Gonna use PEReader (no manual parsing for now)
|
||||
PEReader PEReader = new PEReader(Data.BasePtr, Data.Length, true);
|
||||
MetadataReader = PEReader.GetMetadataReader();
|
||||
foreach (TypeDefinitionHandle TypeHandle in MetadataReader.TypeDefinitions)
|
||||
{
|
||||
// Gonna use PEReader (no manual parsing for now)
|
||||
PEReader PEReader = new PEReader(Stream);
|
||||
MetadataReader = PEReader.GetMetadataReader();
|
||||
foreach (TypeDefinitionHandle TypeHandle in MetadataReader.TypeDefinitions)
|
||||
TypeDefinition TypeDef = MetadataReader.GetTypeDefinition(TypeHandle);
|
||||
string TypeNamespace = TypeDef.Namespace.IsNil ? "" : MetadataReader.GetString(TypeDef.Namespace);
|
||||
string TypeName = MetadataReader.GetString(TypeDef.Name);
|
||||
AssemblyDefinition AsmDef = MetadataReader.GetAssemblyDefinition();
|
||||
string AssemblyName = MetadataReader.GetString(AsmDef.Name);
|
||||
foreach (MethodDefinitionHandle MethodHandle in TypeDef.GetMethods())
|
||||
{
|
||||
TypeDefinition TypeDef = MetadataReader.GetTypeDefinition(TypeHandle);
|
||||
string TypeNamespace = TypeDef.Namespace.IsNil ? "" : MetadataReader.GetString(TypeDef.Namespace);
|
||||
string TypeName = MetadataReader.GetString(TypeDef.Name);
|
||||
AssemblyDefinition AsmDef = MetadataReader.GetAssemblyDefinition();
|
||||
string AssemblyName = MetadataReader.GetString(AsmDef.Name);
|
||||
MethodDefinition MethodDef = MetadataReader.GetMethodDefinition(MethodHandle);
|
||||
string MethodName = MetadataReader.GetString(MethodDef.Name);
|
||||
|
||||
foreach (MethodDefinitionHandle MethodHandle in TypeDef.GetMethods())
|
||||
if (MethodDef.RelativeVirtualAddress == 0)
|
||||
continue;
|
||||
|
||||
uint RVA = (uint)MethodDef.RelativeVirtualAddress;
|
||||
uint FileOffset = RvaToFileOffset(RVA, PE.Sections);
|
||||
if (FileOffset == 0 || FileOffset >= Data.Length - 1)
|
||||
continue;
|
||||
|
||||
byte HeaderByte = Data[FileOffset];
|
||||
bool IsTiny = (HeaderByte & 0x03) == 0x02;
|
||||
uint CodeSize;
|
||||
|
||||
if (IsTiny)
|
||||
{
|
||||
MethodDefinition MethodDef = MetadataReader.GetMethodDefinition(MethodHandle);
|
||||
string MethodName = MetadataReader.GetString(MethodDef.Name);
|
||||
|
||||
if (MethodDef.RelativeVirtualAddress == 0)
|
||||
CodeSize = (uint)(HeaderByte >> 2);
|
||||
FileOffset += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FileOffset + 12 > Data.Length)
|
||||
continue;
|
||||
|
||||
uint RVA = (uint)MethodDef.RelativeVirtualAddress;
|
||||
uint FileOffset = RvaToFileOffset(RVA, PE.Sections);
|
||||
if (FileOffset == 0 || FileOffset >= Data.Length - 1)
|
||||
ushort Flags_Size = ReadStruct<ushort>(DataSpan, (int)FileOffset);
|
||||
CodeSize = ReadStruct<uint>(DataSpan, (int)FileOffset + 4);
|
||||
FileOffset += 12;
|
||||
|
||||
if (CodeSize > 1024 * 1024)
|
||||
continue;
|
||||
}
|
||||
|
||||
byte HeaderByte = Data[FileOffset];
|
||||
bool IsTiny = (HeaderByte & 0x03) == 0x02;
|
||||
uint CodeSize;
|
||||
if (CodeSize == 0 || FileOffset + CodeSize > Data.Length)
|
||||
continue;
|
||||
|
||||
if (IsTiny)
|
||||
ReadOnlySpan<byte> ILCode = DataSpan.Slice((int)FileOffset, (int)CodeSize);
|
||||
|
||||
int ParameterCount = 0;
|
||||
foreach (ParameterHandle ParamHandle in MethodDef.GetParameters())
|
||||
{
|
||||
ParameterCount++;
|
||||
}
|
||||
|
||||
BlobReader SignatureReader = MetadataReader.GetBlobReader(MethodDef.Signature);
|
||||
byte Convention = SignatureReader.ReadByte();
|
||||
bool IsInstance = (Convention & 0x20) != 0;
|
||||
int Token = MetadataTokens.GetToken(MethodHandle);
|
||||
if (!string.IsNullOrEmpty(MethodName))
|
||||
{
|
||||
int LocalsCount = 0;
|
||||
if (ILCode != null)
|
||||
{
|
||||
CodeSize = (uint)(HeaderByte >> 2);
|
||||
FileOffset += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FileOffset + 12 > Data.Length)
|
||||
continue;
|
||||
|
||||
ushort Flags_Size = ReadStruct<ushort>(Data, (int)FileOffset);
|
||||
CodeSize = ReadStruct<uint>(Data, (int)FileOffset + 4);
|
||||
FileOffset += 12;
|
||||
|
||||
if (CodeSize > 1024 * 1024)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CodeSize == 0 || FileOffset + CodeSize > Data.Length)
|
||||
continue;
|
||||
|
||||
byte[] ILCode = new byte[CodeSize];
|
||||
Array.Copy(Data, (int)FileOffset, ILCode, 0, (int)CodeSize);
|
||||
|
||||
int ParameterCount = 0;
|
||||
foreach (ParameterHandle ParamHandle in MethodDef.GetParameters())
|
||||
{
|
||||
ParameterCount++;
|
||||
}
|
||||
|
||||
BlobReader SignatureReader = MetadataReader.GetBlobReader(MethodDef.Signature);
|
||||
byte Convention = SignatureReader.ReadByte();
|
||||
bool IsInstance = (Convention & 0x20) != 0;
|
||||
int Token = MetadataTokens.GetToken(MethodHandle);
|
||||
if (!string.IsNullOrEmpty(MethodName))
|
||||
{
|
||||
int LocalsCount = 0;
|
||||
if (ILCode != null)
|
||||
MethodBodyBlock MethodBody = PEReader.GetMethodBody(MethodDef.RelativeVirtualAddress);
|
||||
if (!MethodBody.LocalSignature.IsNil)
|
||||
{
|
||||
MethodBodyBlock MethodBody = PEReader.GetMethodBody(MethodDef.RelativeVirtualAddress);
|
||||
if (!MethodBody.LocalSignature.IsNil)
|
||||
{
|
||||
StandaloneSignature LocalSignature = MetadataReader.GetStandaloneSignature(MethodBody.LocalSignature);
|
||||
StandaloneSignature LocalSignature = MetadataReader.GetStandaloneSignature(MethodBody.LocalSignature);
|
||||
|
||||
// Get the signature blob reader to read the local variables count
|
||||
BlobReader LocalSignatureReader = MetadataReader.GetBlobReader(LocalSignature.Signature);
|
||||
SignatureHeader SigHeader = LocalSignatureReader.ReadSignatureHeader();
|
||||
if (SigHeader.Kind == SignatureKind.LocalVariables)
|
||||
{
|
||||
LocalsCount = LocalSignatureReader.ReadCompressedInteger();
|
||||
}
|
||||
// Get the signature blob reader to read the local variables count
|
||||
BlobReader LocalSignatureReader = MetadataReader.GetBlobReader(LocalSignature.Signature);
|
||||
SignatureHeader SigHeader = LocalSignatureReader.ReadSignatureHeader();
|
||||
if (SigHeader.Kind == SignatureKind.LocalVariables)
|
||||
{
|
||||
LocalsCount = LocalSignatureReader.ReadCompressedInteger();
|
||||
}
|
||||
}
|
||||
|
||||
DotNetFunctionList.Add(new DotNetFunction
|
||||
{
|
||||
FunctionName = MethodName,
|
||||
TypeName = TypeName,
|
||||
RVA = RVA,
|
||||
FileOffset = FileOffset,
|
||||
CodeSize = CodeSize,
|
||||
Flags = (ushort)MethodDef.Attributes,
|
||||
Token = Token,
|
||||
ParameterCount = ParameterCount,
|
||||
LocalsCount = LocalsCount,
|
||||
ImplFlags = (MethodImplementations)MethodDef.ImplAttributes,
|
||||
ILCode = ILCode,
|
||||
IsInstance = IsInstance,
|
||||
DeclaringType = TypeNamespace + "." + TypeName,
|
||||
AssemblyName = AssemblyName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach (PropertyDefinitionHandle PropertyHandle in TypeDef.GetProperties())
|
||||
{
|
||||
PropertyDefinition PropertyDef = MetadataReader.GetPropertyDefinition(PropertyHandle);
|
||||
int Token = MetadataTokens.GetToken(PropertyHandle);
|
||||
DotNetPropertyList.Add(new DotNetProperty
|
||||
{
|
||||
PropertyName = MetadataReader.GetString(PropertyDef.Name),
|
||||
Token = Token
|
||||
});
|
||||
}
|
||||
|
||||
foreach (FieldDefinitionHandle FieldHandle in TypeDef.GetFields())
|
||||
{
|
||||
FieldDefinition FieldDef = MetadataReader.GetFieldDefinition(FieldHandle);
|
||||
int Token = MetadataTokens.GetToken(FieldHandle);
|
||||
DotNetFieldList.Add(new DotNetField()
|
||||
{
|
||||
FieldName = MetadataReader.GetString(FieldDef.Name),
|
||||
Token = Token
|
||||
});
|
||||
}
|
||||
|
||||
DotNetTypeList.Add(new DotNetType
|
||||
{
|
||||
TypeName = TypeName,
|
||||
Token = MetadataReader.GetToken(TypeHandle)
|
||||
});
|
||||
|
||||
|
||||
foreach (MemberReferenceHandle MemberHandle in MetadataReader.MemberReferences)
|
||||
{
|
||||
MemberReference MemberRef = MetadataReader.GetMemberReference(MemberHandle);
|
||||
string MemberName = MetadataReader.GetString(MemberRef.Name);
|
||||
int Token = MetadataTokens.GetToken(MemberHandle);
|
||||
|
||||
string TypeNameMember = string.Empty;
|
||||
string DeclaringType = string.Empty;
|
||||
string AssemblyNameMember = string.Empty;
|
||||
|
||||
EntityHandle ParentHandle = MemberRef.Parent;
|
||||
if (ParentHandle.Kind == HandleKind.TypeReference)
|
||||
{
|
||||
TypeReference TypeRef = MetadataReader.GetTypeReference((TypeReferenceHandle)ParentHandle);
|
||||
TypeNameMember = MetadataReader.GetString(TypeRef.Name);
|
||||
DeclaringType = MetadataReader.GetString(TypeRef.Namespace) + "." + TypeNameMember;
|
||||
|
||||
EntityHandle Scope = TypeRef.ResolutionScope;
|
||||
if (Scope.Kind == HandleKind.AssemblyReference)
|
||||
{
|
||||
AssemblyReference AsmRef = MetadataReader.GetAssemblyReference((AssemblyReferenceHandle)Scope);
|
||||
AssemblyNameMember = MetadataReader.GetString(AsmRef.Name);
|
||||
}
|
||||
}
|
||||
else if (ParentHandle.Kind == HandleKind.TypeDefinition)
|
||||
{
|
||||
TypeDefinition TypeDefMember = MetadataReader.GetTypeDefinition((TypeDefinitionHandle)ParentHandle);
|
||||
DeclaringType = MetadataReader.GetString(TypeDefMember.Namespace) + "." + MetadataReader.GetString(TypeDefMember.Name);
|
||||
|
||||
AssemblyDefinition AsmDefMember = MetadataReader.GetAssemblyDefinition();
|
||||
AssemblyNameMember = MetadataReader.GetString(AsmDefMember.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeclaringType = ParentHandle.ToString();
|
||||
}
|
||||
|
||||
// Read method signature blob
|
||||
bool IsInstance = false;
|
||||
BlobReader SignatureReader = MetadataReader.GetBlobReader(MemberRef.Signature);
|
||||
SignatureHeader SignatureHeader = SignatureReader.ReadSignatureHeader();
|
||||
IsInstance = SignatureHeader.IsInstance;
|
||||
|
||||
DotNetMemberList.Add(new DotNetMember
|
||||
DotNetFunctionList.Add(new DotNetFunction
|
||||
{
|
||||
MemberName = MemberName,
|
||||
FunctionName = MethodName,
|
||||
TypeName = TypeName,
|
||||
RVA = RVA,
|
||||
FileOffset = FileOffset,
|
||||
CodeSize = CodeSize,
|
||||
Flags = (ushort)MethodDef.Attributes,
|
||||
Token = Token,
|
||||
TypeName = TypeNameMember,
|
||||
DeclaringType = DeclaringType,
|
||||
AssemblyName = AssemblyNameMember,
|
||||
IsInstance = IsInstance
|
||||
ParameterCount = ParameterCount,
|
||||
LocalsCount = LocalsCount,
|
||||
ImplFlags = (MethodImplementations)MethodDef.ImplAttributes,
|
||||
ILCode = ILCode.ToArray(),
|
||||
IsInstance = IsInstance,
|
||||
DeclaringType = TypeNamespace + "." + TypeName,
|
||||
AssemblyName = AssemblyName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach (PropertyDefinitionHandle PropertyHandle in TypeDef.GetProperties())
|
||||
{
|
||||
PropertyDefinition PropertyDef = MetadataReader.GetPropertyDefinition(PropertyHandle);
|
||||
int Token = MetadataTokens.GetToken(PropertyHandle);
|
||||
DotNetPropertyList.Add(new DotNetProperty
|
||||
{
|
||||
PropertyName = MetadataReader.GetString(PropertyDef.Name),
|
||||
Token = Token
|
||||
});
|
||||
}
|
||||
|
||||
foreach (FieldDefinitionHandle FieldHandle in TypeDef.GetFields())
|
||||
{
|
||||
FieldDefinition FieldDef = MetadataReader.GetFieldDefinition(FieldHandle);
|
||||
int Token = MetadataTokens.GetToken(FieldHandle);
|
||||
DotNetFieldList.Add(new DotNetField()
|
||||
{
|
||||
FieldName = MetadataReader.GetString(FieldDef.Name),
|
||||
Token = Token
|
||||
});
|
||||
}
|
||||
|
||||
DotNetTypeList.Add(new DotNetType
|
||||
{
|
||||
TypeName = TypeName,
|
||||
Token = MetadataReader.GetToken(TypeHandle)
|
||||
});
|
||||
}
|
||||
|
||||
foreach (MemberReferenceHandle MemberHandle in MetadataReader.MemberReferences)
|
||||
{
|
||||
MemberReference MemberRef = MetadataReader.GetMemberReference(MemberHandle);
|
||||
string MemberName = MetadataReader.GetString(MemberRef.Name);
|
||||
int Token = MetadataTokens.GetToken(MemberHandle);
|
||||
|
||||
string TypeNameMember = string.Empty;
|
||||
string DeclaringType = string.Empty;
|
||||
string AssemblyNameMember = string.Empty;
|
||||
|
||||
EntityHandle ParentHandle = MemberRef.Parent;
|
||||
if (ParentHandle.Kind == HandleKind.TypeReference)
|
||||
{
|
||||
TypeReference TypeRef = MetadataReader.GetTypeReference((TypeReferenceHandle)ParentHandle);
|
||||
TypeNameMember = MetadataReader.GetString(TypeRef.Name);
|
||||
DeclaringType = MetadataReader.GetString(TypeRef.Namespace) + "." + TypeNameMember;
|
||||
|
||||
EntityHandle Scope = TypeRef.ResolutionScope;
|
||||
if (Scope.Kind == HandleKind.AssemblyReference)
|
||||
{
|
||||
AssemblyReference AsmRef = MetadataReader.GetAssemblyReference((AssemblyReferenceHandle)Scope);
|
||||
AssemblyNameMember = MetadataReader.GetString(AsmRef.Name);
|
||||
}
|
||||
}
|
||||
else if (ParentHandle.Kind == HandleKind.TypeDefinition)
|
||||
{
|
||||
TypeDefinition TypeDefMember = MetadataReader.GetTypeDefinition((TypeDefinitionHandle)ParentHandle);
|
||||
DeclaringType = MetadataReader.GetString(TypeDefMember.Namespace) + "." + MetadataReader.GetString(TypeDefMember.Name);
|
||||
|
||||
AssemblyDefinition AsmDefMember = MetadataReader.GetAssemblyDefinition();
|
||||
AssemblyNameMember = MetadataReader.GetString(AsmDefMember.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeclaringType = ParentHandle.ToString();
|
||||
}
|
||||
|
||||
// Read method signature blob
|
||||
bool IsInstance = false;
|
||||
BlobReader SignatureReader = MetadataReader.GetBlobReader(MemberRef.Signature);
|
||||
SignatureHeader SignatureHeader = SignatureReader.ReadSignatureHeader();
|
||||
IsInstance = SignatureHeader.IsInstance;
|
||||
|
||||
DotNetMemberList.Add(new DotNetMember
|
||||
{
|
||||
MemberName = MemberName,
|
||||
Token = Token,
|
||||
TypeName = TypeNameMember,
|
||||
DeclaringType = DeclaringType,
|
||||
AssemblyName = AssemblyNameMember,
|
||||
IsInstance = IsInstance
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -362,8 +362,8 @@ namespace Brovan.Core.Emulation
|
||||
public bool IsArmGuest => UnicornArch == Arch.ARM;
|
||||
public bool IsX64Guest => UnicornArch == Arch.X86 && UnicornMode == Mode.MODE_64;
|
||||
public bool IsArchX86Guest => UnicornArch == Arch.X86;
|
||||
public ulong BaseAddress = 0x10000000UL; // Base Start
|
||||
public ulong MaxAddress = 0x7FFFFFFFFUL; // Max address limit
|
||||
public readonly ulong BaseAddress = 0x10000000UL; // Base Start
|
||||
public readonly ulong MaxAddress = 0x7FFFFFFFFUL; // Max address limit
|
||||
private ulong _timestampCounter = 0x100000000UL;
|
||||
|
||||
private const ulong TscCyclesPerInstruction = 3;
|
||||
@@ -371,6 +371,7 @@ namespace Brovan.Core.Emulation
|
||||
private const ulong RdtscReadCycles = 60;
|
||||
private const ulong RdtscpReadCycles = 90;
|
||||
private readonly long EmulatedSystemTimeBaseFileTimeUtc = DateTime.UtcNow.ToFileTimeUtc();
|
||||
private readonly Comparison<int> _memoryRegionIndexComparer;
|
||||
|
||||
/// <summary>
|
||||
/// Current deterministic guest tick count in milliseconds.
|
||||
@@ -476,6 +477,8 @@ namespace Brovan.Core.Emulation
|
||||
|
||||
if (Binary.Architecture == BinaryArchitecture.Unknown)
|
||||
throw new BadImageFormatException("Unsupported binary architecture.");
|
||||
|
||||
_memoryRegionIndexComparer = CompareMemoryRegionIndex;
|
||||
_binary = Binary;
|
||||
UnicornArch = Arch.X86;
|
||||
UnicornMode = Binary.Architecture == BinaryArchitecture.x64 ? Mode.MODE_64 : Mode.MODE_32;
|
||||
@@ -515,6 +518,7 @@ namespace Brovan.Core.Emulation
|
||||
if (Data == null || Data.Length == 0)
|
||||
throw new NullReferenceException(nameof(Data));
|
||||
|
||||
_memoryRegionIndexComparer = CompareMemoryRegionIndex;
|
||||
_binary = Binary ?? new BinaryFile(Data, true);
|
||||
UnicornArch = arch;
|
||||
UnicornMode = mode;
|
||||
@@ -1032,7 +1036,7 @@ namespace Brovan.Core.Emulation
|
||||
for (int i = 0; i < _memory.Count; i++)
|
||||
MemoryRegionIndex.Add(i);
|
||||
|
||||
MemoryRegionIndex.Sort(CompareMemoryRegionIndex);
|
||||
MemoryRegionIndex.Sort(_memoryRegionIndexComparer);
|
||||
MemoryRegionIndexDirty = false;
|
||||
}
|
||||
|
||||
@@ -1705,7 +1709,12 @@ namespace Brovan.Core.Emulation
|
||||
/// </summary>
|
||||
public List<EmulatedThread> GetThreadsSnapshot()
|
||||
{
|
||||
return Threads.Values.OrderBy(Thread => Thread.ThreadId).ToList();
|
||||
List<EmulatedThread> Snapshot = new List<EmulatedThread>(Threads.Count);
|
||||
foreach (var Thread in Threads.Values)
|
||||
Snapshot.Add(Thread);
|
||||
|
||||
Snapshot.Sort((a, b) => a.ThreadId.CompareTo(b.ThreadId));
|
||||
return Snapshot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Brovan.Core.Emulation.Guests
|
||||
private readonly BlobData _blob;
|
||||
private readonly WindowsBlobLaunchMode _blobLaunchMode;
|
||||
private IReadOnlyDictionary<uint, IWinSyscall> WinSyscallTable = new Dictionary<uint, IWinSyscall>();
|
||||
private WinModule _ntdllModule;
|
||||
|
||||
private bool UsesDirectBlobStartup => IsBlob && _blobLaunchMode == WindowsBlobLaunchMode.Direct;
|
||||
|
||||
@@ -458,11 +459,6 @@ namespace Brovan.Core.Emulation.Guests
|
||||
|
||||
WinHelper?.InvokeException(ThreadState.ExceptionInformation.Status, ThreadState.ExceptionInformation);
|
||||
|
||||
// The exception is no longer pending once KiUserExceptionDispatcher has been entered.
|
||||
// Keep IsHandlingException set until NtContinue/RtlRestoreContext completes the
|
||||
// continuation, but do not leave DispatchException set while guest ntdll is
|
||||
// dispatching handlers. NtContinue may be called from that path and must be
|
||||
// treated as a local context switch, not as a request to terminate the process.
|
||||
ThreadState.DispatchException = false;
|
||||
|
||||
State = Instance._emulator.Emulate(Instance.ReadRegister(Instance.IPRegister), 0, 0, QuantumInstructions);
|
||||
@@ -539,11 +535,19 @@ namespace Brovan.Core.Emulation.Guests
|
||||
if (Rule != null)
|
||||
{
|
||||
int MaxArgs = Rule.ArgsCount;
|
||||
ulong[] Args = MaxArgs <= 0
|
||||
? Array.Empty<ulong>()
|
||||
: (CaptureSyscallHistory && MaxArgs <= HistoryArgs.Length
|
||||
? HistoryArgs.Take(MaxArgs).ToArray()
|
||||
: ReadWindowsSyscallArguments(Instance, MaxArgs));
|
||||
ulong[] Args = Array.Empty<ulong>();
|
||||
if (MaxArgs > 0)
|
||||
{
|
||||
if (CaptureSyscallHistory && MaxArgs <= HistoryArgs.Length)
|
||||
{
|
||||
Args = new ulong[MaxArgs];
|
||||
Array.Copy(HistoryArgs, Args, MaxArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
Args = ReadWindowsSyscallArguments(Instance, MaxArgs);
|
||||
}
|
||||
}
|
||||
|
||||
SyscallContext Ctx = Instance.Syscalls.HandleSyscall(Syscall, HandlerName, Args);
|
||||
if (Ctx.Handled)
|
||||
@@ -711,11 +715,11 @@ namespace Brovan.Core.Emulation.Guests
|
||||
uint ThreadId = (uint)Instance.CurrentThreadId;
|
||||
if (!Instance.Threads.TryGetValue(ThreadId, out EmulatedThread Thread) || Thread == null)
|
||||
return;
|
||||
|
||||
if (WinEmulatedThread.GetState(Thread).IsHandlingException)
|
||||
WindowsThreadState State = WinEmulatedThread.GetState(Thread);
|
||||
if (State.IsHandlingException)
|
||||
{
|
||||
WinEmulatedThread.GetState(Thread).ExceptionNesting++;
|
||||
if (WinEmulatedThread.GetState(Thread).ExceptionNesting > 2)
|
||||
State.ExceptionNesting++;
|
||||
if (State.ExceptionNesting > 2)
|
||||
{
|
||||
Instance.WinHelper.AbandonMutexesOwnedByThread(Thread.ThreadId);
|
||||
Thread.State = EmulatedThreadState.Terminated;
|
||||
@@ -727,15 +731,15 @@ namespace Brovan.Core.Emulation.Guests
|
||||
}
|
||||
else
|
||||
{
|
||||
WinEmulatedThread.GetState(Thread).IsHandlingException = true;
|
||||
WinEmulatedThread.GetState(Thread).ExceptionNesting = 1;
|
||||
State.IsHandlingException = true;
|
||||
State.ExceptionNesting = 1;
|
||||
}
|
||||
|
||||
ExceptionInformation ExceptionInfo = Info ?? new ExceptionInformation();
|
||||
ExceptionInfo.Status = Status;
|
||||
Thread.State = EmulatedThreadState.Exception;
|
||||
WinEmulatedThread.GetState(Thread).DispatchException = true;
|
||||
WinEmulatedThread.GetState(Thread).ExceptionInformation = ExceptionInfo;
|
||||
State.DispatchException = true;
|
||||
State.ExceptionInformation = ExceptionInfo;
|
||||
Instance.Threads[ThreadId] = Thread;
|
||||
Instance._emulator.StopEmulation();
|
||||
}
|
||||
@@ -747,9 +751,9 @@ namespace Brovan.Core.Emulation.Guests
|
||||
return;
|
||||
|
||||
if (Instance._binary.Architecture == BinaryArchitecture.x64)
|
||||
Instance._emulator.WriteMemory(Teb + 0x68, BitConverter.GetBytes(LastError));
|
||||
Instance._emulator.WriteMemory(Teb + 0x68, LastError);
|
||||
else
|
||||
Instance._emulator.WriteMemory(Teb + 0x34, BitConverter.GetBytes(LastError));
|
||||
Instance._emulator.WriteMemory(Teb + 0x34, LastError);
|
||||
}
|
||||
|
||||
public void SetLastWinErrorRegister(BinaryEmulator Instance, NTSTATUS Status)
|
||||
@@ -782,8 +786,6 @@ namespace Brovan.Core.Emulation.Guests
|
||||
return Teb;
|
||||
}
|
||||
|
||||
byte[] PebPtr = BitConverter.GetBytes(PEB);
|
||||
byte[] TebPtr = BitConverter.GetBytes(Teb);
|
||||
Instance._emulator.WriteMemoryByte(Teb, 0, 0x2000);
|
||||
Instance._emulator.WriteMemory(Teb, ulong.MaxValue, 8);
|
||||
Instance._emulator.WriteMemory(Teb + 0x8, Thread.StackAddress + Thread.StackSize);
|
||||
@@ -791,10 +793,10 @@ namespace Brovan.Core.Emulation.Guests
|
||||
Instance._emulator.WriteMemory(Teb + 0x18, 0UL, 8);
|
||||
Instance._emulator.WriteMemory(Teb + 0x20, 0UL, 8);
|
||||
Instance._emulator.WriteMemory(Teb + 0x28, 0UL, 8);
|
||||
Instance._emulator.WriteMemory(Teb + 0x30, TebPtr, 8);
|
||||
Instance._emulator.WriteMemory(Teb + 0x40, BitConverter.GetBytes(WinHelper.PID), 8);
|
||||
Instance._emulator.WriteMemory(Teb + 0x48, BitConverter.GetBytes(Thread.ThreadId));
|
||||
Instance._emulator.WriteMemory(Teb + 0x60, PebPtr);
|
||||
Instance._emulator.WriteMemory(Teb + 0x30, Teb, 8);
|
||||
Instance._emulator.WriteMemory(Teb + 0x40, WinHelper.PID, 8);
|
||||
Instance._emulator.WriteMemory(Teb + 0x48, Thread.ThreadId);
|
||||
Instance._emulator.WriteMemory(Teb + 0x60, PEB, 8);
|
||||
Instance._emulator.WriteMemory(Teb + 0x68, (uint)0u);
|
||||
Instance._emulator.WriteMemory(Teb + 0x108, (uint)0x0409u);
|
||||
Instance._emulator.WriteMemory(Teb + 0x1760, (uint)0u);
|
||||
@@ -819,11 +821,10 @@ namespace Brovan.Core.Emulation.Guests
|
||||
if (LdrInitializeThunk != 0)
|
||||
return;
|
||||
|
||||
WinModule Module = WinHelper.WinModules.FirstOrDefault(Mod => Mod.Name == "ntdll.dll");
|
||||
if (Module == null)
|
||||
if (_ntdllModule == null)
|
||||
throw new Exception("ntdll.dll is not loaded.");
|
||||
|
||||
LdrInitializeThunk = Instance.TranslateVirtualAddress(Module.ExportsByName["LdrInitializeThunk"], "ntdll.dll");
|
||||
LdrInitializeThunk = Instance.TranslateVirtualAddress(_ntdllModule.ExportsByName["LdrInitializeThunk"], "ntdll.dll");
|
||||
}
|
||||
|
||||
public void ResolveRtlUserThreadStart(BinaryEmulator Instance)
|
||||
@@ -831,11 +832,10 @@ namespace Brovan.Core.Emulation.Guests
|
||||
if (RtlUserThreadStart != 0)
|
||||
return;
|
||||
|
||||
WinModule Module = WinHelper.WinModules.FirstOrDefault(Mod => Mod.Name == "ntdll.dll");
|
||||
if (Module == null)
|
||||
if (_ntdllModule == null)
|
||||
throw new Exception("ntdll.dll is not loaded.");
|
||||
|
||||
RtlUserThreadStart = Instance.TranslateVirtualAddress(Module.ExportsByName["RtlUserThreadStart"], "ntdll.dll");
|
||||
RtlUserThreadStart = Instance.TranslateVirtualAddress(_ntdllModule.ExportsByName["RtlUserThreadStart"], "ntdll.dll");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -871,10 +871,10 @@ namespace Brovan.Core.Emulation.Guests
|
||||
GuestState = new WindowsThreadState()
|
||||
};
|
||||
|
||||
WinEmulatedThread.GetState(Thread);
|
||||
WindowsThreadState State = WinEmulatedThread.GetState(Thread);
|
||||
Thread.Name ??= $"Thread_{Thread.ThreadId}";
|
||||
|
||||
WinEmulatedThread.GetState(Thread).ImpersonationToken = new WinToken
|
||||
State.ImpersonationToken = new WinToken
|
||||
{
|
||||
IsElevated = false,
|
||||
IsRestricted = false,
|
||||
@@ -884,7 +884,7 @@ namespace Brovan.Core.Emulation.Guests
|
||||
SessionId = 1
|
||||
};
|
||||
|
||||
WinEmulatedThread.GetState(Thread).Teb = AllocateAndInitializeTEB(Instance, Thread, CreateFlags, InitialThread);
|
||||
State.Teb = AllocateAndInitializeTEB(Instance, Thread, CreateFlags, InitialThread);
|
||||
|
||||
ulong InitialStack = (Thread.StackAddress + Thread.StackSize) & ~0xFUL;
|
||||
if (Instance._binary.Architecture == BinaryArchitecture.x64)
|
||||
@@ -943,10 +943,10 @@ namespace Brovan.Core.Emulation.Guests
|
||||
GuestState = new WindowsThreadState()
|
||||
};
|
||||
|
||||
WinEmulatedThread.GetState(Thread);
|
||||
WindowsThreadState State = WinEmulatedThread.GetState(Thread);
|
||||
Thread.Name ??= $"Thread_{Thread.ThreadId}";
|
||||
|
||||
WinEmulatedThread.GetState(Thread).ImpersonationToken = new WinToken
|
||||
State.ImpersonationToken = new WinToken
|
||||
{
|
||||
IsElevated = false,
|
||||
IsRestricted = false,
|
||||
@@ -956,7 +956,7 @@ namespace Brovan.Core.Emulation.Guests
|
||||
SessionId = 1
|
||||
};
|
||||
|
||||
WinEmulatedThread.GetState(Thread).Teb = AllocateAndInitializeTEB(Instance, Thread, CreateFlags, InitialThread);
|
||||
State.Teb = AllocateAndInitializeTEB(Instance, Thread, CreateFlags, InitialThread);
|
||||
|
||||
ulong InitialRSP = (Thread.StackAddress + Thread.StackSize) & ~0xFUL;
|
||||
InitialRSP -= 8;
|
||||
@@ -980,7 +980,7 @@ namespace Brovan.Core.Emulation.Guests
|
||||
if (Instance._binary.Architecture == BinaryArchitecture.x64)
|
||||
{
|
||||
Thread.Context.RCX = contextAddress;
|
||||
Thread.Context.RDX = WinHelper.WinModules.FirstOrDefault(Mod => Mod.Name == "ntdll.dll")?.MappedBase ?? 0;
|
||||
Thread.Context.RDX = _ntdllModule?.MappedBase ?? 0;
|
||||
}
|
||||
|
||||
Instance.Threads[Thread.ThreadId] = Thread;
|
||||
@@ -1049,8 +1049,14 @@ namespace Brovan.Core.Emulation.Guests
|
||||
{ "PATH", @"C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\" }
|
||||
};
|
||||
|
||||
string EnvironmentString = string.Join('\0', Env.Select(kv => $"{kv.Key}={kv.Value}")) + "\0\0";
|
||||
byte[] EnvBytes = Encoding.Unicode.GetBytes(EnvironmentString);
|
||||
StringBuilder Builder = new StringBuilder(1024);
|
||||
foreach (var kv in Env)
|
||||
{
|
||||
Builder.Append(kv.Key).Append('=').Append(kv.Value).Append('\0');
|
||||
}
|
||||
Builder.Append('\0');
|
||||
|
||||
byte[] EnvBytes = Encoding.Unicode.GetBytes(Builder.ToString());
|
||||
size = (ulong)EnvBytes.Length;
|
||||
return EnvBytes;
|
||||
}
|
||||
@@ -1193,9 +1199,9 @@ namespace Brovan.Core.Emulation.Guests
|
||||
ulong Handle = WinHelper.ConsoleHandle.Handle;
|
||||
Instance._emulator.WriteMemory(ProcessParams + 0x10, Handle, 8);
|
||||
Instance._emulator.WriteMemory(ProcessParams + 0x18, new byte[] { 0x00, 0x00, 0x00, 0x00 });
|
||||
Instance._emulator.WriteMemory(ProcessParams + 0x20, BitConverter.GetBytes(WinHelper.STD_IN.Handle), 8);
|
||||
Instance._emulator.WriteMemory(ProcessParams + 0x28, BitConverter.GetBytes(WinHelper.STD_OUT.Handle), 8);
|
||||
Instance._emulator.WriteMemory(ProcessParams + 0x30, BitConverter.GetBytes(WinHelper.STD_OUT.Handle), 8);
|
||||
Instance._emulator.WriteMemory(ProcessParams + 0x20, WinHelper.STD_IN.Handle, 8);
|
||||
Instance._emulator.WriteMemory(ProcessParams + 0x28, WinHelper.STD_OUT.Handle, 8);
|
||||
Instance._emulator.WriteMemory(ProcessParams + 0x30, WinHelper.STD_OUT.Handle, 8);
|
||||
}
|
||||
WriteInlineUnicodeString(0x60, ImagePath);
|
||||
WriteInlineUnicodeString(0x70, CommandLine);
|
||||
@@ -1268,8 +1274,11 @@ namespace Brovan.Core.Emulation.Guests
|
||||
Instance._emulator.WriteMemory(LdrData + 0x4, (byte)1, 1);
|
||||
|
||||
List<ulong> Entries = new List<ulong>();
|
||||
foreach (WinModule Module in WinHelper.WinModules.Where(Module => Module != null && Module.MappedBase != 0 && Module.SizeOfImage != 0))
|
||||
foreach (WinModule Module in WinHelper.WinModules)
|
||||
{
|
||||
if (Module == null || Module.MappedBase == 0 || Module.SizeOfImage == 0)
|
||||
continue;
|
||||
|
||||
ulong Entry = Instance.MapUniqueAddress(EntrySize, MemoryProtection.ReadWrite);
|
||||
if (Entry == 0)
|
||||
continue;
|
||||
@@ -1303,8 +1312,11 @@ namespace Brovan.Core.Emulation.Guests
|
||||
Instance._emulator.WriteMemory(LdrData + 0x4, (byte)1, 1);
|
||||
|
||||
List<ulong> Entries = new List<ulong>();
|
||||
foreach (WinModule Module in WinHelper.WinModules.Where(Module => Module != null && Module.MappedBase != 0 && Module.SizeOfImage != 0))
|
||||
foreach (WinModule Module in WinHelper.WinModules)
|
||||
{
|
||||
if (Module == null || Module.MappedBase == 0 || Module.SizeOfImage == 0)
|
||||
continue;
|
||||
|
||||
ulong Entry = Instance.MapUniqueAddress(EntrySize, MemoryProtection.ReadWrite);
|
||||
if (Entry == 0)
|
||||
continue;
|
||||
@@ -1433,7 +1445,7 @@ namespace Brovan.Core.Emulation.Guests
|
||||
|
||||
using (BinaryFile Library = new BinaryFile(NtdllPath, true))
|
||||
{
|
||||
Instance.LoadWinLibrary(Library, true, MapBySections: false);
|
||||
_ntdllModule = Instance.LoadWinLibrary(Library, true, MapBySections: false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -95,6 +95,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
if (WinEmulatedThread.GetState(CurrentThread).ExceptionNesting > 2)
|
||||
{
|
||||
Instance.WinHelper.AbandonMutexesOwnedByThread(CurrentThread.ThreadId);
|
||||
Instance.WinHelper.ClearTerminationState(CurrentThread);
|
||||
CurrentThread.State = EmulatedThreadState.Terminated;
|
||||
CurrentThread.ExitCode = unchecked((int)ExceptionCode);
|
||||
Instance.Threads[(uint)Instance.CurrentThreadId] = CurrentThread;
|
||||
|
||||
@@ -59,13 +59,9 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
continue;
|
||||
|
||||
Instance.WinHelper.AbandonMutexesOwnedByThread(ProcessThread.ThreadId);
|
||||
Instance.WinHelper.ClearTerminationState(ProcessThread);
|
||||
ProcessThread.ExitCode = unchecked((int)ExitStatus);
|
||||
ProcessThread.State = EmulatedThreadState.Terminated;
|
||||
ProcessThread.WaitActive = false;
|
||||
ProcessThread.WaitHandles = null;
|
||||
ProcessThread.WaitDeadline = -1;
|
||||
ProcessThread.WaitTimedOut = false;
|
||||
ProcessThread.WaitSatisfiedIndex = -1;
|
||||
}
|
||||
|
||||
Instance.StopEmulation();
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
{
|
||||
if (EmuThread.ThreadId != CurrentTID)
|
||||
{
|
||||
Instance.WinHelper.ClearTerminationState(EmuThread);
|
||||
EmuThread.State = EmulatedThreadState.Terminated;
|
||||
EmuThread.ExitCode = (int)ExitCode;
|
||||
}
|
||||
@@ -39,6 +40,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
continue;
|
||||
|
||||
Instance.WinHelper.AbandonMutexesOwnedByThread(ProcessThreads.ThreadId);
|
||||
Instance.WinHelper.ClearTerminationState(ProcessThreads);
|
||||
ProcessThreads.State = EmulatedThreadState.Terminated;
|
||||
}
|
||||
Instance.StopEmulation();
|
||||
|
||||
@@ -28,25 +28,8 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
Instance.WinHelper.AbandonMutexesOwnedByThread(TargetThread.ThreadId);
|
||||
|
||||
TargetThread.ExitCode = unchecked((int)(uint)ExitStatus);
|
||||
Instance.WinHelper.ClearTerminationState(TargetThread);
|
||||
TargetThread.State = EmulatedThreadState.Terminated;
|
||||
TargetThread.WaitActive = false;
|
||||
TargetThread.WaitHandles = null;
|
||||
TargetThread.WaitDeadline = -1;
|
||||
TargetThread.WaitTimedOut = false;
|
||||
TargetThread.WaitSatisfiedIndex = -1;
|
||||
|
||||
WindowsThreadState State = WinEmulatedThread.TryGetState(TargetThread);
|
||||
if (State != null)
|
||||
{
|
||||
State.ApcAlertable = false;
|
||||
State.WaitAlertable = false;
|
||||
State.WaitCompleted = false;
|
||||
State.WaitStatus = NTSTATUS.STATUS_SUCCESS;
|
||||
State.WaitResumeRIP = 0;
|
||||
State.WaitReturnRIP = 0;
|
||||
State.WorkerFactoryWaitActive = false;
|
||||
State.AlertByThreadIdWaitActive = false;
|
||||
}
|
||||
|
||||
if (Instance.CurrentThread != null && TargetThread.ThreadId == (uint)Instance.CurrentThreadId)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static Brovan.Core.Helpers.BinaryHelpers;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows
|
||||
|
||||
@@ -5,6 +5,7 @@ using Brovan.Core.Helpers;
|
||||
using System.Text;
|
||||
using System.Buffers.Binary;
|
||||
using Brovan.Core.Emulation.OS.SharedHelpers;
|
||||
using System.IO;
|
||||
|
||||
namespace Brovan.Core.Emulation.OS.Windows
|
||||
{
|
||||
@@ -205,6 +206,38 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears wait, worker-factory, and exception state for a thread that is exiting.
|
||||
/// </summary>
|
||||
public void ClearTerminationState(EmulatedThread Thread, bool ClearAlertByThreadId = false)
|
||||
{
|
||||
if (Thread == null)
|
||||
return;
|
||||
|
||||
ClearWaitState(Thread, true);
|
||||
|
||||
WindowsThreadState State = WinEmulatedThread.TryGetState(Thread);
|
||||
if (State == null)
|
||||
return;
|
||||
|
||||
State.WaitCompleted = false;
|
||||
State.WaitStatus = NTSTATUS.STATUS_SUCCESS;
|
||||
State.WaitObjects = null;
|
||||
State.DispatchException = false;
|
||||
State.IsHandlingException = false;
|
||||
State.ExceptionNesting = 0;
|
||||
State.ExceptionInformation = null;
|
||||
State.WorkerFactoryWaitActive = false;
|
||||
State.WorkerFactoryHandle = 0;
|
||||
State.WorkerFactoryMiniPackets = 0;
|
||||
State.WorkerFactoryPacketsReturned = 0;
|
||||
State.WorkerFactoryMaxPackets = 0;
|
||||
State.WorkerFactoryReservedEntries?.Clear();
|
||||
State.AlertByThreadIdPending = false;
|
||||
State.AlertByThreadIdWaitActive = false;
|
||||
State.AlertByThreadIdAddress = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 64-bit IO_STATUS_BLOCK to emulated memory.
|
||||
/// </summary>
|
||||
@@ -1006,6 +1039,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
private ulong UserSharedDelta;
|
||||
public ulong ActiveWindow;
|
||||
public ulong FocusWindow;
|
||||
private readonly Dictionary<string, string> _normalizedPathCache = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the environment for the helper (Processes, Console, etc).
|
||||
@@ -2113,17 +2147,6 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
return 0;
|
||||
}
|
||||
|
||||
public byte[] StructureToBytes<T>(T str)
|
||||
{
|
||||
int size = Marshal.SizeOf<T>();
|
||||
byte[] arr = new byte[size];
|
||||
IntPtr ptr = Marshal.AllocHGlobal(size);
|
||||
Marshal.StructureToPtr(str, ptr, false);
|
||||
Marshal.Copy(ptr, arr, 0, size);
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert windows memory protection to the internal enum.
|
||||
/// </summary>
|
||||
@@ -3375,8 +3398,13 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
if (string.IsNullOrEmpty(NtPath))
|
||||
return null;
|
||||
|
||||
if (_normalizedPathCache.TryGetValue(NtPath, out string Cached))
|
||||
return Cached;
|
||||
|
||||
NtPath = FixupNtRegistryPath(NtPath);
|
||||
return NormalizeKeyPath(NtPath);
|
||||
NtPath = NormalizeKeyPath(NtPath);
|
||||
_normalizedPathCache[NtPath] = NtPath;
|
||||
return NtPath;
|
||||
}
|
||||
|
||||
private bool IsVirtualRegistryRoot(string NtPath)
|
||||
@@ -3389,7 +3417,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
NtPath.Equals("\\Registry\\User", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private void AddVirtualRegistrySubKeys(string NtPath, SortedSet<string> Names)
|
||||
private void AddVirtualRegistrySubKeys(string NtPath, List<string> Names)
|
||||
{
|
||||
if (string.IsNullOrEmpty(NtPath) || Names == null)
|
||||
return;
|
||||
@@ -3887,7 +3915,7 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
if (string.IsNullOrEmpty(NtPath) || IsRegistryPathDeleted(NtPath))
|
||||
return false;
|
||||
|
||||
SortedSet<string> Names = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
List<string> Names = new List<string>();
|
||||
AddVirtualRegistrySubKeys(NtPath, Names);
|
||||
|
||||
if (RegKey.Hive != null && RegKey.Hive.Reader != null && RegKey.HasParsedKey)
|
||||
@@ -3912,7 +3940,8 @@ namespace Brovan.Core.Emulation.OS.Windows
|
||||
if (Index >= Names.Count)
|
||||
return false;
|
||||
|
||||
Name = Names.ElementAt(Index);
|
||||
Names.Sort(StringComparer.OrdinalIgnoreCase);
|
||||
Name = Names[Index];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1113,7 +1113,7 @@ namespace Brovan.Core.Helpers
|
||||
private MemoryMappedFile Mmf;
|
||||
private MemoryMappedViewAccessor View;
|
||||
private SafeMemoryMappedViewHandle Handle;
|
||||
private byte* BasePtr;
|
||||
public byte* BasePtr;
|
||||
|
||||
public int Length { get; private set; }
|
||||
public bool IsMemoryMapped => ManagedData == null;
|
||||
|
||||
Reference in New Issue
Block a user