0

我的应用程序作为服务运行,在某些时候它需要遍历系统上所有现有的用户帐户(我认为这可以用 来完成NetUserEnum())并尝试访问每个找到的用户的 %APPDATA% 路径下的某个文件。问题是我不知道如何获取该用户特定的路径(%APPDATA%)。

由于应用程序作为服务(SYSTEM)运行,我无法使用环境或SHGetFolderPath(). 最初我以为我可以使用,LogonUser()但无论我是在用户、管理员还是 SYSTEM 下运行我的应用程序测试代码,它总是向我抛出错误 1326。(winxp作为测试平台)。如果有办法获取用户登录句柄,我可以在 API 中使用,对SHGetFolderPath()ExpandEnvironmentStringsForUser()

因此,到目前为止,我使用 LogonUser() 尝试的代码大致如下(是的,用户名是正确的):

LogonUser(
    pw->usri1_name,
    L".",
    NULL,
    LOGON32_LOGON_BATCH,
    LOGON32_PROVIDER_DEFAULT,
    &authtoken
)

它可能需要我的密码,但我无法在客户机器上知道。我通过快速搜索找到的所有 API 都依赖于 LogonUser() 中的 HANDLE,而我显然无法拥有...

欢迎任何非棘手和棘手的想法!

4

3 回答 3

0

到目前为止的解决方案和结论。

你不能LogonUser()正常使用。

相反,您的选择是在用户 homedir(您仍然可以通过任何首选方法获得,我的建议是)之后根据以下之一对路径进行暴力破解:NetUserEnum()

  • SHGetFolderPath(CSIDL_APPDATA)
  • 注册键HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders

如果您知道任何其他方法,请发表评论。

于 2013-10-10T01:54:28.810 回答
0

服务或应用程序作为“本地系统”运行以获取特殊文件夹

这个例子我们得到CSIDL_DESKTOPDIRECTORY,在 xp 上运行良好,win7(32,64)

DWORD ServiceGetDesktopDirectory(LPWSTR lpUserName, LPWSTR lpPassword,
    LPWSTR lpDomain, LPWSTR lpBuffer)
{

HANDLE hToken;
BOOL bRet;
bRet = LogonUserW(lpUserName,
                 lpDomain,
                 lpPassword,
                 LOGON32_LOGON_INTERACTIVE,
                 LOGON32_PROVIDER_DEFAULT,
                 &hToken);
if (!bRet) {
    error("LogonUser failed, gle = %lu", GetLastError());
    return FILE_ERR_INVALID_USERNAME_OR_PASSWORD;
}


NET_API_STATUS ntStatus;
USER_INFO_4 *pUserInfo;
ntStatus = NetUserGetInfo((LPCWSTR)lpDomain,
                          (LPCWSTR)lpUserName,
                          4,
                          (BYTE**)&pUserInfo);
if (ntStatus != NERR_Success) {
    error("NetUserGetInfo failed, ntStatus 0X%x", ntStatus);
    CloseHandle(hToken);
    return FILE_ERR_SYSTEM_ERROR;
}

PROFILEINFOW profile;
memset(&profile, 0, sizeof(PROFILEINFOW));
profile.dwSize = sizeof(PROFILEINFOW);
profile.lpUserName = lpUserName;
profile.lpProfilePath = pUserInfo->usri4_profile;
bRet = LoadUserProfileW(hToken, &profile);
if (!bRet) {
    error("LoadUserProfile failed, gle = %lu", GetLastError());
    CloseHandle(hToken);
    NetApiBufferFree(pUserInfo);
    return FILE_ERR_SYSTEM_ERROR;
}


HRESULT hr;
hr = SHGetFolderPathW(NULL,
              CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE,
              hToken,
              0,
              lpBuffer);
if (FAILED(hr)) {
    error("SHGetFolderPath failed, hr 0X%x", hr);
    NetApiBufferFree(pUserInfo);
    UnloadUserProfile(hToken, profile.hProfile);
    CloseHandle(hToken);
    return FILE_ERR_SYSTEM_ERROR;
}

NetApiBufferFree(pUserInfo);
UnloadUserProfile(hToken, profile.hProfile);
CloseHandle(hToken);
return FILE_ERR_OK;
}
于 2015-12-04T08:06:54.517 回答
-1

您可以使用WTSEnumerateSessions()WTSQueryUserToken()检索每个登录会话的令牌。

另请查看LoadUserProfile(),这是服务访问HKEY_CURRENT_USER特定用户的密钥所必需的。用户必须以交互方式或可编程方式登录,或模拟登录以获得所需的用户令牌。

另一种选择是枚举HKEY_USERS密钥以检索用户帐户的 SID,然后用于LookupAccountSid()检索其用户名,然后根据操作系统版本手动格式化 AppData 路径。没有那么灵活,但较少依赖于用户特定的注册表数据。

否则,忘记尝试从服务写入用户特定的文件夹。改为写入公共共享文件夹,例如CSIDL_COMMON_APPDATAFOLDERID_ProgramData

于 2013-10-08T16:57:55.230 回答