Intro
While working on my Windows authentication package, I needed a way to unload and to unregister it. Registering it was quite easy,
using the AddSecurityPackage
function. So logically,
I assumed that DeleteSecurityPackage
would be the
function to call to unregister it.
The function declaration was also very simple:
But to my chagrin, no matter what I called that function with, it kept returning the same result, 0x80090302
.
I tried everything:
I attempted to provide the pszPackageName
as the full path to my authentication package DLL, it didn't work. I then tried to remove
file extension, it didn't work. I tried to use only file name, with the same bad result. I then even tried to add additional
privileges to the process,
and to adjust the security descriptor. But none of it worked.
Solution
Eventually I gave up, and decided to do what I always do when I don't understand how something works - I reverse engineered it.
And to my amazement I saw this:
sspicli!DeleteSecurityPackageW
function in Ghidra.
That showed me this Assembly code:
Which translated into the following C++ implementation:
😂😂😊
It literally seems like someone at Microsoft had a job to implement that function and just gave up trying at the very outset.
What is also quite amazing is that they have a documentation for that function, that reads:
Deletes a security support provider from the list of providers supported by Microsoft Negotiate.
...
Return value
If the function succeeds, it returns SEC_E_OK.
If the function fails, it returns a nonzero error code.
I wonder at what condition can it succeed? 🤣
Conclusion
So don't be afraid to roll up your sleeves and dig inside the implementation code. You never know what you may find there. And sometimes it may even save you hours, trying to come up with fancy ways to fix something, when in reality the reasons it doesn't work are quite obvious.