Skip to content

Commit d5a6b63

Browse files
committed
Added basic Window Station creation.
1 parent 8a93224 commit d5a6b63

8 files changed

Lines changed: 99 additions & 10 deletions

NtApiDotNet/NtWindowStation.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
using NtApiDotNet.Win32;
1516
using System;
1617
using System.Collections.Generic;
1718
using System.Runtime.InteropServices;
@@ -140,6 +141,43 @@ public static NtWindowStation Open(string winsta_name)
140141
return Open(winsta_name, null);
141142
}
142143

144+
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
145+
private delegate IntPtr GetKbdLayout();
146+
147+
/// <summary>
148+
/// Create a Window Station by name.
149+
/// </summary>
150+
/// <param name="winsta_name">The name of the Window Station.</param>
151+
/// <returns>The Window Station.</returns>
152+
public static NtWindowStation Create(string winsta_name)
153+
{
154+
string dll_path;
155+
IntPtr layout_offset;
156+
using (var kbd_dll = SafeLoadLibraryHandle.LoadLibrary(@"kbdus.dll"))
157+
{
158+
dll_path = kbd_dll.FullPath;
159+
var proc = kbd_dll.GetProcAddress(new IntPtr(1));
160+
GetKbdLayout kbdLayout = (GetKbdLayout)Marshal.GetDelegateForFunctionPointer(proc, typeof(GetKbdLayout));
161+
var layout = kbdLayout();
162+
layout_offset = new IntPtr(layout.ToInt64() - kbd_dll.DangerousGetHandle().ToInt64());
163+
}
164+
165+
using (var buffer = new SafeHGlobalBuffer(0x318))
166+
{
167+
BufferUtils.FillBuffer(buffer, 0);
168+
using (var file = NtFile.Open(NtFileUtils.DosFileNameToNt(dll_path), null,
169+
FileAccessRights.GenericRead | FileAccessRights.Synchronize, FileShareMode.Read | FileShareMode.Delete,
170+
FileOpenOptions.NonDirectoryFile | FileOpenOptions.SynchronousIoNonAlert))
171+
{
172+
using (var obja = new ObjectAttributes(winsta_name, AttributeFlags.CaseInsensitive))
173+
{
174+
return new NtWindowStation(NtSystemCalls.NtUserCreateWindowStation(obja, WindowStationAccessRights.MaximumAllowed, file.Handle,
175+
layout_offset, IntPtr.Zero, buffer, new UnicodeString("00000409"), 0x04090409));
176+
}
177+
}
178+
}
179+
}
180+
143181
/// <summary>
144182
/// Get a list of desktops for this Window Station.
145183
/// </summary>

NtApiDotNet/NtWindowStationNative.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ public static extern SafeKernelObjectHandle NtUserOpenWindowStation(
5050
ObjectAttributes ObjectAttributes,
5151
WindowStationAccessRights DesiredAccess);
5252

53+
[DllImport("win32u.dll", SetLastError = true)]
54+
public static extern SafeKernelObjectHandle NtUserCreateWindowStation(
55+
ObjectAttributes ObjectAttributes,
56+
WindowStationAccessRights DesiredAccess,
57+
SafeKernelObjectHandle KbdDllHandle,
58+
IntPtr KbdTablesOffset, // Offset of tables returned from Ordinal 1 call from DLL base.
59+
IntPtr NlsTablesOffset, // Offset of tables returned from Ordinal 2 call from DLL base.
60+
SafeBuffer KbdMultiDescriptor, // Buffer 0x318 bytes in size. Can be extracted using Ordinal 6.
61+
UnicodeString LanguageIdString, // e.g. "00000409"
62+
int KeyboardLocale); // e.g. 0x04090409 is US English and US Layout
63+
5364
[DllImport("win32u.dll", SetLastError = true)]
5465
public static extern NtStatus NtUserBuildNameList(
5566
SafeKernelObjectHandle Handle, int Size, SafeBuffer NameList, out int RequiredSize);

NtApiDotNet/SecurityCapabilities.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,7 @@ internal static class SecurityCapabilities
879879
"thumbnailCache",
880880
"timezone",
881881
"uiAutomationSystem",
882+
"unvirtualizedResources",
882883
"unzipFile",
883884
"updateAndSecurityDeviceSettings",
884885
"usb",

NtApiDotNet/Win32/SafeLoadLibraryHandle.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -401,10 +401,9 @@ public IntPtr GetProcAddress(IntPtr ordinal)
401401
/// <typeparam name="TDelegate">The delegate type. The name of the delegate is used to lookup the name of the function.</typeparam>
402402
/// <param name="throw_on_error">True to throw on error.</param>
403403
/// <returns>The delegate.</returns>
404-
public TDelegate GetFunctionPointer<TDelegate>(bool throw_on_error) where TDelegate : class
404+
public TDelegate GetFunctionPointer<TDelegate>(bool throw_on_error) where TDelegate : Delegate
405405
{
406-
if (!typeof(TDelegate).IsSubclassOf(typeof(Delegate)) ||
407-
typeof(TDelegate).GetCustomAttribute<UnmanagedFunctionPointerAttribute>() == null)
406+
if (typeof(TDelegate).GetCustomAttribute<UnmanagedFunctionPointerAttribute>() == null)
408407
{
409408
throw new ArgumentException("Invalid delegate type, must have an UnmanagedFunctionPointerAttribute annotation");
410409
}
@@ -419,15 +418,15 @@ public TDelegate GetFunctionPointer<TDelegate>(bool throw_on_error) where TDeleg
419418
return null;
420419
}
421420

422-
return (TDelegate)(object)Marshal.GetDelegateForFunctionPointer(proc, typeof(TDelegate));
421+
return (TDelegate)Marshal.GetDelegateForFunctionPointer(proc, typeof(TDelegate));
423422
}
424423

425424
/// <summary>
426425
/// Get a delegate which points to an unmanaged function.
427426
/// </summary>
428427
/// <typeparam name="TDelegate">The delegate type. The name of the delegate is used to lookup the name of the function.</typeparam>
429428
/// <returns>The delegate.</returns>
430-
public TDelegate GetFunctionPointer<TDelegate>() where TDelegate : class
429+
public TDelegate GetFunctionPointer<TDelegate>() where TDelegate : Delegate
431430
{
432431
return GetFunctionPointer<TDelegate>(true);
433432
}

NtApiDotNet/Win32/SymbolResolver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ int cb
455455
private SymLoadModule64 _sym_load_module;
456456
private SymRefreshModuleList _sym_refresh_module_list;
457457

458-
private void GetFunc<T>(ref T f) where T : class
458+
private void GetFunc<T>(ref T f) where T : Delegate
459459
{
460460
f = _dbghelp_lib.GetFunctionPointer<T>();
461461
}

NtApiDotNet/Win32/Win32NativeMethods.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -971,9 +971,12 @@ internal static extern int SendInput(int nInputs,
971971
[MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs,
972972
int cbSize);
973973

974-
[DllImport("user32.dll", SetLastError = true)]
975-
internal static extern short GetAsyncKeyState(
976-
int vKey
974+
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
975+
internal static extern SafeKernelObjectHandle CreateWindowStation(
976+
string lpwinsta,
977+
int dwFlags,
978+
AccessMask dwDesiredAccess,
979+
SECURITY_ATTRIBUTES lpsa
977980
);
978981
}
979982
#pragma warning restore 1591

NtApiDotNet/Win32/Win32ProcessConfig.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ public bool OverrideChildProcessCreation
191191
/// Specify list of handles to inherit.
192192
/// </summary>
193193
public List<NtJob> JobList { get; }
194+
/// <summary>
195+
/// Specify a service window station and desktop.
196+
/// </summary>
197+
public bool ServiceDesktop { get; set; }
194198

195199
/// <summary>
196200
/// Add an object's handle to the list of inherited handles.
@@ -240,7 +244,7 @@ public Win32ProcessConfig()
240244

241245
private void PopulateStartupInfo(ref STARTUPINFO start_info)
242246
{
243-
start_info.lpDesktop = Desktop;
247+
start_info.lpDesktop = ServiceDesktop ? CreateServiceDesktopName() : Desktop;
244248
start_info.lpTitle = Title;
245249
if (StdInputHandle != Win32Utils.InvalidHandle ||
246250
StdOutputHandle != Win32Utils.InvalidHandle ||
@@ -496,5 +500,25 @@ private static SECURITY_ATTRIBUTES CreateSecurityAttributes(SecurityDescriptor s
496500
}
497501
return ret;
498502
}
503+
504+
private string ServiceDesktopNameFromToken(NtToken token)
505+
{
506+
Luid authid = token.AuthenticationId;
507+
return $@"Service-0x{authid.HighPart:X}-{authid.LowPart:X}$\Default";
508+
}
509+
510+
private string CreateServiceDesktopName()
511+
{
512+
if (Token != null)
513+
{
514+
return ServiceDesktopNameFromToken(Token);
515+
}
516+
517+
NtProcess process = ParentProcess ?? NtProcess.Current;
518+
using (var token = process.OpenToken())
519+
{
520+
return ServiceDesktopNameFromToken(token);
521+
}
522+
}
499523
}
500524
}

NtApiDotNet/Win32/Win32Utils.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,5 +430,18 @@ public static void SendKeys(params VirtualKey[] key_codes)
430430
SendKeyDown(key_codes);
431431
SendKeyUp(key_codes);
432432
}
433+
434+
/// <summary>
435+
/// This creates a Window Station using the User32 API.
436+
/// </summary>
437+
/// <param name="name">The name of the Window Station.</param>
438+
/// <returns>The Window Station.</returns>
439+
public static NtWindowStation CreateWindowStation(string name)
440+
{
441+
var handle = Win32NativeMethods.CreateWindowStation(name, 0, WindowStationAccessRights.MaximumAllowed, null);
442+
if (handle.IsInvalid)
443+
throw new SafeWin32Exception();
444+
return new NtWindowStation(handle);
445+
}
433446
}
434447
}

0 commit comments

Comments
 (0)