You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求Windows 8+下用Win32 API(ISO C)实现从管理员切换至指定账户的示例

Win32 API 实现管理员进程切换至指定账户(含SYSTEM)

需求:编写适用于Windows 8及以上系统、采用ISO C编写的Win32 API示例,将当前拥有管理员权限的进程切换至指定账户(如FOOBAR、chicken.monster、MYFOOBAR、SYSTEM等),仅使用原生Win32 API。

原代码问题:使用LogOnUserA()调用SYSTEM这类特殊本地账户时失败,代码如下:

#include <stdio.h>
#include <windows.h>
#include <iostream>
#include <string>
void get_file_size(std::string path)
{
    struct _stat fileinfo;
    _stat(path.c_str(), &fileinfo);
    std::cout << "file size is " << fileinfo.st_size << std::endl;
}
int main()
{
    HANDLE  tokenHandle;
    puts("#mark0");
    bool returnValue = LogonUserA("SYSTEM", NULL, NULL, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &tokenHandle);
    if (false == returnValue) {
        return 1;
    }
    puts("#mark1");
    bool res = ImpersonateLoggedOnUser(tokenHandle);
    if (res)
    {
        std::string path = "C:\cygwin64\bin\getent.exe";
        puts("#mark2");
        get_file_size(path);
        
        RevertToSelf();
    }
    puts("#mark3");
    CloseHandle(tokenHandle);
    return 0;
}

以管理员身份运行时,LogOnUserA()调用失败。


问题分析

  1. LogOnUserA()仅适用于普通用户的交互式登录,SYSTEM是系统内置特权账户,无可用的交互式登录凭据,无法通过该API直接获取令牌。
  2. 原代码混合C++语法(如std::string),不符合ISO C标准要求。

解决方案

核心思路

  • 普通本地/域账户:使用LogOnUserA获取令牌后模拟登录,需提供正确凭据。
  • SYSTEM账户:通过获取系统进程(如services.exe,始终以SYSTEM身份运行)的令牌来模拟身份。

以下是符合ISO C标准、兼容Windows 8+的完整示例:

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
#include <sys/stat.h>
#include <string.h>

// 获取文件大小(ISO C实现)
void get_file_size(const char* path) {
    struct _stat fileinfo;
    if (_stat(path, &fileinfo) == 0) {
        printf("file size is %lld\n", (long long)fileinfo.st_size);
    } else {
        printf("Failed to get file size, error: %lu\n", GetLastError());
    }
}

// 获取指定进程名的进程ID
DWORD get_process_id(const char* process_name) {
    DWORD pid = 0;
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot != INVALID_HANDLE_VALUE) {
        PROCESSENTRY32 pe32;
        pe32.dwSize = sizeof(PROCESSENTRY32);
        if (Process32First(hSnapshot, &pe32)) {
            do {
                if (_stricmp(pe32.szExeFile, process_name) == 0) {
                    pid = pe32.th32ProcessID;
                    break;
                }
            } while (Process32Next(hSnapshot, &pe32));
        }
        CloseHandle(hSnapshot);
    }
    return pid;
}

// 获取指定账户的令牌
BOOL get_user_token(const char* username, const char* password, HANDLE* out_token) {
    if (!username || !out_token) return FALSE;

    // 处理SYSTEM账户
    if (_stricmp(username, "SYSTEM") == 0) {
        DWORD services_pid = get_process_id("services.exe");
        if (services_pid == 0) {
            printf("Failed to find services.exe\n");
            return FALSE;
        }

        HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, services_pid);
        if (hProcess == NULL) {
            printf("OpenProcess failed, error: %lu\n", GetLastError());
            return FALSE;
        }

        BOOL result = OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_IMPERSONATE, out_token);
        CloseHandle(hProcess);
        return result;
    }

    // 处理普通账户
    return LogonUserA(
        username,
        NULL,
        password,
        LOGON32_LOGON_INTERACTIVE,
        LOGON32_PROVIDER_DEFAULT,
        out_token
    );
}

int main() {
    HANDLE token_handle = NULL;
    const char* target_user = "SYSTEM"; // 可替换为FOOBAR、chicken.monster等
    const char* user_password = "";     // 普通账户需替换为实际密码

    // 获取目标用户令牌
    if (!get_user_token(target_user, user_password, &token_handle)) {
        printf("get_user_token failed, error: %lu\n", GetLastError());
        return 1;
    }

    // 模拟登录目标用户
    if (ImpersonateLoggedOnUser(token_handle)) {
        printf("Impersonated as %s successfully\n", target_user);
        const char* test_path = "C:\\cygwin64\\bin\\getent.exe";
        get_file_size(test_path);

        // 恢复原身份
        RevertToSelf();
        printf("Reverted to original identity\n");
    } else {
        printf("ImpersonateLoggedOnUser failed, error: %lu\n", GetLastError());
    }

    // 关闭令牌句柄
    if (token_handle != NULL) {
        CloseHandle(token_handle);
    }

    return 0;
}

关键说明

  1. SYSTEM账户处理:通过枚举进程找到services.exe,打开其进程令牌用于身份模拟,无需密码。
  2. 普通账户处理:需传入正确的用户名和密码,LogOnUserA才能成功获取令牌。
  3. 权限要求:进程必须以管理员身份运行,否则无法打开系统进程或调用特权API。
  4. 代码完全采用ISO C编写,无C++语法,兼容Windows 8及以上系统。

内容的提问来源于stack exchange,提问作者Roland Mainz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 13:22:18