如何从32位进程读取64位注册表项?

Sti*_*ers 8 windows delphi registry 64-bit 32bit-64bit

我一直在使用键的值MachineGuidHKEY_LOCAL_MACHINE\Software\Microsoft\Cryptography唯一标识主机,但在64位计算机上运行32位的进程,价值似乎已丢失.我猜它正在Wow6432Node下搜索,它确实缺失了.根据这个应该能够通过添加一个标志来获得正确的密钥,但是下面的代码似乎仍然不能完成这项工作.我错过了什么?

const
  KEY_WOW64_64KEY=$0100;
var
  r:HKEY;
  s:string;
  i,l:integer;
begin
  //use cryptography machineguid, keep a local copy of this in initialization?
  l:=40;
  if RegOpenKeyEx(HKEY_LOCAL_MACHINE,PChar('Software\Microsoft\Cryptography'),
    0,KEY_QUERY_VALUE,r)=ERROR_SUCCESS then
   begin
    SetLength(s,l);
    if RegQueryValue(r,'MachineGuid',PChar(s),l)=ERROR_SUCCESS then
     begin
      SetLength(s,l);
      RegCloseKey(r);
     end
    else
     begin
      //try from-32-to-64
      RegCloseKey(r);
      if RegOpenKeyEx(HKEY_LOCAL_MACHINE,PChar('Software\Microsoft\Cryptography'),
        0,KEY_QUERY_VALUE or KEY_WOW64_64KEY,r)=ERROR_SUCCESS then
       begin
        l:=40;
        if RegQueryValue(r,'MachineGuid',PChar(s),l)=ERROR_SUCCESS then
          SetLength(s,l)
        else
          l:=0;
        RegCloseKey(r);
       end;
     end;
   end;
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 10

我建议您使用该IsWow64Process()函数来了解何时是在64位操作系统上运行的32进程,然后仅KEY_WOW64_64KEY在该特定条件下应用标志.如果应用程序是32位操作系统上的32位进程,或64位操作系统上的64位进程,则不需要标记.

例如:

const 
  KEY_WOW64_64KEY = $0100; 
var 
  key: HKEY; 
  str: string; 
  len: DWORD; 
  flag: REGSAM;
  wow64: BOOL;
begin 
  flag := 0;
  wow64 := 0;
  IsWow64Process(GetCurrentProcess(), @wow64);
  if wow64 <> 0 then flag := KEY_WOW64_64KEY;

  if RegOpenKeyEx(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Cryptography', 0, KEY_QUERY_VALUE or flag, key) = ERROR_SUCCESS then 
  try
    SetLength(str, 40); 
    len := Length(str) * SizeOf(Char); 
    if RegQueryValueEx(key, 'MachineGuid', nil, nil, PByte(Pointer(s)), @len) <> ERROR_SUCCESS then len := 0;
    SetLength(str, len div SizeOf(Char)); 
  finally
    RegCloseKey(key); 
  end; 
end;
Run Code Online (Sandbox Code Playgroud)

  • 我认为你可以简单地总是应用标志,它在x86 os上被忽略 (3认同)
  • 仅在XP及更高版本上,即使在32位版本中也能识别64位系统的存在.如果在Win2k或更早版本上指定标志,它将作为未知参数失败.在那些系统上,无论如何都需要动态加载`IsWow64Process()`来检测WOW64是否存在. (2认同)

Dav*_*nan 7

您的代码是不必要的复杂,主要是因为您没有利用内置TRegistry类来保护您免受低级注册表API的所有复杂性的影响.例如,请考虑以下代码:

type
  TRegistryView = (rvDefault, rvRegistry64, rvRegistry32);

function RegistryViewAccessFlag(View: TRegistryView): LongWord;
begin
  case View of
  rvDefault:
    Result := 0;
  rvRegistry64:
    Result := KEY_WOW64_64KEY;
  rvRegistry32:
    Result := KEY_WOW64_32KEY;
  end;
end;

function ReadRegStr(const Root: HKEY; const Key, Name: string;
  const View: TRegistryView=rvDefault): string;
var
  Registry: TRegistry;
begin
  Registry := TRegistry.Create(KEY_READ or RegistryViewAccessFlag(View));
  try
    Registry.RootKey := Root;
    if not Registry.OpenKey(Key) then
      raise ERegistryException.CreateFmt('Key not found: %s', [Key]);
    if not Registry.ValueExists(Name) then
      raise ERegistryException.CreateFmt('Name not found: %s\%s', [Key, Name]);
    Result := Registry.ReadString(Name);//will raise exception in case of failure
  finally
    Registry.Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

该函数ReadRegStr将返回相对于根键Name的键所指定的字符串值.如果存在错误,例如,如果键或名称不存在,或者值的类型错误,则会引发异常.KeyRoot

View参数是一个枚举,使您可以轻松访问注册表的本机,32位或64位视图.请注意,native表示正在运行的进程的本机.因此,对于32位进程,它将是32位视图,对于64位进程,它将是64位视图.此枚举反映了.net中的等效定义.