Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# P/Invoke Win32 function RegQueryInfoKey

I am trying to port the following C++ code:

BOOL SyskeyGetClassBytes(HKEY hKeyReg,LPSTR keyName,LPSTR valueName,LPBYTE classBytes) {
HKEY hKey,hSubKey;
DWORD dwDisposition=0,classSize;
BYTE classStr[16];
LONG ret;
BOOL isSuccess = FALSE;

ret = RegCreateKeyEx(hKeyReg,keyName,0,NULL,REG_OPTION_NON_VOLATILE,KEY_QUERY_VALUE,NULL,&hKey,&dwDisposition);

if(ret!=ERROR_SUCCESS) 
    return FALSE;
else if(dwDisposition!=REG_OPENED_EXISTING_KEY) {
    RegCloseKey(hKey);
    return FALSE;
}
else {
    if(RegOpenKeyEx(hKey,valueName,0,KEY_READ,&hSubKey)==ERROR_SUCCESS) {
        classSize = 8+1;
        ret = RegQueryInfoKey(hSubKey,(LPTSTR)classStr,&classSize,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
        if((ret==ERROR_SUCCESS)&&(classSize==8)) {
            classBytes[0]= (HexDigitToByte(classStr[0]) << 4) | HexDigitToByte(classStr[1]);
            classBytes[1]= (HexDigitToByte(classStr[2]) << 4) | HexDigitToByte(classStr[3]);
            classBytes[2]= (HexDigitToByte(classStr[4]) << 4) | HexDigitToByte(classStr[5]);
            classBytes[3]= (HexDigitToByte(classStr[6]) << 4) | HexDigitToByte(classStr[7]);
            isSuccess = TRUE;
        }
        RegCloseKey(hSubKey);
    }
    RegCloseKey(hKey);
}

return isSuccess;

}

I spent like 5 hours trying to figure out my problem, with no success. I know for a fact that I am properly calling this method. My C# code is

 unsafe static bool SyskeyGetClassBytes(RegistryHive hKeyReg, string keyName, string valueName, byte* classBytes)
    {
        UIntPtr hSubKey;
        UIntPtr hKey;
        RegResult tmp; ;
        uint classSize;
        StringBuilder classStr = new StringBuilder();
        int ret;
        bool isSuccess = false;
        ret = RegCreateKeyEx(hKeyReg, keyName, 0, null, RegOption.NonVolatile, RegSAM.QueryValue, UIntPtr.Zero, out hKey, out tmp);

        if (ret != 0)
        {
            return false;

        }
        else if (tmp != RegResult.OpenedExistingKey)
        {
            return false;
        }
        else
        {
            int res = RegOpenKeyEx(hKey, valueName, 0, (int)RegSAM.Read, out hSubKey);
            if (res == 0)
            {
                classSize = 8 + 1;
                ret = RegQueryInfoKey(hSubKey, out classStr, ref classSize, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

                if ((classSize == 8))
                {
                    classBytes[0] = (byte)((byte)(HexDigitToByte(classStr[0]) << (byte)4) | HexDigitToByte(classStr[1]));
                    classBytes[1] = (byte)((byte)(HexDigitToByte(classStr[2]) << (byte)4) | HexDigitToByte(classStr[3]));
                    classBytes[2] = (byte)((byte)(HexDigitToByte(classStr[4]) << (byte)4) | HexDigitToByte(classStr[5]));
                    classBytes[3] = (byte)((byte)(HexDigitToByte(classStr[6]) << (byte)4) | HexDigitToByte(classStr[7]));
                    isSuccess = true;
                }
                RegCloseKey(hSubKey);
            }
            else
            {
                return false;
            }
            RegCloseKey(hKey);
        }
        return isSuccess;
    }

Its a little bit hard for me to debug, but eventually I determined that the problem is occurring at this line. Execution seems to halt afterwards.

 ret = RegQueryInfoKey(hSubKey, out classStr, ref classSize, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

I know this is not a problem with permissions, as this C# program is running with admin perms AND as the local system account. The method that I need that the .Net APIs don't offer is RegQueryInfoKey. My P/Invoke signatures and types used are:

  [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public int nLength;
        public unsafe byte* lpSecurityDescriptor;
        public int bInheritHandle;
    }
    [Flags]
    public enum RegOption
    {
        NonVolatile = 0x0,
        Volatile = 0x1,
        CreateLink = 0x2,
        BackupRestore = 0x4,
        OpenLink = 0x8
    }

    [Flags]
    public enum RegSAM
    {
        QueryValue = 0x0001,
        SetValue = 0x0002,
        CreateSubKey = 0x0004,
        EnumerateSubKeys = 0x0008,
        Notify = 0x0010,
        CreateLink = 0x0020,
        WOW64_32Key = 0x0200,
        WOW64_64Key = 0x0100,
        WOW64_Res = 0x0300,
        Read = 0x00020019,
        Write = 0x00020006,
        Execute = 0x00020019,
        AllAccess = 0x000f003f
    }

    public enum RegResult
    {
        CreatedNewKey = 0x00000001,
        OpenedExistingKey = 0x00000002
    }
    [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
    public static extern int RegOpenKeyEx(
      UIntPtr hKey,
      string subKey,
      int ulOptions,
      int samDesired,
      out UIntPtr hkResult);
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern int RegCloseKey(
        UIntPtr hKey);
    [DllImport("advapi32.dll", SetLastError = true)]
    static extern int RegCreateKeyEx(
                RegistryHive hKey,
                string lpSubKey,
                int Reserved,
                string lpClass,
                RegOption dwOptions,
                RegSAM samDesired,
                UIntPtr lpSecurityAttributes,
                out UIntPtr phkResult,
                out RegResult lpdwDisposition);
    [DllImport("advapi32.dll", EntryPoint = "RegQueryInfoKey", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    extern private static int RegQueryInfoKey(
        UIntPtr hkey,
        out StringBuilder lpClass,
        ref uint lpcbClass,
        IntPtr lpReserved,
        IntPtr lpcSubKeys,
        IntPtr lpcbMaxSubKeyLen,
        IntPtr lpcbMaxClassLen,
        IntPtr lpcValues,
        IntPtr lpcbMaxValueNameLen,
        IntPtr lpcbMaxValueLen,
        IntPtr lpcbSecurityDescriptor,
        IntPtr lpftLastWriteTime);
like image 348
user1454902 Avatar asked Oct 22 '22 08:10

user1454902


1 Answers

The lpClass parameter is declared incorrectly. Pass the StringBuilder by value.

[DllImport("advapi32.dll")]
extern private static int RegQueryInfoKey(
    UIntPtr hkey,
    StringBuilder lpClass,
    ref uint lpcbClass,
    IntPtr lpReserved,
    IntPtr lpcSubKeys,
    IntPtr lpcbMaxSubKeyLen,
    IntPtr lpcbMaxClassLen,
    IntPtr lpcValues,
    IntPtr lpcbMaxValueNameLen,
    IntPtr lpcbMaxValueLen,
    IntPtr lpcbSecurityDescriptor,
    IntPtr lpftLastWriteTime
);

You also need to allocate the StringBuilder instance to have the desired capacity. So, allocate the StringBuilder like this:

StringBuilder classStr = new StringBuilder(255);//or whatever length you like

And then set classSize like this:

classSize = classStr.Capacity+1;

I removed the parameters to DllImport. Most are not necessary, and the SetLastError is incorrect.

There may be other issues with your code, but with these changes at least the call to RegQueryInfoKey will match your C++ code.

like image 67
David Heffernan Avatar answered Oct 24 '22 03:10

David Heffernan