RDPWInst.dpr 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316
  1. {
  2. Copyright 2018 Stas'M Corp.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. }
  13. program RDPWInst;
  14. {$APPTYPE CONSOLE}
  15. {$R resource.res}
  16. uses
  17. SysUtils,
  18. Windows,
  19. Classes,
  20. WinSvc,
  21. Registry,
  22. WinInet,
  23. AccCtrl,
  24. AclAPI;
  25. function EnumServicesStatusEx(
  26. hSCManager: SC_HANDLE;
  27. InfoLevel,
  28. dwServiceType,
  29. dwServiceState: DWORD;
  30. lpServices: PByte;
  31. cbBufSize: DWORD;
  32. var pcbBytesNeeded,
  33. lpServicesReturned,
  34. lpResumeHandle: DWORD;
  35. pszGroupName: PWideChar): BOOL; stdcall;
  36. external advapi32 name 'EnumServicesStatusExW';
  37. function ConvertStringSidToSid(
  38. StringSid: PWideChar;
  39. var Sid: PSID): BOOL; stdcall;
  40. external advapi32 name 'ConvertStringSidToSidW';
  41. type
  42. FILE_VERSION = record
  43. Version: record case Boolean of
  44. True: (dw: DWORD);
  45. False: (w: record
  46. Minor, Major: Word;
  47. end;)
  48. end;
  49. Release, Build: Word;
  50. bDebug, bPrerelease, bPrivate, bSpecial: Boolean;
  51. end;
  52. SERVICE_STATUS_PROCESS = packed record
  53. dwServiceType,
  54. dwCurrentState,
  55. dwControlsAccepted,
  56. dwWin32ExitCode,
  57. dwServiceSpecificExitCode,
  58. dwCheckPoint,
  59. dwWaitHint,
  60. dwProcessId,
  61. dwServiceFlags: DWORD;
  62. end;
  63. PSERVICE_STATUS_PROCESS = ^SERVICE_STATUS_PROCESS;
  64. ENUM_SERVICE_STATUS_PROCESS = packed record
  65. lpServiceName,
  66. lpDisplayName: PWideChar;
  67. ServiceStatusProcess: SERVICE_STATUS_PROCESS;
  68. end;
  69. PENUM_SERVICE_STATUS_PROCESS = ^ENUM_SERVICE_STATUS_PROCESS;
  70. const
  71. SC_ENUM_PROCESS_INFO = 0;
  72. TermService = 'TermService';
  73. var
  74. Installed: Boolean;
  75. Online: Boolean;
  76. WrapPath: String;
  77. Arch: Byte;
  78. OldWow64RedirectionValue: LongBool;
  79. TermServicePath: String;
  80. FV: FILE_VERSION;
  81. TermServicePID: DWORD;
  82. ShareSvc: Array of String;
  83. sShareSvc: String;
  84. function SupportedArchitecture: Boolean;
  85. var
  86. SI: TSystemInfo;
  87. begin
  88. GetNativeSystemInfo(SI);
  89. case SI.wProcessorArchitecture of
  90. 0:
  91. begin
  92. Arch := 32;
  93. Result := True; // Intel x86
  94. end;
  95. 6: Result := False; // Itanium-based x64
  96. 9: begin
  97. Arch := 64;
  98. Result := True; // Intel/AMD x64
  99. end;
  100. else Result := False;
  101. end;
  102. end;
  103. function DisableWowRedirection: Boolean;
  104. type
  105. TFunc = function(var Wow64FsEnableRedirection: LongBool): LongBool; stdcall;
  106. var
  107. hModule: THandle;
  108. Wow64DisableWow64FsRedirection: TFunc;
  109. begin
  110. Result := False;
  111. hModule := GetModuleHandle(kernel32);
  112. if hModule <> 0 then
  113. Wow64DisableWow64FsRedirection := GetProcAddress(hModule, 'Wow64DisableWow64FsRedirection')
  114. else
  115. Exit;
  116. if @Wow64DisableWow64FsRedirection <> nil then
  117. Result := Wow64DisableWow64FsRedirection(OldWow64RedirectionValue);
  118. end;
  119. function RevertWowRedirection: Boolean;
  120. type
  121. TFunc = function(var Wow64RevertWow64FsRedirection: LongBool): LongBool; stdcall;
  122. var
  123. hModule: THandle;
  124. Wow64RevertWow64FsRedirection: TFunc;
  125. begin
  126. Result := False;
  127. hModule := GetModuleHandle(kernel32);
  128. if hModule <> 0 then
  129. Wow64RevertWow64FsRedirection := GetProcAddress(hModule, 'Wow64RevertWow64FsRedirection')
  130. else
  131. Exit;
  132. if @Wow64RevertWow64FsRedirection <> nil then
  133. Result := Wow64RevertWow64FsRedirection(OldWow64RedirectionValue);
  134. end;
  135. procedure CheckInstall;
  136. var
  137. Code: DWORD;
  138. TermServiceHost: String;
  139. Reg: TRegistry;
  140. begin
  141. if Arch = 64 then
  142. Reg := TRegistry.Create(KEY_WOW64_64KEY)
  143. else
  144. Reg := TRegistry.Create;
  145. Reg.RootKey := HKEY_LOCAL_MACHINE;
  146. if not Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Services\TermService') then
  147. begin
  148. Reg.Free;
  149. Code := GetLastError;
  150. Writeln('[-] OpenKeyReadOnly error (code ', Code, ').');
  151. Halt(Code);
  152. end;
  153. TermServiceHost := Reg.ReadString('ImagePath');
  154. Reg.CloseKey;
  155. if (Pos('svchost.exe', LowerCase(TermServiceHost)) = 0)
  156. and (Pos('svchost -k', LowerCase(TermServiceHost)) = 0) then
  157. begin
  158. Reg.Free;
  159. Writeln('[-] TermService is hosted in a custom application (BeTwin, etc.) - unsupported.');
  160. Writeln('[*] ImagePath: "', TermServiceHost, '".');
  161. Halt(ERROR_NOT_SUPPORTED);
  162. end;
  163. if not Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Services\TermService\Parameters') then
  164. begin
  165. Reg.Free;
  166. Code := GetLastError;
  167. Writeln('[-] OpenKeyReadOnly error (code ', Code, ').');
  168. Halt(Code);
  169. end;
  170. TermServicePath := Reg.ReadString('ServiceDll');
  171. Reg.CloseKey;
  172. if (Pos('termsrv.dll', LowerCase(TermServicePath)) = 0)
  173. and (Pos('rdpwrap.dll', LowerCase(TermServicePath)) = 0) then
  174. begin
  175. Reg.Free;
  176. Writeln('[-] Another third-party TermService library is installed.');
  177. Writeln('[*] ServiceDll: "', TermServicePath, '".');
  178. Halt(ERROR_NOT_SUPPORTED);
  179. end;
  180. Reg.Free;
  181. Installed := Pos('rdpwrap.dll', LowerCase(TermServicePath)) > 0;
  182. end;
  183. function SvcGetStart(SvcName: String): Integer;
  184. var
  185. hSC: SC_HANDLE;
  186. hSvc: THandle;
  187. Code: DWORD;
  188. lpServiceConfig: PQueryServiceConfig;
  189. Buf: Pointer;
  190. cbBufSize, pcbBytesNeeded: Cardinal;
  191. begin
  192. Result := -1;
  193. Writeln('[*] Checking ', SvcName, '...');
  194. hSC := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT);
  195. if hSC = 0 then
  196. begin
  197. Code := GetLastError;
  198. Writeln('[-] OpenSCManager error (code ', Code, ').');
  199. Exit;
  200. end;
  201. hSvc := OpenService(hSC, PWideChar(SvcName), SERVICE_QUERY_CONFIG);
  202. if hSvc = 0 then
  203. begin
  204. CloseServiceHandle(hSC);
  205. Code := GetLastError;
  206. Writeln('[-] OpenService error (code ', Code, ').');
  207. Exit;
  208. end;
  209. if QueryServiceConfig(hSvc, nil, 0, pcbBytesNeeded) then begin
  210. Writeln('[-] QueryServiceConfig failed.');
  211. Exit;
  212. end;
  213. cbBufSize := pcbBytesNeeded;
  214. GetMem(Buf, cbBufSize);
  215. if not QueryServiceConfig(hSvc, Buf, cbBufSize, pcbBytesNeeded) then begin
  216. FreeMem(Buf, cbBufSize);
  217. CloseServiceHandle(hSvc);
  218. CloseServiceHandle(hSC);
  219. Code := GetLastError;
  220. Writeln('[-] QueryServiceConfig error (code ', Code, ').');
  221. Exit;
  222. end else begin
  223. lpServiceConfig := Buf;
  224. Result := Integer(lpServiceConfig^.dwStartType);
  225. end;
  226. FreeMem(Buf, cbBufSize);
  227. CloseServiceHandle(hSvc);
  228. CloseServiceHandle(hSC);
  229. end;
  230. procedure SvcConfigStart(SvcName: String; dwStartType: Cardinal);
  231. var
  232. hSC: SC_HANDLE;
  233. hSvc: THandle;
  234. Code: DWORD;
  235. begin
  236. Writeln('[*] Configuring ', SvcName, '...');
  237. hSC := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT);
  238. if hSC = 0 then
  239. begin
  240. Code := GetLastError;
  241. Writeln('[-] OpenSCManager error (code ', Code, ').');
  242. Exit;
  243. end;
  244. hSvc := OpenService(hSC, PWideChar(SvcName), SERVICE_CHANGE_CONFIG);
  245. if hSvc = 0 then
  246. begin
  247. CloseServiceHandle(hSC);
  248. Code := GetLastError;
  249. Writeln('[-] OpenService error (code ', Code, ').');
  250. Exit;
  251. end;
  252. if not ChangeServiceConfig(hSvc, SERVICE_NO_CHANGE, dwStartType,
  253. SERVICE_NO_CHANGE, nil, nil, nil, nil, nil, nil, nil) then begin
  254. CloseServiceHandle(hSvc);
  255. CloseServiceHandle(hSC);
  256. Code := GetLastError;
  257. Writeln('[-] ChangeServiceConfig error (code ', Code, ').');
  258. Exit;
  259. end;
  260. CloseServiceHandle(hSvc);
  261. CloseServiceHandle(hSC);
  262. end;
  263. procedure SvcStart(SvcName: String);
  264. var
  265. hSC: SC_HANDLE;
  266. hSvc: THandle;
  267. Code: DWORD;
  268. pch: PWideChar;
  269. procedure ExitError(Func: String; ErrorCode: DWORD);
  270. begin
  271. if hSC > 0 then
  272. CloseServiceHandle(hSC);
  273. if hSvc > 0 then
  274. CloseServiceHandle(hSvc);
  275. Writeln('[-] ', Func, ' error (code ', ErrorCode, ').');
  276. end;
  277. begin
  278. hSC := 0;
  279. hSvc := 0;
  280. Writeln('[*] Starting ', SvcName, '...');
  281. hSC := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT);
  282. if hSC = 0 then
  283. begin
  284. ExitError('OpenSCManager', GetLastError);
  285. Exit;
  286. end;
  287. hSvc := OpenService(hSC, PWideChar(SvcName), SERVICE_START);
  288. if hSvc = 0 then
  289. begin
  290. ExitError('OpenService', GetLastError);
  291. Exit;
  292. end;
  293. pch := nil;
  294. if not StartService(hSvc, 0, pch) then begin
  295. Code := GetLastError;
  296. if Code = 1056 then begin // Service already started
  297. Sleep(2000); // or SCM hasn't registered killed process
  298. if not StartService(hSvc, 0, pch) then begin
  299. ExitError('StartService', Code);
  300. Exit;
  301. end;
  302. end else begin
  303. ExitError('StartService', Code);
  304. Exit;
  305. end;
  306. end;
  307. CloseServiceHandle(hSvc);
  308. CloseServiceHandle(hSC);
  309. end;
  310. procedure CheckTermsrvProcess;
  311. label
  312. back;
  313. var
  314. hSC: SC_HANDLE;
  315. dwNeedBytes, dwReturnBytes, dwResumeHandle, Code: DWORD;
  316. Svc: Array of ENUM_SERVICE_STATUS_PROCESS;
  317. I: Integer;
  318. Found, Started: Boolean;
  319. TermServiceName: String;
  320. begin
  321. Started := False;
  322. back:
  323. hSC := OpenSCManager(nil, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CONNECT or SC_MANAGER_ENUMERATE_SERVICE);
  324. if hSC = 0 then
  325. begin
  326. Code := GetLastError;
  327. Writeln('[-] OpenSCManager error (code ', Code, ').');
  328. Halt(Code);
  329. end;
  330. dwResumeHandle := 0;
  331. SetLength(Svc, 1489);
  332. FillChar(Svc[0], sizeof(Svc[0])*Length(Svc), 0);
  333. if not EnumServicesStatusEx(hSC, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
  334. @Svc[0], sizeof(Svc[0])*Length(Svc), dwNeedBytes, dwReturnBytes, dwResumeHandle, nil) then begin
  335. Code := GetLastError;
  336. if Code <> ERROR_MORE_DATA then
  337. begin
  338. CloseServiceHandle(hSC);
  339. Writeln('[-] EnumServicesStatusEx error (code ', Code, ').');
  340. Halt(Code);
  341. end
  342. else
  343. begin
  344. SetLength(Svc, 5957);
  345. FillChar(Svc[0], sizeof(Svc[0])*Length(Svc), 0);
  346. if not EnumServicesStatusEx(hSC, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
  347. @Svc[0], sizeof(Svc[0])*Length(Svc), dwNeedBytes, dwReturnBytes, dwResumeHandle, nil) then begin
  348. CloseServiceHandle(hSC);
  349. Code := GetLastError;
  350. Writeln('[-] EnumServicesStatusEx error (code ', Code, ').');
  351. Halt(Code);
  352. end;
  353. end;
  354. end;
  355. CloseServiceHandle(hSC);
  356. Found := False;
  357. for I := 0 to Length(Svc) - 1 do
  358. begin
  359. if Svc[I].lpServiceName = nil then
  360. Break;
  361. if LowerCase(Svc[I].lpServiceName) = LowerCase(TermService) then
  362. begin
  363. Found := True;
  364. TermServiceName := Svc[I].lpServiceName;
  365. TermServicePID := Svc[I].ServiceStatusProcess.dwProcessId;
  366. Break;
  367. end;
  368. end;
  369. if not Found then
  370. begin
  371. Writeln('[-] TermService not found.');
  372. Halt(ERROR_SERVICE_DOES_NOT_EXIST);
  373. end;
  374. if TermServicePID = 0 then
  375. begin
  376. if Started then begin
  377. Writeln('[-] Failed to set up TermService. Unknown error.');
  378. Halt(ERROR_SERVICE_NOT_ACTIVE);
  379. end;
  380. SvcConfigStart(TermService, SERVICE_AUTO_START);
  381. SvcStart(TermService);
  382. Started := True;
  383. goto back;
  384. end
  385. else
  386. Writeln('[+] TermService found (pid ', TermServicePID, ').');
  387. SetLength(ShareSvc, 0);
  388. for I := 0 to Length(Svc) - 1 do
  389. begin
  390. if Svc[I].lpServiceName = nil then
  391. Break;
  392. if Svc[I].ServiceStatusProcess.dwProcessId = TermServicePID then
  393. if Svc[I].lpServiceName <> TermServiceName then
  394. begin
  395. SetLength(ShareSvc, Length(ShareSvc)+1);
  396. ShareSvc[Length(ShareSvc)-1] := Svc[I].lpServiceName;
  397. end;
  398. end;
  399. sShareSvc := '';
  400. for I := 0 to Length(ShareSvc) - 1 do
  401. if sShareSvc = '' then
  402. sShareSvc := ShareSvc[I]
  403. else
  404. sShareSvc := sShareSvc + ', ' + ShareSvc[I];
  405. if sShareSvc <> '' then
  406. Writeln('[*] Shared services found: ', sShareSvc)
  407. else
  408. Writeln('[*] No shared services found.');
  409. end;
  410. function AddPrivilege(SePriv: String): Boolean;
  411. var
  412. hToken: THandle;
  413. SeNameValue: Int64;
  414. tkp: TOKEN_PRIVILEGES;
  415. ReturnLength: Cardinal;
  416. ErrorCode: Cardinal;
  417. begin
  418. Result := False;
  419. if not OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
  420. or TOKEN_QUERY, hToken) then begin
  421. ErrorCode := GetLastError;
  422. Writeln('[-] OpenProcessToken error (code ' + IntToStr(ErrorCode) + ').');
  423. Exit;
  424. end;
  425. if not LookupPrivilegeValue(nil, PWideChar(SePriv), SeNameValue) then begin
  426. ErrorCode := GetLastError;
  427. Writeln('[-] LookupPrivilegeValue error (code ' + IntToStr(ErrorCode) + ').');
  428. Exit;
  429. end;
  430. tkp.PrivilegeCount := 1;
  431. tkp.Privileges[0].Luid := SeNameValue;
  432. tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
  433. if not AdjustTokenPrivileges(hToken, False, tkp, SizeOf(tkp), tkp, ReturnLength) then begin
  434. ErrorCode := GetLastError;
  435. Writeln('[-] AdjustTokenPrivileges error (code ' + IntToStr(ErrorCode) + ').');
  436. Exit;
  437. end;
  438. Result := True;
  439. end;
  440. procedure KillProcess(PID: DWORD);
  441. var
  442. hProc: THandle;
  443. Code: DWORD;
  444. begin
  445. hProc := OpenProcess(PROCESS_TERMINATE, False, PID);
  446. if hProc = 0 then
  447. begin
  448. Code := GetLastError;
  449. Writeln('[-] OpenProcess error (code ', Code, ').');
  450. Halt(Code);
  451. end;
  452. if not TerminateProcess(hProc, 0) then
  453. begin
  454. CloseHandle(hProc);
  455. Code := GetLastError;
  456. Writeln('[-] TerminateProcess error (code ', Code, ').');
  457. Halt(Code);
  458. end;
  459. CloseHandle(hProc);
  460. end;
  461. function ExecWait(Cmdline: String): Boolean;
  462. var
  463. si: STARTUPINFO;
  464. pi: PROCESS_INFORMATION;
  465. begin
  466. Result := False;
  467. ZeroMemory(@si, sizeof(si));
  468. si.cb := sizeof(si);
  469. UniqueString(Cmdline);
  470. if not CreateProcess(nil, PWideChar(Cmdline), nil, nil, True, 0, nil, nil, si, pi) then begin
  471. Writeln('[-] CreateProcess error (code: ', GetLastError, ').');
  472. Exit;
  473. end;
  474. CloseHandle(pi.hThread);
  475. WaitForSingleObject(pi.hProcess, INFINITE);
  476. CloseHandle(pi.hProcess);
  477. Result := True;
  478. end;
  479. function ExpandPath(Path: String): String;
  480. var
  481. Str: Array[0..511] of Char;
  482. begin
  483. Result := '';
  484. FillChar(Str, 512, 0);
  485. if Arch = 64 then
  486. Path := StringReplace(Path, '%ProgramFiles%', '%ProgramW6432%', [rfReplaceAll, rfIgnoreCase]);
  487. if ExpandEnvironmentStrings(PWideChar(Path), Str, 512) > 0 then
  488. Result := Str;
  489. end;
  490. procedure SetWrapperDll;
  491. var
  492. Reg: TRegistry;
  493. Code: DWORD;
  494. begin
  495. if Arch = 64 then
  496. Reg := TRegistry.Create(KEY_WRITE or KEY_WOW64_64KEY)
  497. else
  498. Reg := TRegistry.Create;
  499. Reg.RootKey := HKEY_LOCAL_MACHINE;
  500. if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Services\TermService\Parameters', True) then
  501. begin
  502. Code := GetLastError;
  503. Writeln('[-] OpenKey error (code ', Code, ').');
  504. Halt(Code);
  505. end;
  506. try
  507. Reg.WriteExpandString('ServiceDll', WrapPath);
  508. if (Arch = 64) and (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 0) then
  509. ExecWait('"'+ExpandPath('%SystemRoot%')+'\system32\reg.exe" add HKLM\SYSTEM\CurrentControlSet\Services\TermService\Parameters /v ServiceDll /t REG_EXPAND_SZ /d "'+WrapPath+'" /f');
  510. except
  511. Writeln('[-] WriteExpandString error.');
  512. Halt(ERROR_ACCESS_DENIED);
  513. end;
  514. Reg.CloseKey;
  515. Reg.Free;
  516. end;
  517. procedure ResetServiceDll;
  518. var
  519. Reg: TRegistry;
  520. Code: DWORD;
  521. begin
  522. if Arch = 64 then
  523. Reg := TRegistry.Create(KEY_WRITE or KEY_WOW64_64KEY)
  524. else
  525. Reg := TRegistry.Create;
  526. Reg.RootKey := HKEY_LOCAL_MACHINE;
  527. if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Services\TermService\Parameters', True) then
  528. begin
  529. Code := GetLastError;
  530. Writeln('[-] OpenKey error (code ', Code, ').');
  531. Halt(Code);
  532. end;
  533. try
  534. Reg.WriteExpandString('ServiceDll', '%SystemRoot%\System32\termsrv.dll');
  535. except
  536. Writeln('[-] WriteExpandString error.');
  537. Halt(ERROR_ACCESS_DENIED);
  538. end;
  539. Reg.CloseKey;
  540. Reg.Free;
  541. end;
  542. procedure ExtractRes(ResName, Path: String);
  543. var
  544. ResStream: TResourceStream;
  545. begin
  546. ResStream := TResourceStream.Create(HInstance, ResName, RT_RCDATA);
  547. try
  548. ResStream.SaveToFile(Path);
  549. except
  550. Writeln('[-] Failed to extract file.');
  551. Writeln('[*] Resource name: ' + ResName);
  552. Writeln('[*] Destination path: ' + Path);
  553. ResStream.Free;
  554. Exit;
  555. end;
  556. Writeln('[+] Extracted ', ResName, ' -> ', Path);
  557. ResStream.Free;
  558. end;
  559. function ExtractResText(ResName: String): String;
  560. var
  561. ResStream: TResourceStream;
  562. Str: TStringList;
  563. begin
  564. ResStream := TResourceStream.Create(HInstance, ResName, RT_RCDATA);
  565. Str := TStringList.Create;
  566. try
  567. Str.LoadFromStream(ResStream);
  568. except
  569. end;
  570. ResStream.Free;
  571. Result := Str.Text;
  572. Str.Free;
  573. end;
  574. function GitINIFile(var Content: String): Boolean;
  575. const
  576. URL = 'https://raw.githubusercontent.com/stascorp/rdpwrap/master/res/rdpwrap.ini';
  577. var
  578. NetHandle: HINTERNET;
  579. UrlHandle: HINTERNET;
  580. Str: String;
  581. Buf: Array[0..1023] of Byte;
  582. BytesRead: DWORD;
  583. begin
  584. Result := False;
  585. Content := '';
  586. NetHandle := InternetOpen('RDP Wrapper Update', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  587. if not Assigned(NetHandle) then
  588. Exit;
  589. UrlHandle := InternetOpenUrl(NetHandle, PChar(URL), nil, 0, INTERNET_FLAG_RELOAD, 0);
  590. if not Assigned(UrlHandle) then
  591. begin
  592. InternetCloseHandle(NetHandle);
  593. Exit;
  594. end;
  595. repeat
  596. InternetReadFile(UrlHandle, @Buf[0], SizeOf(Buf), BytesRead);
  597. SetString(Str, PAnsiChar(@Buf[0]), BytesRead);
  598. Content := Content + Str;
  599. until BytesRead = 0;
  600. InternetCloseHandle(UrlHandle);
  601. InternetCloseHandle(NetHandle);
  602. Result := True;
  603. end;
  604. procedure GrantSidFullAccess(Path, SID: String);
  605. var
  606. p_SID: PSID;
  607. pDACL: PACL;
  608. EA: EXPLICIT_ACCESS;
  609. Code, Result: DWORD;
  610. begin
  611. p_SID := nil;
  612. if not ConvertStringSidToSid(PChar(SID), p_SID) then
  613. begin
  614. Code := GetLastError;
  615. Writeln('[-] ConvertStringSidToSid error (code ', Code, ').');
  616. Exit;
  617. end;
  618. EA.grfAccessPermissions := GENERIC_ALL;
  619. EA.grfAccessMode := GRANT_ACCESS;
  620. EA.grfInheritance := SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  621. EA.Trustee.pMultipleTrustee := nil;
  622. EA.Trustee.MultipleTrusteeOperation := NO_MULTIPLE_TRUSTEE;
  623. EA.Trustee.TrusteeForm := TRUSTEE_IS_SID;
  624. EA.Trustee.TrusteeType := TRUSTEE_IS_WELL_KNOWN_GROUP;
  625. EA.Trustee.ptstrName := p_SID;
  626. Result := SetEntriesInAcl(1, @EA, nil, pDACL);
  627. if Result = ERROR_SUCCESS then
  628. begin
  629. if SetNamedSecurityInfo(pchar(Path), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, pDACL, nil) <> ERROR_SUCCESS then
  630. begin
  631. Code := GetLastError;
  632. Writeln('[-] SetNamedSecurityInfo error (code ', Code, ').');
  633. end;
  634. LocalFree(Cardinal(pDACL));
  635. end
  636. else begin
  637. Code := GetLastError;
  638. Writeln('[-] SetEntriesInAcl error (code ', Code, ').');
  639. end;
  640. end;
  641. procedure ExtractFiles;
  642. var
  643. RDPClipRes, RfxvmtRes, S: String;
  644. OnlineINI: TStringList;
  645. begin
  646. if not DirectoryExists(ExtractFilePath(ExpandPath(WrapPath))) then
  647. if ForceDirectories(ExtractFilePath(ExpandPath(WrapPath))) then begin
  648. S := ExtractFilePath(ExpandPath(WrapPath));
  649. Writeln('[+] Folder created: ', S);
  650. GrantSidFullAccess(S, 'S-1-5-18'); // Local System account
  651. GrantSidFullAccess(S, 'S-1-5-6'); // Service group
  652. end
  653. else begin
  654. Writeln('[-] ForceDirectories error.');
  655. Writeln('[*] Path: ', ExtractFilePath(ExpandPath(WrapPath)));
  656. Halt(0);
  657. end;
  658. if Online then
  659. begin
  660. Writeln('[*] Downloading latest INI file...');
  661. OnlineINI := TStringList.Create;
  662. if GitINIFile(S) then begin
  663. OnlineINI.Text := S;
  664. S := ExtractFilePath(ExpandPath(WrapPath)) + 'rdpwrap.ini';
  665. OnlineINI.SaveToFile(S);
  666. Writeln('[+] Latest INI file -> ', S);
  667. end
  668. else
  669. begin
  670. Writeln('[-] Failed to get online INI file, using built-in.');
  671. Online := False;
  672. end;
  673. OnlineINI.Free;
  674. end;
  675. if not Online then
  676. begin
  677. S := ExtractFilePath(ParamStr(0)) + 'rdpwrap.ini';
  678. if FileExists(S) then
  679. begin
  680. OnlineINI := TStringList.Create;
  681. OnlineINI.LoadFromFile(S);
  682. S := ExtractFilePath(ExpandPath(WrapPath)) + 'rdpwrap.ini';
  683. OnlineINI.SaveToFile(S);
  684. Writeln('[+] Current INI file -> ', S);
  685. OnlineINI.Free;
  686. end else
  687. ExtractRes('config', ExtractFilePath(ExpandPath(WrapPath)) + 'rdpwrap.ini');
  688. end;
  689. RDPClipRes := '';
  690. RfxvmtRes := '';
  691. case Arch of
  692. 32: begin
  693. ExtractRes('rdpw32', ExpandPath(WrapPath));
  694. if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 0) then
  695. RDPClipRes := 'rdpclip6032';
  696. if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 1) then
  697. RDPClipRes := 'rdpclip6132';
  698. if (FV.Version.w.Major = 10) and (FV.Version.w.Minor = 0) then
  699. RfxvmtRes := 'rfxvmt32';
  700. end;
  701. 64: begin
  702. ExtractRes('rdpw64', ExpandPath(WrapPath));
  703. if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 0) then
  704. RDPClipRes := 'rdpclip6064';
  705. if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 1) then
  706. RDPClipRes := 'rdpclip6164';
  707. if (FV.Version.w.Major = 10) and (FV.Version.w.Minor = 0) then
  708. RfxvmtRes := 'rfxvmt64';
  709. end;
  710. end;
  711. if RDPClipRes <> '' then
  712. if not FileExists(ExpandPath('%SystemRoot%\System32\rdpclip.exe')) then
  713. ExtractRes(RDPClipRes, ExpandPath('%SystemRoot%\System32\rdpclip.exe'));
  714. if RfxvmtRes <> '' then
  715. if not FileExists(ExpandPath('%SystemRoot%\System32\rfxvmt.dll')) then
  716. ExtractRes(RfxvmtRes, ExpandPath('%SystemRoot%\System32\rfxvmt.dll'));
  717. end;
  718. procedure DeleteFiles;
  719. var
  720. Code: DWORD;
  721. FullPath, Path: String;
  722. begin
  723. FullPath := ExpandPath(TermServicePath);
  724. Path := ExtractFilePath(FullPath);
  725. if not DeleteFile(PWideChar(Path + 'rdpwrap.ini')) then
  726. begin
  727. Code := GetLastError;
  728. Writeln('[-] DeleteFile error (code ', Code, ').');
  729. Exit;
  730. end;
  731. Writeln('[+] Removed file: ', Path + 'rdpwrap.ini');
  732. if not DeleteFile(PWideChar(FullPath)) then
  733. begin
  734. Code := GetLastError;
  735. Writeln('[-] DeleteFile error (code ', Code, ').');
  736. Exit;
  737. end;
  738. Writeln('[+] Removed file: ', FullPath);
  739. if not RemoveDirectory(PWideChar(ExtractFilePath(ExpandPath(TermServicePath)))) then
  740. begin
  741. Code := GetLastError;
  742. Writeln('[-] RemoveDirectory error (code ', Code, ').');
  743. Exit;
  744. end;
  745. Writeln('[+] Removed folder: ', ExtractFilePath(ExpandPath(TermServicePath)));
  746. end;
  747. function GetFileVersion(const FileName: TFileName; var FileVersion: FILE_VERSION): Boolean;
  748. type
  749. VS_VERSIONINFO = record
  750. wLength, wValueLength, wType: Word;
  751. szKey: Array[1..16] of WideChar;
  752. Padding1: Word;
  753. Value: VS_FIXEDFILEINFO;
  754. Padding2, Children: Word;
  755. end;
  756. PVS_VERSIONINFO = ^VS_VERSIONINFO;
  757. const
  758. VFF_DEBUG = 1;
  759. VFF_PRERELEASE = 2;
  760. VFF_PRIVATE = 8;
  761. VFF_SPECIAL = 32;
  762. var
  763. hFile: HMODULE;
  764. hResourceInfo: HRSRC;
  765. VersionInfo: PVS_VERSIONINFO;
  766. begin
  767. Result := False;
  768. hFile := LoadLibraryEx(PWideChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE);
  769. if hFile = 0 then
  770. Exit;
  771. hResourceInfo := FindResource(hFile, PWideChar(1), PWideChar($10));
  772. if hResourceInfo = 0 then
  773. Exit;
  774. VersionInfo := Pointer(LoadResource(hFile, hResourceInfo));
  775. if VersionInfo = nil then
  776. Exit;
  777. FileVersion.Version.dw := VersionInfo.Value.dwFileVersionMS;
  778. FileVersion.Release := Word(VersionInfo.Value.dwFileVersionLS shr 16);
  779. FileVersion.Build := Word(VersionInfo.Value.dwFileVersionLS);
  780. FileVersion.bDebug := (VersionInfo.Value.dwFileFlags and VFF_DEBUG) = VFF_DEBUG;
  781. FileVersion.bPrerelease := (VersionInfo.Value.dwFileFlags and VFF_PRERELEASE) = VFF_PRERELEASE;
  782. FileVersion.bPrivate := (VersionInfo.Value.dwFileFlags and VFF_PRIVATE) = VFF_PRIVATE;
  783. FileVersion.bSpecial := (VersionInfo.Value.dwFileFlags and VFF_SPECIAL) = VFF_SPECIAL;
  784. FreeLibrary(hFile);
  785. Result := True;
  786. end;
  787. procedure CheckTermsrvVersion;
  788. var
  789. SuppLvl: Byte;
  790. VerTxt: String;
  791. procedure UpdateMsg;
  792. begin
  793. Writeln('Try running "update.bat" or "RDPWInst -w" to download latest INI file.');
  794. Writeln('If it doesn''t help, send your termsrv.dll to project developer for support.');
  795. end;
  796. begin
  797. GetFileVersion(ExpandPath(TermServicePath), FV);
  798. VerTxt := Format('%d.%d.%d.%d',
  799. [FV.Version.w.Major, FV.Version.w.Minor, FV.Release, FV.Build]);
  800. Writeln('[*] Terminal Services version: ', VerTxt);
  801. if (FV.Version.w.Major = 5) and (FV.Version.w.Minor = 1) then
  802. begin
  803. if Arch = 32 then
  804. begin
  805. Writeln('[!] Windows XP is not supported.');
  806. Writeln('You may take a look at RDP Realtime Patch by Stas''M for Windows XP');
  807. Writeln('Link: http://stascorp.com/load/1-1-0-62');
  808. end;
  809. if Arch = 64 then
  810. Writeln('[!] Windows XP 64-bit Edition is not supported.');
  811. Exit;
  812. end;
  813. if (FV.Version.w.Major = 5) and (FV.Version.w.Minor = 2) then
  814. begin
  815. if Arch = 32 then
  816. Writeln('[!] Windows Server 2003 is not supported.');
  817. if Arch = 64 then
  818. Writeln('[!] Windows Server 2003 or XP 64-bit Edition is not supported.');
  819. Exit;
  820. end;
  821. SuppLvl := 0;
  822. if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 0) then begin
  823. SuppLvl := 1;
  824. if (Arch = 32) and (FV.Release = 6000) and (FV.Build = 16386) then begin
  825. Writeln('[!] This version of Terminal Services may crash on logon attempt.');
  826. Writeln('It''s recommended to upgrade to Service Pack 1 or higher.');
  827. end;
  828. end;
  829. if (FV.Version.w.Major = 6) and (FV.Version.w.Minor = 1) then
  830. SuppLvl := 1;
  831. if Pos('[' + VerTxt + ']', ExtractResText('config')) > 0 then
  832. SuppLvl := 2;
  833. case SuppLvl of
  834. 0: begin
  835. Writeln('[-] This version of Terminal Services is not supported.');
  836. UpdateMsg;
  837. end;
  838. 1: begin
  839. Writeln('[!] This version of Terminal Services is supported partially.');
  840. Writeln('It means you may have some limitations such as only 2 concurrent sessions.');
  841. UpdateMsg;
  842. end;
  843. 2: begin
  844. Writeln('[+] This version of Terminal Services is fully supported.');
  845. end;
  846. end;
  847. end;
  848. procedure CheckTermsrvDependencies;
  849. const
  850. CertPropSvc = 'CertPropSvc';
  851. SessionEnv = 'SessionEnv';
  852. begin
  853. if SvcGetStart(CertPropSvc) = SERVICE_DISABLED then
  854. SvcConfigStart(CertPropSvc, SERVICE_DEMAND_START);
  855. if SvcGetStart(SessionEnv) = SERVICE_DISABLED then
  856. SvcConfigStart(SessionEnv, SERVICE_DEMAND_START);
  857. end;
  858. procedure TSConfigRegistry(Enable: Boolean);
  859. var
  860. Reg: TRegistry;
  861. Code: DWORD;
  862. begin
  863. if Arch = 64 then
  864. Reg := TRegistry.Create(KEY_WRITE or KEY_WOW64_64KEY)
  865. else
  866. Reg := TRegistry.Create;
  867. Reg.RootKey := HKEY_LOCAL_MACHINE;
  868. if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server', True) then
  869. begin
  870. Code := GetLastError;
  871. Writeln('[-] OpenKey error (code ', Code, ').');
  872. Halt(Code);
  873. end;
  874. try
  875. Reg.WriteBool('fDenyTSConnections', not Enable);
  876. except
  877. Writeln('[-] WriteBool error.');
  878. Halt(ERROR_ACCESS_DENIED);
  879. end;
  880. Reg.CloseKey;
  881. if Enable then
  882. begin
  883. if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\Licensing Core', True) then
  884. begin
  885. Code := GetLastError;
  886. Writeln('[-] OpenKey error (code ', Code, ').');
  887. Halt(Code);
  888. end;
  889. try
  890. Reg.WriteBool('EnableConcurrentSessions', True);
  891. except
  892. Writeln('[-] WriteBool error.');
  893. Halt(ERROR_ACCESS_DENIED);
  894. end;
  895. Reg.CloseKey;
  896. if not Reg.OpenKey('\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon', True) then
  897. begin
  898. Code := GetLastError;
  899. Writeln('[-] OpenKey error (code ', Code, ').');
  900. Halt(Code);
  901. end;
  902. try
  903. Reg.WriteBool('AllowMultipleTSSessions', True);
  904. except
  905. Writeln('[-] WriteBool error.');
  906. Halt(ERROR_ACCESS_DENIED);
  907. end;
  908. Reg.CloseKey;
  909. if not Reg.KeyExists('\SYSTEM\CurrentControlSet\Control\Terminal Server\AddIns') then begin
  910. if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\AddIns', True) then
  911. begin
  912. Code := GetLastError;
  913. Writeln('[-] OpenKey error (code ', Code, ').');
  914. Halt(Code);
  915. end;
  916. Reg.CloseKey;
  917. if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\AddIns\Clip Redirector', True) then
  918. begin
  919. Code := GetLastError;
  920. Writeln('[-] OpenKey error (code ', Code, ').');
  921. Halt(Code);
  922. end;
  923. try
  924. Reg.WriteString('Name', 'RDPClip');
  925. Reg.WriteInteger('Type', 3);
  926. except
  927. Writeln('[-] WriteInteger error.');
  928. Halt(ERROR_ACCESS_DENIED);
  929. end;
  930. Reg.CloseKey;
  931. if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\AddIns\DND Redirector', True) then
  932. begin
  933. Code := GetLastError;
  934. Writeln('[-] OpenKey error (code ', Code, ').');
  935. Halt(Code);
  936. end;
  937. try
  938. Reg.WriteString('Name', 'RDPDND');
  939. Reg.WriteInteger('Type', 3);
  940. except
  941. Writeln('[-] WriteInteger error.');
  942. Halt(ERROR_ACCESS_DENIED);
  943. end;
  944. Reg.CloseKey;
  945. if not Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Terminal Server\AddIns\Dynamic VC', True) then
  946. begin
  947. Code := GetLastError;
  948. Writeln('[-] OpenKey error (code ', Code, ').');
  949. Halt(Code);
  950. end;
  951. try
  952. Reg.WriteInteger('Type', -1);
  953. except
  954. Writeln('[-] WriteInteger error.');
  955. Halt(ERROR_ACCESS_DENIED);
  956. end;
  957. Reg.CloseKey;
  958. end;
  959. end;
  960. Reg.Free;
  961. end;
  962. procedure TSConfigFirewall(Enable: Boolean);
  963. begin
  964. if Enable then
  965. begin
  966. ExecWait('netsh advfirewall firewall add rule name="Remote Desktop" dir=in protocol=tcp localport=3389 profile=any action=allow');
  967. ExecWait('netsh advfirewall firewall add rule name="Remote Desktop" dir=in protocol=udp localport=3389 profile=any action=allow');
  968. end else
  969. ExecWait('netsh advfirewall firewall delete rule name="Remote Desktop"');
  970. end;
  971. function CheckINIDate(Filename, Content: String; var Date: Integer): Boolean;
  972. var
  973. Str: TStringList;
  974. I: Integer;
  975. begin
  976. Result := False;
  977. Str := TStringList.Create;
  978. if Filename <> '' then begin
  979. try
  980. Str.LoadFromFile(Filename);
  981. except
  982. Writeln('[-] Failed to read INI file.');
  983. Exit;
  984. end;
  985. end else
  986. Str.Text := Content;
  987. for I := 0 to Str.Count - 1 do
  988. if Pos('Updated=', Str[I]) = 1 then
  989. Break;
  990. if I >= Str.Count then begin
  991. Writeln('[-] Failed to check INI date.');
  992. Exit;
  993. end;
  994. Content := StringReplace(Str[I], 'Updated=', '', []);
  995. Content := StringReplace(Content, '-', '', [rfReplaceAll]);
  996. Str.Free;
  997. try
  998. Date := StrToInt(Content);
  999. except
  1000. Writeln('[-] Wrong INI date format.');
  1001. Exit;
  1002. end;
  1003. Result := True;
  1004. end;
  1005. procedure CheckUpdate;
  1006. var
  1007. INIPath, S: String;
  1008. Str: TStringList;
  1009. I, OldDate, NewDate: Integer;
  1010. begin
  1011. INIPath := ExtractFilePath(ExpandPath(TermServicePath)) + 'rdpwrap.ini';
  1012. if not CheckINIDate(INIPath, '', OldDate) then
  1013. Halt(ERROR_ACCESS_DENIED);
  1014. Writeln('[*] Current update date: ',
  1015. Format('%d.%.2d.%.2d', [OldDate div 10000, OldDate div 100 mod 100, OldDate mod 100]));
  1016. if not GitINIFile(S) then begin
  1017. Writeln('[-] Failed to download latest INI from GitHub.');
  1018. Halt(ERROR_ACCESS_DENIED);
  1019. end;
  1020. if not CheckINIDate('', S, NewDate) then
  1021. Halt(ERROR_ACCESS_DENIED);
  1022. Writeln('[*] Latest update date: ',
  1023. Format('%d.%.2d.%.2d', [NewDate div 10000, NewDate div 100 mod 100, NewDate mod 100]));
  1024. if NewDate = OldDate then
  1025. Writeln('[*] Everything is up to date.')
  1026. else
  1027. if NewDate > OldDate then begin
  1028. Writeln('[+] New update is available, updating...');
  1029. CheckTermsrvProcess;
  1030. Writeln('[*] Terminating service...');
  1031. AddPrivilege('SeDebugPrivilege');
  1032. KillProcess(TermServicePID);
  1033. Sleep(1000);
  1034. if Length(ShareSvc) > 0 then
  1035. for I := 0 to Length(ShareSvc) - 1 do
  1036. SvcStart(ShareSvc[I]);
  1037. Sleep(500);
  1038. Str := TStringList.Create;
  1039. Str.Text := S;
  1040. try
  1041. Str.SaveToFile(INIPath);
  1042. except
  1043. Writeln('[-] Failed to write INI file.');
  1044. Halt(ERROR_ACCESS_DENIED);
  1045. end;
  1046. Str.Free;
  1047. SvcStart(TermService);
  1048. Writeln('[+] Update completed.');
  1049. end else
  1050. Writeln('[*] Your INI file is newer than public file. Are you a developer? :)');
  1051. end;
  1052. var
  1053. I: Integer;
  1054. begin
  1055. Writeln('RDP Wrapper Library v1.6.2');
  1056. Writeln('Installer v2.6');
  1057. Writeln('Copyright (C) Stas''M Corp. 2018');
  1058. Writeln('');
  1059. if (ParamCount < 1)
  1060. or (
  1061. (ParamStr(1) <> '-l')
  1062. and (ParamStr(1) <> '-i')
  1063. and (ParamStr(1) <> '-w')
  1064. and (ParamStr(1) <> '-u')
  1065. and (ParamStr(1) <> '-r')
  1066. ) then
  1067. begin
  1068. Writeln('USAGE:');
  1069. Writeln('RDPWInst.exe [-l|-i[-s][-o]|-w|-u[-k]|-r]');
  1070. Writeln('');
  1071. Writeln('-l display the license agreement');
  1072. Writeln('-i install wrapper to Program Files folder (default)');
  1073. Writeln('-i -s install wrapper to System32 folder');
  1074. Writeln('-i -o online install mode (loads latest INI file)');
  1075. Writeln('-w get latest update for INI file');
  1076. Writeln('-u uninstall wrapper');
  1077. Writeln('-u -k uninstall wrapper and keep settings');
  1078. Writeln('-r force restart Terminal Services');
  1079. Exit;
  1080. end;
  1081. if ParamStr(1) = '-l' then
  1082. begin
  1083. Writeln(ExtractResText('license'));
  1084. Exit;
  1085. end;
  1086. if not CheckWin32Version(6,0) then
  1087. begin
  1088. Writeln('[-] Unsupported Windows version:');
  1089. Writeln(' only >= 6.0 (Vista, Server 2008 and newer) are supported.');
  1090. Exit;
  1091. end;
  1092. if not SupportedArchitecture then
  1093. begin
  1094. Writeln('[-] Unsupported processor architecture.');
  1095. Exit;
  1096. end;
  1097. CheckInstall;
  1098. if ParamStr(1) = '-i' then
  1099. begin
  1100. if Installed then
  1101. begin
  1102. Writeln('[*] RDP Wrapper Library is already installed.');
  1103. Halt(ERROR_INVALID_FUNCTION);
  1104. end;
  1105. Writeln('[*] Notice to user:');
  1106. Writeln(' - By using all or any portion of this software, you are agreeing');
  1107. Writeln(' to be bound by all the terms and conditions of the license agreement.');
  1108. Writeln(' - To read the license agreement, run the installer with -l parameter.');
  1109. Writeln(' - If you do not agree to any terms of the license agreement,');
  1110. Writeln(' do not use the software.');
  1111. Writeln('[*] Installing...');
  1112. if ParamStr(2) = '-s' then
  1113. WrapPath := '%SystemRoot%\system32\rdpwrap.dll'
  1114. else
  1115. WrapPath := '%ProgramFiles%\RDP Wrapper\rdpwrap.dll';
  1116. if Arch = 64 then
  1117. DisableWowRedirection;
  1118. CheckTermsrvVersion;
  1119. CheckTermsrvProcess;
  1120. Writeln('[*] Extracting files...');
  1121. Online := (ParamStr(2) = '-o') or (ParamStr(3) = '-o');
  1122. ExtractFiles;
  1123. Writeln('[*] Configuring service library...');
  1124. SetWrapperDll;
  1125. Writeln('[*] Checking dependencies...');
  1126. CheckTermsrvDependencies;
  1127. Writeln('[*] Terminating service...');
  1128. AddPrivilege('SeDebugPrivilege');
  1129. KillProcess(TermServicePID);
  1130. Sleep(1000);
  1131. if Length(ShareSvc) > 0 then
  1132. for I := 0 to Length(ShareSvc) - 1 do
  1133. SvcStart(ShareSvc[I]);
  1134. Sleep(500);
  1135. SvcStart(TermService);
  1136. Sleep(500);
  1137. Writeln('[*] Configuring registry...');
  1138. TSConfigRegistry(True);
  1139. Writeln('[*] Configuring firewall...');
  1140. TSConfigFirewall(True);
  1141. Writeln('[+] Successfully installed.');
  1142. if Arch = 64 then
  1143. RevertWowRedirection;
  1144. end;
  1145. if ParamStr(1) = '-u' then
  1146. begin
  1147. if not Installed then
  1148. begin
  1149. Writeln('[*] RDP Wrapper Library is not installed.');
  1150. Halt(ERROR_INVALID_FUNCTION);
  1151. end;
  1152. Writeln('[*] Uninstalling...');
  1153. if Arch = 64 then
  1154. DisableWowRedirection;
  1155. CheckTermsrvProcess;
  1156. Writeln('[*] Resetting service library...');
  1157. ResetServiceDll;
  1158. Writeln('[*] Terminating service...');
  1159. AddPrivilege('SeDebugPrivilege');
  1160. KillProcess(TermServicePID);
  1161. Sleep(1000);
  1162. Writeln('[*] Removing files...');
  1163. DeleteFiles;
  1164. if Length(ShareSvc) > 0 then
  1165. for I := 0 to Length(ShareSvc) - 1 do
  1166. SvcStart(ShareSvc[I]);
  1167. Sleep(500);
  1168. SvcStart(TermService);
  1169. Sleep(500);
  1170. if ParamStr(2) <> '-k' then
  1171. begin
  1172. Writeln('[*] Configuring registry...');
  1173. TSConfigRegistry(False);
  1174. Writeln('[*] Configuring firewall...');
  1175. TSConfigFirewall(False);
  1176. end;
  1177. if Arch = 64 then
  1178. RevertWowRedirection;
  1179. Writeln('[+] Successfully uninstalled.');
  1180. end;
  1181. if ParamStr(1) = '-w' then
  1182. begin
  1183. if not Installed then
  1184. begin
  1185. Writeln('[*] RDP Wrapper Library is not installed.');
  1186. Halt(ERROR_INVALID_FUNCTION);
  1187. end;
  1188. Writeln('[*] Checking for updates...');
  1189. CheckUpdate;
  1190. end;
  1191. if ParamStr(1) = '-r' then
  1192. begin
  1193. Writeln('[*] Restarting...');
  1194. CheckTermsrvProcess;
  1195. Writeln('[*] Terminating service...');
  1196. AddPrivilege('SeDebugPrivilege');
  1197. KillProcess(TermServicePID);
  1198. Sleep(1000);
  1199. if Length(ShareSvc) > 0 then
  1200. for I := 0 to Length(ShareSvc) - 1 do
  1201. SvcStart(ShareSvc[I]);
  1202. Sleep(500);
  1203. SvcStart(TermService);
  1204. Writeln('[+] Done.');
  1205. end;
  1206. end.