internal static void CopyValues(this VirtualRegistry virtualRegistry, VirtualKey sourceKey, KeyInfo sourceKeyInfo, VirtualKey destinationKey) { using (HGlobalPtr lpValueName = new HGlobalPtr((sourceKeyInfo.MaxValueNameLength + 1) * sizeof(char)), lpcValueName = new HGlobalPtr(sizeof(int)), lpReserved = new HGlobalPtr(IntPtr.Zero), lpdwType = new HGlobalPtr(sizeof(int)), lpvData = new HGlobalPtr(sourceKeyInfo.MaxValueLength), lpcData = new HGlobalPtr(sizeof(int))) { for (uint i = 0; i < sourceKeyInfo.ValuesNumber; ++i) { Marshal.WriteInt32(lpcValueName.Ptr, unchecked ((int)sourceKeyInfo.MaxValueNameLength) + 1); Marshal.WriteInt32(lpcData.Ptr, unchecked ((int)sourceKeyInfo.MaxValueLength)); sourceKey.EnumValue(i, lpValueName.Ptr, lpcValueName.Ptr, lpReserved.Ptr, lpdwType.Ptr, lpvData.Ptr, lpcData.Ptr); Win32Api.RegValueType valueType = (Win32Api.RegValueType)Marshal.ReadInt32(lpdwType.Ptr); int currentValueLength = Marshal.ReadInt32(lpcData.Ptr); int currentValueNameLength = Marshal.ReadInt32(lpcValueName.Ptr); string currentValueName = Marshal.PtrToStringUni(lpValueName.Ptr, currentValueNameLength); destinationKey.SetValue(null, currentValueName, 0, valueType, lpvData.Ptr, currentValueLength); } } }
// TODO: query info does not take data altering into account, // data may be replaced by some larger data and this may lead to // buffer overflow in client's code public void QueryInfo( /*out StringBuilder*/ IntPtr lpClass, /*ref */ IntPtr lpcClass, IntPtr lpReserved, /*out */ IntPtr lpcSubKeys, /*out */ IntPtr lpcbMaxSubKeyLen, /*out */ IntPtr lpcbMaxClassLen, /*out */ IntPtr lpcValues, /*out */ IntPtr lpcbMaxValueNameLen, /*out */ IntPtr lpcbMaxValueLen, /*out */ IntPtr lpcbSecurityDescriptor, IntPtr lpftLastWriteTime) { // TODO: this function does not take into accout the intersection // of subkey names between windows regisry key and offreg key, and // the same thing about value names, this is // to be done in the next version // It does not matter if the current key is open in windows registry or in offreg // we need to open and both of them // if the class or security descriptor is defined for both of keys and are // different, then the values of windows registry keys just take priority. // TODO: during implementation of RegSetSecurity* probably the logic should be // changed to take security descriptor from OffReg key if it is there bool callSucceeded = false; KeyInfo result = new KeyInfo(); foreach (KeyDisposition disposition in HIVES_REVERSE_ORDER) { KeyInfo current = new KeyInfo(); if (!TryApplyOperation(disposition, null, new KeySecurity(Win32Api.KeySecurity.KEY_QUERY_VALUE), keyImpl => { current = keyImpl.QueryInfo(); return(true); })) { continue; } // Taking class and security descriptor from higher level (windows registry) // if possible, this is subject to change as soon as Reg*Security functions // are implemented if (!callSucceeded) { result.Class = current.Class; result.SecurityDescriptorLength = current.SecurityDescriptorLength; } callSucceeded = true; result.SubKeysNumber += current.SubKeysNumber; result.MaxSubKeyLength = Math.Max(result.MaxSubKeyLength, current.MaxSubKeyLength); result.MaxClassLength = Math.Max(result.MaxClassLength, current.MaxClassLength); result.ValuesNumber += current.ValuesNumber; result.MaxValueNameLength = Math.Max(result.MaxValueNameLength, current.MaxValueNameLength); result.MaxValueLength = Math.Max(result.MaxValueLength, current.MaxValueLength); if (DateTime.FromFileTime(result.LastWriteTime.AsLong) < DateTime.FromFileTime(current.LastWriteTime.AsLong)) { result.LastWriteTime = current.LastWriteTime; } } // At least one of windows or OffReg key exists (because it is open // and passed as hKey to this function), so at least one of calls did not return // FILE_NOT_FOUND, thus suppressing it here if (lpcSubKeys != IntPtr.Zero) { Marshal.WriteInt32(lpcSubKeys, unchecked ((int)result.SubKeysNumber)); } if (lpcbMaxSubKeyLen != IntPtr.Zero) { Marshal.WriteInt32(lpcbMaxSubKeyLen, unchecked ((int)result.MaxSubKeyLength)); } if (lpcbMaxClassLen != IntPtr.Zero) { Marshal.WriteInt32(lpcbMaxClassLen, unchecked ((int)result.MaxClassLength)); } if (lpcValues != IntPtr.Zero) { Marshal.WriteInt32(lpcValues, unchecked ((int)result.ValuesNumber)); } if (lpcbMaxValueNameLen != IntPtr.Zero) { Marshal.WriteInt32(lpcbMaxValueNameLen, unchecked ((int)result.MaxValueNameLength)); } if (lpcbMaxValueLen != IntPtr.Zero) { Marshal.WriteInt32(lpcbMaxValueLen, unchecked ((int)result.MaxValueLength)); } if (lpftLastWriteTime != IntPtr.Zero) { Marshal.StructureToPtr(result.LastWriteTime, lpftLastWriteTime, true); } Win32Exception.CheckResult( new Data(lpClass, lpcClass, Data.CountIn.Chars).FillWithString( new ManagedString(result.Class), HookBarrier.IsLastInjectedFuncAnsi ? StringFormat.Ansi : StringFormat.Unicode, Data.NullCharHandling.NotCountingOnReturn)); }
public bool Handle(OffRegKey key) { // TODO: exceptions thrown from this function should use STATUS_* error codes set // instead of ERROR_* string name = key.Identity.GetSystemPath(); KeyInfo info = key.QueryInfo(); // TODO: either test the following error-prone code with offsets thoroughly // or replace it with safer alternative code int offset = 0; switch (KeyInformationClass_) { case Win32Api.KeyInformationClass.KeyBasicInformation: ResultLength_ = unchecked((uint)(16 + sizeof(char) * name.Length)); if (Length_ < ResultLength_) { throw Win32Exception.Create((int)Win32Api.Status.STATUS_BUFFER_TOO_SMALL); } if (KeyInformation_ != IntPtr.Zero) { Marshal.StructureToPtr(info.LastWriteTime, KeyInformation_, false); offset += 8; Marshal.WriteInt32(KeyInformation_, offset, 0); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, sizeof(char) * name.Length); offset += 4; PInvokeHelper.CopyStringUni(name, (IntPtr)((Int64)KeyInformation_ + offset), name.Length); } return true; case Win32Api.KeyInformationClass.KeyNodeInformation: ResultLength_ = unchecked((uint)(24 + sizeof(char) * (name.Length + info.Class.Length))); if (Length_ < ResultLength_) { throw Win32Exception.Create((int)Win32Api.Status.STATUS_BUFFER_TOO_SMALL); } if (KeyInformation_ != IntPtr.Zero) { // TODO: fill the parts of structures w/o strings using // C# structures (until now I don't know solution for strings, but // at least all other fields will be set carefully) // do this throughout the function Marshal.StructureToPtr(info.LastWriteTime, KeyInformation_, false); offset += 8; Marshal.WriteInt32(KeyInformation_, offset, 0); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, 24 + sizeof(char) * name.Length); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, sizeof(char) * info.Class.Length); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, sizeof(char) * name.Length); offset += 4; PInvokeHelper.CopyStringUni(name, (IntPtr)((Int64)KeyInformation_ + offset), name.Length); offset += name.Length * sizeof(char); PInvokeHelper.CopyStringUni(info.Class, (IntPtr)((Int64)KeyInformation_ + offset), info.Class.Length); } return true; case Win32Api.KeyInformationClass.KeyFullInformation: ResultLength_ = unchecked((uint)(44 + sizeof(char) * (info.Class.Length))); if (Length_ < ResultLength_) { throw Win32Exception.Create((int)Win32Api.Status.STATUS_BUFFER_TOO_SMALL); } if (KeyInformation_ != IntPtr.Zero) { Marshal.StructureToPtr(info.LastWriteTime, KeyInformation_, false); offset += 8; Marshal.WriteInt32(KeyInformation_, offset, 0); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, 44); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, sizeof(char) * info.Class.Length); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, unchecked((int)info.SubKeysNumber)); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, unchecked((int)info.MaxSubKeyLength)); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, unchecked((int)info.MaxClassLength)); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, unchecked((int)info.ValuesNumber)); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, unchecked((int)info.MaxValueNameLength)); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, unchecked((int)info.MaxValueLength)); offset += 4; PInvokeHelper.CopyStringUni(info.Class, (IntPtr)((Int64)KeyInformation_ + offset), info.Class.Length); } return true; case Win32Api.KeyInformationClass.KeyNameInformation: ResultLength_ = unchecked((uint)(4 + sizeof(char) * name.Length)); if (Length_ < ResultLength_) { throw Win32Exception.Create((int)Win32Api.Status.STATUS_BUFFER_TOO_SMALL); } if (KeyInformation_ != IntPtr.Zero) { Marshal.WriteInt32(KeyInformation_, sizeof(char) * name.Length); offset += 4; PInvokeHelper.CopyStringUni(name, (IntPtr)((Int64)KeyInformation_ + offset), name.Length); } return true; case Win32Api.KeyInformationClass.KeyCachedInformation: ResultLength_ = 36; if (Length_ < ResultLength_) { throw Win32Exception.Create((int)Win32Api.Status.STATUS_BUFFER_TOO_SMALL); } if (KeyInformation_ != IntPtr.Zero) { Marshal.StructureToPtr(info.LastWriteTime, KeyInformation_, false); offset += 8; Marshal.WriteInt32(KeyInformation_, offset, 0); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, unchecked((int)info.SubKeysNumber)); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, unchecked((int)info.MaxSubKeyLength)); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, unchecked((int)info.ValuesNumber)); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, unchecked((int)info.MaxValueNameLength)); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, unchecked((int)info.MaxValueLength)); offset += 4; Marshal.WriteInt32(KeyInformation_, offset, name.Length); } return true; case Win32Api.KeyInformationClass.KeyFlagsInformation: // Reserved break; case Win32Api.KeyInformationClass.KeyVirtualizationInformation: // Not implemented break; case Win32Api.KeyInformationClass.KeyHandleTagsInformation: // Reserved break; } return false; }