Можно ли читать / записывать реестр удаленной машины с другими учетными данными? - PullRequest
5 голосов
/ 12 мая 2011

Я использую Delphi для удаленного чтения и записи реестра удаленного компьютера.Это работает, когда моя учетная запись на моей машине имеет доступ администратора к удаленной машине.

Однако я хотел бы иметь возможность указать имя пользователя / pwd при подключении для чтения реестра, чтобы я мог подключиться с альтернативными учетными данными.

С файловой системой я вызвал следующее(с именем пользователя и паролем) и смог установить соединение с удаленной системой и выполнять функции, связанные с файловой системой.Однако это не похоже на работу с реестром.

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 ]

7 голосов
/ 12 мая 2011

Мик, я не могу удержаться, чтобы дать вам решение 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;

Для получения дополнительных опций вы должны проверить документацию об этом классе.

Надеюсь, это поможет вам.

3 голосов
/ 12 мая 2011

Теперь, используя 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');
0 голосов
/ 22 марта 2018

Если кто-то захочет правильно использовать WNetAddConnection2 в C #, вот код.Проблема в том, что 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


}
0 голосов
/ 12 мая 2011

Может быть, вам нужно WNetAddConnection3 ?Я не думаю, что он позволяет удаленный реестр.

Лично я бы посмотрел на WMI и network-named-pipe, которые представляют собой методы удаленного доступа к реестру, которые Windows поддерживает "из коробки".

Кроме того, вы знаете о TRegistry.RegistryConnect.Кажется, у него нет идентификатора пользователя / пароля, но вы все еще не знаете, почему этого недостаточно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...