是否可以读取/写入具有不同凭据的远程计算机的注册表?

时间:2011-05-12 01:19:31

标签: windows delphi winapi

我正在使用Delphi远程读取和编写远程计算机的注册表。当我的计算机上的帐户具有远程计算机的管理员访问权限时,此功能正常

但是,我希望能够在连接时指定用户名/密码以读取注册表,以便我可以使用备用凭据进行连接。

使用文件系统,我调用了以下内容(使用用户名和密码),并且能够建立与远程系统的连接并执行与文件系统相关的功能。但是,这似乎不适用于注册表。

var
  netResource       : TNetResource;
begin

  FillChar(netResource, SizeOf(netResource), 0);
  netResource.dwScope := RESOURCE_GLOBALNET;
  netResource.dwType := RESOURCETYPE_DISK;
  netResource.dwDisplayType := RESOURCEDISPLAYTYPE_SHARE;
  netResource.dwUsage := RESOURCEUSAGE_CONNECTABLE;
  netResource.lpRemoteName := PChar('\\192.168.1.105\IPC$');

  WNetAddConnection2(netResource, PChar(password), PChar(username), 0);
end;

...

以下是我希望能够调用的函数示例,但指定了可以访问远程计算机的凭据:

procedure TForm1.SetWallpaperKey() ;
var
   reg:TRegistry;
begin
   reg:=TRegistry.Create;

   with reg do begin
    try
     if RegistryConnect('192.168.1.105') then
       if OpenKey('\Control Panel\desktop', False) then begin
       //change wallpaper and tile it
        reg.WriteString ('Wallpaper','c:\windows\CIRCLES.bmp') ;
        reg.WriteString ('TileWallpaper','1') ;
        //disable screen saver//('0'=disable, '1'=enable)
        reg.WriteString('ScreenSaveActive','0') ;
       end
    finally
      reg.Free;
    end;
   end;
end;

4 个答案:

答案 0 :(得分:7)

Mick,我无法抗拒为您提供WMI解决方案问题;),wmi有一个名为StdRegProv的类,它允许您访问本地和远程计算机中的注册表。关键点是类所在的命名空间,这取决于远程计算机中安装的Windows版本。因此,对于Windows Server 2003,Windows XP,Windows 2000,Windows NT 4.0和Windows Me / 98/95,StdRegProv类可用于root\default命名空间,而其他版本(如Windows Vista / 7)则可用名称空间为root\CIMV2

现在要配置凭据以访问注册表,您必须以这种方式在SWbemLocator.ConnectServer方法中设置这些值:

FSWbemLocator.ConnectServer(Server, 'root\default', User, Pass);

另一个重点是这个类只是暴露了访问注册表而不是属性的方法,所以你不能使用wmi查询,而是必须执行wmi方法。

检查下一个样本以了解它是如何工作的。

检查您是否拥有密钥

的权限
uses
  Windows,
  SysUtils,
  ActiveX,
  ComObj;

// The CheckAccess method verifies that the user possesses the specified
// permissions. The method returns a uint32 which is 0 if successful or some other
// value if any other error occurred.

procedure  Invoke_StdRegProv_CheckAccess;
const
  Server = '192.168.52.128';
  User   = 'Administrator';
  Pass   = 'password';
var
  FSWbemLocator   : OLEVariant;
  FWMIService     : OLEVariant;
  FWbemObjectSet  : OLEVariant;
  FInParams       : OLEVariant;
  FOutParams      : OLEVariant;
begin
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  //http://msdn.microsoft.com/en-us/library/aa393664%28v=vs.85%29.aspx
  //StdRegProv is preinstalled in the WMI namespaces root\default and root\cimv2.
  //Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95:  StdRegProv is available only in root\default namespace.
  FWMIService   := FSWbemLocator.ConnectServer(Server, 'root\default', User, Pass);
  //For Windows Vista or Windows 7 you must use the  root\CIMV2 namespace
  //FWMIService   := FSWbemLocator.ConnectServer(Server, 'root\CIMV2', User, Pass);
  FWbemObjectSet:= FWMIService.Get('StdRegProv');
  FInParams     := FWbemObjectSet.Methods_.Item('CheckAccess').InParameters.SpawnInstance_();
  FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
  FInParams.sSubKeyName:='SYSTEM\CurrentControlSet';
  FInParams.uRequired:=KEY_QUERY_VALUE;

  FOutParams    := FWMIService.ExecMethod('StdRegProv', 'CheckAccess', FInParams);
  Writeln(Format('bGranted              %s',[FOutParams.bGranted]));
  Writeln(Format('ReturnValue           %s',[FOutParams.ReturnValue]));
end;

读取字符串值

// The GetStringValue method returns the data value for a named value whose data 
// type is REG_SZ. 
procedure  Invoke_StdRegProv_GetStringValue;
const
  Server = '192.168.52.128';
  User   = 'Administrator';
  Pass   = 'password';
var
  FSWbemLocator   : OLEVariant;
  FWMIService     : OLEVariant;
  FWbemObjectSet  : OLEVariant;
  FInParams       : OLEVariant;
  FOutParams      : OLEVariant;
begin
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  //http://msdn.microsoft.com/en-us/library/aa393664%28v=vs.85%29.aspx
  //StdRegProv is preinstalled in the WMI namespaces root\default and root\cimv2.
  //Windows Server 2003, Windows XP, Windows 2000, Windows NT 4.0, and Windows Me/98/95:  StdRegProv is available only in root\default namespace.
  FWMIService   := FSWbemLocator.ConnectServer(Server, 'root\default', User, Pass);
  //For Windows Vista or Windows 7 you must use the  root\CIMV2 namespace
  //FWMIService   := FSWbemLocator.ConnectServer(Server, 'root\CIMV2', User, Pass);
  FWbemObjectSet:= FWMIService.Get('StdRegProv');
  FInParams     := FWbemObjectSet.Methods_.Item('GetStringValue').InParameters.SpawnInstance_();
  FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
  FInParams.sSubKeyName:='SOFTWARE\Borland\Delphi\5.0';
  FInParams.sValueName:='App';

  FOutParams    := FWMIService.ExecMethod('StdRegProv', 'GetStringValue', FInParams);
  Writeln(Format('sValue                %s',[FOutParams.sValue]));
  Writeln(Format('ReturnValue           %s',[FOutParams.ReturnValue]));
end;

写一个字符串值

// The SetStringValue method sets the data value for a named value whose data type 
// is REG_SZ.
procedure  Invoke_StdRegProv_SetStringValue;
const
  Server = '192.168.52.128';
  User   = 'Administrator';
  Pass   = 'password';
var
  FSWbemLocator   : OLEVariant;
  FWMIService     : OLEVariant;
  FWbemObjectSet  : OLEVariant;
  FInParams       : OLEVariant;
  FOutParams      : OLEVariant;
begin
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  FWMIService   := FSWbemLocator.ConnectServer(Server, 'root\default', User, Pass);
  FWbemObjectSet:= FWMIService.Get('StdRegProv');
  FInParams     := FWbemObjectSet.Methods_.Item('SetStringValue').InParameters.SpawnInstance_();
  FInParams.hDefKey:=HKEY_LOCAL_MACHINE;
  FInParams.sSubKeyName:='SOFTWARE\Borland\Delphi\5.0';
  FInParams.sValueName:='Dummy';
  FInParams.sValue:='ADummyValue';

  FOutParams    := FWMIService.ExecMethod('StdRegProv', 'SetStringValue', FInParams);
  Writeln(Format('ReturnValue           %s',[FOutParams.ReturnValue]));
end;

如需更多选项,您必须查看关于此课程的documentation

我希望这对你有所帮助。

答案 1 :(得分:3)

现在使用Windows API,TRegistry.RegistryConnect函数在内部调用RegConnectRegistry windows函数,文档说:

  

如果当前用户没有   正确访问远程计算机,   对RegConnectRegistry的调用失败。   要连接到远程注册表,请致电   LogonUser用   LOGON32_LOGON_NEW_CREDENTIALS和   调用之前的ImpersonateLoggedOnUser   RegConnectRegistry。

Windows 2000:  One possible workaround is to establish a session
     

到诸如的管理共享   IPC $使用不同的一组   证书。指定凭据   除了当前用户的那些,   使用WNetAddConnection2函数   连接到共享。当你有   完成访问注册表,   取消连接。

Windows XP Home Edition:  You cannot use this function to connect to
     

运行Windows XP的远程计算机   家庭版。这个功能确实有效   使用本地计算机的名称   即使它运行的是Windows XP Home   版本,因为这绕过了   身份验证层。

检查下一个样本

使用windows api注册表函数

uses
  Windows,
  Registry,
  SysUtils;

procedure AccessRemoteRegistry(const lpMachineName, lpszUsername , lpszPassword: PChar);
const
 LOGON32_LOGON_NEW_CREDENTIALS = 9;
 REG_OPTION_OPEN_LINK          = $00000008;
var
  netResource : TNetResource;
  dwFlags     : DWORD;
  dwRetVal    : DWORD;
  phToken     : THandle;
  phkResult   : HKEY;
  phkResult2  : HKEY;
  lpType      : DWORD;
  lpData      : PByte;
  lpcbData    : DWORD;
begin
  ZeroMemory(@netResource, SizeOf(netResource));
  netResource.dwType      := RESOURCETYPE_ANY;
  netResource.lpLocalName := nil;
  netResource.lpRemoteName:= lpMachineName;
  netResource.lpProvider  := nil;
  dwFlags  := CONNECT_UPDATE_PROFILE;

  dwRetVal := WNetAddConnection2(netResource, lpszPassword, lpszUsername, dwFlags);
  if dwRetVal=NO_ERROR then
  begin
    try
     Writeln('Connected');
     if LogonUser(lpszUsername, nil, lpszPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50,phToken) then
     begin
       try
          if ImpersonateLoggedOnUser(phToken) then
          begin
           try
             dwRetVal:=RegConnectRegistry(lpMachineName,HKEY_LOCAL_MACHINE,phkResult);
             if dwRetVal = ERROR_SUCCESS then
             begin
               dwRetVal:=RegOpenKeyEx(phkResult,PChar('SOFTWARE\Borland\Delphi\5.0'), REG_OPTION_OPEN_LINK, KEY_QUERY_VALUE, phkResult2);
               if dwRetVal = ERROR_SUCCESS then
               begin
                try
                 lpType:=REG_SZ;
                 //get the size of the buffer
                 dwRetVal:=RegQueryValueEx(phkResult2, PChar('App'), nil, @lpType, nil, @lpcbData);
                 if dwRetVal = ERROR_SUCCESS then
                 begin
                   GetMem(lpData,lpcbData);
                   try
                     dwRetVal:=RegQueryValueEx(phkResult2, 'App', nil, @lpType, lpData, @lpcbData);
                     if dwRetVal = ERROR_SUCCESS then
                      WriteLn(PChar(lpData))
                     else
                     Writeln(Format('RegQueryValueEx  error %d',[dwRetVal]));
                   finally
                     FreeMem(lpData);
                   end;
                 end
                 else
                 Writeln(Format('RegQueryValueEx  error %d',[dwRetVal]));
                finally
                 RegCloseKey(phkResult2);
                end;
               end
               else
               Writeln(Format('RegOpenKeyEx error %d',[dwRetVal]));
             end
             else
              Writeln(Format('RegConnectRegistry error %d',[dwRetVal]));
           finally
              RevertToSelf;
           end;
          end
          else
          RaiseLastOSError;
       finally
         CloseHandle(phToken);
       end;
     end
     else
       RaiseLastOSError;
    finally
       dwRetVal:=WNetCancelConnection2(netResource.lpRemoteName, CONNECT_UPDATE_PROFILE, false);
       if dwRetVal<>NO_ERROR then
         Writeln(Format('WNetCancelConnection2 error %d',[dwRetVal]));
    end;
  end
  else
    Writeln(Format('WNetAddConnection2 Connection error %d',[dwRetVal]));
end;

以这种方式使用

AccessRemoteRegistry('\\192.168.52.128','NormalUser','password');

使用TRegistry delphi类

procedure AccessRemoteRegistry2(const lpMachineName, lpszUsername , lpszPassword: PChar);
const
 LOGON32_LOGON_NEW_CREDENTIALS = 9;
 REG_OPTION_OPEN_LINK          = $00000008;
var
  netResource : TNetResource;
  dwFlags     : DWORD;
  dwRetVal    : DWORD;
  phToken     : THandle;
  Reg         : TRegistry;
begin
  ZeroMemory(@netResource, SizeOf(netResource));
  netResource.dwType      := RESOURCETYPE_ANY;
  netResource.lpLocalName := nil;
  netResource.lpRemoteName:= lpMachineName;
  netResource.lpProvider  := nil;
  dwFlags  := CONNECT_UPDATE_PROFILE;
  dwRetVal := WNetAddConnection2(netResource, lpszPassword, lpszUsername, dwFlags);
  if dwRetVal=NO_ERROR then
  begin
    try
     Writeln('Connected');
     if LogonUser(lpszUsername, nil, lpszPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50,phToken) then
     begin
       try
        if ImpersonateLoggedOnUser(phToken) then
        begin
         try
           reg:=TRegistry.Create;
           try
             reg.RootKey:=HKEY_LOCAL_MACHINE;
             if reg.RegistryConnect(lpMachineName) then
              if reg.OpenKey('SOFTWARE\Borland\Delphi\5.0',False) then
                WriteLn(reg.ReadString('App'));
           finally
             reg.CloseKey;
             reg.Free;
           end;
         finally
            RevertToSelf;
         end;
        end
        else
        RaiseLastOSError;
       finally
         CloseHandle(phToken);
       end;
     end
     else
     RaiseLastOSError;
    finally
       dwRetVal:=WNetCancelConnection2(netResource.lpRemoteName, CONNECT_UPDATE_PROFILE, false);
       if dwRetVal<>NO_ERROR then
         Writeln(Format('WNetCancelConnection2 error %d',[dwRetVal]));
    end;
  end
  else
    Writeln(Format('WNetAddConnection2 Connection error %d',[dwRetVal]));
end;

以这种方式使用

AccessRemoteRegistry2('\\192.168.52.128','NormalUser','password');

答案 2 :(得分:0)

也许你需要WNetAddConnection3?我认为它不支持远程注册。

我个人会查看WMI和网络命名管道,它们是Windows支持的远程注册表访问方法。

另外,您了解TRegistry.RegistryConnect。它似乎没有用户名/密码,你想要的东西,但我仍然不清楚为什么这还不够。

答案 3 :(得分:0)

如果有人想在C#中正确使用WNetAddConnection2,这里有一些代码。问题是WNetAddConnection2需要一个IntPtr来保存NETRESOURCE的缓冲区,否则你得到的返回代码是487(0x1E7),它是ERROR_INVALID_ADDRESS。尝试访问无效地址。

我个人试图获得通过连接到IPC $来提升权限和思想的注册表项,但是它当然没有用,似乎唯一的办法就是使用RegCreateKeyEx和RegConnectRegistry的基本密钥...这是可以接受的哈哈,只要它实际上有效,哈哈!

public class IPCShareSession : IDisposable
{
    #region PInvoke Functions,Structs,Enums

    [DllImport("mpr.dll", CharSet = CharSet.Unicode)]
    private static extern int WNetAddConnection2(IntPtr NetResource, string Password, string Username, WNetConnect Flags);

    [DllImport("mpr.dll", CharSet = CharSet.Unicode)]
    private static extern int WNetCancelConnection2(string ServerName, WNetDisconnect Flags, bool Force);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    private class NETRESOURCE
    {
        public WNetResourceScope dwScope = 0;
        public WNetResourceType dwType = 0;
        public WNetResourceDisplayType dwDisplayType = 0;
        public WNetResourceUsage dwUsage = 0;
        public string lpLocalName = null;
        public string lpRemoteName = null;
        public string lpComment = null;
        public string lpProvider = null;
    };

    private enum WNetResourceScope
    {
        Connected = 0x1,
        GlobalNetwork = 0x2,
        Remembered = 0x3,
        Recent = 0x4,
        Context = 0x5
    }

    public enum WNetResourceType
    {
        Any = 0,
        Disk = 1,
        Print = 2,
        Reserved = 8
    }

    private enum WNetResourceUsage
    {
        Connectable = 0x1,
        Container = 0x2,
        NoLocalDevice = 0x4,
        Sibling = 0x8,
        Attached = 0x10,
        All = Connectable | Container | Attached
    }

    private enum WNetResourceDisplayType
    {
        Generic = 0x0,
        Domain = 0x1,
        Server = 0x2,
        Share = 0x3,
        File = 0x4,
        Group = 0x5,
        Network = 0x6,
        Root = 0x7,
        ShareAdmin = 0x8,
        Directory = 0x9,
        Tree = 0xa,
        NDSContainer = 0xb
    }

    private enum WNetConnect : int
    {
        CONNECT_UPDATE_PROFILE = 0x00000001,
        CONNECT_UPDATE_RECENT = 0x00000002,
        CONNECT_TEMPORARY = 0x00000004,
        CONNECT_INTERACTIVE = 0x00000008,
        CONNECT_PROMPT = 0x00000010,
        CONNECT_REDIRECT = 0x00000080,
        CONNECT_CURRENT_MEDIA = 0x00000200,
        CONNECT_COMMANDLINE = 0x00000800,
        CONNECT_CMD_SAVECRED = 0x00001000,
        CONNECT_CRED_RESET = 0x00002000
    }

    private enum WNetDisconnect
    {
        DISCONNECT=0,
        DISCONNECT_AND_REMOVE=1
    }

    #endregion

    private string ServerShare = null;
    private NETRESOURCE serverNR = null;
    private bool bConnected = false;

    public IPCShareSession(string ServerName, string ShareName = "IPC$")
    {
        ServerShare = string.Format(@"\\{0}\{1}", ServerName, ShareName);
        //Setup nr to be a IPC share session
        serverNR = new NETRESOURCE
        {
            dwType = WNetResourceType.Disk,
            lpLocalName = null,
            lpRemoteName = ServerShare,
            lpProvider = null,
            dwDisplayType = WNetResourceDisplayType.ShareAdmin,
            dwUsage = WNetResourceUsage.Connectable,
        };
    }

    public int Connect()
    {
        if(!bConnected)
        {
            IntPtr pNR = Marshal.AllocHGlobal(Marshal.SizeOf(serverNR));
            Marshal.StructureToPtr(serverNR, pNR, false);
            int ret = WNetAddConnection2(pNR, null, null, WNetConnect.CONNECT_TEMPORARY);
            //Free our unmanaged pointer now that we're done with it.
            Marshal.FreeHGlobal(pNR);
            bConnected = ret == 0;
            return ret;
        }
        else
        {
            return -1;
        }
    }

    public int Disconnect()
    {
        int ret = 0;
        if (bConnected)
        {
            ret = WNetCancelConnection2(ServerShare, WNetDisconnect.DISCONNECT, true);
            bConnected = false;
        }
        else
        {
            ret = -1;
        }
        return ret;
    }

    #region IDisposable Support

    private bool disposedValue = false; // To detect redundant calls

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                if (bConnected)
                {
                    Disconnect();
                }
            }
            disposedValue = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
    }

    #endregion


}