0

I have a remote access app that uses IDXGIOutputDuplication to capture the primary display. To do that, I need to acquire the display IDXGIOutput:

// intermediate variables for casting
    IDXGIOutput* pDisplay_old;

    IDXGIFactory1* pFactory;
    IDXGIAdapter* pGPU;
    ID3D11Device* pD3D;
    ID3D11DeviceContext* pD3DContext;
    IDXGIOutput1* pDisplay;

    // create DXGI factory
    res = CreateDXGIFactory1(IID_PPV_ARGS(&pFactory));
    if (FAILED(res))
    {
        cerr << "CreateDXGIFactory1 " << res;
        return 1;
    }

    // get GPU adapter
    res = pFactory->EnumAdapters(0, &pGPU);
    if (FAILED(res))
    {
        cerr << "EnumAdapters " << res;
        return 1;
    }

    // create D3D11 device
    res = D3D11CreateDevice(pGPU, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &pD3D, NULL, &pD3DContext);
    if (FAILED(res))
    {
        cerr << "D3D11CreateDevice " << res;
        return 1;
    }

    // get display
    res = pGPU->EnumOutputs(0, &pDisplay_old);
    if (FAILED(res))
    {
        cerr << "EnumOutputs " << res;
        return 1;
    }
    res = pDisplay_old->QueryInterface(&pDisplay);
    if (FAILED(res))
    {
        cerr << "QueryInterface " << res;
        return 1;
    }

    // free resources
    pDisplay_old->Release();
    pGPU->Release();
    pFactory->Release();

this works fine when debugging in visual studio, but EnumOutputs() doesn't work in a session 0 process. I want to run my app as a service because it's a remote access app that must be online at all times, and it must be run under localsystem so that IDXGIOutput1::DuplicateOutput can capture secure desktops such as the sign in page and uac prompts.

clearly, based on the documentation, using IDXGIOutputDuplication in a session 0 service is a supported use case, and I wish to know how to acquire the primary display IDXGIOutput in a session 0 service running under LocalSystem, so that I can call DuplicateOutput() on it as normal.

Update: I have added this code at the beginning of the snippet above:

// Assigns the specified desktop to the calling thread
    HDESK currentInputDesktop = OpenInputDesktop(0, false, GENERIC_ALL);
    if (currentInputDesktop == NULL)
    {
        cerr << "OpenInputDesktop " << GetLastError();
        return 1;
    }

    res = SetThreadDesktop(currentInputDesktop);
    if (res == 0)
    {
        cerr << "SetThreadDesktop " << GetLastError();
        return 1;
    }

    CloseDesktop(currentInputDesktop);

running my code as localsystem using psexec -s -h led to OpenInputDesktop erroring, with the code from GetLastError() being simply "1", which I don't know how to parse

Tiger Yang
  • 61
  • 4
  • Where do you see evidence that "based on the documentation, using IDXGIOutputDuplication in a session 0 service is a supported use case"? – Simon Mourier May 03 '23 at 20:44
  • one of the return values of IDXGIOutput1::DuplicateOutput is E_ACCESSDENIED, "if the application does not have access privilege to the current desktop image. For example, only an application that runs at LOCAL_SYSTEM can access the secure desktop." to me, running as LocalSystem is synonymous with session zero, but I could be wrong about that. – Tiger Yang May 04 '23 at 01:31
  • This specific phrase is about the secure desktop only (the special one used to login). If you want to duplicate the desktop that receives user input, try to use SetThreadDesktop like what's shown here https://stackoverflow.com/questions/46257471/desktop-duplication-screen-capturing-duplicateoutput-returns-e-accessdenied-er – Simon Mourier May 04 '23 at 06:12
  • sorry I think I should clarify my overarching goal: I want my app to start at a system startup, and be able to capture secure scenarios, notably uac prompts, and the sign-in screen. So far the only way I know to manage that is running my app as a service under the localsystem user. However, the app is now also running in session 0, which prevents me from acquiring the display with EnumOutputs. as far as I know, running as localSystem and in session 0 cannot be uncoupled in the context of services. I just want a solution that would allow my app to achieve the two goals above – Tiger Yang May 04 '23 at 15:56
  • also I considered the link you gave and updated my post with my attempt nonetheless. the post doesn't explain how the guy was able to acquire the display IDXGIOutput while running as localSystem (and also in session 0 I assume). – Tiger Yang May 04 '23 at 16:06
  • UAC prompts and the sign-in screen are BY DESIGN isolated and not accessible from services or other potential malware. – Chuck Walbourn May 24 '23 at 03:03

0 Answers0