Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inaccessible performance counters (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009) #951

Open
birdie-github opened this issue Jul 1, 2021 · 14 comments
Labels
Stalled work Progress stopped due to uncertainty ToDo To be done

Comments

@birdie-github
Copy link

I've discovered that I cannot use applications which query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009 - they receive access denied.

I've tried granting ANONYMOUS LOGON and even EVERYONE the permission to read this registry path (to be precise HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib as 009 inherits it) but it didn't work.

Please advise. I'm not sure if it's an actual bug.

@isaak654
Copy link
Collaborator

isaak654 commented Jul 3, 2021

I've discovered that I cannot use applications which query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009 - they receive access denied.

Which applications, exactly?

@isaak654 isaak654 added the more info needed More information is needed to move forward label Jul 3, 2021
@birdie-github
Copy link
Author

birdie-github commented Jul 3, 2021

https://github.com/sp00n/corecycler

It's written in Power Shell.

@DavidXanatos DavidXanatos added ToDo To be done under investigation and removed more info needed More information is needed to move forward labels Jul 3, 2021
@DavidXanatos
Copy link
Member

this is a pretty strange issue, a windows NT call, on this key is always failing even without the sandbox

int main()
{
	HANDLE h = NULL;
	NTSTATUS status;
	UNICODE_STRING UnicodeRegPath;
	OBJECT_ATTRIBUTES ObjectAttributes;

	WCHAR RegPath[100] = L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009";
	RtlInitUnicodeString(&UnicodeRegPath, RegPath);
	
	InitializeObjectAttributes(&ObjectAttributes, &UnicodeRegPath, OBJ_CASE_INSENSITIVE, 0, 0);
	status = NtOpenKey(&h,KEY_READ, &ObjectAttributes);
	
	ULONG bufferSize = 256;
	void* buffer = malloc(bufferSize);

	status = NtQueryKey(h, 0, name, length, &length); // <--- this always fails with 0xC0000008 invalid handle

	return 0;
}

the problem is that sandboxie needs this call for som functionality, I can use NtQueryObject instead but I have to check if this can cause any other issues

@DavidXanatos
Copy link
Member

using NtQueryObject the script still doe snot work but it seam to fail much later

@DavidXanatos
Copy link
Member

you can try the 0.8.5 build if you can pin point where it now crashes i can look into fixing the next proglem with this script

@isaak654
Copy link
Collaborator

isaak654 commented Jul 6, 2021

Update: there are some performance issues in 0.8.5, so you might want to wait the next release:
https://www.wilderssecurity.com/threads/sandboxie-plus-0-8-5.438816/#post-3017625

@DavidXanatos
Copy link
Member

@birdie-github any update on that issue?

@birdie-github
Copy link
Author

Starting the CoreCycler...
FATAL ERROR: Could not get the localized Performance Process Counter name!

You may need to re-enable the Performance Process Counter (PerfProc).
Please see the "Troubleshooting / FAQ" section in the readme.txt.

The full thrown error message:
Get-PerformanceCounterLocalName : Unable to retrieve localized name. Check computer name and performance counter ID.
At C:\CoreCycler-v0.8.2.4\script-corecycler.ps1:802 char:9
+         Throw 'Get-PerformanceCounterLocalName : Unable to retrieve l ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Get-Performance...nce counter ID.:String) [], RuntimeException
    + FullyQualifiedErrorId : Get-PerformanceCounterLocalName : Unable to retrieve localized name. Check computer name
    and performance counter ID.



You can find more information in the log file:
C:\CoreCycler-v0.8.2.4\logs\CoreCycler_2021-07-12_00-03-45_PRIME95_SSE.log
When reporting this error, please provide this log file.
Press Enter to exit:

Running:

sha256sum Sandboxie-Classic-x64-v5.50.7.exe 
ed570395db7bd60656f29bb74351368d7361780436fc5d0bc41b2872df1bc90a  Sandboxie-Classic-x64-v5.50.7.exe

@sp00n
Copy link

sp00n commented Jul 24, 2021

Author of CoreCycler here, subscribing to this thread.
I found it by accident by searching for Perflib\009, as this Performance Counter registry entry seems to be the cause of problems for some users over and over again.

The Performance Counters can become corrupted in Windows (for reasons unknown to me), normally the key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009 should contain the English strings, and HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage the strings in the currently selected display language of Windows.

Since Microsoft in its infinite wisdom decided that the id:name pairs can be dynamic and are localized, each computer can have a unique order of the strings, and CoreCycler tries to find the relevant ones first in the English registry entry (009) and then use the id to get the localized name (CurrentLanguage) to be able to query the Performance Counters from Windows (which uses the localized names and not the id),

@DavidXanatos
Copy link
Member

well the problem with Perflib\009 seams solved with the "UseObjectNameForKeys=y" setting the next issue is a different one,
can you tell me whats going wrong (i.e. what sbie does not the way its expected) there or provide a short script that triggers only the second issue directly?
that would help with debugging the problem a lot.

@sp00n
Copy link

sp00n commented Jul 24, 2021

I'm not sure what you mean with second issue, but this PowerShell code would try to access the registry keys:

$directory         = $env:TEMP
$fileEnglish       = $directory + '\_performanceCounters.English.txt'
$fileLocalized     = $directory + '\_performanceCounters.Localized.txt'
$keyEnglish        = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009'
$keyLocalized      = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage'
$countersEnglish   = (Get-ItemProperty -Path $keyEnglish -Name Counter).Counter
$countersLocalized = (Get-ItemProperty -Path $keyLocalized -Name Counter).Counter
cd $directory
Set-Content -Path $fileEnglish -Value $countersEnglish
Set-Content -Path $fileLocalized -Value $countersLocalized

And this would roughly be the function that's used in CoreCycler:

function Get-PerformanceCounterIDs {
    param (
        [Parameter(Mandatory=$true)]
        [Array]
        $englishCounterNames
    )

    $key          = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009'
    $allCounters  = (Get-ItemProperty -Path $key -Name Counter).Counter
    $numCounters  = $allCounters.Count
    $countersHash = @{}
    
    # The string contains two-line pairs
    # The first line is the ID
    # The second line is the name
    for ($i = 0; $i -lt $numCounters; $i += 2) {
        $counterId   = [Int]$allCounters[$i]
        $counterName = [String]$allCounters[$i+1]

        if ($englishCounterNames.Contains($counterName) -and !$countersHash.ContainsKey($counterName)) {
            $countersHash[$counterName] = $counterId
        }

    }

    return $countersHash
}

function Get-PerformanceCounterLocalName {
    param (
        [UInt32]
        $ID,
        $ComputerName = $env:COMPUTERNAME
    )

    try {
        $code = '[DllImport("pdh.dll", SetLastError=true, CharSet=CharSet.Unicode)] public static extern UInt32 PdhLookupPerfNameByIndex(string szMachineName, uint dwNameIndex, System.Text.StringBuilder szNameBuffer, ref uint pcchNameBufferSize);'

        $Buffer = New-Object System.Text.StringBuilder(1024)
        [UInt32]$BufferSize = $Buffer.Capacity

        $t = Add-Type -MemberDefinition $code -PassThru -Name PerfCounter -Namespace Utility
        $rv = $t::PdhLookupPerfNameByIndex($ComputerName, $ID, $Buffer, [Ref]$BufferSize)
        
        'ID:           ' + $ID
        'Found String: ' + $Buffer

        if ($rv -eq 0) {
            'Final Result:'
            $Buffer.ToString().Substring(0, $BufferSize-1)
        }
        else {
            Throw 'Get-PerformanceCounterLocalName : Unable to retrieve localized name. Check computer name and performance counter ID.'
        }
    }
    catch {
        'ERROR!'
        $Error
        $Error.Clear()
    }
}


$englishCounterNames = @(
    'Process',
    'ID Process',
    '% Processor Time'
)
$counterNames = @{}
$counterNameIds = Get-PerformanceCounterIDs $englishCounterNames

''
''
'-----------------'
'Counter Name IDs:'
'-----------------'
$counterNameIds

''
''
'------------------------'
'Localized Counter Names:'
'------------------------'

Get-PerformanceCounterLocalName $counterNameIds['Process']
Get-PerformanceCounterLocalName $counterNameIds['ID Process']
Get-PerformanceCounterLocalName $counterNameIds['% Processor Time']

@DavidXanatos
Copy link
Member

@sp00n
ok let me be more clear, the issue with accessing those wired registry locations is solved when you add "UseObjectNameForKeys=y" to your sandboxie.ini, it is not on by default as it seams to break some older w10 versions bit not w7 or w8 strangely.

So once we have this working fine the CoreCycler however runs into an other IMHO unrelated crash:

Starting the CoreCycler...
FATAL ERROR: Could not get the localized Performance Process Counter name!

You may need to re-enable the Performance Process Counter (PerfProc).
Please see the "Troubleshooting / FAQ" section in the readme.txt.

The full thrown error message:
Get-PerformanceCounterLocalName : Unable to retrieve localized name. Check computer name and performance counter ID.
In C:\test\CoreCycler-v0.8.2.4\CoreCycler-v0.8.2.4\script-corecycler.ps1:802 Zeichen:9
+         Throw 'Get-PerformanceCounterLocalName : Unable to retrieve l ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Get-Performance...nce counter ID.:String) [], RuntimeException
    + FullyQualifiedErrorId : Get-PerformanceCounterLocalName : Unable to retrieve localized name. Check computer name
    and performance counter ID.



You can find more information in the log file:
C:\test\CoreCycler-v0.8.2.4\CoreCycler-v0.8.2.4\logs\CoreCycler_2021-07-26_08-26-40_PRIME95_SSE.log
When reporting this error, please provide this log file.

@sp00n
Copy link

sp00n commented Jul 26, 2021

@DavidXanatos
Ok, yes, those errors are actually tightly connected. As explained above, CoreCycler tries to read the English names from the Perflib\009 registry entry and then tries to map the id:name pairs of certain entries (Process, ID Process, % Processor Time) to the localized strings in Perflib\CurrentLanguage.
If this fails for some reason, the above error is thrown.

Sometimes these Performance Counters will be corrupted for whatever reason, in which case you need to rebuild those (I've explained a way how to do so in the readme.txt mentioned in the error message).
So this might be a Sandboxie problem where it has still problems reading the registry entries, but also an actually corrupted Performance Counter issue.

The code I posted above can be saved as a .ps1 script and then executed, and should give you an indication whether it's related to Sandboxie or not (there should be no error messages).

@sp00n
Copy link

sp00n commented Jul 26, 2021

I've updated my older Sandboxie installation now (didn't even know it had gone open source), and made some tests. The script fails in the following section:

$code = '[DllImport("pdh.dll", SetLastError=true, CharSet=CharSet.Unicode)] public static extern UInt32 PdhLookupPerfNameByIndex(string szMachineName, uint dwNameIndex, System.Text.StringBuilder szNameBuffer, ref uint pcchNameBufferSize);'

$Buffer = New-Object System.Text.StringBuilder(1024)
[UInt32]$BufferSize = $Buffer.Capacity

$t = Add-Type -MemberDefinition $code -PassThru -Name PerfCounter -Namespace Utility
$rv = $t::PdhLookupPerfNameByIndex($ComputerName, $ID, $Buffer, [Ref]$BufferSize)

The PdhLookupPerfNameByIndex call returns an error code 5, which apparently is ERROR_ACCESS_DENIED. Looks like the candidate to investigate.

@isaak654 isaak654 added Stalled work Progress stopped due to uncertainty and removed under investigation labels Apr 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Stalled work Progress stopped due to uncertainty ToDo To be done
Projects
None yet
Development

No branches or pull requests

4 participants