我正在使用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;
答案 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 版本,因为这绕过了 身份验证层。
检查下一个样本
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');
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
}