有没有一种本地化安全的方法来获取SYSTEM帐户的AppData目录?

时间:2019-04-16 18:39:49

标签: winapi visual-c++

我知道我可以使用GetSystemDirectory()来获取C:\Windows\System32的目录,但是我想知道是否有一种方法可以在下面获取此目录路径,而不管操作系统如何本地化或是否m以普通用户或SYSTEM帐户运行:

C:\Windows\System32\config\systemprofile\AppData\Local\TEMP

或至少达到C:\Windows\System32\config\systemprofile\AppData

我尝试为SHGFP_TYPE_DEFAULT使用SHGFP_TYPE_CURRENT而不是SHGetFolderPath()选项,但是当不以SYSTEM身份运行时,这将返回当前正在运行的用户目录,而不是SYSTEM的目录。

void GetUserLocalTempPath(std::wstring& input_parameter) {
    HWND folder_handle = { 0 };
    WCHAR temp_path[MAX_PATH];
    auto get_folder = SHGetFolderPath(
        folder_handle, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_DEFAULT, temp_path
    );
    if (get_folder == S_OK) {
        input_parameter = static_cast<const wchar_t*>(temp_path);
        input_parameter.append(L"\\TEMP");
        CloseHandle(folder_handle);
    }
}

2 个答案:

答案 0 :(得分:1)

You need a process running under the SYSTEM account in order to query the SYSTEM profile.

Create a separate service that runs as SYSTEM. When needed, have it call SHGetFolderPath(CSIDL_LOCAL_APPDATA) or SHGetKnownFolderPath(FOLDERID_LocalAppData), specifying NULL for the user token so that it queries the calling user's (ie SYSTEM) profile (or, just use GetTempPath(), which will also work in this context).

Then, the service can pass that path back to your main app through any session-agnostic IPC mechanism that you want (pipes, sockets, etc).

On a side note:

  • you do not need to type-cast temp_path when assigning it to input_parameter. temp_path will implicitly decay into a wchar_t* pointer, which can be passed as-is to the const wchar_t* pointer that std::wstring::operator=() takes as input.

  • rather than using input_parameter.append(L"\\TEMP") manually (which you would not need at all if you use GetTempPath()), you should consider using PathCchCombineEx() (or related) or SHGetFolderPathAndSubDir() instead. Let the OS handle the appending for you.

  • you are calling CloseHandle() with an HWND as input, which is wrong since it expects a HANDLE instead (but this is a no-op in your case since the HWND is NULL, so just remove the CloseHandle() altogether). Clearly you are not compiling your project with STRICT Type Checking enabled, otherwise the compiler would have prevented an HWND from being passed to a HANDLE parameter.

答案 1 :(得分:0)

Remy Lebeau's answer是以编程方式执行此操作的正确方法。但是,它可能超出了 you 的要求;如果您需要这样做的理由不需要多代OS支持,则可能不想跳过所有这些麻烦。因此,如果您使用的是Windows 10操作系统,那么似乎现在可以安全地执行此操作。就是说,我不建议这样做,因为它有根本的缺点。这只是一个简单的草率解决方法,因此使用后果自负

对于该潜在解决方案的使用寿命,我没有任何支持文档,只是轶事反馈和一些个人测试。

我从几个人那里听说重要的OS系统目录未本地化。我将Windows 10 Pro日语映像作为虚拟机安装到Hyper-V主机上。将字符串C:\Windows\System32\config\systemprofile\AppData粘贴并输入到日语资源管理器的地址栏中,如下所示,效果很好,


japanese_win10_vm_sysprof_appdata


要点是,在获得系统目录的值(我们不能假设C:\WINODWS\system32)之后,您应该可以使用简单的英语对其余部分进行硬编码。这是一个示例应用程序,可以为您完成此任务:

#define STRICT
#include <Windows.h>
#include <wchar.h>
#include <memory>

int wmain()
{
    static constexpr const wchar_t * SystemProfileAppData_RemainingPath
        = L"\\config\\systemprofile\\AppData";

    wchar_t system_path_buffer[MAX_PATH];
    const std::size_t winapi_worked = GetSystemDirectory(system_path_buffer, MAX_PATH);

    if (winapi_worked) {
        const std::size_t system32_offset = wcsnlen_s(system_path_buffer, MAX_PATH);
        const std::size_t appdata_offset  = wcsnlen_s(SystemProfileAppData_RemainingPath, MAX_PATH);
        const std::size_t path_bytes_size = (appdata_offset + system32_offset) * sizeof(wchar_t);

        memcpy_s(
            &system_path_buffer[system32_offset],
            path_bytes_size,
            SystemProfileAppData_RemainingPath,
            path_bytes_size
        );

        wprintf_s(L"SYSTEM's AppData is here: %s\r\n", system_path_buffer);

        return 0;
    }
    return 1;
}
  

SYSTEM's AppData is here: C:\WINDOWS\system32\config\systemprofile\AppData