├── leechcore ├── leechcore.rc ├── leechrpc.idl ├── leechcore.vcxproj.user ├── version.h ├── Makefile ├── Makefile.macos ├── leechcore_internal.h ├── device_vmm.c ├── util.h ├── leechcore.vcxproj.filters ├── ob │ ├── ob_core.c │ └── ob_bytequeue.c ├── util.c ├── leechcore_device.h ├── leechrpc.h ├── memmap.c ├── leechrpcshared.c └── device_vmware.c ├── leechagent ├── leechagent.rc ├── leechagent.vcxproj.user ├── leechrpc.idl ├── leechagent_rpc.h ├── version.h ├── util.h ├── util.c ├── leechagent_svc.h ├── leechagent.vcxproj.filters ├── leechagent_proc.h ├── leechagent.h ├── leechrpc.h └── leechrpcshared.c ├── includes ├── lib32 │ └── leechcore.lib ├── lib64 │ └── leechcore.lib ├── libarm64 │ └── leechcore.lib └── libpdbcrust.h ├── leechcorepyc ├── leechcorepyc.rc ├── Makefile ├── version.h ├── leechcorepyc.h ├── leechcorepyc.vcxproj.user ├── leechcorepyc.vcxproj.filters ├── pkggen_linux.sh ├── leechcorepyemb.c ├── leechcorepyc_barrequest.c ├── oscompatibility.c └── oscompatibility.h ├── leechagent_linux ├── leechagent_linux.code-workspace ├── leechagent_rpc.h ├── Makefile ├── leechagent.h ├── leechagent_proc.h ├── leechagent_rpc.c ├── leechrpc.h ├── leechrpcshared.c └── oscompatibility.h ├── files ├── agent │ ├── x64 │ │ ├── python │ │ │ └── readme.txt │ │ ├── Certs │ │ │ └── readme.txt │ │ └── readme.txt │ └── x86 │ │ ├── Python │ │ └── readme.txt │ │ ├── readme.txt │ │ └── Certs │ │ └── readme.txt └── Certs │ └── readme.txt ├── .gitignore ├── .gitattributes └── LeechCore.sln /leechcore/leechcore.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufrisk/LeechCore/HEAD/leechcore/leechcore.rc -------------------------------------------------------------------------------- /leechagent/leechagent.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufrisk/LeechCore/HEAD/leechagent/leechagent.rc -------------------------------------------------------------------------------- /includes/lib32/leechcore.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufrisk/LeechCore/HEAD/includes/lib32/leechcore.lib -------------------------------------------------------------------------------- /includes/lib64/leechcore.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufrisk/LeechCore/HEAD/includes/lib64/leechcore.lib -------------------------------------------------------------------------------- /leechcorepyc/leechcorepyc.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufrisk/LeechCore/HEAD/leechcorepyc/leechcorepyc.rc -------------------------------------------------------------------------------- /includes/libarm64/leechcore.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ufrisk/LeechCore/HEAD/includes/libarm64/leechcore.lib -------------------------------------------------------------------------------- /leechagent/leechagent.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /leechagent_linux/leechagent_linux.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "files.associations": { 9 | "leechrpc.h": "c" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /files/agent/x64/python/readme.txt: -------------------------------------------------------------------------------- 1 | Put your Python 3.6 (or later) embedded for Windows 64-bit in this directory to enable Python functionality. 2 | Download Python 3.6 (or later) "Windows embeddable package (64-bit)" and unzip in this folder. 3 | Python may be downloaded from: https://www.python.org/downloads/ -------------------------------------------------------------------------------- /files/agent/x86/Python/readme.txt: -------------------------------------------------------------------------------- 1 | Put your Python 3.6 (or later) embedded for Windows 32-bit in this directory to enable Python functionality. 2 | Download Python 3.6 (or later) "Windows embeddable package (32-bit)" and unzip in this folder. 3 | Python may be downloaded from: https://www.python.org/downloads/ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.ilk 2 | *.pdb 3 | *.exp 4 | *.iobj 5 | *.ipdb 6 | *.lastcodeanalysissucceeded 7 | *.exe 8 | *.dll 9 | *.pyd 10 | *.so 11 | *.dylib 12 | *.o 13 | /.vs 14 | leechrpc_h.h 15 | leechrpc_c.c 16 | leechrpc_s.c 17 | /files/lib 18 | /files/temp 19 | /files/ARM64 20 | /files/x86/lib 21 | /leechcorepyc/pkg_linux 22 | /files/leechagent 23 | -------------------------------------------------------------------------------- /leechagent_linux/leechagent_rpc.h: -------------------------------------------------------------------------------- 1 | // leechagent_rpc.h : definitions of RPC related functionality. 2 | // 3 | // (c) Ulf Frisk, 2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __LEECHAGENT_RPC_H__ 7 | #define __LEECHAGENT_RPC_H__ 8 | 9 | #include "oscompatibility.h" 10 | 11 | _Success_(return) BOOL RpcStartGRPC(_In_ PLEECHSVC_CONFIG pConfig); 12 | void RpcStop(); 13 | 14 | #endif /* __LEECHAGENT_RPC_H__ */ 15 | -------------------------------------------------------------------------------- /leechagent/leechrpc.idl: -------------------------------------------------------------------------------- 1 | [ 2 | uuid(906B0DC2-1337-0666-0001-0000657A63DD), 3 | version(1.0), 4 | endpoint("ncacn_ip_tcp:0.0.0.0[28473]"), 5 | pointer_default(unique) 6 | ] 7 | 8 | interface LeechRpc 9 | { 10 | //[helpstring("Submit a command to the remote leech service.")] 11 | error_status_t LeechRpc_ReservedSubmitCommand([in] handle_t hBinding, [in] long cbIn, [in, size_is(cbIn)] byte *pbIn, [out] long *pcbOut, [out, size_is(,*pcbOut)] byte **ppbOut); 12 | } 13 | -------------------------------------------------------------------------------- /leechcore/leechrpc.idl: -------------------------------------------------------------------------------- 1 | [ 2 | uuid(906B0DC2-1337-0666-0001-0000657A63DD), 3 | version(1.0), 4 | endpoint("ncacn_ip_tcp:0.0.0.0[28473]"), 5 | pointer_default(unique) 6 | ] 7 | 8 | interface LeechRpc 9 | { 10 | //[helpstring("Submit a command to the remote leech service.")] 11 | error_status_t LeechRpc_ReservedSubmitCommand([in] handle_t hBinding, [in] long cbIn, [in, size_is(cbIn)] byte *pbIn, [out] long *pcbOut, [out, size_is(,*pcbOut)] byte **ppbOut); 12 | } 13 | -------------------------------------------------------------------------------- /leechagent/leechagent_rpc.h: -------------------------------------------------------------------------------- 1 | // leechagent_rpc.h : definitions of RPC related functionality. 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __LEECHAGENT_RPC_H__ 7 | #define __LEECHAGENT_RPC_H__ 8 | 9 | #include 10 | 11 | _Success_(return) BOOL RpcStartGRPC(_In_ PLEECHSVC_CONFIG pConfig); 12 | RPC_STATUS RpcStartMSRPC(_In_ BOOL fInsecure, _In_ BOOL fSvc); 13 | void RpcStop(); 14 | 15 | #endif /* __LEECHAGENT_RPC_H__ */ 16 | -------------------------------------------------------------------------------- /files/agent/x86/readme.txt: -------------------------------------------------------------------------------- 1 | The LeechAgent have dependencies on external software for memory capture which should be placed in this folder if needed. 2 | 3 | 32-bit LeechAgent does not support Python or MemProcFS functionality. It however supports memory acquisition via driver! 4 | 5 | Recommended for (default) service mode: WinPMEM: 6 | https://github.com/Velocidex/WinPmem/raw/master/kernel/binaries/winpmem_x86.sys 7 | 8 | Recommended for interactive mode: DumpIt: 9 | https://www.comae.com 10 | -------------------------------------------------------------------------------- /leechcorepyc/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS= -I. -I../includes -D LINUX -L. -l:leechcore.so -shared -fPIC -fvisibility=hidden `pkg-config python3 --libs --cflags` 3 | LDFLAGS= -Wl,-rpath,'$$ORIGIN' -g -ldl -shared 4 | DEPS = 5 | OBJ = leechcorepyc.o leechcorepyc_barrequest.o oscompatibility.o 6 | 7 | %.o: %.c $(DEPS) 8 | $(CC) -c -o $@ $< $(CFLAGS) 9 | 10 | leechcorepyc: $(OBJ) 11 | cp ../files/leechcore.so . || true 12 | $(CC) -o $@ $^ $(CFLAGS) -o leechcorepyc.so $(LDFLAGS) 13 | mv leechcorepyc.so ../files/ || true 14 | rm -f *.o || true 15 | rm -f *.so || true 16 | true 17 | 18 | clean: 19 | rm -f *.o || true 20 | rm -f *.so || true 21 | -------------------------------------------------------------------------------- /files/Certs/readme.txt: -------------------------------------------------------------------------------- 1 | Example commands for generating test certificates used for gRPC mTLS remote connections. 2 | 3 | Password to the .pfx files: test 4 | 5 | Generate with commands: 6 | 7 | openssl req -x509 -newkey rsa:2048 -keyout client-tls.key -out client-tls.crt -days 365 -nodes -subj "/CN=localhost" 8 | openssl pkcs12 -export -out client-tls.p12 -inkey client-tls.key -in client-tls.crt -password pass:test 9 | 10 | openssl req -x509 -newkey rsa:2048 -keyout server-tls.key -out server-tls.crt -days 365 -nodes -subj "/CN=localhost" 11 | openssl pkcs12 -export -out server-tls.p12 -inkey server-tls.key -in server-tls.crt -password pass:test 12 | -------------------------------------------------------------------------------- /files/agent/x64/Certs/readme.txt: -------------------------------------------------------------------------------- 1 | Example commands for generating test certificates used for gRPC mTLS remote connections. 2 | 3 | Password to the .pfx files: test 4 | 5 | Generate with commands: 6 | 7 | openssl req -x509 -newkey rsa:2048 -keyout client-tls.key -out client-tls.crt -days 365 -nodes -subj "/CN=localhost" 8 | openssl pkcs12 -export -out client-tls.p12 -inkey client-tls.key -in client-tls.crt -password pass:test 9 | 10 | openssl req -x509 -newkey rsa:2048 -keyout server-tls.key -out server-tls.crt -days 365 -nodes -subj "/CN=localhost" 11 | openssl pkcs12 -export -out server-tls.p12 -inkey server-tls.key -in server-tls.crt -password pass:test 12 | -------------------------------------------------------------------------------- /files/agent/x86/Certs/readme.txt: -------------------------------------------------------------------------------- 1 | Example commands for generating test certificates used for gRPC mTLS remote connections. 2 | 3 | Password to the .pfx files: test 4 | 5 | Generate with commands: 6 | 7 | openssl req -x509 -newkey rsa:2048 -keyout client-tls.key -out client-tls.crt -days 365 -nodes -subj "/CN=localhost" 8 | openssl pkcs12 -export -out client-tls.p12 -inkey client-tls.key -in client-tls.crt -password pass:test 9 | 10 | openssl req -x509 -newkey rsa:2048 -keyout server-tls.key -out server-tls.crt -days 365 -nodes -subj "/CN=localhost" 11 | openssl pkcs12 -export -out server-tls.p12 -inkey server-tls.key -in server-tls.crt -password pass:test 12 | -------------------------------------------------------------------------------- /leechcore/leechcore.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WindowsLocalDebugger 5 | 6 | 7 | WindowsRemoteDebugger 8 | 9 | 10 | WindowsRemoteDebugger 11 | 12 | -------------------------------------------------------------------------------- /files/agent/x64/readme.txt: -------------------------------------------------------------------------------- 1 | The LeechAgent have dependencies on external software for memory capture which should be placed in this folder if required. 2 | 3 | Please check out the Guide for detailed up-to-date information: 4 | https://github.com/ufrisk/LeechCore/wiki/LeechAgent 5 | https://github.com/ufrisk/LeechCore/wiki/LeechAgent_Install 6 | 7 | 8 | Also there is a depencency on embedded Python - please check the Python sub-folder for information. 9 | 10 | Recommended for (default) service mode: WinPMEM: 11 | https://github.com/Velocidex/WinPmem/raw/master/kernel/binaries/winpmem_x64.sys 12 | 13 | Recommended for interactive mode: DumpIt: 14 | https://www.comae.com 15 | 16 | --- 17 | 18 | If connecting to FPGA devices on the remote system 'FTD3XX.dll' is required. 19 | If opening Hyper-V save files on the remote system 'vmsavedstatedumpprovider.dll' is required. 20 | -------------------------------------------------------------------------------- /leechagent_linux/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS += -I. -I../includes/ -D LINUX -D _GNU_SOURCE -fPIC -fvisibility=hidden -pthread 3 | CFLAGS += -fPIE -fPIC -fstack-protector-strong -D_FORTIFY_SOURCE=2 -O1 4 | CFLAGS += -Wall -Wno-multichar -Wno-unused-result -Wno-unused-variable -Wno-unused-value -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast 5 | ifeq ($(shell basename $(CC)),gcc) 6 | CFLAGS += -pie 7 | endif 8 | LDFLAGS +=-Wl,-rpath,'$$ORIGIN' -ldl -L. -l:leechcore.so -Wl,-z,noexecstack 9 | DEPS = leechagent.h 10 | OBJ = oscompatibility.o leechagent.o leechrpcshared.o leechagent_rpc.o leechrpcserver.o 11 | 12 | %.o: %.c $(DEPS) 13 | $(CC) -c -o $@ $< $(CFLAGS) 14 | 15 | leechagent: $(OBJ) 16 | cp ../files/leechcore.so . || cp ../../LeechCore*/files/leechcore.so . || true 17 | $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) 18 | mv leechagent ../files/ |true 19 | rm -f *.o || true 20 | rm -f */*.o || true 21 | rm -f *.so || true 22 | true 23 | 24 | clean: 25 | rm -f *.o || true 26 | rm -f */*.o || true 27 | rm -f *.so || true 28 | -------------------------------------------------------------------------------- /leechagent/version.h: -------------------------------------------------------------------------------- 1 | #define STRINGIZE2(s) #s 2 | #define STRINGIZE(s) STRINGIZE2(s) 3 | 4 | #define VERSION_MAJOR 2 5 | #define VERSION_MINOR 22 6 | #define VERSION_REVISION 4 7 | #define VERSION_BUILD 90 8 | 9 | #define VER_FILE_DESCRIPTION_STR "LeechAgent Memory Acquisition Service" 10 | #define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD 11 | #define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \ 12 | "." STRINGIZE(VERSION_MINOR) \ 13 | "." STRINGIZE(VERSION_REVISION) \ 14 | "." STRINGIZE(VERSION_BUILD) \ 15 | 16 | #define VER_COMPANY_NAME_STR "" 17 | #define VER_PRODUCTNAME_STR "LeechAgent" 18 | #define VER_PRODUCT_VERSION VER_FILE_VERSION 19 | #define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR 20 | #define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".exe" 21 | #define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR 22 | #define VER_COPYRIGHT_STR "Copyright (c) Ulf Frisk 2018-2025" 23 | -------------------------------------------------------------------------------- /leechcore/version.h: -------------------------------------------------------------------------------- 1 | #define STRINGIZE2(s) #s 2 | #define STRINGIZE(s) STRINGIZE2(s) 3 | 4 | #define VERSION_MAJOR 2 5 | #define VERSION_MINOR 22 6 | #define VERSION_REVISION 4 7 | #define VERSION_BUILD 90 8 | 9 | #define VER_FILE_DESCRIPTION_STR "LeechCore Memory Acquisition Library" 10 | #define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD 11 | #define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \ 12 | "." STRINGIZE(VERSION_MINOR) \ 13 | "." STRINGIZE(VERSION_REVISION) \ 14 | "." STRINGIZE(VERSION_BUILD) \ 15 | 16 | #define VER_COMPANY_NAME_STR "" 17 | #define VER_PRODUCTNAME_STR "LeechCore" 18 | #define VER_PRODUCT_VERSION VER_FILE_VERSION 19 | #define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR 20 | #define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".dll" 21 | #define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR 22 | #define VER_COPYRIGHT_STR "Copyright (c) Ulf Frisk 2018-2025" 23 | -------------------------------------------------------------------------------- /leechcorepyc/version.h: -------------------------------------------------------------------------------- 1 | #define STRINGIZE2(s) #s 2 | #define STRINGIZE(s) STRINGIZE2(s) 3 | 4 | #define VERSION_MAJOR 2 5 | #define VERSION_MINOR 22 6 | #define VERSION_REVISION 4 7 | #define VERSION_BUILD 90 8 | 9 | #define VER_FILE_DESCRIPTION_STR "LeechCore Memory Acquisition Library : Python API" 10 | #define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD 11 | #define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \ 12 | "." STRINGIZE(VERSION_MINOR) \ 13 | "." STRINGIZE(VERSION_REVISION) \ 14 | "." STRINGIZE(VERSION_BUILD) \ 15 | 16 | #define VER_COMPANY_NAME_STR "" 17 | #define VER_PRODUCTNAME_STR "LeechCorePyC" 18 | #define VER_PRODUCT_VERSION VER_FILE_VERSION 19 | #define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR 20 | #define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".pyd" 21 | #define VER_INTERNAL_NAME_STR VER_ORIGINAL_FILENAME_STR 22 | #define VER_COPYRIGHT_STR "Copyright (c) Ulf Frisk 2019-2025" 23 | -------------------------------------------------------------------------------- /leechagent/util.h: -------------------------------------------------------------------------------- 1 | // util.h : definitions of various utility functions. 2 | // 3 | // (c) Ulf Frisk, 2020-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __UTIL_H__ 7 | #define __UTIL_H__ 8 | #include "leechcore.h" 9 | 10 | /* 11 | * Return the path of the specified hModule (DLL) - ending with a backslash, or current Executable. 12 | * -- szPath 13 | * -- hModule = Optional, HMODULE handle for path to DLL, NULL for path to EXE. 14 | */ 15 | VOID Util_GetPathDllW(_Out_writes_(MAX_PATH) PWCHAR wszPath, _In_opt_ HMODULE hModule); 16 | 17 | /* 18 | * Perform a wszncat_s on an arbitrary number of LPWSTR that is terminated by a NULL argument. 19 | * -- _Destination 20 | * -- _SizeInWords 21 | * -- _MaxCount 22 | * -- ... = arbitrary number of LPWSTR terminated with NULL argument. 23 | */ 24 | VOID Util_wcsncat_s_N(_Inout_updates_z_(_SizeInWords) wchar_t* _Destination, _In_ rsize_t _SizeInWords, _In_ rsize_t _MaxCount, ...); 25 | 26 | #ifdef _WIN32 27 | 28 | /* 29 | * "Eternal" reading loop until all requested data is read or until there is an error. 30 | * -- hPipe_Rd 31 | * -- pb 32 | * -- cb 33 | * -- return 34 | */ 35 | _Success_(return) 36 | BOOL Util_GetBytesPipe(_In_ HANDLE hPipe_Rd, _Out_writes_opt_(cb) PBYTE pb, _In_ DWORD cb); 37 | 38 | #endif /* _WIN32 */ 39 | 40 | #endif /* __UTIL_H__ */ 41 | -------------------------------------------------------------------------------- /leechagent/util.c: -------------------------------------------------------------------------------- 1 | // util.h : implementations of various utility functions. 2 | // 3 | // (c) Ulf Frisk, 2020-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #include "util.h" 7 | 8 | VOID Util_wcsncat_s_N(_Inout_updates_z_(_SizeInWords) wchar_t* _Destination, _In_ rsize_t _SizeInWords, _In_ rsize_t _MaxCount, ...) 9 | { 10 | LPWSTR wsz; 11 | va_list args; 12 | va_start(args, _MaxCount); 13 | while((wsz = va_arg(args, LPWSTR))) { 14 | wcsncat_s(_Destination, _SizeInWords, wsz, _MaxCount); 15 | } 16 | va_end(args); 17 | } 18 | 19 | VOID Util_GetPathDllW(_Out_writes_(MAX_PATH) PWCHAR wszPath, _In_opt_ HMODULE hModule) 20 | { 21 | SIZE_T i; 22 | GetModuleFileNameW(hModule, wszPath, MAX_PATH - 4); 23 | for(i = wcslen(wszPath) - 1; i > 0; i--) { 24 | if(wszPath[i] == L'/' || wszPath[i] == L'\\') { 25 | wszPath[i + 1] = '\0'; 26 | return; 27 | } 28 | } 29 | } 30 | 31 | #ifdef _WIN32 32 | 33 | _Success_(return) 34 | BOOL Util_GetBytesPipe(_In_ HANDLE hPipe_Rd, _Out_writes_opt_(cb) PBYTE pb, _In_ DWORD cb) 35 | { 36 | DWORD cbReadTotal = 0, cbRead = 0; 37 | while((cbReadTotal < cb) && ReadFile(hPipe_Rd, pb + cbReadTotal, cb - cbReadTotal, &cbRead, NULL)) { 38 | cbReadTotal += cbRead; 39 | } 40 | return (cb == cbReadTotal); 41 | } 42 | 43 | #endif /* _WIN32 */ 44 | -------------------------------------------------------------------------------- /leechcorepyc/leechcorepyc.h: -------------------------------------------------------------------------------- 1 | // leechcorepyc.c : Implementation of the LeechCore Python API 2 | // 3 | // (c) Ulf Frisk, 2020-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __LEECHCOREPYC_H__ 7 | #define __LEECHCOREPYC_H__ 8 | 9 | #define PY_SSIZE_T_CLEAN 10 | #define Py_LIMITED_API 0x03060000 11 | #ifdef _DEBUG 12 | #undef _DEBUG 13 | #include 14 | #include 15 | #define _DEBUG 16 | #else 17 | #include 18 | #include 19 | #endif 20 | #ifdef _WIN32 21 | #include 22 | #endif /* _WIN32 */ 23 | #include 24 | #include "oscompatibility.h" 25 | 26 | extern PyObject *g_pPyType_LeechCore; 27 | extern PyObject *g_pPyType_BarRequest; 28 | 29 | typedef struct tdPyObj_LeechCore { 30 | PyObject_HEAD 31 | BOOL fValid; 32 | HANDLE hLC; 33 | LC_CONFIG cfg; 34 | PHANDLE phLCkeepalive; 35 | PyObject *fnBarCB; 36 | PyObject *fnTlpReadCB; 37 | PyObject *pyBarDictSingle[6]; // dict of pcie bar info. 38 | PyObject *pyBarListAll; // list of pyBarSingle[0..5]. 39 | } PyObj_LeechCore; 40 | 41 | typedef struct tdPyObj_BarRequest { 42 | PyObject_HEAD 43 | BOOL fValid; 44 | PyObj_LeechCore *pyLC; 45 | PLC_BAR_REQUEST pReq; 46 | } PyObj_BarRequest; 47 | 48 | _Success_(return) BOOL LcPy_BarRequest_InitializeType(PyObject *pModule); 49 | 50 | PyObj_BarRequest* LcPy_BarRequest_InitializeInternal(_In_ PyObj_LeechCore *pyLC, _In_ PLC_BAR_REQUEST pReq); 51 | 52 | #endif /* __LEECHCOREPYC_H__ */ 53 | -------------------------------------------------------------------------------- /leechcore/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS += -I. -I../includes/ -D LINUX -D _GNU_SOURCE -shared -fPIC -fvisibility=hidden -pthread `pkg-config libusb-1.0 --libs --cflags` 3 | # DEBUG FLAGS BELOW 4 | # export ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:detect_invalid_pointer_pairs=2 5 | # CFLAGS += -g -O0 -Wextra -Wno-unused-parameter -Wno-cast-function-type 6 | # CFLAGS += -fsanitize=address -fsanitize=leak -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=bounds-strict -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow 7 | # CFLAGS += -fsanitize=pointer-compare -fsanitize=pointer-subtract -fanalyzer 8 | # DEBUG FLAGS ABOVE 9 | CFLAGS += -fPIE -fPIC -pie -fstack-protector-strong -D_FORTIFY_SOURCE=2 -O1 -Wl,-z,noexecstack 10 | CFLAGS += -Wall -Wno-multichar -Wno-unused-result -Wno-unused-variable -Wno-unused-value -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast 11 | LDFLAGS += -g -ldl -shared 12 | DEPS = leechcore.h 13 | OBJ = oscompatibility.o leechcore.o util.o memmap.o device_file.o device_fpga.o device_hibr.o device_pmem.o device_tmd.o device_usb3380.o device_vmm.o device_vmware.o leechrpcclient.o ob/ob_core.o ob/ob_map.o ob/ob_set.o ob/ob_bytequeue.o 14 | 15 | %.o: %.c $(DEPS) 16 | $(CC) -c -o $@ $< $(CFLAGS) 17 | 18 | leechcore: $(OBJ) 19 | $(CC) -o $@ $^ $(CFLAGS) -o leechcore.so $(LDFLAGS) 20 | mv leechcore.so ../files/ 21 | rm -f *.o || true 22 | rm -f */*.o || true 23 | rm -f *.so || true 24 | true 25 | 26 | clean: 27 | rm -f *.o || true 28 | rm -f */*.o || true 29 | rm -f *.so || true 30 | -------------------------------------------------------------------------------- /leechcorepyc/leechcorepyc.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | python.exe 5 | $(SolutionDir)\files\test.py 6 | WindowsRemoteDebugger 7 | C:\Program Files\Python39\python.exe 8 | \\ad.frizk.net\data\dev-pcileech\bin\test.py 9 | WORKSTATION.ad.frizk.net 10 | \\ad.frizk.net\data\dev-pcileech\bin\ 11 | 12 | 13 | python.exe 14 | $(SolutionDir)\files\test.py 15 | WindowsRemoteDebugger 16 | C:\Program Files\Python39\python.exe 17 | \\ad.frizk.net\data\dev-pcileech\bin\test.py 18 | WORKSTATION.ad.frizk.net 19 | \\ad.frizk.net\data\dev-pcileech\bin\ 20 | 21 | -------------------------------------------------------------------------------- /leechagent_linux/leechagent.h: -------------------------------------------------------------------------------- 1 | // leechagent.h : definitions related to the leech agent. 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __LEECHAGENT_H__ 7 | #define __LEECHAGENT_H__ 8 | 9 | #include "oscompatibility.h" 10 | 11 | #define LEECHSVC_NAME "LeechAgent" 12 | #define LEECHSVC_DISPLAY_NAME "Leech Memory Acquisition Agent" 13 | #define LEECHSVC_DESCR_LONG "The Leech Memory Acquisition Agent allows for LeechCore library users to connect remotely to the agent." 14 | #define LEECHSVC_TCP_PORT_GRPC "28474" 15 | #define LEECHSVC_LOCKFILE "/var/run/lock/leechagent.pid" 16 | 17 | #define LEECHAGENT_CLIENTKEEPALIVE_MAX_CLIENTS 0x40 18 | #define LEECHAGENT_CLIENTKEEPALIVE_TIMEOUT_MS 75*1000 // recommended to be less than LEECHAGENT_CHILDPROCESS_TIMEOUT_DEFAULT_MS 19 | #define LEECHAGENT_CHILDPROCESS_TIMEOUT_MAX_MS 30*60*1000 20 | #define LEECHAGENT_CHILDPROCESS_TIMEOUT_DEFAULT_MS 2*60*1000 21 | 22 | #define LEECHGRPC_LIBRARY_NAME "libleechgrpc"LC_LIBRARY_FILETYPE 23 | #define LEECHAGENT_CONFIG_FILE "leechagent_config.txt" 24 | 25 | typedef struct tdLEECHAGENT_CONFIG { 26 | BOOL fDaemon; 27 | BOOL fNoLock; 28 | BOOL fInteractive; 29 | BOOL fInsecure; 30 | CHAR szRemote[MAX_PATH]; 31 | CHAR szTcpPortGRPC[0x10]; 32 | HMODULE hModuleGRPC; 33 | struct { 34 | CHAR szCurrentDirectory[MAX_PATH]; 35 | CHAR szListenAddress[MAX_PATH]; 36 | CHAR szTlsClientCaCert[MAX_PATH]; 37 | CHAR szTlsServerP12[MAX_PATH]; 38 | CHAR szTlsServerP12Pass[MAX_PATH]; 39 | } grpc; 40 | int fdLockFile; 41 | } LEECHSVC_CONFIG, *PLEECHSVC_CONFIG; 42 | 43 | /* 44 | * Read arguments from a the config file 'leechagent_config.txt' into the config. 45 | */ 46 | VOID LeechSvc_ParseArgs_FromConfigFile(_In_ PLEECHSVC_CONFIG pConfig); 47 | 48 | #endif /* __LEECHAGENT_H__ */ 49 | -------------------------------------------------------------------------------- /leechcore/Makefile.macos: -------------------------------------------------------------------------------- 1 | CC=clang 2 | CFLAGS += -I. -D MACOS -D _GNU_SOURCE -fPIC -fvisibility=hidden -pthread 3 | CFLAGS += -fPIC -fstack-protector-strong -D_FORTIFY_SOURCE=2 -O1 4 | CFLAGS += -Wall -Wno-multichar -Wno-unused-result -Wno-unused-variable -Wno-unused-value 5 | CFLAGS += -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast 6 | CFLAGS += -mmacosx-version-min=11.0 7 | # DEBUG FLAGS BELOW 8 | #CFLAGS += -O0 9 | #CFLAGS += -fsanitize=address 10 | # DEBUG FLAGS ABOVE 11 | LDFLAGS += -g -dynamiclib -mmacosx-version-min=11.0 12 | 13 | DEPS = leechcore.h 14 | OBJ = oscompatibility.o leechcore.o util.o memmap.o device_file.o device_fpga.o device_hibr.o device_pmem.o device_tmd.o device_usb3380.o device_vmm.o device_vmware.o leechrpcclient.o ob/ob_core.o ob/ob_map.o ob/ob_set.o ob/ob_bytequeue.o 15 | 16 | # ARCH SPECIFIC FLAGS: 17 | CFLAGS_X86_64 = $(CFLAGS) -arch x86_64 18 | CFLAGS_ARM64 = $(CFLAGS) -arch arm64 19 | LDFLAGS_X86_64 = $(LDFLAGS) -arch x86_64 20 | LDFLAGS_ARM64 = $(LDFLAGS) -arch arm64 21 | OBJ_X86_64 = $(OBJ:.o=.o.x86_64) 22 | OBJ_ARM64 = $(OBJ:.o=.o.arm64) 23 | 24 | all: leechcore.dylib 25 | 26 | %.o.x86_64: %.c $(DEPS) 27 | $(CC) $(CFLAGS_X86_64) -c -o $@ $< 28 | 29 | %.o.arm64: %.c $(DEPS) 30 | $(CC) $(CFLAGS_ARM64) -c -o $@ $< 31 | 32 | leechcore_x86_64.dylib: $(OBJ_X86_64) 33 | $(CC) $(LDFLAGS_X86_64) -o $@ $^ 34 | 35 | leechcore_arm64.dylib: $(OBJ_ARM64) 36 | $(CC) $(LDFLAGS_ARM64) -o $@ $^ 37 | 38 | leechcore.dylib: leechcore_x86_64.dylib leechcore_arm64.dylib 39 | lipo -create -output leechcore.dylib leechcore_x86_64.dylib leechcore_arm64.dylib 40 | install_name_tool -id @rpath/leechcore.dylib leechcore.dylib 41 | mv leechcore.dylib ../files/ 42 | rm -f *.o *.o.x86_64 *.o.arm64 || true 43 | rm -f */*.o */*.o.x86_64 */*.o.arm64 || true 44 | rm -f *.dylib || true 45 | true 46 | 47 | clean: 48 | rm -f *.o *.o.x86_64 *.o.arm64 || true 49 | rm -f */*.o */*.o.x86_64 */*.o.arm64 || true 50 | rm -f *.dylib || true 51 | -------------------------------------------------------------------------------- /leechagent/leechagent_svc.h: -------------------------------------------------------------------------------- 1 | // leechagent_svc.h : definitions related to leechagent service functionality 2 | // 3 | // (c) Ulf Frisk, 2024-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __LEECHAGENT_SVC_H__ 7 | #define __LEECHAGENT_SVC_H__ 8 | #include 9 | 10 | /* 11 | * Log a message to the event log 12 | * -- wszFunction = name of function that failed. 13 | */ 14 | VOID LeechSvc_ReportEvent(LPWSTR wszFunction); 15 | 16 | /* 17 | * Main entry point for the SCM. 18 | * -- dwArgc = # of pwszArgv. 19 | * -- pwszArgv = arguments passed from the SCM (not currently used by function). 20 | */ 21 | VOID WINAPI LeechSvc_SvcMain(DWORD dwArgc, LPWSTR *pwszArgv); 22 | 23 | /* 24 | * Run the "service" in interactive mode - i.e. run it as a normal application. 25 | * -- pConfig 26 | */ 27 | VOID LeechSvc_Interactive(_In_ PLEECHSVC_CONFIG pConfig); 28 | 29 | /* 30 | * Install the service. 31 | * -- szComputer = remote computer name (NULL for local computer). 32 | * -- wszRemoteLocalPath = remote local path (including file) of LeechAgent.exe (if remote installation). 33 | * -- return 34 | */ 35 | _Success_(return) 36 | BOOL LeechSvc_Install(_In_opt_ LPWSTR wszComputer, _In_reads_opt_(MAX_PATH) LPWSTR wszRemoteLocalPathOpt); 37 | 38 | /* 39 | * Install the service on a remote computer using SMB to copy files and RPC to 40 | * install the service via the remote service manager. 41 | * -- wszComputer 42 | * -- return 43 | */ 44 | _Success_(return) 45 | BOOL LeechSvc_InstallRemoteRpc(_In_ LPWSTR wszComputer); 46 | 47 | /* 48 | * Delete the installed service from the services database. 49 | * -- wszComputer = remote computer name (NULL for local computer) 50 | * -- fSilent = do not display error messages on screen. 51 | * -- return 52 | */ 53 | _Success_(return) 54 | BOOL LeechSvc_Delete(_In_opt_ LPWSTR wszComputer, _In_ BOOL fSilent); 55 | 56 | /* 57 | * Remove the service on a remote computer using RPC. 58 | * -- wszComputer = remote computer name (NULL for local computer) 59 | * -- fSilent = do not display error messages on screen. 60 | * -- wszRemotePathOpt = remote local path (including file) of LeechAgent.exe (if remote installation). 61 | */ 62 | _Success_(return) 63 | BOOL LeechSvc_DeleteRemoteRpc(_In_ LPWSTR wszComputer, _In_ BOOL fSilent, _In_opt_ LPWSTR wszRemotePathOpt); 64 | 65 | 66 | #endif /* __LEECHAGENT_SVC_H__ */ 67 | -------------------------------------------------------------------------------- /leechcorepyc/leechcorepyc.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {1451d3ca-05c1-4721-b6fe-e8ab6a3602ca} 18 | 19 | 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files\includes 43 | 44 | 45 | Header Files 46 | 47 | 48 | 49 | 50 | Resource Files 51 | 52 | 53 | 54 | 55 | Resource Files 56 | 57 | 58 | Resource Files 59 | 60 | 61 | -------------------------------------------------------------------------------- /leechcore/leechcore_internal.h: -------------------------------------------------------------------------------- 1 | // leechcore_internal.h : definitions of internal leechcore functionality such 2 | // as non exported parts of memory map functionality. 3 | // 4 | // (c) Ulf Frisk, 2020-2025 5 | // Author: Ulf Frisk, pcileech@frizk.net 6 | // 7 | 8 | #ifndef __LEECHCORE_INTERNAL_H__ 9 | #define __LEECHCORE_INTERNAL_H__ 10 | #include "leechcore.h" 11 | #include "leechcore_device.h" 12 | 13 | /* 14 | * Translate each individual MEM. The qwA field will be overwritten with the 15 | * translated value - or on error -1. 16 | * -- ctxLC 17 | * -- cMEMs 18 | * -- ppMEMs 19 | */ 20 | VOID LcMemMap_TranslateMEMs(_In_ PLC_CONTEXT ctxLC, _In_ DWORD cMEMs, _Inout_ PPMEM_SCATTER ppMEMs); 21 | 22 | /* 23 | * Retrieve the memory ranges as an array of LC_MEMMAP_ENTRY. 24 | * -- ctxLC 25 | * -- ppbDataOut 26 | * -- pcbDataOut 27 | */ 28 | _Success_(return) 29 | BOOL LcMemMap_GetRangesAsStruct(_In_ PLC_CONTEXT ctxLC, _Out_ PBYTE * ppbDataOut, _Out_opt_ PDWORD pcbDataOut); 30 | 31 | /* 32 | * Retrieve the memory ranges as ascii text in a null-terminated text buffer. 33 | * CALLER LcFreeMem: *ppbDataOut 34 | * -- ctxLC 35 | * -- ppbDataOut 36 | * -- pcbDataOut 37 | */ 38 | _Success_(return) 39 | BOOL LcMemMap_GetRangesAsText(_In_ PLC_CONTEXT ctxLC, _Out_ PBYTE *ppbDataOut, _Out_opt_ PDWORD pcbDataOut); 40 | 41 | /* 42 | * Set ranges by memmap struct data. 43 | * NB! all previous ranges will be overwritten. 44 | * -- ctxLC 45 | * -- pStruct 46 | * -- cStruct 47 | * -- return 48 | */ 49 | _Success_(return) 50 | BOOL LcMemMap_SetRangesFromStruct(_In_ PLC_CONTEXT ctxLC, _In_ PLC_MEMMAP_ENTRY pMemMap, _In_ DWORD cMemMap); 51 | 52 | /* 53 | * Set ranges by parsing ascii text in the buffer pb. The ranges should be 54 | * specified on a line-by-line basis with hexascii numericals on the format: 55 | * 56 | * NB! all previous ranges will be overwritten. 57 | * -- ctxLC 58 | * -- pb 59 | * -- cb 60 | * -- return 61 | */ 62 | _Success_(return) 63 | BOOL LcMemMap_SetRangesFromText(_In_ PLC_CONTEXT ctxLC, _In_ PBYTE pb, _In_ DWORD cb); 64 | 65 | /* 66 | * Create helper function to parse optional device configuration parameters. 67 | * Outside of the main function context this should be avoided unless forwarding 68 | * a create function call to another device type. 69 | * -- ctxLC 70 | */ 71 | VOID LcCreate_FetchDeviceParameter(_Inout_ PLC_CONTEXT ctxLC); 72 | 73 | #endif /* __LEECHCORE_INTERNAL_H__ */ 74 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /includes/libpdbcrust.h: -------------------------------------------------------------------------------- 1 | // C library wrapper around the rust PDB crate and related useful utilities. 2 | // 3 | // (c) Ulf Frisk, 2023 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 9 | // copied, modified, or distributed except according to those terms. 10 | // 11 | 12 | #include 13 | #include 14 | 15 | /* 16 | * Open a PDB file given its full path and return a handle to it. 17 | * The handle should be closed by calling pdbcrust_close(). 18 | */ 19 | size_t pdbcrust_open( 20 | char *sz_pdb_full_path 21 | ); 22 | 23 | /* 24 | * Close a PDB handle and free its resources. 25 | */ 26 | void pdbcrust_close( 27 | size_t hnd 28 | ); 29 | 30 | /* 31 | * Ensure that a PDB file exists on the specified path and upon success return 32 | * the full file path in sz_pdb_path_result. If the PDB file does not exist it 33 | * may optionally be downloaded from the Microsoft symbol server. 34 | * -- sz_pdb_basepath = base path (directory must exist). 35 | * -- sz_pdb_guidage = the combined GUID+AGE in uppercase hexascii string. 36 | * -- sz_pdb_name = the pdb file name. 37 | * -- is_mspdb_download = download the PDB from the microsoft symbol server. 38 | * -- len_path_path_result = byte length of sz_pdb_path_result. 39 | * -- sz_pdb_path_result = buffer to receive full pdb file path on success. 40 | * -- return 41 | */ 42 | bool pdbcrust_pdb_download_ensure( 43 | char *sz_pdb_basepath, 44 | char *sz_pdb_guidage, 45 | char *sz_pdb_name, 46 | bool is_mspdb_download, 47 | size_t len_path_path_result, 48 | char *sz_pdb_path_result 49 | ); 50 | 51 | /* 52 | * Retrieve a symbol offset given a symbol name. 53 | * -- hnd 54 | * -- sz_symbol_name = the symbol name to retrieve 55 | * -- return = the symbol offset on success. zero on fail. 56 | */ 57 | unsigned int pdbcrust_symbol_offset( 58 | size_t hnd, 59 | char *sz_symbol_name 60 | ); 61 | 62 | /* 63 | * Retrieve a symbol name given an offset. 64 | * -- hnd 65 | * -- symbol_offset = the symbol offset. 66 | * -- len_symbol_name 67 | * -- sz_symbol_name 68 | * -- displacement = the displacement, currently not functional. 69 | * -- return 70 | */ 71 | bool pdbcrust_symbol_name_from_offset( 72 | size_t hnd, 73 | unsigned int symbol_offset, 74 | size_t len_symbol_name, 75 | char *sz_symbol_name, 76 | unsigned int *displacement 77 | ); 78 | 79 | /* 80 | * Retrieve the size of a type / struct. 81 | * -- hnd 82 | * -- sz_type_name 83 | * -- return = the type size on success, 0 on fail. 84 | */ 85 | unsigned int pdbcrust_type_size( 86 | size_t hnd, 87 | char *sz_type_name 88 | ); 89 | 90 | /* 91 | * Retrieve the child offset inside a type/struct. 92 | * -- hnd 93 | * -- sz_type_name 94 | * -- sz_type_child 95 | * -- offset_type_child = ptr to receive the child offset on success. 96 | * -- return 97 | */ 98 | bool pdbcrust_type_child_offset( 99 | size_t hnd, 100 | char *sz_type_name, 101 | char *sz_type_child, 102 | unsigned int *offset_type_child 103 | ); 104 | -------------------------------------------------------------------------------- /leechagent/leechagent.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {464d5c38-9fa4-410f-a6d0-00e4b4c6f5f9} 18 | 19 | 20 | 21 | 22 | Resource Files 23 | 24 | 25 | 26 | 27 | Resource Files 28 | 29 | 30 | 31 | 32 | Source Files 33 | 34 | 35 | Source Files 36 | 37 | 38 | Source Files 39 | 40 | 41 | Source Files 42 | 43 | 44 | Source Files 45 | 46 | 47 | Source Files 48 | 49 | 50 | Source Files 51 | 52 | 53 | Source Files 54 | 55 | 56 | Source Files 57 | 58 | 59 | 60 | 61 | Header Files 62 | 63 | 64 | Header Files 65 | 66 | 67 | Header Files 68 | 69 | 70 | Header Files 71 | 72 | 73 | Header Files 74 | 75 | 76 | Header Files 77 | 78 | 79 | Header Files 80 | 81 | 82 | Header Files\leechcore 83 | 84 | 85 | Header Files 86 | 87 | 88 | -------------------------------------------------------------------------------- /leechagent/leechagent_proc.h: -------------------------------------------------------------------------------- 1 | // leechagent_proc.h : Definitions of parent/child process functionality. 2 | // Child processes host execution environments such as the 3 | // Python environment which allows for execution of scripts. 4 | // Child processes are spawned and controlled by the main 5 | // LeechAgent process. 6 | // 7 | // (c) Ulf Frisk, 2020-2025 8 | // Author: Ulf Frisk, pcileech@frizk.net 9 | // 10 | #ifndef __LEECHAGENT_PROC_H__ 11 | #define __LEECHAGENT_PROC_H__ 12 | #include "leechagent.h" 13 | 14 | #define LEECHAGENT_PROC_CMD_MAGIC 0x20f02ab8 15 | #define LEECHAGENT_PROC_CMD_EXITCLIENT 0x00000001 16 | #define LEECHAGENT_PROC_CMD_INIT_VMM 0x00000002 17 | #define LEECHAGENT_PROC_CMD_INIT_PYTHON 0x00000003 18 | #define LEECHAGENT_PROC_CMD_EXEC_PYTHON 0x00000004 19 | #define LEECHAGENT_PROC_CMD_VFS_LIST 0x00000005 20 | #define LEECHAGENT_PROC_CMD_VFS_READ 0x00000006 21 | #define LEECHAGENT_PROC_CMD_VFS_WRITE 0x00000007 22 | #define LEECHAGENT_PROC_CMD_VFS_OPT_GET 0x00000008 23 | #define LEECHAGENT_PROC_CMD_VFS_OPT_SET 0x00000009 24 | 25 | typedef struct tdLEECHAGENT_PROC_CMD { 26 | DWORD dwMagic; 27 | DWORD dwCmd; 28 | BOOL fSuccess; 29 | DWORD cb; 30 | BYTE pb[]; 31 | } LEECHAGENT_PROC_CMD, *PLEECHAGENT_PROC_CMD; 32 | 33 | VOID LeechAgent_ProcChild_Main(int argc, wchar_t* argv[]); 34 | 35 | _Success_(return) 36 | BOOL LeechAgent_ProcParent_ExecPy(_In_ HANDLE hLC, _In_ DWORD dwTimeout, _In_reads_(cbDataIn) PBYTE pbDataIn, _In_ DWORD cbDataIn, _Out_opt_ PBYTE* ppbDataOut, _Out_opt_ PDWORD pcbDataOut); 37 | 38 | /* 39 | * Execute a virtual file system command towards MemProcFS / vmm.dll. 40 | * CALLER LocalFree: *ppbDataOut 41 | * -- hLC 42 | * -- phPP = ptr to "ParentProcess" handle to update as required. 43 | * -- dwCMD = LEECHAGENT_PROC_CMD_VFS_LIST | LEECHAGENT_PROC_CMD_VFS_READ | LEECHAGENT_PROC_CMD_VFS_WRITE 44 | * -- pbDataIn 45 | * -- cbDataIn 46 | * -- ppbDataOut 47 | * -- pcbDataOut 48 | * -- return 49 | */ 50 | _Success_(return) 51 | BOOL LeechAgent_ProcParent_VfsCMD(_In_ HANDLE hLC, _Inout_ PHANDLE phPP, _In_ DWORD dwCMD, _In_reads_(cbDataIn) PBYTE pbDataIn, _In_ DWORD cbDataIn, _Out_opt_ PBYTE* ppbDataOut, _Out_opt_ PDWORD pcbDataOut); 52 | 53 | /* 54 | * Initialize a virtual file system handle towards MemProcFS / vmm.dll. 55 | * CALLER LocalFree: *ppbDataOut 56 | * -- hLC 57 | * -- phPP = ptr to "ParentProcess" handle to update as required. 58 | * -- pbDataIn 59 | * -- cbDataIn 60 | * -- ppbDataOut 61 | * -- pcbDataOut 62 | * -- return 63 | */ 64 | _Success_(return) 65 | BOOL LeechAgent_ProcParent_VfsInitialize(_In_ HANDLE hLC, _Inout_ PHANDLE phPP, _In_reads_(cbDataIn) PBYTE pbDataIn, _In_ DWORD cbDataIn, _Out_opt_ PBYTE * ppbDataOut, _Out_opt_ PDWORD pcbDataOut); 66 | 67 | /* 68 | * Retrieve console information from the child process (if any) and perform a a 69 | * keepalive operation. 70 | * CALLER LocalFree: *ppbDataOut 71 | * -- hLC 72 | * -- phPP = ptr to "ParentProcess" handle to update as required. 73 | * -- ppbDataOut 74 | * -- pcbDataOut 75 | * -- return 76 | */ 77 | _Success_(return) 78 | BOOL LeechAgent_ProcParent_VfsConsole(_In_ HANDLE hLC, _Inout_ PHANDLE phPP, _Out_opt_ PBYTE *ppbDataOut, _Out_opt_ PDWORD pcbDataOut); 79 | 80 | /* 81 | * Close a ProcParent handle kept by the leechrpcserver. 82 | * This is usually done on vfs close / handle close after vfs operations. 83 | * -- hPP = handle to destroy / close. 84 | */ 85 | VOID LeechAgent_ProcParent_Close(_In_opt_ HANDLE hPP); 86 | 87 | #endif /* __LEECHAGENT_PROC_H__ */ 88 | -------------------------------------------------------------------------------- /leechagent_linux/leechagent_proc.h: -------------------------------------------------------------------------------- 1 | // leechagent_proc.h : Definitions of parent/child process functionality. 2 | // Child processes host execution environments such as the 3 | // Python environment which allows for execution of scripts. 4 | // Child processes are spawned and controlled by the main 5 | // LeechAgent process. 6 | // 7 | // (c) Ulf Frisk, 2020-2025 8 | // Author: Ulf Frisk, pcileech@frizk.net 9 | // 10 | #ifndef __LEECHAGENT_PROC_H__ 11 | #define __LEECHAGENT_PROC_H__ 12 | #include "leechagent.h" 13 | 14 | #define LEECHAGENT_PROC_CMD_MAGIC 0x20f02ab8 15 | #define LEECHAGENT_PROC_CMD_EXITCLIENT 0x00000001 16 | #define LEECHAGENT_PROC_CMD_INIT_VMM 0x00000002 17 | #define LEECHAGENT_PROC_CMD_INIT_PYTHON 0x00000003 18 | #define LEECHAGENT_PROC_CMD_EXEC_PYTHON 0x00000004 19 | #define LEECHAGENT_PROC_CMD_VFS_LIST 0x00000005 20 | #define LEECHAGENT_PROC_CMD_VFS_READ 0x00000006 21 | #define LEECHAGENT_PROC_CMD_VFS_WRITE 0x00000007 22 | #define LEECHAGENT_PROC_CMD_VFS_OPT_GET 0x00000008 23 | #define LEECHAGENT_PROC_CMD_VFS_OPT_SET 0x00000009 24 | 25 | typedef struct tdLEECHAGENT_PROC_CMD { 26 | DWORD dwMagic; 27 | DWORD dwCmd; 28 | BOOL fSuccess; 29 | DWORD cb; 30 | BYTE pb[]; 31 | } LEECHAGENT_PROC_CMD, *PLEECHAGENT_PROC_CMD; 32 | 33 | VOID LeechAgent_ProcChild_Main(int argc, wchar_t* argv[]); 34 | 35 | _Success_(return) 36 | BOOL LeechAgent_ProcParent_ExecPy(_In_ HANDLE hLC, _In_ DWORD dwTimeout, _In_reads_(cbDataIn) PBYTE pbDataIn, _In_ DWORD cbDataIn, _Out_opt_ PBYTE* ppbDataOut, _Out_opt_ PDWORD pcbDataOut); 37 | 38 | /* 39 | * Execute a virtual file system command towards MemProcFS / vmm.dll. 40 | * CALLER LocalFree: *ppbDataOut 41 | * -- hLC 42 | * -- phPP = ptr to "ParentProcess" handle to update as required. 43 | * -- dwCMD = LEECHAGENT_PROC_CMD_VFS_LIST | LEECHAGENT_PROC_CMD_VFS_READ | LEECHAGENT_PROC_CMD_VFS_WRITE 44 | * -- pbDataIn 45 | * -- cbDataIn 46 | * -- ppbDataOut 47 | * -- pcbDataOut 48 | * -- return 49 | */ 50 | _Success_(return) 51 | BOOL LeechAgent_ProcParent_VfsCMD(_In_ HANDLE hLC, _Inout_ PHANDLE phPP, _In_ DWORD dwCMD, _In_reads_(cbDataIn) PBYTE pbDataIn, _In_ DWORD cbDataIn, _Out_opt_ PBYTE* ppbDataOut, _Out_opt_ PDWORD pcbDataOut); 52 | 53 | /* 54 | * Initialize a virtual file system handle towards MemProcFS / vmm.dll. 55 | * CALLER LocalFree: *ppbDataOut 56 | * -- hLC 57 | * -- phPP = ptr to "ParentProcess" handle to update as required. 58 | * -- pbDataIn 59 | * -- cbDataIn 60 | * -- ppbDataOut 61 | * -- pcbDataOut 62 | * -- return 63 | */ 64 | _Success_(return) 65 | BOOL LeechAgent_ProcParent_VfsInitialize(_In_ HANDLE hLC, _Inout_ PHANDLE phPP, _In_reads_(cbDataIn) PBYTE pbDataIn, _In_ DWORD cbDataIn, _Out_opt_ PBYTE * ppbDataOut, _Out_opt_ PDWORD pcbDataOut); 66 | 67 | /* 68 | * Retrieve console information from the child process (if any) and perform a a 69 | * keepalive operation. 70 | * CALLER LocalFree: *ppbDataOut 71 | * -- hLC 72 | * -- phPP = ptr to "ParentProcess" handle to update as required. 73 | * -- ppbDataOut 74 | * -- pcbDataOut 75 | * -- return 76 | */ 77 | _Success_(return) 78 | BOOL LeechAgent_ProcParent_VfsConsole(_In_ HANDLE hLC, _Inout_ PHANDLE phPP, _Out_opt_ PBYTE *ppbDataOut, _Out_opt_ PDWORD pcbDataOut); 79 | 80 | /* 81 | * Close a ProcParent handle kept by the leechrpcserver. 82 | * This is usually done on vfs close / handle close after vfs operations. 83 | * -- hPP = handle to destroy / close. 84 | */ 85 | VOID LeechAgent_ProcParent_Close(_In_opt_ HANDLE hPP); 86 | 87 | #endif /* __LEECHAGENT_PROC_H__ */ 88 | -------------------------------------------------------------------------------- /leechagent_linux/leechagent_rpc.c: -------------------------------------------------------------------------------- 1 | // leechsvc_rpc.c : implementation of RPC related functionality. 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #include "leechagent.h" 7 | #include "leechagent_rpc.h" 8 | #include "leechrpc.h" 9 | #include 10 | 11 | // gRPC: 12 | HANDLE g_hGRPC = NULL; 13 | 14 | pfn_leechgrpc_server_create_insecure g_pfn_leechgrpc_server_create_insecure; 15 | pfn_leechgrpc_server_create_secure_p12 g_pfn_leechgrpc_server_create_secure_p12; 16 | pfn_leechgrpc_server_shutdown g_pfn_leechgrpc_server_shutdown; 17 | VOID LeechGRPC_ReservedSubmitCommand(_In_opt_ PVOID ctx, _In_ PBYTE pbIn, _In_ SIZE_T cbIn, _Out_ PBYTE *ppbOut, _Out_ SIZE_T *pcbOut); 18 | 19 | VOID RpcStopGRPC() 20 | { 21 | if(g_hGRPC) { 22 | g_pfn_leechgrpc_server_shutdown(g_hGRPC); 23 | g_hGRPC = NULL; 24 | } 25 | } 26 | 27 | _Success_(return) 28 | BOOL RpcStartGRPC(_In_ PLEECHSVC_CONFIG pConfig) 29 | { 30 | DWORD dwTcpPort = 0; 31 | if(!pConfig->hModuleGRPC) { 32 | printf("Failed: gRPC: library 'libleechgrpc"LC_LIBRARY_FILETYPE"' missing - gRPC functionality is disabled.\n"); 33 | return FALSE; 34 | } 35 | dwTcpPort = atoi(pConfig->szTcpPortGRPC); 36 | if(!dwTcpPort) { 37 | printf("Failed: gRPC: Invalid port number '%i' - gRPC functionality is disabled.\n", dwTcpPort); 38 | return FALSE; 39 | } 40 | g_pfn_leechgrpc_server_create_insecure = (pfn_leechgrpc_server_create_insecure)GetProcAddress(pConfig->hModuleGRPC, "leechgrpc_server_create_insecure"); 41 | g_pfn_leechgrpc_server_create_secure_p12 = (pfn_leechgrpc_server_create_secure_p12)GetProcAddress(pConfig->hModuleGRPC, "leechgrpc_server_create_secure_p12"); 42 | g_pfn_leechgrpc_server_shutdown = (pfn_leechgrpc_server_shutdown)GetProcAddress(pConfig->hModuleGRPC, "leechgrpc_server_shutdown"); 43 | if(!g_pfn_leechgrpc_server_create_insecure || !g_pfn_leechgrpc_server_create_secure_p12 || !g_pfn_leechgrpc_server_shutdown) { 44 | printf("Failed: gRPC: library 'libleechgrpc"LC_LIBRARY_FILETYPE"' missing required functions, gRPC functionality is disabled.\n"); 45 | RpcStopGRPC(); 46 | return FALSE; 47 | } 48 | if(pConfig->fInsecure) { 49 | g_hGRPC = g_pfn_leechgrpc_server_create_insecure( 50 | pConfig->grpc.szListenAddress, 51 | dwTcpPort, 52 | NULL, 53 | LeechGRPC_ReservedSubmitCommand 54 | ); 55 | } else { 56 | g_hGRPC = g_pfn_leechgrpc_server_create_secure_p12( 57 | pConfig->grpc.szListenAddress, 58 | dwTcpPort, 59 | NULL, LeechGRPC_ReservedSubmitCommand, 60 | pConfig->grpc.szTlsClientCaCert, 61 | pConfig->grpc.szTlsServerP12, 62 | pConfig->grpc.szTlsServerP12Pass 63 | ); 64 | } 65 | if(!g_hGRPC) { 66 | printf("Failed: gRPC: initialization failed, gRPC functionality is disabled.\n"); 67 | RpcStopGRPC(); 68 | return FALSE; 69 | } 70 | if(pConfig->fInsecure) { 71 | printf( 72 | "WARNING! Starting LeechAgent in INSECURE gRPC mode! \n" \ 73 | " Any user may connect unauthenticated unless firewalled! \n" \ 74 | " Ensure that port tcp/%i is properly configured in firewall!\n" \ 75 | " \n", dwTcpPort); 76 | } else { 77 | printf( 78 | "INFO: Starting LeechAgent in gRPC mTLS mode! \n" \ 79 | " Ensure that port tcp/%i is properly configured in firewall!\n" \ 80 | " \n", dwTcpPort); 81 | } 82 | return TRUE; 83 | } 84 | 85 | void RpcStop() 86 | { 87 | // stop gRPC server: 88 | RpcStopGRPC(); 89 | } 90 | -------------------------------------------------------------------------------- /leechcore/device_vmm.c: -------------------------------------------------------------------------------- 1 | // device_vmm.c : implementation of the vmm loopback device. 2 | // this is typically used for virtual machines. 3 | // 4 | // Syntax: vmm://hvmm=0x,hvm=0x,max= 5 | // 6 | // (c) Ulf Frisk, 2022-2025 7 | // Author: Ulf Frisk, pcileech@frizk.net 8 | // 9 | #include "leechcore.h" 10 | #include "leechcore_device.h" 11 | #include "leechcore_internal.h" 12 | #include "util.h" 13 | 14 | typedef struct tdVMM_HANDLE *VMM_HANDLE; 15 | typedef struct tdVMMVM_HANDLE *VMMVM_HANDLE; 16 | typedef BOOL(*FN_VMMDLL_ConfigGet)(_In_ VMM_HANDLE hVMM, _In_ ULONG64 fOption, _Out_ PULONG64 pqwValue); 17 | typedef DWORD(*FN_VMMDLL_VmMemReadScatter)(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM, _Inout_ PPMEM_SCATTER ppMEMsGPA, _In_ DWORD cpMEMsGPA, _In_ DWORD flags); 18 | typedef DWORD(*FN_VMMDLL_VmMemWriteScatter)(_In_ VMM_HANDLE hVMM, _In_ VMMVM_HANDLE hVM, _Inout_ PPMEM_SCATTER ppMEMsGPA, _In_ DWORD cpMEMsGPA); 19 | 20 | //----------------------------------------------------------------------------- 21 | // GENERAL FUNCTIONALITY BELOW: 22 | //----------------------------------------------------------------------------- 23 | 24 | VOID DeviceVMM_ReadScatter(_In_ PLC_CONTEXT ctxLC, _In_ DWORD cpMEMs, _Inout_ PPMEM_SCATTER ppMEMs) 25 | { 26 | PLC_VMM ctx = (PLC_VMM)ctxLC->hDevice; 27 | ((FN_VMMDLL_VmMemReadScatter)ctx->pfnVMMDLL_VmMemReadScatter)(ctx->hVMM, ctx->hVMMVM, ppMEMs, cpMEMs, 0); 28 | } 29 | 30 | VOID DeviceVMM_WriteScatter(_In_ PLC_CONTEXT ctxLC, _In_ DWORD cpMEMs, _Inout_ PPMEM_SCATTER ppMEMs) 31 | { 32 | PLC_VMM ctx = (PLC_VMM)ctxLC->hDevice; 33 | ((FN_VMMDLL_VmMemWriteScatter)ctx->pfnVMMDLL_VmMemWriteScatter)(ctx->hVMM, ctx->hVMMVM, ppMEMs, cpMEMs); 34 | } 35 | 36 | VOID DeviceVMM_Close(_Inout_ PLC_CONTEXT ctxLC) 37 | { 38 | PLC_VMM ctx = (PLC_VMM)ctxLC->hDevice; 39 | ctxLC->hDevice = 0; 40 | LocalFree(ctx); 41 | } 42 | 43 | #define VMM_PARAMETER_HANDLE_LCVMM "hlcvmm" 44 | 45 | _Success_(return) 46 | BOOL DeviceVMM_Open(_Inout_ PLC_CONTEXT ctxLC, _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcCreateErrorInfo) 47 | { 48 | PLC_VMM ctx, ctxSrc; 49 | QWORD qwReadOnly = 0, qwVolatile = 0; 50 | if(ppLcCreateErrorInfo) { *ppLcCreateErrorInfo = NULL; } 51 | // 1: initialize core context: 52 | if(sizeof(PVOID) != 8) { return FALSE; } // only supported on 64-bit os (due to resource constraints) 53 | ctx = (PLC_VMM)LocalAlloc(LMEM_ZEROINIT, sizeof(LC_VMM)); 54 | if(!ctx) { return FALSE; } 55 | // 2: initialize device 56 | ctxSrc = (PLC_VMM)LcDeviceParameterGetNumeric(ctxLC, VMM_PARAMETER_HANDLE_LCVMM); 57 | if(!ctxSrc || (ctxSrc->dwVersion != LC_VMM_VERSION) || !ctxSrc->hVMM || !ctxSrc->hVMMVM || !ctxSrc->pfnVMMDLL_ConfigGet || !ctxSrc->pfnVMMDLL_VmMemReadScatter || !ctxSrc->pfnVMMDLL_VmMemWriteScatter) { 58 | lcprintfv(ctxLC, "DEVICE: VMM: Unable to open loopback device #1\n"); 59 | goto fail; 60 | } 61 | memcpy(ctx, ctxSrc, sizeof(LC_VMM)); 62 | // 3: fetch config parameters: 63 | if(!((FN_VMMDLL_ConfigGet)ctx->pfnVMMDLL_ConfigGet)(ctx->hVMM, LC_OPT_CORE_VOLATILE, &qwVolatile)) { // inherit from vm parent vmm 64 | lcprintfv(ctxLC, "DEVICE: VMM: Unable to communicate with loopback device #1.\n"); 65 | goto fail; 66 | } 67 | if(!((FN_VMMDLL_ConfigGet)ctx->pfnVMMDLL_ConfigGet)(ctx->hVMM, LC_OPT_CORE_READONLY, &qwReadOnly)) { // inherit from vm parent vmm 68 | lcprintfv(ctxLC, "DEVICE: VMM: Unable to communicate with loopback device #2.\n"); 69 | goto fail; 70 | } 71 | // 4: set callback functions and fix up config 72 | ctxLC->hDevice = (HANDLE)ctx; 73 | ctxLC->fMultiThread = TRUE; 74 | ctxLC->Config.fVolatile = qwVolatile ? TRUE : FALSE; 75 | ctxLC->pfnClose = DeviceVMM_Close; 76 | ctxLC->pfnReadScatter = DeviceVMM_ReadScatter; 77 | ctxLC->pfnWriteScatter = qwReadOnly ? NULL : DeviceVMM_WriteScatter; 78 | return TRUE; 79 | fail: 80 | DeviceVMM_Close(ctxLC); 81 | return FALSE; 82 | } 83 | -------------------------------------------------------------------------------- /leechcore/util.h: -------------------------------------------------------------------------------- 1 | // util.h : definitions of various utility functions. 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __UTIL_H__ 7 | #define __UTIL_H__ 8 | #include "leechcore.h" 9 | #include "leechcore_device.h" 10 | #include "oscompatibility.h" 11 | 12 | /* 13 | * Retrieve the operating system path of the directory which is containing this: 14 | * .dll/.so file. 15 | * -- szPath 16 | */ 17 | VOID Util_GetPathLib(_Out_writes_(MAX_PATH) PCHAR szPath); 18 | 19 | /* 20 | * Try retrieve a numerical value from sz. If sz starts with '0x' it will be 21 | * interpreted as hex (base 16), otherwise decimal (base 10). 22 | * -- sz 23 | * -- return 24 | */ 25 | QWORD Util_GetNumericA(_In_ LPSTR sz); 26 | 27 | /* 28 | * Print a maximum of 8192 bytes of binary data as hexascii on the screen. 29 | * -- ctxLC 30 | * -- pb 31 | * -- cb 32 | * -- cbInitialOffset = offset, must be max 0x1000 and multiple of 0x10. 33 | */ 34 | VOID Util_PrintHexAscii(_In_opt_ PLC_CONTEXT ctxLC, _In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset); 35 | 36 | /* 37 | * Fill a human readable hex ascii memory dump into the caller supplied sz buffer. 38 | * -- pb 39 | * -- cb 40 | * -- cbInitialOffset = offset, must be max 0x1000 and multiple of 0x10. 41 | * -- sz = buffer to fill, NULL to retrieve size in pcsz parameter. 42 | * -- pcsz = IF sz==NULL :: size of buffer (including space for terminating NULL) on exit 43 | * IF sz!=NULL :: size of buffer on entry, size of characters (excluding terminating NULL) on exit. 44 | */ 45 | BOOL Util_FillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Inout_ PDWORD pcsz); 46 | 47 | /* 48 | * Split a string into two at the first chDelimiter character. If no 2nd string 49 | * is not found then it's returned as null character '\0' (i.e. not as NULL). 50 | * The Util_Split3 function is analogous to Util_Split2. 51 | * -- sz = the original string to split (of maximum MAX_PATH length) 52 | * -- szDelimiter = the delimiter character splitting the string. 53 | * -- _szBuf = MAX_PATH sized buffer that will be overwritten and used throughout the lifetime of psz1/psz2 outputs. 54 | * -- psz1 55 | * -- psz2 56 | */ 57 | VOID Util_Split2(_In_ LPSTR sz, _In_ CHAR chDelimiter, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Out_ LPSTR *psz1, _Out_ LPSTR *psz2); 58 | VOID Util_Split3(_In_ LPSTR sz, _In_ CHAR chDelimiter, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Out_ LPSTR *psz1, _Out_ LPSTR *psz2, _Out_ LPSTR *psz3); 59 | 60 | /* 61 | * Split a string into N strings at the chDelimiter character. If no Nth string 62 | * is not found then it's returned as null character '\0' (i.e. not as NULL). 63 | * -- sz = the original string to split (of maximum MAX_PATH length) 64 | * -- szDelimiter = the delimiter character splitting the string. 65 | * -- cpsz = the number of strings to split the input string into. 66 | * -- _szBuf = MAX_PATH sized buffer that will be overwritten and used throughout the lifetime of *ppsz outputs. 67 | * -- psz = array of pointers to receive the N strings. 68 | */ 69 | VOID Util_SplitN(_In_ LPSTR sz, _In_ CHAR chDelimiter, _In_ DWORD cpsz, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Inout_ LPSTR *psz); 70 | 71 | /* 72 | * Simple random number function. 73 | * -- pb = buffer to receive random data. 74 | * -- cb = length of random data to create. 75 | */ 76 | VOID Util_GenRandom(_Out_ PBYTE pb, _In_ DWORD cb); 77 | 78 | /* 79 | * Returns true if this is a 64-bit Windows operating system. 80 | * This is regardless of whether this is a 32-bit WoW process or not. 81 | * Function have no meaning on Linux. 82 | * -- return 83 | */ 84 | BOOL Util_IsPlatformBitness64(); 85 | 86 | /* 87 | * Return true if this program is a 64-bit program. 88 | * -- return 89 | */ 90 | BOOL Util_IsProgramBitness64(); 91 | 92 | #ifdef _WIN32 93 | 94 | /* 95 | * "Eternal" reading loop until all requested data is read or until there is an error. 96 | * -- hPipe_Rd 97 | * -- pb 98 | * -- cb 99 | * -- return 100 | */ 101 | _Success_(return) 102 | BOOL Util_GetBytesPipe(_In_ HANDLE hPipe_Rd, _Out_writes_opt_(cb) PBYTE pb, _In_ DWORD cb); 103 | 104 | #endif /* _WIN32 */ 105 | 106 | #endif /* __UTIL_H__ */ 107 | -------------------------------------------------------------------------------- /leechagent/leechagent.h: -------------------------------------------------------------------------------- 1 | // leechagent.h : definitions related to the leech agent. 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __LEECHAGENT_H__ 7 | #define __LEECHAGENT_H__ 8 | #include 9 | 10 | #define LEECHSVC_NAME L"LeechAgent" 11 | #define LEECHSVC_DISPLAY_NAME L"Leech Memory Acquisition Agent" 12 | #define LEECHSVC_DESCR_LONG L"The Leech Memory Acquisition Agent allows for LeechCore library users to connect remotely to the agent." 13 | #define LEECHSVC_TCP_PORT_MSRPC L"28473" 14 | #define LEECHSVC_TCP_PORT_GRPC L"28474" 15 | #define SVC_ERROR 0x0000 16 | 17 | #define LEECHAGENT_CLIENTKEEPALIVE_MAX_CLIENTS 0x40 18 | #define LEECHAGENT_CLIENTKEEPALIVE_TIMEOUT_MS 75*1000 // recommended to be less than LEECHAGENT_CHILDPROCESS_TIMEOUT_DEFAULT_MS 19 | #define LEECHAGENT_CHILDPROCESS_TIMEOUT_MAX_MS 30*60*1000 20 | #define LEECHAGENT_CHILDPROCESS_TIMEOUT_DEFAULT_MS 2*60*1000 21 | 22 | #define LEECHGRPC_LIBRARY_NAME L"libleechgrpc.dll" 23 | #define LEECHAGENT_CONFIG_FILE L"leechagent_config.txt" 24 | 25 | typedef struct tdLEECHAGENT_CONFIG { 26 | BOOL fInstall; 27 | BOOL fUpdate; 28 | BOOL fUninstall; 29 | BOOL fInteractive; 30 | BOOL fInsecure; 31 | BOOL fChildProcess; 32 | BOOL fMSRPC; 33 | BOOL fgRPC; 34 | WCHAR wszRemote[MAX_PATH]; 35 | WCHAR wszTcpPortMSRPC[0x10]; 36 | WCHAR wszTcpPortGRPC[0x10]; 37 | HMODULE hModuleGRPC; 38 | struct { 39 | CHAR szCurrentDirectory[MAX_PATH]; 40 | CHAR szTlsClientCaCert[MAX_PATH]; 41 | CHAR szTlsServerP12[MAX_PATH]; 42 | CHAR szTlsServerP12Pass[MAX_PATH]; 43 | CHAR szListenAddress[MAX_PATH]; 44 | } grpc; 45 | } LEECHSVC_CONFIG, *PLEECHSVC_CONFIG; 46 | 47 | typedef struct tdLEECHAGENT_REMOTE_ENTRY { 48 | BOOL f32; 49 | BOOL f64; 50 | LPWSTR wsz; 51 | } LEECHAGENT_REMOTE_ENTRY, *PLEECHAGENT_REMOTE_ENTRY; 52 | 53 | static LEECHAGENT_REMOTE_ENTRY g_REMOTE_FILES_REQUIRED[] = { 54 | {.f32 = TRUE,.f64 = TRUE,.wsz = L"leechagent.exe"}, // LeechAgent is required to be 1st entry (used in service creation) 55 | {.f32 = TRUE,.f64 = TRUE,.wsz = L"leechcore.dll"}, 56 | {.f32 = TRUE,.f64 = TRUE,.wsz = L"vcruntime140.dll"}, 57 | }; 58 | static LEECHAGENT_REMOTE_ENTRY g_REMOTE_FILES_OPTIONAL[] = { 59 | // 32/64-bit MemProcFS 60 | {.f32 = TRUE,.f64 = TRUE,.wsz = L"vmm.dll"}, 61 | {.f32 = TRUE,.f64 = TRUE,.wsz = L"info.db"}, 62 | {.f32 = TRUE,.f64 = TRUE,.wsz = L"libpdbcrust.dll"}, 63 | {.f32 = TRUE,.f64 = TRUE,.wsz = L"vmmyara.dll"}, 64 | {.f32 = TRUE,.f64 = TRUE,.wsz = L"dbghelp.dll"}, 65 | {.f32 = TRUE,.f64 = TRUE,.wsz = L"symsrv.dll"}, 66 | {.f32 = TRUE,.f64 = TRUE,.wsz = L"symsrv.yes"}, 67 | // 64-bit MemProcFS Python 68 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"leechcorepyc.pyd"}, 69 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"vmmpyc.pyd"}, 70 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"memprocfs.py"}, 71 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"vmmpyplugin.py"}, 72 | // 32-bit winpmem 73 | {.f32 = TRUE,.f64 = FALSE,.wsz = L"winpmem_x86.sys"}, 74 | // 64-bit winpmem 75 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"winpmem_x64.sys"}, 76 | // 64-bit HyperV saved state 77 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"leechcore_device_hvsavedstate.dll"}, 78 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"vmsavedstatedumpprovider.dll"}, 79 | // 64-bit HyperV HVMM (LiveCloudKd) 80 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"leechcore_device_hvmm.dll"}, 81 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"LiveCloudKdSdk.dll"}, 82 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"hvlib.dll"}, 83 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"hvmm.sys"}, 84 | // 32/64-bit FTDI driver (PCIe DMA FPGA) 85 | {.f32 = TRUE,.f64 = TRUE,.wsz = L"FTD3XX.dll"}, 86 | // config file 87 | {.f32 = TRUE,.f64 = TRUE,.wsz = LEECHAGENT_CONFIG_FILE}, 88 | // grpc library 89 | {.f32 = TRUE,.f64 = TRUE,.wsz = LEECHGRPC_LIBRARY_NAME}, 90 | }; 91 | static LEECHAGENT_REMOTE_ENTRY g_REMOTE_DIRS_OPTIONAL[] = { 92 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"Plugins"}, 93 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"Python"}, 94 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"Yara"}, 95 | {.f32 = FALSE,.f64 = TRUE,.wsz = L"Cert"}, 96 | }; 97 | 98 | BOOL g_LeechAgent_IsService; 99 | 100 | /* 101 | * Read arguments from a the config file 'leechagent_config.txt' into the config. 102 | */ 103 | VOID LeechSvc_ParseArgs_FromConfigFile(_In_ PLEECHSVC_CONFIG pConfig); 104 | 105 | #endif /* __LEECHAGENT_H__ */ 106 | -------------------------------------------------------------------------------- /leechcorepyc/pkggen_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf pkg_linux 4 | mkdir pkg_linux 5 | mkdir pkg_linux/files 6 | touch pkg_linux/files/dummy 7 | mkdir pkg_linux/leechcorepyc 8 | cp -r ../includes pkg_linux/ 9 | cp -r ../leechcore pkg_linux/ 10 | cp -r ../../LeechCore-plugins*/leechcore_device_qemu pkg_linux/ 11 | cp -r ../../LeechCore-plugins*/leechcore_device_rawtcp pkg_linux/ 12 | cp -r ../../LeechCore-plugins*/leechcore_ft601_driver_linux pkg_linux/ 13 | mkdir pkg_linux/ms-compress 14 | cp ../../ms-compress/Makefile pkg_linux/ms-compress/ 15 | cp -r ../../ms-compress/include pkg_linux/ms-compress/ 16 | cp -r ../../ms-compress/src pkg_linux/ms-compress/ 17 | cp ../leechcore/leechcore_device.h pkg_linux/includes/leechcore_device.h 18 | cp ../LICENSE pkg_linux/ 19 | cp *.h pkg_linux/ 20 | cp *.c pkg_linux/ 21 | 22 | 23 | 24 | cat << 'EOF' > pkg_linux/setup.py 25 | 26 | import subprocess 27 | from setuptools import setup, Extension 28 | 29 | subprocess.call(['make', 'clean']) 30 | subprocess.call(['make']) 31 | 32 | leechcorepyc = Extension( 33 | 'leechcorepyc.leechcorepyc', 34 | sources = ['leechcorepyc.c', 'leechcorepyc_barrequest.c', 'oscompatibility.c'], 35 | libraries = ['usb-1.0', ':leechcore.so'], 36 | library_dirs = ['.'], 37 | define_macros = [("LINUX", "")], 38 | include_dirs = ["includes", "/usr/include/libusb-1.0/"], 39 | extra_compile_args=["-I.", "-L.", "-l:leechcore.so", "-shared", "-fPIC", "-fvisibility=hidden"], 40 | extra_link_args=["-Wl,-rpath,$ORIGIN", "-g", "-ldl", "-shared"], 41 | py_limited_api=True 42 | ) 43 | 44 | setup( 45 | name='leechcorepyc', 46 | version='2.22.4', # VERSION_END 47 | description='LeechCore for Python', 48 | long_description='LeechCore for Python : native extension for physical memory access', 49 | url='https://github.com/ufrisk/LeechCore', 50 | author='Ulf Frisk', 51 | author_email='pcileech@frizk.net', 52 | license='GNU General Public License v3.0', 53 | platforms='manylinux1_x86_64', 54 | python_requires='>=3.6', 55 | classifiers=[ 56 | "Programming Language :: C", 57 | "Programming Language :: Python :: 3", 58 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 59 | "Operating System :: POSIX :: Linux", 60 | ], 61 | packages=['leechcorepyc'], 62 | package_data={'leechcorepyc': ['leechcore.so', 'leechcore_ft601_driver_linux.so', 'leechcore_device_qemu.so', 'leechcore_device_rawtcp.so', 'libMSCompression.so']}, 63 | ext_modules = [leechcorepyc], 64 | ) 65 | 66 | EOF 67 | 68 | 69 | 70 | cat << 'EOF' > pkg_linux/README 71 | 72 | LeechCore for Python: please see 73 | https://github.com/ufrisk/LeechCore 74 | and 75 | https://github.com/ufrisk/LeechCore/wiki/LeechCore_API_Python 76 | EOF 77 | 78 | 79 | 80 | cat << 'EOF' > pkg_linux/MANIFEST.in 81 | 82 | include Makefile 83 | include leechcorepyc.h 84 | include oscompatibility.h 85 | include includes/*.h 86 | graft files 87 | graft leechcore 88 | graft leechcore_device_rawtcp 89 | graft leechcore_device_qemu 90 | graft leechcore_ft601_driver_linux 91 | graft ms-compress 92 | global-exclude *vcxproj* 93 | global-exclude *.so 94 | 95 | EOF 96 | 97 | 98 | 99 | cat << 'EOF' > pkg_linux/leechcorepyc/__init__.py 100 | from .leechcorepyc import LeechCore 101 | 102 | # CONSTANTS AUTO-GENERATED FROM 'leechcore.h' BELOW: 103 | EOF 104 | cat ../includes/leechcore.h |grep "#define LC_" |grep -v "_VERSION " |grep -v "_FUNCTION_CALLBACK_" >> pkg_linux/leechcorepyc/__init__.py 105 | sed -i 's/#define //' pkg_linux/leechcorepyc/__init__.py 106 | sed -i 's/0x/= 0x/' pkg_linux/leechcorepyc/__init__.py 107 | sed -i 's/\/\//#/' pkg_linux/leechcorepyc/__init__.py 108 | 109 | 110 | 111 | cat << 'EOF' > pkg_linux/Makefile 112 | 113 | all: 114 | $(MAKE) -C leechcore 115 | $(MAKE) -C leechcore_ft601_driver_linux || true 116 | $(MAKE) -C leechcore_device_qemu || true 117 | $(MAKE) -C leechcore_device_rawtcp || true 118 | $(MAKE) -C ms-compress || true 119 | cp ms-compress/libMSCompression.so files/ || true 120 | cp files/leechcore.so . 121 | cp files/*.so leechcorepyc/ 122 | 123 | clean: 124 | $(MAKE) clean -C leechcore 125 | $(MAKE) clean -C leechcore_ft601_driver_linux || true 126 | $(MAKE) clean -C leechcore_device_qemu || true 127 | $(MAKE) clean -C leechcore_device_rawtcp || true 128 | $(MAKE) clean -C ms-compress || true 129 | rm files/*.so || true 130 | rm leechcore.so || true 131 | rm leechcorepyc/*.so || true 132 | 133 | EOF 134 | 135 | #python3 setup.py sdist 136 | #mkdir ~/tmp 137 | #python3 setup.py bdist_wheel --bdist-dir ~/tmp/ --py-limited-api cp36 --plat-name manylinux1_x86_64 138 | -------------------------------------------------------------------------------- /leechcorepyc/leechcorepyemb.c: -------------------------------------------------------------------------------- 1 | // leechcorepyemb.c : Implementation of the LeechCore embedded Python environment 2 | // used to execute python code in the context of MemProcFS API 3 | // from the LeechAgent. This is in a separate file to avoid 4 | // issues with missing python environments at process creation. 5 | // 6 | // (c) Ulf Frisk, 2020-2025 7 | // Author: Ulf Frisk, pcileech@frizk.net 8 | // 9 | #define Py_LIMITED_API 0x03060000 10 | #ifdef _DEBUG 11 | #undef _DEBUG 12 | #include 13 | #define _DEBUG 14 | #else 15 | #include 16 | #endif 17 | #include 18 | #include 19 | #include "leechcorepyc.h" 20 | 21 | #define PYTHON_PATH_MAX 7*MAX_PATH 22 | #define PYTHON_PATH_DELIMITER L";" 23 | 24 | int(*g_PyRun_SimpleString)(const char* command) = NULL; 25 | PyThreadState* g_pyThreadState = NULL; 26 | 27 | VOID Util_GetPathDll(_Out_writes_(MAX_PATH) PWCHAR wszPath, _In_opt_ HMODULE hModule) 28 | { 29 | SIZE_T i; 30 | GetModuleFileNameW(hModule, wszPath, MAX_PATH - 4); 31 | for(i = wcslen(wszPath) - 1; i > 0; i--) { 32 | if(wszPath[i] == L'/' || wszPath[i] == L'\\') { 33 | wszPath[i + 1] = L'\0'; 34 | return; 35 | } 36 | } 37 | } 38 | 39 | _Success_(return) __declspec(dllexport) 40 | BOOL LeechCorePyC_EmbPythonInitialize(_In_ HMODULE hDllPython) 41 | { 42 | PyObject *pName = NULL, *pModule = NULL; 43 | WCHAR wszPathExe[MAX_PATH], wszPathBasePython[MAX_PATH], wszPathPython[PYTHON_PATH_MAX]; 44 | WCHAR wszPythonLib[] = { L'p', L'y', L't', L'h', L'o', L'n', L'X', L'X', L'.', L'z', L'i', L'p', 0 }; 45 | ZeroMemory(wszPathBasePython, MAX_PATH * sizeof(WCHAR)); 46 | ZeroMemory(wszPathPython, PYTHON_PATH_MAX * sizeof(WCHAR)); 47 | g_PyRun_SimpleString = (int(*)(const char*))GetProcAddress(hDllPython, "PyRun_SimpleString"); 48 | if(!g_PyRun_SimpleString) { return FALSE; } 49 | // 0: fixup python zip version 50 | wszPythonLib[6] = (WCHAR)Py_GetVersion()[0]; 51 | wszPythonLib[7] = (WCHAR)Py_GetVersion()[2]; 52 | // 1: Construct Python Path 53 | Util_GetPathDll(wszPathExe, NULL); 54 | Util_GetPathDll(wszPathBasePython, hDllPython); 55 | // 1.1: python base directory (where python dll is located) 56 | wcscpy_s(wszPathPython, PYTHON_PATH_MAX, wszPathBasePython); 57 | // 1.2: python zip 58 | wcscat_s(wszPathPython, PYTHON_PATH_MAX, PYTHON_PATH_DELIMITER); 59 | wcscat_s(wszPathPython, PYTHON_PATH_MAX, wszPathBasePython); 60 | wcscat_s(wszPathPython, PYTHON_PATH_MAX, wszPythonLib); 61 | // 1.3: main executable directory 62 | wcscat_s(wszPathPython, PYTHON_PATH_MAX, PYTHON_PATH_DELIMITER); 63 | wcscat_s(wszPathPython, PYTHON_PATH_MAX, wszPathExe); 64 | // 1.4: plugins directory 65 | wcscat_s(wszPathPython, PYTHON_PATH_MAX, PYTHON_PATH_DELIMITER); 66 | wcscat_s(wszPathPython, PYTHON_PATH_MAX, wszPathExe); 67 | wcscat_s(wszPathPython, PYTHON_PATH_MAX, L"plugins\\"); 68 | // 2: Initialize (Embedded) Python. 69 | Py_SetProgramName(L"LeechCorePythonEmbedded"); 70 | Py_SetPath(wszPathPython); 71 | //wprintf(L"LeechSvc: Python Path: %s\n", wszPathPython); 72 | Py_Initialize(); 73 | //PyEval_InitThreads(); 74 | /* 75 | g_PyRun_SimpleString( 76 | "try: \n" \ 77 | " import leechcorepyc \n" \ 78 | "except: \n" \ 79 | " pass \n" \ 80 | "try: \n" \ 81 | " import memprocfs \n" \ 82 | "except: \n" \ 83 | " pass \n" ); 84 | */ 85 | //PyEval_ReleaseLock(); 86 | g_pyThreadState = PyEval_SaveThread(); 87 | return TRUE; 88 | } 89 | 90 | /* 91 | * Execute a python script in-memory inside the execution environment. 92 | * -- szPythonProgram 93 | */ 94 | __declspec(dllexport) 95 | BOOL LeechCorePyC_EmbExecPyInMem(_In_ LPSTR szPythonProgram) 96 | { 97 | PyGILState_STATE gstate; 98 | if(!g_PyRun_SimpleString) { return FALSE; } 99 | gstate = PyGILState_Ensure(); 100 | g_PyRun_SimpleString(szPythonProgram); 101 | PyGILState_Release(gstate); 102 | return TRUE; 103 | } 104 | 105 | /* 106 | * Finalize the Python interpreter. This will also flush any remaining buffers 107 | * to stdout / stderr. No calls must be made to Python after this call! 108 | * -- szPythonProgram 109 | */ 110 | __declspec(dllexport) 111 | VOID LeechCorePyC_EmbClose() 112 | { 113 | __try { 114 | if(g_pyThreadState) { 115 | PyEval_RestoreThread(g_pyThreadState); 116 | } 117 | Py_FinalizeEx(); 118 | } __except(EXCEPTION_EXECUTE_HANDLER) { ; } 119 | } 120 | -------------------------------------------------------------------------------- /leechcore/leechcore.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {0d7968b8-c699-4099-a783-9482426d0802} 18 | 19 | 20 | {b6ad61ff-a1bb-4908-90dc-116c7af6e5c1} 21 | 22 | 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | Source Files 65 | 66 | 67 | Source Files\ob 68 | 69 | 70 | Source Files\ob 71 | 72 | 73 | Source Files\ob 74 | 75 | 76 | Source Files\ob 77 | 78 | 79 | Source Files 80 | 81 | 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | Header Files 94 | 95 | 96 | Header Files 97 | 98 | 99 | Header Files 100 | 101 | 102 | Header Files 103 | 104 | 105 | Header Files 106 | 107 | 108 | Header Files\ob 109 | 110 | 111 | 112 | 113 | Resource Files 114 | 115 | 116 | 117 | 118 | Resource Files 119 | 120 | 121 | 122 | 123 | Resource Files 124 | 125 | 126 | Resource Files 127 | 128 | 129 | -------------------------------------------------------------------------------- /LeechCore.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32505.173 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "leechcore", "leechcore\leechcore.vcxproj", "{3476ABD2-5DEA-43E6-A676-8BE25F74535A}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "leechcorepyc", "leechcorepyc\leechcorepyc.vcxproj", "{1DD086DE-3BC9-458F-A2E1-F20142AA4977}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A} = {3476ABD2-5DEA-43E6-A676-8BE25F74535A} 11 | EndProjectSection 12 | EndProject 13 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "leechagent", "leechagent\leechagent.vcxproj", "{931BE9A5-0C7A-4D2F-8E37-7E3010A9979F}" 14 | ProjectSection(ProjectDependencies) = postProject 15 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A} = {3476ABD2-5DEA-43E6-A676-8BE25F74535A} 16 | EndProjectSection 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "leechagent_linux", "leechagent_linux", "{51A6D505-4CE1-4F3A-8213-9E9B92FF21B7}" 19 | ProjectSection(SolutionItems) = preProject 20 | leechagent_linux\leechagent.c = leechagent_linux\leechagent.c 21 | leechagent_linux\leechagent.h = leechagent_linux\leechagent.h 22 | leechagent_linux\leechagent_linux.code-workspace = leechagent_linux\leechagent_linux.code-workspace 23 | leechagent_linux\leechagent_proc.h = leechagent_linux\leechagent_proc.h 24 | leechagent_linux\leechagent_rpc.c = leechagent_linux\leechagent_rpc.c 25 | leechagent_linux\leechagent_rpc.h = leechagent_linux\leechagent_rpc.h 26 | leechagent_linux\leechrpc.h = leechagent_linux\leechrpc.h 27 | leechagent_linux\leechrpcserver.c = leechagent_linux\leechrpcserver.c 28 | leechagent_linux\leechrpcshared.c = leechagent_linux\leechrpcshared.c 29 | leechagent_linux\Makefile = leechagent_linux\Makefile 30 | leechagent_linux\oscompatibility.c = leechagent_linux\oscompatibility.c 31 | leechagent_linux\oscompatibility.h = leechagent_linux\oscompatibility.h 32 | EndProjectSection 33 | EndProject 34 | Global 35 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 36 | Debug|ARM64 = Debug|ARM64 37 | Debug|x64 = Debug|x64 38 | Debug|x86 = Debug|x86 39 | Release|ARM64 = Release|ARM64 40 | Release|x64 = Release|x64 41 | Release|x86 = Release|x86 42 | EndGlobalSection 43 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 44 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|ARM64.ActiveCfg = Debug|ARM64 45 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|ARM64.Build.0 = Debug|ARM64 46 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x64.ActiveCfg = Debug|x64 47 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x64.Build.0 = Debug|x64 48 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x86.ActiveCfg = Debug|Win32 49 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Debug|x86.Build.0 = Debug|Win32 50 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|ARM64.ActiveCfg = Release|ARM64 51 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|ARM64.Build.0 = Release|ARM64 52 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x64.ActiveCfg = Release|x64 53 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x64.Build.0 = Release|x64 54 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x86.ActiveCfg = Release|Win32 55 | {3476ABD2-5DEA-43E6-A676-8BE25F74535A}.Release|x86.Build.0 = Release|Win32 56 | {1DD086DE-3BC9-458F-A2E1-F20142AA4977}.Debug|ARM64.ActiveCfg = Debug|x64 57 | {1DD086DE-3BC9-458F-A2E1-F20142AA4977}.Debug|x64.ActiveCfg = Debug|x64 58 | {1DD086DE-3BC9-458F-A2E1-F20142AA4977}.Debug|x64.Build.0 = Debug|x64 59 | {1DD086DE-3BC9-458F-A2E1-F20142AA4977}.Debug|x86.ActiveCfg = Debug|Win32 60 | {1DD086DE-3BC9-458F-A2E1-F20142AA4977}.Release|ARM64.ActiveCfg = Release|x64 61 | {1DD086DE-3BC9-458F-A2E1-F20142AA4977}.Release|x64.ActiveCfg = Release|x64 62 | {1DD086DE-3BC9-458F-A2E1-F20142AA4977}.Release|x64.Build.0 = Release|x64 63 | {1DD086DE-3BC9-458F-A2E1-F20142AA4977}.Release|x86.ActiveCfg = Release|Win32 64 | {931BE9A5-0C7A-4D2F-8E37-7E3010A9979F}.Debug|ARM64.ActiveCfg = Debug|x64 65 | {931BE9A5-0C7A-4D2F-8E37-7E3010A9979F}.Debug|x64.ActiveCfg = Debug|x64 66 | {931BE9A5-0C7A-4D2F-8E37-7E3010A9979F}.Debug|x64.Build.0 = Debug|x64 67 | {931BE9A5-0C7A-4D2F-8E37-7E3010A9979F}.Debug|x86.ActiveCfg = Debug|Win32 68 | {931BE9A5-0C7A-4D2F-8E37-7E3010A9979F}.Debug|x86.Build.0 = Debug|Win32 69 | {931BE9A5-0C7A-4D2F-8E37-7E3010A9979F}.Release|ARM64.ActiveCfg = Release|x64 70 | {931BE9A5-0C7A-4D2F-8E37-7E3010A9979F}.Release|x64.ActiveCfg = Release|x64 71 | {931BE9A5-0C7A-4D2F-8E37-7E3010A9979F}.Release|x64.Build.0 = Release|x64 72 | {931BE9A5-0C7A-4D2F-8E37-7E3010A9979F}.Release|x86.ActiveCfg = Release|Win32 73 | {931BE9A5-0C7A-4D2F-8E37-7E3010A9979F}.Release|x86.Build.0 = Release|Win32 74 | EndGlobalSection 75 | GlobalSection(SolutionProperties) = preSolution 76 | HideSolutionNode = FALSE 77 | EndGlobalSection 78 | GlobalSection(ExtensibilityGlobals) = postSolution 79 | SolutionGuid = {C56A097C-48F0-4688-BCF6-6B94DDE5C3B9} 80 | EndGlobalSection 81 | EndGlobal 82 | -------------------------------------------------------------------------------- /leechcore/ob/ob_core.c: -------------------------------------------------------------------------------- 1 | // ob_core.c : implementation of object manager core functionality. 2 | // 3 | // The object manager is a minimal non-threaded way of allocating objects with 4 | // reference counts. When reference count reach zero the object is deallocated 5 | // automatically. 6 | // 7 | // All Ob functions are thread-safe and performs only minimum locking. 8 | // 9 | // A thread calls Ob_Alloc to allocate an object of a specific length. The 10 | // object initially have reference count 1. Reference counts may be increased 11 | // by calling Ob_INCREF and decreased by calling Ob_DECREF. If the refcount 12 | // reach one or zero in a call to Ob_DECREF optional callbacks may be made 13 | // (specified at Ob_Alloc time). Callbacks may be useful for cleanup tasks 14 | // - such as decreasing reference count of sub-objects contained in the object 15 | // that is to be deallocated. 16 | // 17 | // (c) Ulf Frisk, 2018-2025 18 | // Author: Ulf Frisk, pcileech@frizk.net 19 | // 20 | #include "ob.h" 21 | #include 22 | 23 | #define obprintf_fn(format, ...) printf("%s: "format, __func__, ##__VA_ARGS__); 24 | #define OB_DEBUG_FOOTER_SIZE 0x20 25 | #define OB_DEBUG_FOOTER_MAGIC 0x001122334455667788 26 | 27 | /* 28 | * Allocate a new object manager memory object. 29 | * -- H = an optional handle to embed as OB.H in the header. 30 | * -- tag = tag of the object to be allocated. 31 | * -- uFlags = flags as given by LocalAlloc. 32 | * -- uBytes = bytes of object (_including_ object headers). 33 | * -- pfnRef_0 = optional callback for cleanup o be called before object is destroyed. 34 | * (if object has references that should be decremented before destruction). 35 | * -- pfnRef_1 = optional callback for when object reach refcount = 1 (excl. initial). 36 | * -- return = allocated object on success, with refcount = 1, - NULL on fail. 37 | */ 38 | PVOID Ob_AllocEx(_In_opt_ VMM_HANDLE H, _In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1) 39 | { 40 | POB pOb; 41 | if((uBytes > 0x40000000) || (uBytes < sizeof(OB))) { return NULL; } 42 | pOb = (POB)LocalAlloc(uFlags, uBytes + OB_DEBUG_FOOTER_SIZE); 43 | if(!pOb) { return NULL; } 44 | pOb->_magic1 = OB_HEADER_MAGIC; 45 | pOb->_magic2 = OB_HEADER_MAGIC; 46 | pOb->_count = 1; 47 | pOb->_tag = tag; 48 | pOb->_pfnRef_0 = pfnRef_0; 49 | pOb->_pfnRef_1 = pfnRef_1; 50 | pOb->H = H; 51 | pOb->cbData = (DWORD)uBytes - sizeof(OB); 52 | #ifdef OB_DEBUG 53 | DWORD i, cb = sizeof(OB) + pOb->cbData; 54 | PBYTE pb = (PBYTE)pOb; 55 | for(i = 0; i < OB_DEBUG_FOOTER_SIZE; i += 8) { 56 | *(PQWORD)(pb + cb + i) = OB_DEBUG_FOOTER_MAGIC; 57 | } 58 | #endif /* OB_DEBUG */ 59 | return pOb; 60 | } 61 | 62 | /* 63 | * Increase the reference count of a object manager object. 64 | * -- pOb 65 | * -- return 66 | */ 67 | PVOID Ob_XINCREF(_In_opt_ PVOID pObIn) 68 | { 69 | POB pOb = (POB)pObIn; 70 | if(pOb) { 71 | if((pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC)) { 72 | InterlockedIncrement(&pOb->_count); 73 | return (POB)pOb; 74 | } else { 75 | obprintf_fn("ObCORE: CRITICAL: INCREF OF NON OBJECT MANAGER OBJECT!\n") 76 | } 77 | } 78 | return NULL; 79 | } 80 | 81 | /* 82 | * Decrease the reference count of a object manager object. If the reference 83 | * count reaches zero the object will be cleaned up. 84 | * -- pObIn 85 | * -- return = pObIn if pObIn is valid and refcount > 0 after decref. 86 | */ 87 | PVOID Ob_XDECREF(_In_opt_ PVOID pObIn) 88 | { 89 | POB pOb = (POB)pObIn; 90 | DWORD c; 91 | if(pOb) { 92 | if((pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC)) { 93 | c = InterlockedDecrement(&pOb->_count); 94 | #ifdef OB_DEBUG 95 | DWORD i, cb = sizeof(OB) + pOb->cbData; 96 | PBYTE pb = (PBYTE)pOb; 97 | for(i = 0; i < OB_DEBUG_FOOTER_SIZE; i += 8) { 98 | if(*(PQWORD)(pb + cb + i) != OB_DEBUG_FOOTER_MAGIC) { 99 | obprintf_fn("ObCORE: CRITICAL: FOOTER OVERWRITTEN - MEMORY CORRUPTION? REFCNT: %i TAG: %04X\n", c, pOb->_tag) 100 | } 101 | } 102 | #endif /* OB_DEBUG */ 103 | if(c == 0) { 104 | if(pOb->_pfnRef_0) { pOb->_pfnRef_0(pOb); } 105 | pOb->_magic1 = 0; 106 | pOb->_magic2 = 0; 107 | #ifdef OB_DEBUG_MEMZERO 108 | ZeroMemory(pOb, sizeof(OB) + pOb->cbData); 109 | #endif /* OB_DEBUG_MEMZERO */ 110 | LocalFree(pOb); 111 | } else if((c == 1) && pOb->_pfnRef_1) { 112 | pOb->_pfnRef_1(pOb); 113 | return pOb; 114 | } else { 115 | return pOb; 116 | } 117 | } else { 118 | obprintf_fn("ObCORE: CRITICAL: DECREF OF NON OBJECT MANAGER OBJECT!\n") 119 | } 120 | } 121 | return NULL; 122 | } 123 | 124 | /* 125 | * Decrease the reference count of a object manager object. 126 | * If the reference count reaches zero the object will be cleaned up. 127 | * Also set the incoming pointer to NULL. 128 | * -- ppOb 129 | */ 130 | VOID Ob_XDECREF_NULL(_In_opt_ PVOID *ppOb) 131 | { 132 | POB pOb; 133 | if(ppOb) { 134 | pOb = (POB)*ppOb; 135 | *ppOb = NULL; 136 | Ob_DECREF(pOb); 137 | } 138 | } 139 | 140 | /* 141 | * Checks if pObIn is a valid object manager object with the specified tag. 142 | * -- pObIn 143 | * -- tag 144 | * -- return 145 | */ 146 | BOOL Ob_VALID_TAG(_In_ PVOID pObIn, _In_ DWORD tag) 147 | { 148 | POB pOb = (POB)pObIn; 149 | return pOb && (pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC) && (pOb->_tag = tag); 150 | } 151 | 152 | /* 153 | * Create a new object manager data object in which the ObHdr->cbData is equal 154 | * to the number of bytes in the data buffer supplied to this function. 155 | * May also be created with Ob_Alloc with size: sizeof(OB_HDR) + length of data. 156 | * CALLER DECREF: return 157 | * -- H 158 | * -- pb 159 | * -- cb 160 | * -- return 161 | */ 162 | _Success_(return != NULL) 163 | POB_DATA ObData_New(_In_opt_ VMM_HANDLE H, _In_ PBYTE pb, _In_ DWORD cb) 164 | { 165 | POB_DATA pObData = NULL; 166 | if((pObData = Ob_AllocEx(H, OB_TAG_CORE_DATA, 0, sizeof(OB) + cb, NULL, NULL))) { 167 | memcpy(pObData->pb, pb, cb); 168 | } 169 | return pObData; 170 | } 171 | -------------------------------------------------------------------------------- /leechcore/util.c: -------------------------------------------------------------------------------- 1 | // util.c : implementation of various utility functions. 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #include "util.h" 7 | 8 | /* 9 | * Retrieve the operating system path of the directory which is containing this: 10 | * .dll/.so file. 11 | * -- szPath 12 | */ 13 | VOID Util_GetPathLib(_Out_writes_(MAX_PATH) PCHAR szPath) 14 | { 15 | SIZE_T i; 16 | ZeroMemory(szPath, MAX_PATH); 17 | #ifdef _WIN32 18 | HMODULE hModuleLeechCore; 19 | hModuleLeechCore = LoadLibraryA("leechcore.dll"); 20 | GetModuleFileNameA(hModuleLeechCore, szPath, MAX_PATH - 4); 21 | if(hModuleLeechCore) { FreeLibrary(hModuleLeechCore); } 22 | #endif /* _WIN32 */ 23 | #if defined(LINUX) || defined(MACOS) 24 | Dl_info Info = { 0 }; 25 | if(!dladdr((void *)Util_GetPathLib, &Info) || !Info.dli_fname) { return; } 26 | strncpy(szPath, Info.dli_fname, MAX_PATH - 1); 27 | #endif /* LINUX || MACOS */ 28 | for(i = strlen(szPath) - 1; i > 0; i--) { 29 | if(szPath[i] == '/' || szPath[i] == '\\') { 30 | szPath[i + 1] = '\0'; 31 | return; 32 | } 33 | } 34 | } 35 | 36 | /* 37 | * Try retrieve a numerical value from sz. If sz starts with '0x' it will be 38 | * interpreted as hex (base 16), otherwise decimal (base 10). 39 | * -- sz 40 | * -- return 41 | */ 42 | QWORD Util_GetNumericA(_In_ LPSTR sz) 43 | { 44 | BOOL fhex = sz[0] && sz[1] && (sz[0] == '0') && ((sz[1] == 'x') || (sz[1] == 'X')); 45 | return strtoull(sz, NULL, fhex ? 16 : 10); 46 | } 47 | 48 | //----------------------------------------------------------------------------- 49 | 50 | #define Util_2HexChar(x) (((((x) & 0xf) <= 9) ? '0' : ('a' - 10)) + ((x) & 0xf)) 51 | 52 | #define UTIL_PRINTASCII \ 53 | "................................ !\"#$%&'()*+,-./0123456789:;<=>?" \ 54 | "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ " \ 55 | "................................................................" \ 56 | "................................................................" \ 57 | 58 | BOOL Util_FillHexAscii(_In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset, _Inout_opt_ LPSTR sz, _Inout_ PDWORD pcsz) 59 | { 60 | DWORD i, j, o = 0, iMod, cRows; 61 | // checks 62 | if((cbInitialOffset > cb) || (cbInitialOffset > 0x1000) || (cbInitialOffset & 0xf)) { return FALSE; } 63 | cRows = (cb + 0xf) >> 4; 64 | if(!sz) { 65 | *pcsz = 1 + cRows * 76; 66 | return TRUE; 67 | } 68 | if(!pb || (*pcsz <= cRows * 76)) { return FALSE; } 69 | // fill buffer with bytes 70 | for(i = cbInitialOffset; i < cb + ((cb % 16) ? (16 - cb % 16) : 0); i++) 71 | { 72 | // address 73 | if(0 == i % 16) { 74 | iMod = i % 0x10000; 75 | sz[o++] = Util_2HexChar(iMod >> 12); 76 | sz[o++] = Util_2HexChar(iMod >> 8); 77 | sz[o++] = Util_2HexChar(iMod >> 4); 78 | sz[o++] = Util_2HexChar(iMod); 79 | sz[o++] = ' '; 80 | sz[o++] = ' '; 81 | sz[o++] = ' '; 82 | sz[o++] = ' '; 83 | } else if(0 == i % 8) { 84 | sz[o++] = ' '; 85 | } 86 | // hex 87 | if(i < cb) { 88 | sz[o++] = Util_2HexChar(pb[i] >> 4); 89 | sz[o++] = Util_2HexChar(pb[i]); 90 | sz[o++] = ' '; 91 | } else { 92 | sz[o++] = ' '; 93 | sz[o++] = ' '; 94 | sz[o++] = ' '; 95 | } 96 | // ascii 97 | if(15 == i % 16) { 98 | sz[o++] = ' '; 99 | sz[o++] = ' '; 100 | for(j = i - 15; j <= i; j++) { 101 | if(j >= cb) { 102 | sz[o++] = ' '; 103 | } else { 104 | sz[o++] = UTIL_PRINTASCII[pb[j]]; 105 | } 106 | } 107 | sz[o++] = '\n'; 108 | } 109 | } 110 | sz[o] = 0; 111 | *pcsz = o; 112 | return TRUE; 113 | } 114 | 115 | VOID Util_PrintHexAscii(_In_opt_ PLC_CONTEXT ctxLC, _In_ PBYTE pb, _In_ DWORD cb, _In_ DWORD cbInitialOffset) 116 | { 117 | DWORD szMax = 0; 118 | LPSTR sz; 119 | if(cb > 0x10000) { 120 | if(ctxLC) { 121 | lcprintf(ctxLC, "Large output. Only displaying first 65kB.\n"); 122 | } else { 123 | printf("Large output. Only displaying first 65kB.\n"); 124 | } 125 | cb = 0x10000 - cbInitialOffset; 126 | } 127 | Util_FillHexAscii(pb, cb, cbInitialOffset, NULL, &szMax); 128 | if(!(sz = LocalAlloc(0, szMax))) { return; } 129 | Util_FillHexAscii(pb, cb, cbInitialOffset, sz, &szMax); 130 | if(ctxLC) { 131 | lcprintf(ctxLC, "%s", sz); 132 | } else { 133 | printf("%s", sz); 134 | } 135 | LocalFree(sz); 136 | } 137 | 138 | VOID Util_SplitN(_In_ LPSTR sz, _In_ CHAR chDelimiter, _In_ DWORD cpsz, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Inout_ LPSTR *psz) 139 | { 140 | DWORD i, j; 141 | strcpy_s(_szBuf, MAX_PATH, sz); 142 | psz[0] = _szBuf; 143 | for(i = 1; i < cpsz; i++) { 144 | psz[i] = ""; 145 | } 146 | for(i = 0, j = 0; i < MAX_PATH; i++) { 147 | if('\0' == _szBuf[i]) { 148 | return; 149 | } 150 | if(chDelimiter == _szBuf[i]) { 151 | j++; 152 | if(j >= cpsz) { 153 | return; 154 | } 155 | _szBuf[i] = '\0'; 156 | psz[j] = _szBuf + i + 1; 157 | } 158 | } 159 | } 160 | 161 | VOID Util_Split2(_In_ LPSTR sz, _In_ CHAR chDelimiter, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Out_ LPSTR *psz1, _Out_ LPSTR *psz2) 162 | { 163 | LPSTR psz[2] = { 0 }; 164 | Util_SplitN(sz, chDelimiter, 2, _szBuf, psz); 165 | *psz1 = psz[0]; 166 | *psz2 = psz[1]; 167 | } 168 | 169 | VOID Util_Split3(_In_ LPSTR sz, _In_ CHAR chDelimiter, _Out_writes_(MAX_PATH) PCHAR _szBuf, _Out_ LPSTR *psz1, _Out_ LPSTR *psz2, _Out_ LPSTR *psz3) 170 | { 171 | LPSTR psz[3] = { 0 }; 172 | Util_SplitN(sz, chDelimiter, 3, _szBuf, psz); 173 | *psz1 = psz[0]; 174 | *psz2 = psz[1]; 175 | *psz3 = psz[2]; 176 | } 177 | 178 | VOID Util_GenRandom(_Out_ PBYTE pb, _In_ DWORD cb) 179 | { 180 | DWORD i = 0; 181 | srand((unsigned int)GetTickCount64()); 182 | if(cb % 2) { 183 | *(PBYTE)(pb) = (BYTE)rand(); 184 | i++; 185 | } 186 | for(; i <= cb - 2; i += 2) { 187 | *(PWORD)(pb + i) = (WORD)rand(); 188 | } 189 | } 190 | 191 | BOOL Util_IsPlatformBitness64() 192 | { 193 | BOOL fWow64 = TRUE; 194 | if(Util_IsProgramBitness64()) { 195 | return TRUE; 196 | } 197 | IsWow64Process(GetCurrentProcess(), &fWow64); 198 | return fWow64; 199 | } 200 | 201 | BOOL Util_IsProgramBitness64() 202 | { 203 | #ifndef _WIN64 204 | return FALSE; 205 | #endif /* _WIN64 */ 206 | return TRUE; 207 | } 208 | -------------------------------------------------------------------------------- /leechcore/leechcore_device.h: -------------------------------------------------------------------------------- 1 | // leechcore_device.h : external header file to be used by LeechCore plug-in 2 | // modules implemented as separate libraries. 3 | // 4 | // A LeechCore device plugin module must be placed alongside leechcore.[dll|so] 5 | // and follow the naming convention leechcore_device_xxxx.[dll|so] where xxxx 6 | // is the name of the device. 7 | // 8 | // The DLL load function must not initialize the device itself or do anything 9 | // special that may take time to perform - since the plugin module will always 10 | // be loaded even if not used. 11 | // 12 | // The plugin module must implement and export the open function: 13 | // BOOL LcPluginCreate(_In_ PLC_CONTEXT ctx); 14 | // The LcPluginCreate() function will be called whenever a new instance of the 15 | // device may be created/opened - if only one instance may be open at the same 16 | // time this should be handled by the plugin module itself. 17 | // 18 | // (c) Ulf Frisk, 2020-2025 19 | // Author: Ulf Frisk, pcileech@frizk.net 20 | // 21 | // Header Version: 2.5 22 | // 23 | 24 | #ifndef __LEECHCORE_DEVICE_H__ 25 | #define __LEECHCORE_DEVICE_H__ 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif /* __cplusplus */ 29 | #include 30 | #include "leechcore.h" 31 | 32 | #if defined(LINUX) || defined(MACOS) 33 | #include 34 | #include 35 | #ifndef _LINUX_DEF_CRITICAL_SECTION 36 | #define _LINUX_DEF_CRITICAL_SECTION 37 | typedef struct tdCRITICAL_SECTION { 38 | pthread_mutex_t mutex; 39 | pthread_mutexattr_t mta; 40 | } CRITICAL_SECTION, *LPCRITICAL_SECTION; 41 | #endif /* _LINUX_DEF_CRITICAL_SECTION */ 42 | #endif /* LINUX || MACOS */ 43 | 44 | #define LC_CONTEXT_VERSION 0xc0e10004 45 | #define LC_DEVICE_PARAMETER_MAX_ENTRIES 0x10 46 | 47 | #define LC_MEMMAP_FORCE_OFFSET 0x8000000000000000 48 | 49 | typedef struct tdLC_DEVICE_PARAMETER_ENTRY { 50 | CHAR szName[MAX_PATH]; 51 | CHAR szValue[MAX_PATH]; 52 | QWORD qwValue; 53 | } LC_DEVICE_PARAMETER_ENTRY, *PLC_DEVICE_PARAMETER_ENTRY; 54 | 55 | typedef struct tdLC_CONTEXT LC_CONTEXT, *PLC_CONTEXT; 56 | 57 | typedef struct tdLC_READ_CONTIGIOUS_CONTEXT { 58 | PLC_CONTEXT ctxLC; 59 | HANDLE hEventWakeup; 60 | HANDLE hEventFinish; 61 | HANDLE hThread; 62 | DWORD iRL; 63 | DWORD cMEMs; 64 | PPMEM_SCATTER ppMEMs; 65 | QWORD paBase; 66 | DWORD cbRead; 67 | DWORD cb; 68 | BYTE pb[0]; 69 | } LC_READ_CONTIGIOUS_CONTEXT, *PLC_READ_CONTIGIOUS_CONTEXT; 70 | 71 | #define LC_PRINTF_ENABLE 0 72 | #define LC_PRINTF_V 1 73 | #define LC_PRINTF_VV 2 74 | #define LC_PRINTF_VVV 3 75 | 76 | typedef struct tdLC_CONTEXT { 77 | DWORD version; // LC_CONTEXT_VERSION 78 | DWORD dwHandleCount; 79 | HANDLE FLink; 80 | union { 81 | CRITICAL_SECTION Lock; 82 | BYTE _PadLinux[48]; 83 | }; 84 | QWORD cReadScatterMEM; 85 | LC_STATISTICS CallStat; 86 | HANDLE hDeviceModule; 87 | BOOL(*pfnCreate)(_Inout_ PLC_CONTEXT ctxLC, _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcCreateErrorInfo); 88 | // Config for use by devices below: 89 | LC_CONFIG Config; 90 | DWORD cDeviceParameter; 91 | LC_DEVICE_PARAMETER_ENTRY pDeviceParameter[LC_DEVICE_PARAMETER_MAX_ENTRIES]; 92 | BOOL fWritable; // deprecated - do not use! 93 | BOOL fPrintf[4]; 94 | HANDLE hDevice; 95 | BOOL fMultiThread; 96 | VOID(*pfnReadScatter)(_In_ PLC_CONTEXT ctxLC, _In_ DWORD cpMEMs, _Inout_ PPMEM_SCATTER ppMEMs); 97 | VOID(*pfnReadContigious)(_Inout_ PLC_READ_CONTIGIOUS_CONTEXT ctxReadContigious); 98 | VOID(*pfnWriteScatter)(_In_ PLC_CONTEXT ctxLC, _In_ DWORD cpMEMs, _Inout_ PPMEM_SCATTER ppMEMs); 99 | BOOL(*pfnWriteContigious)(_In_ PLC_CONTEXT ctxLC, _In_ QWORD pa, _In_ DWORD cb, _In_reads_(cb) PBYTE pb); 100 | BOOL(*pfnGetOption)(_In_ PLC_CONTEXT ctxLC, _In_ QWORD fOption, _Out_ PQWORD pqwValue); 101 | BOOL(*pfnSetOption)(_In_ PLC_CONTEXT ctxLC, _In_ QWORD fOption, _In_ QWORD qwValue); 102 | BOOL(*pfnCommand)(_In_ PLC_CONTEXT ctxLC, _In_ QWORD fOption, _In_ DWORD cbDataIn, _In_reads_opt_(cbDataIn) PBYTE pbDataIn, _Out_opt_ PBYTE *ppbDataOut, _Out_opt_ PDWORD pcbDataOut); 103 | VOID(*pfnClose)(_Inout_ PLC_CONTEXT ctxLC); 104 | struct { 105 | DWORD cThread; 106 | DWORD cbChunkSize; 107 | BOOL fLoadBalance; 108 | } ReadContigious; 109 | // Internal ReadContigious functionality: 110 | struct { 111 | BOOL fActive; 112 | HANDLE hEventFinish[8]; 113 | PLC_READ_CONTIGIOUS_CONTEXT ctx[8]; 114 | } RC; 115 | // MemMap functionality: 116 | DWORD cMemMap; 117 | DWORD cMemMapMax; 118 | PLC_MEMMAP_ENTRY pMemMap; 119 | // Remote functionality: 120 | struct { 121 | BOOL fCompress; 122 | DWORD dwRpcClientId; 123 | } Rpc; 124 | } LC_CONTEXT, *PLC_CONTEXT; 125 | 126 | /* 127 | * Retrieve a device parameter by its name (if exists). 128 | * -- ctxLc 129 | * -- szName 130 | * -- return 131 | */ 132 | EXPORTED_FUNCTION PLC_DEVICE_PARAMETER_ENTRY LcDeviceParameterGet(_In_ PLC_CONTEXT ctxLC, _In_ LPSTR szName); 133 | 134 | /* 135 | * Retrieve the numeric value of a device parameter (if exists). 136 | * -- ctxLc 137 | * -- szName 138 | * -- return = the numeric value of the device parameter - 0 on fail. 139 | */ 140 | EXPORTED_FUNCTION QWORD LcDeviceParameterGetNumeric(_In_ PLC_CONTEXT ctxLC, _In_ LPSTR szName); 141 | 142 | #define lcprintf(ctxLC, _Format, ...) { if(ctxLC->fPrintf[0]) { ctxLC->Config.pfn_printf_opt ? ctxLC->Config.pfn_printf_opt(_Format, ##__VA_ARGS__) : printf(_Format, ##__VA_ARGS__); } } 143 | #define lcprintfv(ctxLC, _Format, ...) { if(ctxLC->fPrintf[1]) { lcprintf(ctxLC, _Format, ##__VA_ARGS__); } } 144 | #define lcprintfvv(ctxLC, _Format, ...) { if(ctxLC->fPrintf[2]) { lcprintf(ctxLC, _Format, ##__VA_ARGS__); } } 145 | #define lcprintfvvv(ctxLC, _Format, ...) { if(ctxLC->fPrintf[3]) { lcprintf(ctxLC, _Format, ##__VA_ARGS__); } } 146 | #define lcprintf_fn(ctxLC, _Format, ...) { if(ctxLC->fPrintf[0]) { lcprintf(ctxLC, "%s: "_Format, __func__, ##__VA_ARGS__); } } 147 | #define lcprintfv_fn(ctxLC, _Format, ...) { if(ctxLC->fPrintf[1]) { lcprintf(ctxLC, "%s: "_Format, __func__, ##__VA_ARGS__); } } 148 | #define lcprintfvv_fn(ctxLC, _Format, ...) { if(ctxLC->fPrintf[2]) { lcprintf(ctxLC, "%s: "_Format, __func__, ##__VA_ARGS__); } } 149 | #define lcprintfvvv_fn(ctxLC, _Format, ...) { if(ctxLC->fPrintf[3]) { lcprintf(ctxLC, "%s: "_Format, __func__, ##__VA_ARGS__); } } 150 | 151 | /* 152 | * Check whether the memory map is initialized or not. 153 | * -- ctxLC 154 | * -- return 155 | */ 156 | EXPORTED_FUNCTION BOOL LcMemMap_IsInitialized(_In_ PLC_CONTEXT ctxLC); 157 | 158 | /* 159 | * Add a memory range to the memory map. 160 | * -- ctxLC 161 | * -- pa 162 | * -- cb 163 | * -- paRemap = remap offset within file (if relevant). 164 | * -- return 165 | */ 166 | _Success_(return) 167 | EXPORTED_FUNCTION BOOL LcMemMap_AddRange(_In_ PLC_CONTEXT ctxLC, _In_ QWORD pa, _In_ QWORD cb, _In_opt_ QWORD paRemap); 168 | 169 | /* 170 | * Get the max physical address from the memory map. 171 | * -- ctxLC 172 | * -- return 173 | */ 174 | _Success_(return != 0) 175 | EXPORTED_FUNCTION QWORD LcMemMap_GetMaxAddress(_In_ PLC_CONTEXT ctxLC); 176 | 177 | #ifdef __cplusplus 178 | } 179 | #endif /* __cplusplus */ 180 | #endif /* __LEECHCORE_DEVICE_H__ */ 181 | -------------------------------------------------------------------------------- /leechagent/leechrpc.h: -------------------------------------------------------------------------------- 1 | // leechrpcclient.h : definitions related to the leech rpc service. 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __LEECHRPC_H__ 7 | #define __LEECHRPC_H__ 8 | #include "leechcore.h" 9 | #include 10 | 11 | #ifdef _WIN32 12 | #include 13 | 14 | #define CLSID_BINDING_INTERFACE_LEECHRPC "906B0DC2-1337-0666-0001-0000657A63DD" 15 | 16 | #define LEECHRPC_COMPRESS_MAXTHREADS 8 17 | 18 | typedef NTSTATUS WINAPI PFN_RtlCompressBuffer( 19 | _In_ USHORT CompressionFormatAndEngine, 20 | _In_ PUCHAR UncompressedBuffer, 21 | _In_ ULONG UncompressedBufferSize, 22 | _Out_ PUCHAR CompressedBuffer, 23 | _In_ ULONG CompressedBufferSize, 24 | _In_ ULONG UncompressedChunkSize, 25 | _Out_ PULONG FinalCompressedSize, 26 | _In_ PVOID WorkSpace 27 | ); 28 | 29 | typedef NTSTATUS WINAPI PFN_RtlDecompressBuffer( 30 | _In_ USHORT CompressionFormat, 31 | _Out_ PUCHAR UncompressedBuffer, 32 | _In_ ULONG UncompressedBufferSize, 33 | _In_ PUCHAR CompressedBuffer, 34 | _In_ ULONG CompressedBufferSize, 35 | _Out_ PULONG FinalUncompressedSize 36 | ); 37 | 38 | typedef struct tdLEECHRPC_COMPRESS { 39 | BOOL fValid; 40 | HANDLE hDll; 41 | DWORD iCompress; 42 | struct { 43 | CRITICAL_SECTION Lock; 44 | PVOID pbWorkspace; 45 | } Compress[LEECHRPC_COMPRESS_MAXTHREADS]; 46 | struct { 47 | PFN_RtlCompressBuffer *pfnRtlCompressBuffer; 48 | PFN_RtlDecompressBuffer *pfnRtlDecompressBuffer; 49 | } fn; 50 | } LEECHRPC_COMPRESS, *PLEECHRPC_COMPRESS; 51 | 52 | #endif /* _WIN32 */ 53 | #if defined(LINUX) || defined(MACOS) 54 | 55 | #define WINAPI 56 | #define RPC_BINDING_HANDLE PVOID 57 | #define RPC_CSTR LPSTR 58 | typedef const void *LPCVOID; 59 | 60 | typedef int(*pfn_xpress_compress)(PBYTE pbIn, SIZE_T cbIn, PBYTE pbOut, SIZE_T *pcbOut); 61 | typedef int(*pfn_xpress_decompress)(PBYTE pbIn, SIZE_T cbIn, PBYTE pbOut, SIZE_T *pcbOut); 62 | 63 | typedef struct tdLEECHRPC_COMPRESS { 64 | BOOL fValid; 65 | HMODULE lib_mscompress; 66 | pfn_xpress_compress pfn_xpress_compress; 67 | pfn_xpress_decompress pfn_xpress_decompress; 68 | } LEECHRPC_COMPRESS, *PLEECHRPC_COMPRESS; 69 | 70 | #endif /* LINUX || MACOS */ 71 | 72 | #define LEECHRPC_MSGMAGIC 0xd05a2667 73 | #define LEECHRPC_FLAG_NOCOMPRESS 0x0010 74 | #define LEECHRPC_FLAG_FNEXIST_ReadScatterMEM 0x0100 75 | #define LEECHRPC_FLAG_FNEXIST_WriteScatterMEM 0x0200 76 | #define LEECHRPC_FLAG_FNEXIST_Close 0x0800 77 | #define LEECHRPC_FLAG_FNEXIST_GetOption 0x1000 78 | #define LEECHRPC_FLAG_FNEXIST_SetOption 0x2000 79 | #define LEECHRPC_FLAG_FNEXIST_Command 0x4000 80 | 81 | typedef struct LEECHRPC_GRPC { 82 | HMODULE hDll; 83 | HANDLE hGRPC; 84 | pfn_leechgrpc_client_create_insecure pfn_leechgrpc_client_create_insecure; 85 | pfn_leechgrpc_client_create_secure_p12 pfn_leechgrpc_client_create_secure_p12; 86 | pfn_leechgrpc_client_free pfn_leechgrpc_client_free; 87 | pfn_leechgrpc_client_submit_command pfn_leechgrpc_client_submit_command; 88 | CHAR szClientTlsP12Path[MAX_PATH]; 89 | CHAR szClientTlsP12Password[MAX_PATH]; 90 | CHAR szServerCertCaPath[MAX_PATH]; 91 | CHAR szServerCertHostnameOverride[MAX_PATH]; 92 | } LEECHRPC_GRPC, *PLEECHRPC_GRPC; 93 | 94 | typedef struct tdLEECHRPC_CLIENT_CONTEXT { 95 | BOOL fIsProtoRpc; // RPC over TCP/IP. 96 | BOOL fIsProtoSmb; // RPC over SMB (named pipe). 97 | BOOL fIsProtoGRpc; // gRPC over TCP/IP. 98 | BOOL fHousekeeperThread; 99 | BOOL fHousekeeperThreadIsRunning; 100 | HANDLE hHousekeeperThread; 101 | // RPC functionality below: 102 | BOOL fIsAuthInsecure; // No authentication (insecure connection). 103 | BOOL fIsAuthNTLM; // NTLM authentication (no server validation). 104 | BOOL fIsAuthKerberos; // Kerberos authentication (mutual authentication). 105 | BOOL fIsAuthNTLMCredPrompt; // NTLM authentication (with credential prompt). 106 | CHAR szRemoteSPN[MAX_PATH]; 107 | CHAR szTcpAddr[MAX_PATH]; 108 | CHAR szTcpPort[6]; 109 | LPSTR szAuthNtlmUserInitOnly; // NTLM username (only valid during initialization phase). 110 | LPSTR szAuthNtlmPasswordInitOnly; // NTLM password (only valid during initialization phase). 111 | RPC_BINDING_HANDLE hRPC; 112 | RPC_CSTR szStringBinding; 113 | LEECHRPC_COMPRESS Compress; 114 | LEECHRPC_GRPC grpc; 115 | } LEECHRPC_CLIENT_CONTEXT, *PLEECHRPC_CLIENT_CONTEXT; 116 | 117 | typedef enum { 118 | LEECHRPC_MSGTYPE_NA = 0, 119 | LEECHRPC_MSGTYPE_PING_REQ = 1, 120 | LEECHRPC_MSGTYPE_PING_RSP = 2, 121 | LEECHRPC_MSGTYPE_OPEN_REQ = 3, 122 | LEECHRPC_MSGTYPE_OPEN_RSP = 4, 123 | LEECHRPC_MSGTYPE_CLOSE_REQ = 5, 124 | LEECHRPC_MSGTYPE_CLOSE_RSP = 6, 125 | LEECHRPC_MSGTYPE_READSCATTER_REQ = 7, 126 | LEECHRPC_MSGTYPE_READSCATTER_RSP = 8, 127 | LEECHRPC_MSGTYPE_WRITESCATTER_REQ = 9, 128 | LEECHRPC_MSGTYPE_WRITESCATTER_RSP = 10, 129 | LEECHRPC_MSGTYPE_GETOPTION_REQ = 11, 130 | LEECHRPC_MSGTYPE_GETOPTION_RSP = 12, 131 | LEECHRPC_MSGTYPE_SETOPTION_REQ = 13, 132 | LEECHRPC_MSGTYPE_SETOPTION_RSP = 14, 133 | LEECHRPC_MSGTYPE_COMMAND_REQ = 15, 134 | LEECHRPC_MSGTYPE_COMMAND_RSP = 16, 135 | LEECHRPC_MSGTYPE_KEEPALIVE_REQ = 17, 136 | LEECHRPC_MSGTYPE_KEEPALIVE_RSP = 18, 137 | LEECHRPC_MSGTYPE_MAX = 18, 138 | } LEECHRPC_MSGTYPE; 139 | 140 | typedef struct tdLEECHRPC_MSG_HDR { 141 | DWORD dwMagic; 142 | DWORD cbMsg; 143 | LEECHRPC_MSGTYPE tpMsg; 144 | BOOL fMsgResult; 145 | DWORD dwRpcClientID; 146 | DWORD flags; 147 | } LEECHRPC_MSG_HDR, *PLEECHRPC_MSG_HDR, **PPLEECHRPC_MSG_HDR; 148 | 149 | typedef struct tdLEECHRPC_MSG_OPEN { 150 | // HDR 151 | DWORD dwMagic; 152 | DWORD cbMsg; 153 | LEECHRPC_MSGTYPE tpMsg; 154 | BOOL fMsgResult; 155 | DWORD dwRpcClientID; 156 | DWORD flags; 157 | // MSG 158 | BOOL fValidOpen; 159 | LC_CONFIG cfg; 160 | LC_CONFIG_ERRORINFO errorinfo; 161 | } LEECHRPC_MSG_OPEN, *PLEECHRPC_MSG_OPEN; 162 | 163 | typedef struct tdLEECHRPC_MSG_BIN { 164 | // HDR 165 | DWORD dwMagic; 166 | DWORD cbMsg; 167 | LEECHRPC_MSGTYPE tpMsg; 168 | BOOL fMsgResult; 169 | DWORD dwRpcClientID; 170 | DWORD flags; 171 | // MSG 172 | QWORD qwData[2]; 173 | DWORD cbDecompress; // cb uncompressed data, 0 = no compression 174 | DWORD cb; 175 | BYTE pb[]; 176 | } LEECHRPC_MSG_BIN, *PLEECHRPC_MSG_BIN; 177 | 178 | typedef struct tdLEECHRPC_MSG_DATA { 179 | // HDR 180 | DWORD dwMagic; 181 | DWORD cbMsg; 182 | LEECHRPC_MSGTYPE tpMsg; 183 | BOOL fMsgResult; 184 | DWORD dwRpcClientID; 185 | DWORD flags; 186 | // MSG 187 | QWORD qwData[2]; 188 | } LEECHRPC_MSG_DATA, *PLEECHRPC_MSG_DATA; 189 | 190 | /* 191 | * Initialize the compression context. 192 | * -- ctxCompress 193 | * -- return 194 | */ 195 | BOOL LeechRPC_CompressInitialize(_Inout_ PLEECHRPC_COMPRESS ctxCompress); 196 | 197 | /* 198 | * Close the compression context 199 | * -- ctxCompress 200 | */ 201 | VOID LeechRPC_CompressClose(_Inout_ PLEECHRPC_COMPRESS ctxCompress); 202 | 203 | /* 204 | * Compresses data already enclosed in the pMsg contiguous buffer. Existing data 205 | * is overwritten with compressed data. (If possible and desirable). 206 | * -- ctxCompress 207 | * -- pMsg 208 | * -- fCompressDisable = do not perform compression 209 | */ 210 | VOID LeechRPC_Compress(_In_ PLEECHRPC_COMPRESS ctxCompress, _Inout_ PLEECHRPC_MSG_BIN pMsg, _In_ BOOL fCompressDisable); 211 | 212 | /* 213 | * Decompresses the data in pMsgIn if possible. The uncompressed data is allocated 214 | * by the function and is returned in ppMsgOut. Caller must FREE. 215 | * NB! CALLER FREE: ppMsgOut 216 | * -- ctxCompress 217 | * -- pMsgIn = original pMsg to decompress. 218 | * -- ppMsgOut = function allocated decompressed data! 219 | * -- return 220 | */ 221 | _Success_(return) 222 | BOOL LeechRPC_Decompress(_In_ PLEECHRPC_COMPRESS ctxCompress, _In_ PLEECHRPC_MSG_BIN pMsgIn, _Out_ PLEECHRPC_MSG_BIN *ppMsgOut); 223 | 224 | /* 225 | * Utility function to retrieve a time stamp on the format 'YYYY-MM-DD HH:MM:SS' 226 | * -- szTime = user-allocated buffer to receive result. 227 | */ 228 | VOID LeechSvc_GetTimeStamp(_Out_writes_(32) LPSTR szTime); 229 | 230 | /* 231 | * Service functions. 232 | * (server-side only). 233 | */ 234 | VOID LeechRpcOnLoadInitialize(); 235 | VOID LeechRpcOnUnloadClose(); 236 | 237 | #endif /* __LEECHRPC_H__ */ 238 | -------------------------------------------------------------------------------- /leechcore/leechrpc.h: -------------------------------------------------------------------------------- 1 | // leechrpcclient.h : definitions related to the leech rpc service. 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __LEECHRPC_H__ 7 | #define __LEECHRPC_H__ 8 | #include "leechcore.h" 9 | #include 10 | 11 | #ifdef _WIN32 12 | #include 13 | 14 | #define CLSID_BINDING_INTERFACE_LEECHRPC "906B0DC2-1337-0666-0001-0000657A63DD" 15 | 16 | #define LEECHRPC_COMPRESS_MAXTHREADS 8 17 | 18 | typedef NTSTATUS WINAPI PFN_RtlCompressBuffer( 19 | _In_ USHORT CompressionFormatAndEngine, 20 | _In_ PUCHAR UncompressedBuffer, 21 | _In_ ULONG UncompressedBufferSize, 22 | _Out_ PUCHAR CompressedBuffer, 23 | _In_ ULONG CompressedBufferSize, 24 | _In_ ULONG UncompressedChunkSize, 25 | _Out_ PULONG FinalCompressedSize, 26 | _In_ PVOID WorkSpace 27 | ); 28 | 29 | typedef NTSTATUS WINAPI PFN_RtlDecompressBuffer( 30 | _In_ USHORT CompressionFormat, 31 | _Out_ PUCHAR UncompressedBuffer, 32 | _In_ ULONG UncompressedBufferSize, 33 | _In_ PUCHAR CompressedBuffer, 34 | _In_ ULONG CompressedBufferSize, 35 | _Out_ PULONG FinalUncompressedSize 36 | ); 37 | 38 | typedef struct tdLEECHRPC_COMPRESS { 39 | BOOL fValid; 40 | HANDLE hDll; 41 | DWORD iCompress; 42 | struct { 43 | CRITICAL_SECTION Lock; 44 | PVOID pbWorkspace; 45 | } Compress[LEECHRPC_COMPRESS_MAXTHREADS]; 46 | struct { 47 | PFN_RtlCompressBuffer *pfnRtlCompressBuffer; 48 | PFN_RtlDecompressBuffer *pfnRtlDecompressBuffer; 49 | } fn; 50 | } LEECHRPC_COMPRESS, *PLEECHRPC_COMPRESS; 51 | 52 | #endif /* _WIN32 */ 53 | #if defined(LINUX) || defined(MACOS) 54 | 55 | #define WINAPI 56 | #define RPC_BINDING_HANDLE PVOID 57 | #define RPC_CSTR LPSTR 58 | typedef const void *LPCVOID; 59 | 60 | typedef int(*pfn_xpress_compress)(PBYTE pbIn, SIZE_T cbIn, PBYTE pbOut, SIZE_T *pcbOut); 61 | typedef int(*pfn_xpress_decompress)(PBYTE pbIn, SIZE_T cbIn, PBYTE pbOut, SIZE_T *pcbOut); 62 | 63 | typedef struct tdLEECHRPC_COMPRESS { 64 | BOOL fValid; 65 | HMODULE lib_mscompress; 66 | pfn_xpress_compress pfn_xpress_compress; 67 | pfn_xpress_decompress pfn_xpress_decompress; 68 | } LEECHRPC_COMPRESS, *PLEECHRPC_COMPRESS; 69 | 70 | #endif /* LINUX || MACOS */ 71 | 72 | #define LEECHRPC_MSGMAGIC 0xd05a2667 73 | #define LEECHRPC_FLAG_NOCOMPRESS 0x0010 74 | #define LEECHRPC_FLAG_FNEXIST_ReadScatterMEM 0x0100 75 | #define LEECHRPC_FLAG_FNEXIST_WriteScatterMEM 0x0200 76 | #define LEECHRPC_FLAG_FNEXIST_Close 0x0800 77 | #define LEECHRPC_FLAG_FNEXIST_GetOption 0x1000 78 | #define LEECHRPC_FLAG_FNEXIST_SetOption 0x2000 79 | #define LEECHRPC_FLAG_FNEXIST_Command 0x4000 80 | 81 | typedef struct LEECHRPC_GRPC { 82 | HMODULE hDll; 83 | HANDLE hGRPC; 84 | pfn_leechgrpc_client_create_insecure pfn_leechgrpc_client_create_insecure; 85 | pfn_leechgrpc_client_create_secure_p12 pfn_leechgrpc_client_create_secure_p12; 86 | pfn_leechgrpc_client_free pfn_leechgrpc_client_free; 87 | pfn_leechgrpc_client_submit_command pfn_leechgrpc_client_submit_command; 88 | CHAR szClientTlsP12Path[MAX_PATH]; 89 | CHAR szClientTlsP12Password[MAX_PATH]; 90 | CHAR szServerCertCaPath[MAX_PATH]; 91 | CHAR szServerCertHostnameOverride[MAX_PATH]; 92 | } LEECHRPC_GRPC, *PLEECHRPC_GRPC; 93 | 94 | typedef struct tdLEECHRPC_CLIENT_CONTEXT { 95 | BOOL fIsProtoRpc; // RPC over TCP/IP. 96 | BOOL fIsProtoSmb; // RPC over SMB (named pipe). 97 | BOOL fIsProtoGRpc; // gRPC over TCP/IP. 98 | BOOL fHousekeeperThread; 99 | BOOL fHousekeeperThreadIsRunning; 100 | HANDLE hHousekeeperThread; 101 | // RPC functionality below: 102 | BOOL fIsAuthInsecure; // No authentication (insecure connection). 103 | BOOL fIsAuthNTLM; // NTLM authentication (no server validation). 104 | BOOL fIsAuthKerberos; // Kerberos authentication (mutual authentication). 105 | BOOL fIsAuthNTLMCredPrompt; // NTLM authentication (with credential prompt). 106 | CHAR szRemoteSPN[MAX_PATH]; 107 | CHAR szTcpAddr[MAX_PATH]; 108 | CHAR szTcpPort[6]; 109 | LPSTR szAuthNtlmUserInitOnly; // NTLM username (only valid during initialization phase). 110 | LPSTR szAuthNtlmPasswordInitOnly; // NTLM password (only valid during initialization phase). 111 | RPC_BINDING_HANDLE hRPC; 112 | RPC_CSTR szStringBinding; 113 | LEECHRPC_COMPRESS Compress; 114 | LEECHRPC_GRPC grpc; 115 | } LEECHRPC_CLIENT_CONTEXT, *PLEECHRPC_CLIENT_CONTEXT; 116 | 117 | typedef enum { 118 | LEECHRPC_MSGTYPE_NA = 0, 119 | LEECHRPC_MSGTYPE_PING_REQ = 1, 120 | LEECHRPC_MSGTYPE_PING_RSP = 2, 121 | LEECHRPC_MSGTYPE_OPEN_REQ = 3, 122 | LEECHRPC_MSGTYPE_OPEN_RSP = 4, 123 | LEECHRPC_MSGTYPE_CLOSE_REQ = 5, 124 | LEECHRPC_MSGTYPE_CLOSE_RSP = 6, 125 | LEECHRPC_MSGTYPE_READSCATTER_REQ = 7, 126 | LEECHRPC_MSGTYPE_READSCATTER_RSP = 8, 127 | LEECHRPC_MSGTYPE_WRITESCATTER_REQ = 9, 128 | LEECHRPC_MSGTYPE_WRITESCATTER_RSP = 10, 129 | LEECHRPC_MSGTYPE_GETOPTION_REQ = 11, 130 | LEECHRPC_MSGTYPE_GETOPTION_RSP = 12, 131 | LEECHRPC_MSGTYPE_SETOPTION_REQ = 13, 132 | LEECHRPC_MSGTYPE_SETOPTION_RSP = 14, 133 | LEECHRPC_MSGTYPE_COMMAND_REQ = 15, 134 | LEECHRPC_MSGTYPE_COMMAND_RSP = 16, 135 | LEECHRPC_MSGTYPE_KEEPALIVE_REQ = 17, 136 | LEECHRPC_MSGTYPE_KEEPALIVE_RSP = 18, 137 | LEECHRPC_MSGTYPE_MAX = 18, 138 | } LEECHRPC_MSGTYPE; 139 | 140 | typedef struct tdLEECHRPC_MSG_HDR { 141 | DWORD dwMagic; 142 | DWORD cbMsg; 143 | LEECHRPC_MSGTYPE tpMsg; 144 | BOOL fMsgResult; 145 | DWORD dwRpcClientID; 146 | DWORD flags; 147 | } LEECHRPC_MSG_HDR, *PLEECHRPC_MSG_HDR, **PPLEECHRPC_MSG_HDR; 148 | 149 | typedef struct tdLEECHRPC_MSG_OPEN { 150 | // HDR 151 | DWORD dwMagic; 152 | DWORD cbMsg; 153 | LEECHRPC_MSGTYPE tpMsg; 154 | BOOL fMsgResult; 155 | DWORD dwRpcClientID; 156 | DWORD flags; 157 | // MSG 158 | BOOL fValidOpen; 159 | LC_CONFIG cfg; 160 | LC_CONFIG_ERRORINFO errorinfo; 161 | } LEECHRPC_MSG_OPEN, *PLEECHRPC_MSG_OPEN; 162 | 163 | typedef struct tdLEECHRPC_MSG_BIN { 164 | // HDR 165 | DWORD dwMagic; 166 | DWORD cbMsg; 167 | LEECHRPC_MSGTYPE tpMsg; 168 | BOOL fMsgResult; 169 | DWORD dwRpcClientID; 170 | DWORD flags; 171 | // MSG 172 | QWORD qwData[2]; 173 | DWORD cbDecompress; // cb uncompressed data, 0 = no compression 174 | DWORD cb; 175 | BYTE pb[]; 176 | } LEECHRPC_MSG_BIN, *PLEECHRPC_MSG_BIN; 177 | 178 | typedef struct tdLEECHRPC_MSG_DATA { 179 | // HDR 180 | DWORD dwMagic; 181 | DWORD cbMsg; 182 | LEECHRPC_MSGTYPE tpMsg; 183 | BOOL fMsgResult; 184 | DWORD dwRpcClientID; 185 | DWORD flags; 186 | // MSG 187 | QWORD qwData[2]; 188 | } LEECHRPC_MSG_DATA, *PLEECHRPC_MSG_DATA; 189 | 190 | /* 191 | * Initialize the compression context. 192 | * -- ctxCompress 193 | * -- return 194 | */ 195 | BOOL LeechRPC_CompressInitialize(_Inout_ PLEECHRPC_COMPRESS ctxCompress); 196 | 197 | /* 198 | * Close the compression context 199 | * -- ctxCompress 200 | */ 201 | VOID LeechRPC_CompressClose(_Inout_ PLEECHRPC_COMPRESS ctxCompress); 202 | 203 | /* 204 | * Compresses data already enclosed in the pMsg contiguous buffer. Existing data 205 | * is overwritten with compressed data. (If possible and desirable). 206 | * -- ctxCompress 207 | * -- pMsg 208 | * -- fCompressDisable = do not perform compression 209 | */ 210 | VOID LeechRPC_Compress(_In_ PLEECHRPC_COMPRESS ctxCompress, _Inout_ PLEECHRPC_MSG_BIN pMsg, _In_ BOOL fCompressDisable); 211 | 212 | /* 213 | * Decompresses the data in pMsgIn if possible. The uncompressed data is allocated 214 | * by the function and is returned in ppMsgOut. Caller must FREE. 215 | * NB! CALLER FREE: ppMsgOut 216 | * -- ctxCompress 217 | * -- pMsgIn = original pMsg to decompress. 218 | * -- ppMsgOut = function allocated decompressed data! 219 | * -- return 220 | */ 221 | _Success_(return) 222 | BOOL LeechRPC_Decompress(_In_ PLEECHRPC_COMPRESS ctxCompress, _In_ PLEECHRPC_MSG_BIN pMsgIn, _Out_ PLEECHRPC_MSG_BIN *ppMsgOut); 223 | 224 | /* 225 | * Utility function to retrieve a time stamp on the format 'YYYY-MM-DD HH:MM:SS' 226 | * -- szTime = user-allocated buffer to receive result. 227 | */ 228 | VOID LeechSvc_GetTimeStamp(_Out_writes_(32) LPSTR szTime); 229 | 230 | /* 231 | * Service functions. 232 | * (server-side only). 233 | */ 234 | VOID LeechRpcOnLoadInitialize(); 235 | VOID LeechRpcOnUnloadClose(); 236 | 237 | #endif /* __LEECHRPC_H__ */ 238 | -------------------------------------------------------------------------------- /leechagent_linux/leechrpc.h: -------------------------------------------------------------------------------- 1 | // leechrpcclient.h : definitions related to the leech rpc service. 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __LEECHRPC_H__ 7 | #define __LEECHRPC_H__ 8 | #include "leechcore.h" 9 | #include 10 | 11 | #ifdef _WIN32 12 | #include 13 | 14 | #define CLSID_BINDING_INTERFACE_LEECHRPC "906B0DC2-1337-0666-0001-0000657A63DD" 15 | 16 | #define LEECHRPC_COMPRESS_MAXTHREADS 8 17 | 18 | typedef NTSTATUS WINAPI PFN_RtlCompressBuffer( 19 | _In_ USHORT CompressionFormatAndEngine, 20 | _In_ PUCHAR UncompressedBuffer, 21 | _In_ ULONG UncompressedBufferSize, 22 | _Out_ PUCHAR CompressedBuffer, 23 | _In_ ULONG CompressedBufferSize, 24 | _In_ ULONG UncompressedChunkSize, 25 | _Out_ PULONG FinalCompressedSize, 26 | _In_ PVOID WorkSpace 27 | ); 28 | 29 | typedef NTSTATUS WINAPI PFN_RtlDecompressBuffer( 30 | _In_ USHORT CompressionFormat, 31 | _Out_ PUCHAR UncompressedBuffer, 32 | _In_ ULONG UncompressedBufferSize, 33 | _In_ PUCHAR CompressedBuffer, 34 | _In_ ULONG CompressedBufferSize, 35 | _Out_ PULONG FinalUncompressedSize 36 | ); 37 | 38 | typedef struct tdLEECHRPC_COMPRESS { 39 | BOOL fValid; 40 | HANDLE hDll; 41 | DWORD iCompress; 42 | struct { 43 | CRITICAL_SECTION Lock; 44 | PVOID pbWorkspace; 45 | } Compress[LEECHRPC_COMPRESS_MAXTHREADS]; 46 | struct { 47 | PFN_RtlCompressBuffer *pfnRtlCompressBuffer; 48 | PFN_RtlDecompressBuffer *pfnRtlDecompressBuffer; 49 | } fn; 50 | } LEECHRPC_COMPRESS, *PLEECHRPC_COMPRESS; 51 | 52 | #endif /* _WIN32 */ 53 | #if defined(LINUX) || defined(MACOS) 54 | 55 | #define WINAPI 56 | #define RPC_BINDING_HANDLE PVOID 57 | #define RPC_CSTR LPSTR 58 | typedef const void *LPCVOID; 59 | 60 | typedef int(*pfn_xpress_compress)(PBYTE pbIn, SIZE_T cbIn, PBYTE pbOut, SIZE_T *pcbOut); 61 | typedef int(*pfn_xpress_decompress)(PBYTE pbIn, SIZE_T cbIn, PBYTE pbOut, SIZE_T *pcbOut); 62 | 63 | typedef struct tdLEECHRPC_COMPRESS { 64 | BOOL fValid; 65 | HMODULE lib_mscompress; 66 | pfn_xpress_compress pfn_xpress_compress; 67 | pfn_xpress_decompress pfn_xpress_decompress; 68 | } LEECHRPC_COMPRESS, *PLEECHRPC_COMPRESS; 69 | 70 | #endif /* LINUX || MACOS */ 71 | 72 | #define LEECHRPC_MSGMAGIC 0xd05a2667 73 | #define LEECHRPC_FLAG_NOCOMPRESS 0x0010 74 | #define LEECHRPC_FLAG_FNEXIST_ReadScatterMEM 0x0100 75 | #define LEECHRPC_FLAG_FNEXIST_WriteScatterMEM 0x0200 76 | #define LEECHRPC_FLAG_FNEXIST_Close 0x0800 77 | #define LEECHRPC_FLAG_FNEXIST_GetOption 0x1000 78 | #define LEECHRPC_FLAG_FNEXIST_SetOption 0x2000 79 | #define LEECHRPC_FLAG_FNEXIST_Command 0x4000 80 | 81 | typedef struct LEECHRPC_GRPC { 82 | HMODULE hDll; 83 | HANDLE hGRPC; 84 | pfn_leechgrpc_client_create_insecure pfn_leechgrpc_client_create_insecure; 85 | pfn_leechgrpc_client_create_secure_p12 pfn_leechgrpc_client_create_secure_p12; 86 | pfn_leechgrpc_client_free pfn_leechgrpc_client_free; 87 | pfn_leechgrpc_client_submit_command pfn_leechgrpc_client_submit_command; 88 | CHAR szClientTlsP12Path[MAX_PATH]; 89 | CHAR szClientTlsP12Password[MAX_PATH]; 90 | CHAR szServerCertCaPath[MAX_PATH]; 91 | CHAR szServerCertHostnameOverride[MAX_PATH]; 92 | } LEECHRPC_GRPC, *PLEECHRPC_GRPC; 93 | 94 | typedef struct tdLEECHRPC_CLIENT_CONTEXT { 95 | BOOL fIsProtoRpc; // RPC over TCP/IP. 96 | BOOL fIsProtoSmb; // RPC over SMB (named pipe). 97 | BOOL fIsProtoGRpc; // gRPC over TCP/IP. 98 | BOOL fHousekeeperThread; 99 | BOOL fHousekeeperThreadIsRunning; 100 | HANDLE hHousekeeperThread; 101 | // RPC functionality below: 102 | BOOL fIsAuthInsecure; // No authentication (insecure connection). 103 | BOOL fIsAuthNTLM; // NTLM authentication (no server validation). 104 | BOOL fIsAuthKerberos; // Kerberos authentication (mutual authentication). 105 | BOOL fIsAuthNTLMCredPrompt; // NTLM authentication (with credential prompt). 106 | CHAR szRemoteSPN[MAX_PATH]; 107 | CHAR szTcpAddr[MAX_PATH]; 108 | CHAR szTcpPort[6]; 109 | LPSTR szAuthNtlmUserInitOnly; // NTLM username (only valid during initialization phase). 110 | LPSTR szAuthNtlmPasswordInitOnly; // NTLM password (only valid during initialization phase). 111 | RPC_BINDING_HANDLE hRPC; 112 | RPC_CSTR szStringBinding; 113 | LEECHRPC_COMPRESS Compress; 114 | LEECHRPC_GRPC grpc; 115 | } LEECHRPC_CLIENT_CONTEXT, *PLEECHRPC_CLIENT_CONTEXT; 116 | 117 | typedef enum { 118 | LEECHRPC_MSGTYPE_NA = 0, 119 | LEECHRPC_MSGTYPE_PING_REQ = 1, 120 | LEECHRPC_MSGTYPE_PING_RSP = 2, 121 | LEECHRPC_MSGTYPE_OPEN_REQ = 3, 122 | LEECHRPC_MSGTYPE_OPEN_RSP = 4, 123 | LEECHRPC_MSGTYPE_CLOSE_REQ = 5, 124 | LEECHRPC_MSGTYPE_CLOSE_RSP = 6, 125 | LEECHRPC_MSGTYPE_READSCATTER_REQ = 7, 126 | LEECHRPC_MSGTYPE_READSCATTER_RSP = 8, 127 | LEECHRPC_MSGTYPE_WRITESCATTER_REQ = 9, 128 | LEECHRPC_MSGTYPE_WRITESCATTER_RSP = 10, 129 | LEECHRPC_MSGTYPE_GETOPTION_REQ = 11, 130 | LEECHRPC_MSGTYPE_GETOPTION_RSP = 12, 131 | LEECHRPC_MSGTYPE_SETOPTION_REQ = 13, 132 | LEECHRPC_MSGTYPE_SETOPTION_RSP = 14, 133 | LEECHRPC_MSGTYPE_COMMAND_REQ = 15, 134 | LEECHRPC_MSGTYPE_COMMAND_RSP = 16, 135 | LEECHRPC_MSGTYPE_KEEPALIVE_REQ = 17, 136 | LEECHRPC_MSGTYPE_KEEPALIVE_RSP = 18, 137 | LEECHRPC_MSGTYPE_MAX = 18, 138 | } LEECHRPC_MSGTYPE; 139 | 140 | typedef struct tdLEECHRPC_MSG_HDR { 141 | DWORD dwMagic; 142 | DWORD cbMsg; 143 | LEECHRPC_MSGTYPE tpMsg; 144 | BOOL fMsgResult; 145 | DWORD dwRpcClientID; 146 | DWORD flags; 147 | } LEECHRPC_MSG_HDR, *PLEECHRPC_MSG_HDR, **PPLEECHRPC_MSG_HDR; 148 | 149 | typedef struct tdLEECHRPC_MSG_OPEN { 150 | // HDR 151 | DWORD dwMagic; 152 | DWORD cbMsg; 153 | LEECHRPC_MSGTYPE tpMsg; 154 | BOOL fMsgResult; 155 | DWORD dwRpcClientID; 156 | DWORD flags; 157 | // MSG 158 | BOOL fValidOpen; 159 | LC_CONFIG cfg; 160 | LC_CONFIG_ERRORINFO errorinfo; 161 | } LEECHRPC_MSG_OPEN, *PLEECHRPC_MSG_OPEN; 162 | 163 | typedef struct tdLEECHRPC_MSG_BIN { 164 | // HDR 165 | DWORD dwMagic; 166 | DWORD cbMsg; 167 | LEECHRPC_MSGTYPE tpMsg; 168 | BOOL fMsgResult; 169 | DWORD dwRpcClientID; 170 | DWORD flags; 171 | // MSG 172 | QWORD qwData[2]; 173 | DWORD cbDecompress; // cb uncompressed data, 0 = no compression 174 | DWORD cb; 175 | BYTE pb[]; 176 | } LEECHRPC_MSG_BIN, *PLEECHRPC_MSG_BIN; 177 | 178 | typedef struct tdLEECHRPC_MSG_DATA { 179 | // HDR 180 | DWORD dwMagic; 181 | DWORD cbMsg; 182 | LEECHRPC_MSGTYPE tpMsg; 183 | BOOL fMsgResult; 184 | DWORD dwRpcClientID; 185 | DWORD flags; 186 | // MSG 187 | QWORD qwData[2]; 188 | } LEECHRPC_MSG_DATA, *PLEECHRPC_MSG_DATA; 189 | 190 | /* 191 | * Initialize the compression context. 192 | * -- ctxCompress 193 | * -- return 194 | */ 195 | BOOL LeechRPC_CompressInitialize(_Inout_ PLEECHRPC_COMPRESS ctxCompress); 196 | 197 | /* 198 | * Close the compression context 199 | * -- ctxCompress 200 | */ 201 | VOID LeechRPC_CompressClose(_Inout_ PLEECHRPC_COMPRESS ctxCompress); 202 | 203 | /* 204 | * Compresses data already enclosed in the pMsg contiguous buffer. Existing data 205 | * is overwritten with compressed data. (If possible and desirable). 206 | * -- ctxCompress 207 | * -- pMsg 208 | * -- fCompressDisable = do not perform compression 209 | */ 210 | VOID LeechRPC_Compress(_In_ PLEECHRPC_COMPRESS ctxCompress, _Inout_ PLEECHRPC_MSG_BIN pMsg, _In_ BOOL fCompressDisable); 211 | 212 | /* 213 | * Decompresses the data in pMsgIn if possible. The uncompressed data is allocated 214 | * by the function and is returned in ppMsgOut. Caller must FREE. 215 | * NB! CALLER FREE: ppMsgOut 216 | * -- ctxCompress 217 | * -- pMsgIn = original pMsg to decompress. 218 | * -- ppMsgOut = function allocated decompressed data! 219 | * -- return 220 | */ 221 | _Success_(return) 222 | BOOL LeechRPC_Decompress(_In_ PLEECHRPC_COMPRESS ctxCompress, _In_ PLEECHRPC_MSG_BIN pMsgIn, _Out_ PLEECHRPC_MSG_BIN *ppMsgOut); 223 | 224 | /* 225 | * Utility function to retrieve a time stamp on the format 'YYYY-MM-DD HH:MM:SS' 226 | * -- szTime = user-allocated buffer to receive result. 227 | */ 228 | VOID LeechSvc_GetTimeStamp(_Out_writes_(32) LPSTR szTime); 229 | 230 | /* 231 | * Service functions. 232 | * (server-side only). 233 | */ 234 | VOID LeechRpcOnLoadInitialize(); 235 | VOID LeechRpcOnUnloadClose(); 236 | 237 | #endif /* __LEECHRPC_H__ */ 238 | -------------------------------------------------------------------------------- /leechcore/memmap.c: -------------------------------------------------------------------------------- 1 | // memmap.c : implementation : memory map. 2 | // 3 | // (c) Ulf Frisk, 2020-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | 7 | #include "leechcore.h" 8 | #include "leechcore_device.h" 9 | #include "oscompatibility.h" 10 | 11 | /* 12 | * Check whether the memory map is initialized or not. 13 | * -- ctxLC 14 | * -- return 15 | */ 16 | EXPORTED_FUNCTION BOOL LcMemMap_IsInitialized(_In_ PLC_CONTEXT ctxLC) 17 | { 18 | return ctxLC->cMemMap > 0; 19 | } 20 | 21 | /* 22 | * Add a memory range to the memory map. 23 | * -- ctxLC 24 | * -- pa 25 | * -- cb 26 | * -- paRemap = remap offset within file (if relevant). 27 | * -- return 28 | */ 29 | _Success_(return) 30 | EXPORTED_FUNCTION BOOL LcMemMap_AddRange(_In_ PLC_CONTEXT ctxLC, _In_ QWORD pa, _In_ QWORD cb, _In_opt_ QWORD paRemap) 31 | { 32 | PVOID pvGrowMemMap; 33 | if((cb & 0xfff) == 1) { cb--; } 34 | if((pa & 0xfff) || (cb & 0xfff)) { return FALSE; } 35 | if(ctxLC->cMemMap >= 0x00100000) { return FALSE; } 36 | if(ctxLC->cMemMap == ctxLC->cMemMapMax) { 37 | // grow memmap with with factor x2: 38 | pvGrowMemMap = LocalAlloc(LMEM_ZEROINIT, ctxLC->cMemMapMax * sizeof(LC_MEMMAP_ENTRY) * 2); 39 | if(!pvGrowMemMap) { return FALSE; } 40 | memcpy(pvGrowMemMap, ctxLC->pMemMap, ctxLC->cMemMap * sizeof(LC_MEMMAP_ENTRY)); 41 | LocalFree(ctxLC->pMemMap); 42 | ctxLC->pMemMap = (PLC_MEMMAP_ENTRY)pvGrowMemMap; 43 | ctxLC->cMemMapMax = ctxLC->cMemMapMax * 2; 44 | } 45 | if(ctxLC->cMemMap && (ctxLC->pMemMap[ctxLC->cMemMap - 1].pa + ctxLC->pMemMap[ctxLC->cMemMap - 1].cb > pa)) { return FALSE; } 46 | ctxLC->pMemMap[ctxLC->cMemMap].pa = pa; 47 | ctxLC->pMemMap[ctxLC->cMemMap].cb = cb; 48 | ctxLC->pMemMap[ctxLC->cMemMap].paRemap = paRemap ? (paRemap & ~LC_MEMMAP_FORCE_OFFSET) : pa; 49 | ctxLC->cMemMap++; 50 | lcprintfvv_fn(ctxLC, "%016llx-%016llx -> %016llx\n", pa, pa + cb - 1, paRemap); 51 | return TRUE; 52 | } 53 | 54 | /* 55 | * Get the max physical address from the memory map. 56 | * -- ctxLC 57 | * -- return 58 | */ 59 | _Success_(return != 0) 60 | EXPORTED_FUNCTION QWORD LcMemMap_GetMaxAddress(_In_ PLC_CONTEXT ctxLC) 61 | { 62 | if(ctxLC->cMemMap == 0) { return 0x0000ffffffffffff; } 63 | return ctxLC->pMemMap[ctxLC->cMemMap - 1].pa + ctxLC->pMemMap[ctxLC->cMemMap - 1].cb; 64 | } 65 | 66 | /* 67 | * Translate each individual MEM. The qwA field will be overwritten with the 68 | * translated value - or on error -1. 69 | * -- ctxLC 70 | * -- cMEMs 71 | * -- ppMEMs 72 | */ 73 | VOID LcMemMap_TranslateMEMs(_In_ PLC_CONTEXT ctxLC, _In_ DWORD cMEMs, _Inout_ PPMEM_SCATTER ppMEMs) 74 | { 75 | DWORD iMEM, iMap, oMap; 76 | PMEM_SCATTER pMEM; 77 | PLC_MEMMAP_ENTRY peMap; 78 | if(ctxLC->cMemMap == 0) { return; } 79 | peMap = ctxLC->pMemMap + 0; 80 | for(iMEM = 0; iMEM < cMEMs; iMEM++) { 81 | pMEM = ppMEMs[iMEM]; 82 | if(pMEM->qwA == (QWORD)-1) { continue; } 83 | // check already existing (optimization). 84 | if((pMEM->qwA >= peMap->pa) && (pMEM->qwA + pMEM->cb <= peMap->pa + peMap->cb)) { 85 | pMEM->qwA = pMEM->qwA + peMap->paRemap - peMap->pa; 86 | continue; 87 | } 88 | // check all memmap ranges. 89 | iMap = 0; 90 | if(ctxLC->cMemMap > 0x40) { // fast find (large map optimization) 91 | iMap = ctxLC->cMemMap >> 1; 92 | oMap = iMap; 93 | while((oMap = oMap >> 1)) { 94 | iMap = (pMEM->qwA > ctxLC->pMemMap[iMap].pa) ? (iMap + oMap) : (iMap - oMap); 95 | } 96 | while(iMap && (pMEM->qwA < ctxLC->pMemMap[iMap].pa)) { 97 | iMap--; 98 | } 99 | } 100 | for(; iMap < ctxLC->cMemMap; iMap++) { // find entry 101 | peMap = ctxLC->pMemMap + iMap; 102 | if((pMEM->qwA >= peMap->pa) && (pMEM->qwA + pMEM->cb <= peMap->pa + peMap->cb)) { 103 | break; 104 | } 105 | if(pMEM->qwA < peMap->pa) { 106 | break; 107 | } 108 | } 109 | if((pMEM->qwA >= peMap->pa) && (pMEM->qwA + pMEM->cb <= peMap->pa + peMap->cb)) { 110 | pMEM->qwA = pMEM->qwA + peMap->paRemap - peMap->pa; 111 | } else { 112 | pMEM->qwA = (QWORD)-1; 113 | } 114 | } 115 | } 116 | 117 | /* 118 | * Retrieve the memory ranges as an array of LC_MEMMAP_ENTRY. 119 | * -- ctxLC 120 | * -- ppbDataOut 121 | * -- pcbDataOut 122 | */ 123 | _Success_(return) 124 | BOOL LcMemMap_GetRangesAsStruct(_In_ PLC_CONTEXT ctxLC, _Out_ PBYTE *ppbDataOut, _Out_opt_ PDWORD pcbDataOut) 125 | { 126 | PBYTE pb; 127 | DWORD cb; 128 | if(ctxLC->cMemMap > 0x00100000) { return FALSE; } 129 | cb = ctxLC->cMemMap * sizeof(LC_MEMMAP_ENTRY); 130 | if(!(pb = LocalAlloc(LMEM_ZEROINIT, cb))) { return FALSE; } 131 | memcpy(pb, ctxLC->pMemMap, cb); 132 | *ppbDataOut = pb; 133 | if(pcbDataOut) { *pcbDataOut = cb; } 134 | return TRUE; 135 | } 136 | 137 | /* 138 | * Retrieve the memory ranges as ascii text in a null-terminated text buffer. 139 | * CALLER LcFreeMem: *ppbDataOut 140 | * -- ctxLC 141 | * -- ppbDataOut 142 | * -- pcbDataOut 143 | */ 144 | _Success_(return) 145 | BOOL LcMemMap_GetRangesAsText(_In_ PLC_CONTEXT ctxLC, _Out_ PBYTE *ppbDataOut, _Out_opt_ PDWORD pcbDataOut) 146 | { 147 | PBYTE pb; 148 | DWORD i, o, cb; 149 | if(ctxLC->cMemMap > 0x00100000) { return FALSE; } 150 | cb = ctxLC->cMemMap * (4 + 1 + 16 + 3 + 16 + 4 + 16 + 1); 151 | if(!(pb = LocalAlloc(LMEM_ZEROINIT, cb))) { return FALSE; } 152 | for(i = 0, o = 0; i < ctxLC->cMemMap; i++) { 153 | o += snprintf( 154 | (LPSTR)pb + o, 155 | cb - o, 156 | "%04x %16llx - %16llx -> %16llx\n", 157 | i, 158 | ctxLC->pMemMap[i].pa, 159 | ctxLC->pMemMap[i].pa + ctxLC->pMemMap[i].cb - 1, 160 | ctxLC->pMemMap[i].paRemap 161 | ); 162 | } 163 | pb[cb - 1] = 0; 164 | *ppbDataOut = pb; 165 | if(pcbDataOut) { *pcbDataOut = cb; } 166 | return TRUE; 167 | } 168 | 169 | /* 170 | * Set ranges by memmap struct data. 171 | * NB! all previous ranges will be overwritten. 172 | * -- ctxLC 173 | * -- pStruct 174 | * -- cStruct 175 | * -- return 176 | */ 177 | _Success_(return) 178 | BOOL LcMemMap_SetRangesFromStruct(_In_ PLC_CONTEXT ctxLC, _In_ PLC_MEMMAP_ENTRY pMemMap, _In_ DWORD cMemMap) 179 | { 180 | DWORD i; 181 | ctxLC->cMemMap = 0; 182 | for(i = 0; i < cMemMap; i++) { 183 | LcMemMap_AddRange(ctxLC, pMemMap[i].pa, pMemMap[i].cb, pMemMap[i].paRemap); 184 | } 185 | return TRUE; 186 | } 187 | 188 | /* 189 | * Set ranges by parsing ascii text in the buffer pb. The ranges should be 190 | * specified on a line-by-line basis with hexascii numericals on the format: 191 | * 192 | * NB! all previous ranges will be overwritten. 193 | * -- ctxLC 194 | * -- pb 195 | * -- cb 196 | * -- return 197 | */ 198 | _Success_(return) 199 | BOOL LcMemMap_SetRangesFromText(_In_ PLC_CONTEXT ctxLC, _In_ PBYTE pb, _In_ DWORD cb) 200 | { 201 | DWORD i, iMax; 202 | LPSTR sz, szLine, szLineContext = NULL, szToken, szTokenContext; 203 | QWORD v[3]; 204 | ctxLC->cMemMap = 0; 205 | if(!(sz = LocalAlloc(0, cb + 1ULL))) { return FALSE; } 206 | memcpy(sz, pb, cb); 207 | sz[cb] = 0; 208 | // parse 209 | szLine = strtok_s(sz, "\r\n", &szLineContext); 210 | while(szLine) { 211 | if(szLine[0] == '0' && szLine[1] == '0' && szLine[4] == ' ') { 212 | szLine += 4; 213 | } 214 | for(i = 0, iMax = (DWORD)strlen(szLine); i < iMax; i++) { 215 | if((szLine[i] == '0') && (szLine[i + 1] == 'x')) { szLine[i] = ' '; szLine[i + 1] = ' '; } 216 | if((szLine[i] >= '0') && (szLine[i] <= '9')) { continue; } 217 | if((szLine[i] >= 'a') && (szLine[i] <= 'f')) { continue; } 218 | if((szLine[i] >= 'A') && (szLine[i] <= 'F')) { continue; } 219 | if(szLine[i] == '#') { szLine[i] = 0; } 220 | szLine[i] = ' '; 221 | } 222 | i = 0; 223 | v[0] = 0, v[1] = 0, v[2] = 0; 224 | szTokenContext = NULL; 225 | szToken = strtok_s(szLine, " ", &szTokenContext); 226 | while((i < 3) && szToken) { 227 | v[i++] = strtoull(szToken, NULL, 16); 228 | szToken = strtok_s(NULL, " ", &szTokenContext); 229 | } 230 | if(!(v[0] & 0xfff) && (v[0] < v[1])) { 231 | if(!v[2]) { v[2] = v[0]; } 232 | LcMemMap_AddRange(ctxLC, v[0], v[1] + 1 - v[0], v[2]); 233 | } 234 | szLine = strtok_s(NULL, "\r\n", &szLineContext); 235 | } 236 | LocalFree(sz); 237 | return TRUE; 238 | } 239 | -------------------------------------------------------------------------------- /leechcore/ob/ob_bytequeue.c: -------------------------------------------------------------------------------- 1 | // ob_bytequeue.c : implementation of object manager byte queue. 2 | // 3 | // The byte queue contains a fixed number of bytes as buffer. The queue size 4 | // is defined at queue creation and cannot be changed. 5 | // 6 | // Bytes in the form of packets [pb, cb, tag] is pushed on the queue as long 7 | // as there is available space. 8 | // 9 | // Bytes may be popped from the queue. This will also free up space for more 10 | // bytes to be pushed on the queue. 11 | // 12 | // The bytes queue is FIFO and will always pop the oldest bytes first. 13 | // 14 | // The ObByteQueue is an object manager object and must be DECREF'ed when required. 15 | // 16 | // (c) Ulf Frisk, 2019-2025 17 | // Author: Ulf Frisk, pcileech@frizk.net 18 | // 19 | #include "ob.h" 20 | 21 | #define OB_BYTEQUEUE_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_BYTEQUEUE)) 22 | 23 | typedef struct tdOB_BYTEQUEUE { 24 | OB ObHdr; 25 | SRWLOCK LockSRW; 26 | DWORD cPackets; 27 | DWORD cboHead; 28 | DWORD cboTail; 29 | DWORD cb; 30 | BYTE pb[0]; 31 | } OB_BYTEQUEUE, *POB_BYTEQUEUE; 32 | 33 | typedef struct tdBYTEQUEUE_PACKET { 34 | QWORD qwTag; 35 | DWORD cboNext; 36 | DWORD cb; 37 | BYTE pb[0]; 38 | } BYTEQUEUE_PACKET, *PBYTEQUEUE_PACKET; 39 | 40 | #define OB_BYTEQUEUE_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, RetTp, RetValFail, fn) { \ 41 | if(!OB_BYTEQUEUE_IS_VALID(pm)) { return RetValFail; } \ 42 | RetTp retVal; \ 43 | AcquireSRWLockExclusive(&pm->LockSRW); \ 44 | retVal = fn; \ 45 | ReleaseSRWLockExclusive(&pm->LockSRW); \ 46 | return retVal; \ 47 | } 48 | 49 | #define OB_BYTEQUEUE_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, RetTp, RetValFail, fn) { \ 50 | if(!OB_BYTEQUEUE_IS_VALID(pm)) { return RetValFail; } \ 51 | RetTp retVal; \ 52 | AcquireSRWLockShared(&pm->LockSRW); \ 53 | retVal = fn; \ 54 | ReleaseSRWLockShared(&pm->LockSRW); \ 55 | return retVal; \ 56 | } 57 | 58 | 59 | 60 | //----------------------------------------------------------------------------- 61 | // IMPLEMENTATION BELOW: 62 | //----------------------------------------------------------------------------- 63 | 64 | _Success_(return) 65 | BOOL _ObByteQueue_Peek(_In_ POB_BYTEQUEUE pq, _Out_opt_ QWORD *pqwTag, _In_ SIZE_T cb, _Out_ PBYTE pb, _Out_ SIZE_T *pcbRead) 66 | { 67 | PBYTEQUEUE_PACKET p = (PBYTEQUEUE_PACKET)(pq->pb + pq->cboHead); 68 | if(!pq->cPackets) { 69 | *pcbRead = 0; 70 | return FALSE; 71 | } 72 | *pcbRead = p->cb; 73 | if(p->cb < cb) { 74 | return FALSE; 75 | } 76 | if(pqwTag) { 77 | *pqwTag = p->qwTag; 78 | } 79 | memcpy(pb, p->pb, p->cb); 80 | return TRUE; 81 | } 82 | 83 | _Success_(return) 84 | BOOL _ObByteQueue_Pop(_In_ POB_BYTEQUEUE pq, _Out_opt_ QWORD *pqwTag, _In_ SIZE_T cb, _Out_ PBYTE pb, _Out_ SIZE_T *pcbRead) 85 | { 86 | PBYTEQUEUE_PACKET p = (PBYTEQUEUE_PACKET)(pq->pb + pq->cboHead); 87 | if(!pq->cPackets) { 88 | *pcbRead = 0; 89 | return FALSE; 90 | } 91 | *pcbRead = p->cb; 92 | if(p->cb > cb) { 93 | return FALSE; 94 | } 95 | if(pqwTag) { 96 | *pqwTag = p->qwTag; 97 | } 98 | memcpy(pb, p->pb, p->cb); 99 | pq->cPackets--; 100 | if(!pq->cPackets) { 101 | pq->cboHead = 0; 102 | pq->cboTail = 0; 103 | } else { 104 | pq->cboHead = p->cboNext; 105 | } 106 | return TRUE; 107 | } 108 | 109 | _Success_(return) 110 | BOOL _ObByteQueue_Push(_In_ POB_BYTEQUEUE pq, _In_opt_ QWORD qwTag, _In_ SIZE_T cb, _In_reads_bytes_(cb) PBYTE pb) 111 | { 112 | PBYTEQUEUE_PACKET p; 113 | SIZE_T cboEoQ, cbEoQ, cbPkt = sizeof(BYTEQUEUE_PACKET) + cb; 114 | if(pq->cb < cbPkt) { 115 | return FALSE; 116 | } 117 | if(!pq->cPackets) { 118 | // 1st packet to be inserted at start-of-queue. 119 | p = (PBYTEQUEUE_PACKET)pq->pb; 120 | } else { 121 | // Nth packet to be inserted at end-of-queue. 122 | p = (PBYTEQUEUE_PACKET)(pq->pb + pq->cboTail); 123 | cboEoQ = pq->cboTail + sizeof(BYTEQUEUE_PACKET) + p->cb; 124 | cbEoQ = ((pq->cboHead < cboEoQ) ? pq->cb : pq->cboHead) - cboEoQ; 125 | if(cbEoQ >= cbPkt) { 126 | // Insert packet at next position in the circular buffer. 127 | p->cboNext = (DWORD)cboEoQ; 128 | p = (PBYTEQUEUE_PACKET)(pq->pb + p->cboNext); 129 | } else if((pq->cboTail > pq->cboHead) && (pq->cboHead >= cbPkt)) { 130 | // Insert packet at start of the circular buffer. 131 | p->cboNext = 0; 132 | p = (PBYTEQUEUE_PACKET)(pq->pb + p->cboNext); 133 | } else { 134 | // Not enough space. 135 | return FALSE; 136 | } 137 | } 138 | p->qwTag = qwTag; 139 | p->cb = (DWORD)cb; 140 | p->cboNext = 0; 141 | memcpy(p->pb, pb, cb); 142 | pq->cPackets++; 143 | pq->cboTail = (DWORD)((SIZE_T)p - (SIZE_T)pq->pb); 144 | return TRUE; 145 | } 146 | 147 | /* 148 | * Retrieve the number of packets (not bytes) in the byte queue. 149 | * -- pq 150 | * -- return 151 | */ 152 | DWORD ObByteQueue_Size(_In_opt_ POB_BYTEQUEUE pq) 153 | { 154 | OB_BYTEQUEUE_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pq, DWORD, 0, pq->cPackets) 155 | } 156 | 157 | /* 158 | * Peek data from the byte queue. The data is copied into the user-supplied buffer. 159 | * If the buffer is insufficient the function will return FALSE and the required 160 | * size will be returned in pcbRead. 161 | * -- pq 162 | * -- pqwTag 163 | * -- cb 164 | * -- pb 165 | * -- pcbRead 166 | * -- return = TRUE if there was data to peek, FALSE otherwise. 167 | */ 168 | _Success_(return) 169 | BOOL ObByteQueue_Peek(_In_opt_ POB_BYTEQUEUE pq, _Out_opt_ QWORD *pqwTag, _In_ SIZE_T cb, _Out_ PBYTE pb, _Out_ SIZE_T *pcbRead) 170 | { 171 | OB_BYTEQUEUE_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pq, BOOL, FALSE, _ObByteQueue_Peek(pq, pqwTag, cb, pb, pcbRead)) 172 | } 173 | 174 | /* 175 | * Pop data from the byte queue. The data is copied into the user-supplied buffer. 176 | * If the buffer is insufficient the function will return FALSE and the required 177 | * size will be returned in pcbRead. 178 | * -- pq 179 | * -- pqwTag 180 | * -- cb 181 | * -- pb 182 | * -- pcbRead 183 | * -- return = TRUE if there was data to pop, FALSE otherwise. 184 | */ 185 | _Success_(return) 186 | BOOL ObByteQueue_Pop(_In_opt_ POB_BYTEQUEUE pq, _Out_opt_ QWORD *pqwTag, _In_ SIZE_T cb, _Out_ PBYTE pb, _Out_ SIZE_T *pcbRead) 187 | { 188 | OB_BYTEQUEUE_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pq, BOOL, FALSE, _ObByteQueue_Pop(pq, pqwTag, cb, pb, pcbRead)) 189 | } 190 | 191 | /* 192 | * Push / Insert into the ObByteQueue. The data is copied into the queue. 193 | * -- pq 194 | * -- qwTag 195 | * -- cb 196 | * -- pb 197 | * -- return = TRUE on insertion, FALSE otherwise - i.e. if the byte queue 198 | * is insufficient to hold the byte data. 199 | */ 200 | _Success_(return) 201 | BOOL ObByteQueue_Push(_In_opt_ POB_BYTEQUEUE pq, _In_opt_ QWORD qwTag, _In_ SIZE_T cb, _In_reads_bytes_(cb) PBYTE pb) 202 | { 203 | OB_BYTEQUEUE_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pq, BOOL, FALSE, _ObByteQueue_Push(pq, qwTag, cb, pb)) 204 | } 205 | 206 | /* 207 | * Create a new byte queue. A byte queue (ObByteQueue) provides atomic queuing 208 | * operations for pushing/popping bytes as packets on a FIFO queue. 209 | * The ObByteQueue is an object manager object and must be DECREF'ed when required. 210 | * CALLER DECREF: return 211 | * -- H 212 | * -- cbQueueSize = the queue size in bytes. Must be larger than 4096 bytes. 213 | * -- return 214 | */ 215 | POB_BYTEQUEUE ObByteQueue_New(_In_opt_ VMM_HANDLE H, _In_ DWORD cbQueueSize) 216 | { 217 | POB_BYTEQUEUE pObQ; 218 | if(cbQueueSize < 0x1000) { return NULL; } 219 | pObQ = Ob_AllocEx(H, OB_TAG_CORE_BYTEQUEUE, LMEM_ZEROINIT, sizeof(POB_BYTEQUEUE) + cbQueueSize, NULL, NULL); 220 | if(!pObQ) { return NULL; } 221 | InitializeSRWLock(&pObQ->LockSRW); 222 | pObQ->cb = cbQueueSize; 223 | return pObQ; 224 | } 225 | -------------------------------------------------------------------------------- /leechcorepyc/leechcorepyc_barrequest.c: -------------------------------------------------------------------------------- 1 | // leechcorepyc_barrequest.c : implementation of LeechCore PCIe BAR request. 2 | // 3 | // (c) Ulf Frisk, 2024-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | 7 | #include "leechcorepyc.h" 8 | 9 | PyObject *g_pPyType_BarRequest = NULL; 10 | 11 | // (PBYTE) -> None 12 | static PyObject* 13 | LcPy_BarRequest_Reply(PyObj_BarRequest *self, PyObject *args) 14 | { 15 | PBYTE pb; 16 | Py_ssize_t cb; 17 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.reply(): Not initialized."); } 18 | if(!self->pReq->fRead) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.reply(): Only possible to reply to read requests."); } 19 | if(!PyArg_ParseTuple(args, "y#", &pb, &cb)) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.reply(): Illegal argument."); } 20 | if(cb != self->pReq->cbData) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.reply(): Provided length (%i) does not match required (%i) length.", cb, self->pReq->cbData); } 21 | memcpy(self->pReq->pbData, pb, cb); 22 | self->pReq->fReadReply = TRUE; 23 | Py_RETURN_NONE; 24 | } 25 | 26 | // () -> None 27 | static PyObject* 28 | LcPy_BarRequest_ReplyFail(PyObj_BarRequest *self, PyObject *args) 29 | { 30 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.reply_fail(): Not initialized."); } 31 | if(!self->pReq->fRead) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.reply_fail(): Only possible to reply to read requests."); } 32 | self->pReq->fReadReply = TRUE; 33 | self->pReq->cbData = 0; 34 | Py_RETURN_NONE; 35 | } 36 | 37 | // -> int 38 | static PyObject* 39 | LcPy_BarRequest_IBar(PyObj_BarRequest *self, PyObject *args) 40 | { 41 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.i_bar: Not initialized."); } 42 | return PyLong_FromLong((long)self->pReq->pBar->iBar); 43 | } 44 | 45 | // -> {} 46 | static PyObject* 47 | LcPy_BarRequest_Bar(PyObj_BarRequest *self, PyObject *args) 48 | { 49 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.bar: Not initialized."); } 50 | if(!self->pyLC->pyBarDictSingle[self->pReq->pBar->iBar]) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.bar: Fail."); } 51 | Py_IncRef(self->pyLC->pyBarDictSingle[self->pReq->pBar->iBar]); 52 | return self->pyLC->pyBarDictSingle[self->pReq->pBar->iBar]; 53 | } 54 | 55 | // -> int 56 | static PyObject* 57 | LcPy_BarRequest_BeFirst(PyObj_BarRequest *self, PyObject *args) 58 | { 59 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.be_first: Not initialized."); } 60 | return PyLong_FromLong((long)self->pReq->bFirstBE); 61 | } 62 | 63 | // -> int 64 | static PyObject* 65 | LcPy_BarRequest_BeLast(PyObj_BarRequest *self, PyObject *args) 66 | { 67 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.be_last: Not initialized."); } 68 | return PyLong_FromLong((long)self->pReq->bLastBE); 69 | } 70 | 71 | // -> int 72 | static PyObject* 73 | LcPy_BarRequest_Tag(PyObj_BarRequest *self, PyObject *args) 74 | { 75 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.tag: Not initialized."); } 76 | return PyLong_FromLong((long)self->pReq->bTag); 77 | } 78 | 79 | // -> bool 80 | static PyObject* 81 | LcPy_BarRequest_IsRead(PyObj_BarRequest *self, PyObject *args) 82 | { 83 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.is_read: Not initialized."); } 84 | return PyBool_FromLong((long)self->pReq->fRead); 85 | } 86 | 87 | // -> bool 88 | static PyObject* 89 | LcPy_BarRequest_IsWrite(PyObj_BarRequest *self, PyObject *args) 90 | { 91 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.is_write: Not initialized."); } 92 | return PyBool_FromLong((long)self->pReq->fWrite); 93 | } 94 | 95 | // -> int 96 | static PyObject* 97 | LcPy_BarRequest_DataOffset(PyObj_BarRequest *self, PyObject *args) 98 | { 99 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.data_offset: Not initialized."); } 100 | return PyLong_FromLongLong(self->pReq->oData); 101 | } 102 | 103 | // -> int 104 | static PyObject* 105 | LcPy_BarRequest_DataLength(PyObj_BarRequest *self, PyObject *args) 106 | { 107 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.data_length: Not initialized."); } 108 | return PyLong_FromLong(self->pReq->cbData); 109 | } 110 | 111 | // -> bytes 112 | static PyObject* 113 | LcPy_BarRequest_DataWrite(PyObj_BarRequest *self, PyObject *args) 114 | { 115 | if(!self->fValid) { return PyErr_Format(PyExc_RuntimeError, "LcBarRequest.data_write: Not initialized."); } 116 | if(!self->pReq->fWrite) { 117 | Py_RETURN_NONE; 118 | } 119 | return PyBytes_FromStringAndSize((const char*)self->pReq->pbData, (Py_ssize_t)self->pReq->cbData); 120 | } 121 | 122 | 123 | 124 | //----------------------------------------------------------------------------- 125 | // LcPy_BarRequest INITIALIZATION AND CORE FUNCTIONALITY BELOW: 126 | //----------------------------------------------------------------------------- 127 | 128 | PyObj_BarRequest* 129 | LcPy_BarRequest_InitializeInternal(_In_ PyObj_LeechCore *pyLC, _In_ PLC_BAR_REQUEST pReq) 130 | { 131 | PyObj_BarRequest *pyObjBarRequest; 132 | if(!(pyObjBarRequest = PyObject_New(PyObj_BarRequest, (PyTypeObject*)g_pPyType_BarRequest))) { return NULL; } 133 | Py_INCREF(pyLC); pyObjBarRequest->pyLC = pyLC; 134 | pyObjBarRequest->pReq = pReq; 135 | pyObjBarRequest->fValid = TRUE; 136 | return pyObjBarRequest; 137 | } 138 | 139 | static PyObject* 140 | LcPy_BarRequest_repr(PyObj_BarRequest *self) 141 | { 142 | if(!self->fValid) { 143 | return PyUnicode_FromFormat("LcBarRequest:NotValid"); 144 | } 145 | return PyUnicode_FromFormat("LcBarRequest:%i:%s:%x:%x", 146 | self->pReq->pBar->iBar, 147 | (self->pReq->fRead ? "Read" : "Write"), 148 | self->pReq->oData, 149 | self->pReq->cbData 150 | ); 151 | } 152 | 153 | static int 154 | LcPy_BarRequest_init(PyObj_BarRequest *self, PyObject *args, PyObject *kwds) 155 | { 156 | PyErr_SetString(PyExc_TypeError, "LcBarRequest.init(): Not allowed."); 157 | return -1; 158 | } 159 | 160 | static void 161 | LcPy_BarRequest_dealloc(PyObj_BarRequest *self) 162 | { 163 | self->fValid = FALSE; 164 | Py_XDECREF(self->pyLC); 165 | PyObject_Del(self); 166 | } 167 | 168 | _Success_(return) 169 | BOOL LcPy_BarRequest_InitializeType(PyObject *pModule) 170 | { 171 | static PyMethodDef PyMethods[] = { 172 | {"reply", (PyCFunction)LcPy_BarRequest_Reply, METH_VARARGS, "Reply to a read request."}, 173 | {"reply_fail", (PyCFunction)LcPy_BarRequest_ReplyFail, METH_VARARGS, "Reply fail/unsupported to a read request."}, 174 | {NULL, NULL, 0, NULL} 175 | }; 176 | static PyMemberDef PyMembers[] = { 177 | {NULL} 178 | }; 179 | static PyGetSetDef PyGetSet[] = { 180 | {"i_bar", (getter)LcPy_BarRequest_IBar, (setter)NULL, "BAR index.", NULL}, 181 | {"bar", (getter)LcPy_BarRequest_Bar, (setter)NULL, "PCIe BAR information.", NULL}, 182 | {"be_first", (getter)LcPy_BarRequest_BeFirst, (setter)NULL, "First byte enable.", NULL}, 183 | {"be_last", (getter)LcPy_BarRequest_BeLast, (setter)NULL, "Last byte enable.", NULL}, 184 | {"data_offset", (getter)LcPy_BarRequest_DataOffset, (setter)NULL, "Offset of data within BAR.", NULL}, 185 | {"data_length", (getter)LcPy_BarRequest_DataLength, (setter)NULL, "Length of data to read/write.", NULL}, 186 | {"data_write", (getter)LcPy_BarRequest_DataWrite, (setter)NULL, "Data to write (also check byte enables).", NULL}, 187 | {"is_read", (getter)LcPy_BarRequest_IsRead, (setter)NULL, "Is a read request (that should be replied to).", NULL}, 188 | {"is_write", (getter)LcPy_BarRequest_IsWrite, (setter)NULL, "Is a write request.", NULL}, 189 | {"tag", (getter)LcPy_BarRequest_Tag, (setter)NULL, "PCIe TLP tag.", NULL}, 190 | {NULL} 191 | }; 192 | static PyType_Slot PyTypeSlot[] = { 193 | {Py_tp_init, LcPy_BarRequest_init}, 194 | {Py_tp_dealloc, LcPy_BarRequest_dealloc}, 195 | {Py_tp_repr, LcPy_BarRequest_repr}, 196 | {Py_tp_methods, PyMethods}, 197 | {Py_tp_members, PyMembers}, 198 | {Py_tp_getset, PyGetSet}, 199 | {0, 0} 200 | }; 201 | static PyType_Spec PyTypeSpec = { 202 | .name = "leechcorepyc.LcBarRequest", 203 | .basicsize = sizeof(PyObj_BarRequest), 204 | .itemsize = 0, 205 | .flags = Py_TPFLAGS_DEFAULT, 206 | .slots = PyTypeSlot, 207 | }; 208 | if((g_pPyType_BarRequest = PyType_FromSpec(&PyTypeSpec))) { 209 | if(PyModule_AddObject(pModule, "LcBarRequest", g_pPyType_BarRequest) < 0) { 210 | Py_DECREF(g_pPyType_BarRequest); 211 | g_pPyType_BarRequest = NULL; 212 | } 213 | } 214 | return g_pPyType_BarRequest ? TRUE : FALSE; 215 | } 216 | -------------------------------------------------------------------------------- /leechagent/leechrpcshared.c: -------------------------------------------------------------------------------- 1 | // leechrpcshared.c : implementation of the remote procedure call (RPC) shared functionality (client/server). 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #include 7 | #include "leechrpc.h" 8 | 9 | #ifdef _WIN32 10 | 11 | //----------------------------------------------------------------------------- 12 | // MIDL ALLOCATE AND FREE: 13 | //----------------------------------------------------------------------------- 14 | 15 | _Must_inspect_result_ 16 | _Ret_maybenull_ _Post_writable_byte_size_(size) 17 | void * __RPC_USER MIDL_user_allocate(_In_ size_t size) 18 | { 19 | return LocalAlloc(0, size); 20 | } 21 | 22 | void __RPC_USER MIDL_user_free(_Pre_maybenull_ _Post_invalid_ void* ptr) 23 | { 24 | LocalFree(ptr); 25 | } 26 | 27 | //----------------------------------------------------------------------------- 28 | // COMPRESSION FUNCTIONALITY BELOW: 29 | //----------------------------------------------------------------------------- 30 | 31 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth 32 | #define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS)0x00000117L) 33 | 34 | VOID LeechRPC_CompressClose(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 35 | { 36 | DWORD i; 37 | for(i = 0; i < LEECHRPC_COMPRESS_MAXTHREADS; i++) { 38 | if(ctxCompress->fValid) { 39 | DeleteCriticalSection(&ctxCompress->Compress[i].Lock); 40 | LocalFree(ctxCompress->Compress[i].pbWorkspace); 41 | } 42 | } 43 | if(ctxCompress->hDll) { FreeLibrary(ctxCompress->hDll); } 44 | ZeroMemory(ctxCompress, sizeof(LEECHRPC_COMPRESS)); 45 | } 46 | 47 | BOOL LeechRPC_CompressInitialize(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 48 | { 49 | DWORD i; 50 | LeechRPC_CompressClose(ctxCompress); 51 | ctxCompress->hDll = LoadLibraryA("ntdll.dll"); 52 | if(!ctxCompress->hDll) { return FALSE; } 53 | if(!(ctxCompress->fn.pfnRtlCompressBuffer = (PFN_RtlCompressBuffer*)GetProcAddress(ctxCompress->hDll, "RtlCompressBuffer"))) { goto fail; } 54 | if(!(ctxCompress->fn.pfnRtlDecompressBuffer = (PFN_RtlDecompressBuffer*)GetProcAddress(ctxCompress->hDll, "RtlDecompressBuffer"))) { goto fail; } 55 | ctxCompress->fValid = TRUE; 56 | for(i = 0; i < LEECHRPC_COMPRESS_MAXTHREADS; i++) { 57 | InitializeCriticalSection(&ctxCompress->Compress[i].Lock); 58 | ctxCompress->fValid = ctxCompress->fValid && (ctxCompress->Compress[i].pbWorkspace = LocalAlloc(0, 0x00100000)); 59 | } 60 | // fall-through 61 | fail: 62 | if(!ctxCompress->fValid) { 63 | LeechRPC_CompressClose(ctxCompress); 64 | } 65 | return ctxCompress->fValid; 66 | } 67 | 68 | VOID LeechRPC_Compress(_In_ PLEECHRPC_COMPRESS ctxCompress, _Inout_ PLEECHRPC_MSG_BIN pMsg, _In_ BOOL fCompressDisable) 69 | { 70 | NTSTATUS nt; 71 | PBYTE pb; 72 | ULONG cb; 73 | DWORD i; 74 | if(ctxCompress->fValid && (pMsg->cb > 0x1800) && !fCompressDisable) { 75 | if(!(pb = LocalAlloc(0, pMsg->cb))) { return; } 76 | do { 77 | i = InterlockedIncrement(&ctxCompress->iCompress) % LEECHRPC_COMPRESS_MAXTHREADS; 78 | } while(!TryEnterCriticalSection(&ctxCompress->Compress[i].Lock)); 79 | nt = ctxCompress->fn.pfnRtlCompressBuffer(COMPRESSION_FORMAT_XPRESS, pMsg->pb, pMsg->cb, pb, pMsg->cb, 4096, &cb, ctxCompress->Compress[i].pbWorkspace); 80 | LeaveCriticalSection(&ctxCompress->Compress[i].Lock); 81 | if(((nt == STATUS_SUCCESS) || (nt == STATUS_BUFFER_ALL_ZEROS)) && (cb <= pMsg->cb)) { 82 | memcpy(pMsg->pb, pb, cb); 83 | pMsg->cbDecompress = pMsg->cb; 84 | pMsg->cb = (DWORD)cb; 85 | pMsg->cbMsg = sizeof(LEECHRPC_MSG_BIN) + (DWORD)cb; 86 | } 87 | LocalFree(pb); 88 | } 89 | } 90 | 91 | _Success_(return) 92 | BOOL LeechRPC_Decompress(_In_ PLEECHRPC_COMPRESS ctxCompress, _In_ PLEECHRPC_MSG_BIN pMsgIn, _Out_ PLEECHRPC_MSG_BIN *ppMsgOut) 93 | { 94 | NTSTATUS nt; 95 | ULONG cb; 96 | PLEECHRPC_MSG_BIN pMsgOut = NULL; 97 | *ppMsgOut = NULL; 98 | if(!pMsgIn->cbDecompress) { return FALSE; } 99 | if(!ctxCompress->fValid || (pMsgIn->cbDecompress > 0x04000000)) { return FALSE; } 100 | if(!(pMsgOut = (PLEECHRPC_MSG_BIN)LocalAlloc(0, sizeof(LEECHRPC_MSG_BIN) + pMsgIn->cbDecompress))) { return FALSE; } 101 | memcpy(pMsgOut, pMsgIn, sizeof(LEECHRPC_MSG_BIN)); 102 | nt = ctxCompress->fn.pfnRtlDecompressBuffer(COMPRESSION_FORMAT_XPRESS, pMsgOut->pb, pMsgOut->cbDecompress, pMsgIn->pb, pMsgIn->cb, &cb); 103 | if((nt != STATUS_SUCCESS) || (cb != pMsgIn->cbDecompress)) { 104 | LocalFree(pMsgOut); 105 | return FALSE; 106 | } 107 | pMsgOut->cb = (DWORD)cb; 108 | pMsgOut->cbMsg = sizeof(LEECHRPC_MSG_BIN) + pMsgOut->cb; 109 | pMsgOut->cbDecompress = 0; 110 | *ppMsgOut = pMsgOut; 111 | return TRUE; 112 | } 113 | 114 | //----------------------------------------------------------------------------- 115 | // GENERAL FUNCTIONALITY BELOW: 116 | //----------------------------------------------------------------------------- 117 | 118 | VOID LeechSvc_GetTimeStamp(_Out_writes_(32) LPSTR szTime) 119 | { 120 | SYSTEMTIME time; 121 | GetLocalTime(&time); 122 | sprintf_s( 123 | szTime, 124 | 32, 125 | "%04i-%02i-%02i %02i:%02i:%02i", 126 | time.wYear, 127 | time.wMonth, 128 | time.wDay, 129 | time.wHour, 130 | time.wMinute, 131 | time.wSecond 132 | ); 133 | } 134 | 135 | #endif /* _WIN32 */ 136 | #if defined(LINUX) || defined(MACOS) 137 | 138 | #include "oscompatibility.h" 139 | 140 | //----------------------------------------------------------------------------- 141 | // COMPRESSION FUNCTIONALITY BELOW: 142 | //----------------------------------------------------------------------------- 143 | 144 | VOID LeechRPC_CompressClose(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 145 | { 146 | if(ctxCompress->lib_mscompress) { 147 | dlclose(ctxCompress->lib_mscompress); 148 | ZeroMemory(ctxCompress, sizeof(LEECHRPC_COMPRESS)); 149 | } 150 | } 151 | 152 | BOOL LeechRPC_CompressInitialize(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 153 | { 154 | CHAR szPathLib[MAX_PATH] = { 0 }; 155 | if(!ctxCompress->fValid) { 156 | Util_GetPathLib(szPathLib); 157 | strncat_s(szPathLib, sizeof(szPathLib), "libMSCompression"LC_LIBRARY_FILETYPE, _TRUNCATE); 158 | ctxCompress->lib_mscompress = dlopen(szPathLib, RTLD_NOW); 159 | if(ctxCompress->lib_mscompress) { 160 | ctxCompress->pfn_xpress_compress = (pfn_xpress_decompress)dlsym(ctxCompress->lib_mscompress, "xpress_compress"); 161 | ctxCompress->pfn_xpress_decompress = (pfn_xpress_decompress)dlsym(ctxCompress->lib_mscompress, "xpress_decompress"); 162 | ctxCompress->fValid = ctxCompress->pfn_xpress_compress && ctxCompress->pfn_xpress_decompress; 163 | } 164 | } 165 | return ctxCompress->fValid; 166 | } 167 | 168 | VOID LeechRPC_Compress(_In_ PLEECHRPC_COMPRESS ctxCompress, _Inout_ PLEECHRPC_MSG_BIN pMsg, _In_ BOOL fCompressDisable) 169 | { 170 | int rc; 171 | PBYTE pb; 172 | SIZE_T cb; 173 | DWORD i; 174 | if(ctxCompress->fValid && (pMsg->cb > 0x1800) && !fCompressDisable) { 175 | if(!(pb = LocalAlloc(0, pMsg->cb))) { return; } 176 | cb = pMsg->cb; 177 | rc = ctxCompress->pfn_xpress_compress(pMsg->pb, pMsg->cb, pb, &cb); 178 | if((rc >= 0) && (cb <= pMsg->cb)) { 179 | memcpy(pMsg->pb, pb, cb); 180 | pMsg->cbDecompress = pMsg->cb; 181 | pMsg->cb = (DWORD)cb; 182 | pMsg->cbMsg = sizeof(LEECHRPC_MSG_BIN) + (DWORD)cb; 183 | } 184 | LocalFree(pb); 185 | } 186 | } 187 | 188 | _Success_(return) 189 | BOOL LeechRPC_Decompress(_In_ PLEECHRPC_COMPRESS ctxCompress, _In_ PLEECHRPC_MSG_BIN pMsgIn, _Out_ PLEECHRPC_MSG_BIN * ppMsgOut) 190 | { 191 | int rc; 192 | DWORD i; 193 | SIZE_T cb; 194 | PLEECHRPC_MSG_BIN pMsgOut = NULL; 195 | *ppMsgOut = NULL; 196 | if(!pMsgIn->cbDecompress) { return FALSE; } 197 | if(!ctxCompress->fValid || (pMsgIn->cbDecompress > 0x04000000)) { return FALSE; } 198 | if(!(pMsgOut = (PLEECHRPC_MSG_BIN)LocalAlloc(0, sizeof(LEECHRPC_MSG_BIN) + pMsgIn->cbDecompress))) { return FALSE; } 199 | memcpy(pMsgOut, pMsgIn, sizeof(LEECHRPC_MSG_BIN)); 200 | cb = pMsgOut->cbDecompress; 201 | rc = ctxCompress->pfn_xpress_decompress(pMsgIn->pb, (SIZE_T)pMsgIn->cb, pMsgOut->pb, &cb); 202 | if((rc < 0) || (cb != pMsgIn->cbDecompress)) { 203 | LocalFree(pMsgOut); 204 | return FALSE; 205 | } 206 | pMsgOut->cb = (DWORD)cb; 207 | pMsgOut->cbMsg = sizeof(LEECHRPC_MSG_BIN) + pMsgOut->cb; 208 | pMsgOut->cbDecompress = 0; 209 | *ppMsgOut = pMsgOut; 210 | return TRUE; 211 | } 212 | 213 | //----------------------------------------------------------------------------- 214 | // GENERAL FUNCTIONALITY BELOW: 215 | //----------------------------------------------------------------------------- 216 | 217 | VOID LeechSvc_GetTimeStamp(_Out_writes_(32) LPSTR szTime) 218 | { 219 | struct tm localTime; 220 | time_t now = time(NULL); 221 | localtime_r(&now, &localTime); 222 | snprintf(szTime, 32, "%04i-%02i-%02i %02i:%02i:%02i", 223 | localTime.tm_year + 1900, 224 | localTime.tm_mon + 1, 225 | localTime.tm_mday, 226 | localTime.tm_hour, 227 | localTime.tm_min, 228 | localTime.tm_sec); 229 | } 230 | 231 | #endif /* LINUX || MACOS */ 232 | -------------------------------------------------------------------------------- /leechcore/leechrpcshared.c: -------------------------------------------------------------------------------- 1 | // leechrpcshared.c : implementation of the remote procedure call (RPC) shared functionality (client/server). 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #include 7 | #include "leechrpc.h" 8 | 9 | #ifdef _WIN32 10 | 11 | //----------------------------------------------------------------------------- 12 | // MIDL ALLOCATE AND FREE: 13 | //----------------------------------------------------------------------------- 14 | 15 | _Must_inspect_result_ 16 | _Ret_maybenull_ _Post_writable_byte_size_(size) 17 | void * __RPC_USER MIDL_user_allocate(_In_ size_t size) 18 | { 19 | return LocalAlloc(0, size); 20 | } 21 | 22 | void __RPC_USER MIDL_user_free(_Pre_maybenull_ _Post_invalid_ void* ptr) 23 | { 24 | LocalFree(ptr); 25 | } 26 | 27 | //----------------------------------------------------------------------------- 28 | // COMPRESSION FUNCTIONALITY BELOW: 29 | //----------------------------------------------------------------------------- 30 | 31 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth 32 | #define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS)0x00000117L) 33 | 34 | VOID LeechRPC_CompressClose(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 35 | { 36 | DWORD i; 37 | for(i = 0; i < LEECHRPC_COMPRESS_MAXTHREADS; i++) { 38 | if(ctxCompress->fValid) { 39 | DeleteCriticalSection(&ctxCompress->Compress[i].Lock); 40 | LocalFree(ctxCompress->Compress[i].pbWorkspace); 41 | } 42 | } 43 | if(ctxCompress->hDll) { FreeLibrary(ctxCompress->hDll); } 44 | ZeroMemory(ctxCompress, sizeof(LEECHRPC_COMPRESS)); 45 | } 46 | 47 | BOOL LeechRPC_CompressInitialize(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 48 | { 49 | DWORD i; 50 | LeechRPC_CompressClose(ctxCompress); 51 | ctxCompress->hDll = LoadLibraryA("ntdll.dll"); 52 | if(!ctxCompress->hDll) { return FALSE; } 53 | if(!(ctxCompress->fn.pfnRtlCompressBuffer = (PFN_RtlCompressBuffer*)GetProcAddress(ctxCompress->hDll, "RtlCompressBuffer"))) { goto fail; } 54 | if(!(ctxCompress->fn.pfnRtlDecompressBuffer = (PFN_RtlDecompressBuffer*)GetProcAddress(ctxCompress->hDll, "RtlDecompressBuffer"))) { goto fail; } 55 | ctxCompress->fValid = TRUE; 56 | for(i = 0; i < LEECHRPC_COMPRESS_MAXTHREADS; i++) { 57 | InitializeCriticalSection(&ctxCompress->Compress[i].Lock); 58 | ctxCompress->fValid = ctxCompress->fValid && (ctxCompress->Compress[i].pbWorkspace = LocalAlloc(0, 0x00100000)); 59 | } 60 | // fall-through 61 | fail: 62 | if(!ctxCompress->fValid) { 63 | LeechRPC_CompressClose(ctxCompress); 64 | } 65 | return ctxCompress->fValid; 66 | } 67 | 68 | VOID LeechRPC_Compress(_In_ PLEECHRPC_COMPRESS ctxCompress, _Inout_ PLEECHRPC_MSG_BIN pMsg, _In_ BOOL fCompressDisable) 69 | { 70 | NTSTATUS nt; 71 | PBYTE pb; 72 | ULONG cb; 73 | DWORD i; 74 | if(ctxCompress->fValid && (pMsg->cb > 0x1800) && !fCompressDisable) { 75 | if(!(pb = LocalAlloc(0, pMsg->cb))) { return; } 76 | do { 77 | i = InterlockedIncrement(&ctxCompress->iCompress) % LEECHRPC_COMPRESS_MAXTHREADS; 78 | } while(!TryEnterCriticalSection(&ctxCompress->Compress[i].Lock)); 79 | nt = ctxCompress->fn.pfnRtlCompressBuffer(COMPRESSION_FORMAT_XPRESS, pMsg->pb, pMsg->cb, pb, pMsg->cb, 4096, &cb, ctxCompress->Compress[i].pbWorkspace); 80 | LeaveCriticalSection(&ctxCompress->Compress[i].Lock); 81 | if(((nt == STATUS_SUCCESS) || (nt == STATUS_BUFFER_ALL_ZEROS)) && (cb <= pMsg->cb)) { 82 | memcpy(pMsg->pb, pb, cb); 83 | pMsg->cbDecompress = pMsg->cb; 84 | pMsg->cb = (DWORD)cb; 85 | pMsg->cbMsg = sizeof(LEECHRPC_MSG_BIN) + (DWORD)cb; 86 | } 87 | LocalFree(pb); 88 | } 89 | } 90 | 91 | _Success_(return) 92 | BOOL LeechRPC_Decompress(_In_ PLEECHRPC_COMPRESS ctxCompress, _In_ PLEECHRPC_MSG_BIN pMsgIn, _Out_ PLEECHRPC_MSG_BIN *ppMsgOut) 93 | { 94 | NTSTATUS nt; 95 | ULONG cb; 96 | PLEECHRPC_MSG_BIN pMsgOut = NULL; 97 | *ppMsgOut = NULL; 98 | if(!pMsgIn->cbDecompress) { return FALSE; } 99 | if(!ctxCompress->fValid || (pMsgIn->cbDecompress > 0x04000000)) { return FALSE; } 100 | if(!(pMsgOut = (PLEECHRPC_MSG_BIN)LocalAlloc(0, sizeof(LEECHRPC_MSG_BIN) + pMsgIn->cbDecompress))) { return FALSE; } 101 | memcpy(pMsgOut, pMsgIn, sizeof(LEECHRPC_MSG_BIN)); 102 | nt = ctxCompress->fn.pfnRtlDecompressBuffer(COMPRESSION_FORMAT_XPRESS, pMsgOut->pb, pMsgOut->cbDecompress, pMsgIn->pb, pMsgIn->cb, &cb); 103 | if((nt != STATUS_SUCCESS) || (cb != pMsgIn->cbDecompress)) { 104 | LocalFree(pMsgOut); 105 | return FALSE; 106 | } 107 | pMsgOut->cb = (DWORD)cb; 108 | pMsgOut->cbMsg = sizeof(LEECHRPC_MSG_BIN) + pMsgOut->cb; 109 | pMsgOut->cbDecompress = 0; 110 | *ppMsgOut = pMsgOut; 111 | return TRUE; 112 | } 113 | 114 | //----------------------------------------------------------------------------- 115 | // GENERAL FUNCTIONALITY BELOW: 116 | //----------------------------------------------------------------------------- 117 | 118 | VOID LeechSvc_GetTimeStamp(_Out_writes_(32) LPSTR szTime) 119 | { 120 | SYSTEMTIME time; 121 | GetLocalTime(&time); 122 | sprintf_s( 123 | szTime, 124 | 32, 125 | "%04i-%02i-%02i %02i:%02i:%02i", 126 | time.wYear, 127 | time.wMonth, 128 | time.wDay, 129 | time.wHour, 130 | time.wMinute, 131 | time.wSecond 132 | ); 133 | } 134 | 135 | #endif /* _WIN32 */ 136 | #if defined(LINUX) || defined(MACOS) 137 | 138 | #include "oscompatibility.h" 139 | 140 | //----------------------------------------------------------------------------- 141 | // COMPRESSION FUNCTIONALITY BELOW: 142 | //----------------------------------------------------------------------------- 143 | 144 | VOID LeechRPC_CompressClose(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 145 | { 146 | if(ctxCompress->lib_mscompress) { 147 | dlclose(ctxCompress->lib_mscompress); 148 | ZeroMemory(ctxCompress, sizeof(LEECHRPC_COMPRESS)); 149 | } 150 | } 151 | 152 | BOOL LeechRPC_CompressInitialize(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 153 | { 154 | CHAR szPathLib[MAX_PATH] = { 0 }; 155 | if(!ctxCompress->fValid) { 156 | Util_GetPathLib(szPathLib); 157 | strncat_s(szPathLib, sizeof(szPathLib), "libMSCompression"LC_LIBRARY_FILETYPE, _TRUNCATE); 158 | ctxCompress->lib_mscompress = dlopen(szPathLib, RTLD_NOW); 159 | if(ctxCompress->lib_mscompress) { 160 | ctxCompress->pfn_xpress_compress = (pfn_xpress_decompress)dlsym(ctxCompress->lib_mscompress, "xpress_compress"); 161 | ctxCompress->pfn_xpress_decompress = (pfn_xpress_decompress)dlsym(ctxCompress->lib_mscompress, "xpress_decompress"); 162 | ctxCompress->fValid = ctxCompress->pfn_xpress_compress && ctxCompress->pfn_xpress_decompress; 163 | } 164 | } 165 | return ctxCompress->fValid; 166 | } 167 | 168 | VOID LeechRPC_Compress(_In_ PLEECHRPC_COMPRESS ctxCompress, _Inout_ PLEECHRPC_MSG_BIN pMsg, _In_ BOOL fCompressDisable) 169 | { 170 | int rc; 171 | PBYTE pb; 172 | SIZE_T cb; 173 | DWORD i; 174 | if(ctxCompress->fValid && (pMsg->cb > 0x1800) && !fCompressDisable) { 175 | if(!(pb = LocalAlloc(0, pMsg->cb))) { return; } 176 | cb = pMsg->cb; 177 | rc = ctxCompress->pfn_xpress_compress(pMsg->pb, pMsg->cb, pb, &cb); 178 | if((rc >= 0) && (cb <= pMsg->cb)) { 179 | memcpy(pMsg->pb, pb, cb); 180 | pMsg->cbDecompress = pMsg->cb; 181 | pMsg->cb = (DWORD)cb; 182 | pMsg->cbMsg = sizeof(LEECHRPC_MSG_BIN) + (DWORD)cb; 183 | } 184 | LocalFree(pb); 185 | } 186 | } 187 | 188 | _Success_(return) 189 | BOOL LeechRPC_Decompress(_In_ PLEECHRPC_COMPRESS ctxCompress, _In_ PLEECHRPC_MSG_BIN pMsgIn, _Out_ PLEECHRPC_MSG_BIN * ppMsgOut) 190 | { 191 | int rc; 192 | DWORD i; 193 | SIZE_T cb; 194 | PLEECHRPC_MSG_BIN pMsgOut = NULL; 195 | *ppMsgOut = NULL; 196 | if(!pMsgIn->cbDecompress) { return FALSE; } 197 | if(!ctxCompress->fValid || (pMsgIn->cbDecompress > 0x04000000)) { return FALSE; } 198 | if(!(pMsgOut = (PLEECHRPC_MSG_BIN)LocalAlloc(0, sizeof(LEECHRPC_MSG_BIN) + pMsgIn->cbDecompress))) { return FALSE; } 199 | memcpy(pMsgOut, pMsgIn, sizeof(LEECHRPC_MSG_BIN)); 200 | cb = pMsgOut->cbDecompress; 201 | rc = ctxCompress->pfn_xpress_decompress(pMsgIn->pb, (SIZE_T)pMsgIn->cb, pMsgOut->pb, &cb); 202 | if((rc < 0) || (cb != pMsgIn->cbDecompress)) { 203 | LocalFree(pMsgOut); 204 | return FALSE; 205 | } 206 | pMsgOut->cb = (DWORD)cb; 207 | pMsgOut->cbMsg = sizeof(LEECHRPC_MSG_BIN) + pMsgOut->cb; 208 | pMsgOut->cbDecompress = 0; 209 | *ppMsgOut = pMsgOut; 210 | return TRUE; 211 | } 212 | 213 | //----------------------------------------------------------------------------- 214 | // GENERAL FUNCTIONALITY BELOW: 215 | //----------------------------------------------------------------------------- 216 | 217 | VOID LeechSvc_GetTimeStamp(_Out_writes_(32) LPSTR szTime) 218 | { 219 | struct tm localTime; 220 | time_t now = time(NULL); 221 | localtime_r(&now, &localTime); 222 | snprintf(szTime, 32, "%04i-%02i-%02i %02i:%02i:%02i", 223 | localTime.tm_year + 1900, 224 | localTime.tm_mon + 1, 225 | localTime.tm_mday, 226 | localTime.tm_hour, 227 | localTime.tm_min, 228 | localTime.tm_sec); 229 | } 230 | 231 | #endif /* LINUX || MACOS */ 232 | -------------------------------------------------------------------------------- /leechagent_linux/leechrpcshared.c: -------------------------------------------------------------------------------- 1 | // leechrpcshared.c : implementation of the remote procedure call (RPC) shared functionality (client/server). 2 | // 3 | // (c) Ulf Frisk, 2018-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #include 7 | #include "leechrpc.h" 8 | 9 | #ifdef _WIN32 10 | 11 | //----------------------------------------------------------------------------- 12 | // MIDL ALLOCATE AND FREE: 13 | //----------------------------------------------------------------------------- 14 | 15 | _Must_inspect_result_ 16 | _Ret_maybenull_ _Post_writable_byte_size_(size) 17 | void * __RPC_USER MIDL_user_allocate(_In_ size_t size) 18 | { 19 | return LocalAlloc(0, size); 20 | } 21 | 22 | void __RPC_USER MIDL_user_free(_Pre_maybenull_ _Post_invalid_ void* ptr) 23 | { 24 | LocalFree(ptr); 25 | } 26 | 27 | //----------------------------------------------------------------------------- 28 | // COMPRESSION FUNCTIONALITY BELOW: 29 | //----------------------------------------------------------------------------- 30 | 31 | #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth 32 | #define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS)0x00000117L) 33 | 34 | VOID LeechRPC_CompressClose(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 35 | { 36 | DWORD i; 37 | for(i = 0; i < LEECHRPC_COMPRESS_MAXTHREADS; i++) { 38 | if(ctxCompress->fValid) { 39 | DeleteCriticalSection(&ctxCompress->Compress[i].Lock); 40 | LocalFree(ctxCompress->Compress[i].pbWorkspace); 41 | } 42 | } 43 | if(ctxCompress->hDll) { FreeLibrary(ctxCompress->hDll); } 44 | ZeroMemory(ctxCompress, sizeof(LEECHRPC_COMPRESS)); 45 | } 46 | 47 | BOOL LeechRPC_CompressInitialize(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 48 | { 49 | DWORD i; 50 | LeechRPC_CompressClose(ctxCompress); 51 | ctxCompress->hDll = LoadLibraryA("ntdll.dll"); 52 | if(!ctxCompress->hDll) { return FALSE; } 53 | if(!(ctxCompress->fn.pfnRtlCompressBuffer = (PFN_RtlCompressBuffer*)GetProcAddress(ctxCompress->hDll, "RtlCompressBuffer"))) { goto fail; } 54 | if(!(ctxCompress->fn.pfnRtlDecompressBuffer = (PFN_RtlDecompressBuffer*)GetProcAddress(ctxCompress->hDll, "RtlDecompressBuffer"))) { goto fail; } 55 | ctxCompress->fValid = TRUE; 56 | for(i = 0; i < LEECHRPC_COMPRESS_MAXTHREADS; i++) { 57 | InitializeCriticalSection(&ctxCompress->Compress[i].Lock); 58 | ctxCompress->fValid = ctxCompress->fValid && (ctxCompress->Compress[i].pbWorkspace = LocalAlloc(0, 0x00100000)); 59 | } 60 | // fall-through 61 | fail: 62 | if(!ctxCompress->fValid) { 63 | LeechRPC_CompressClose(ctxCompress); 64 | } 65 | return ctxCompress->fValid; 66 | } 67 | 68 | VOID LeechRPC_Compress(_In_ PLEECHRPC_COMPRESS ctxCompress, _Inout_ PLEECHRPC_MSG_BIN pMsg, _In_ BOOL fCompressDisable) 69 | { 70 | NTSTATUS nt; 71 | PBYTE pb; 72 | ULONG cb; 73 | DWORD i; 74 | if(ctxCompress->fValid && (pMsg->cb > 0x1800) && !fCompressDisable) { 75 | if(!(pb = LocalAlloc(0, pMsg->cb))) { return; } 76 | do { 77 | i = InterlockedIncrement(&ctxCompress->iCompress) % LEECHRPC_COMPRESS_MAXTHREADS; 78 | } while(!TryEnterCriticalSection(&ctxCompress->Compress[i].Lock)); 79 | nt = ctxCompress->fn.pfnRtlCompressBuffer(COMPRESSION_FORMAT_XPRESS, pMsg->pb, pMsg->cb, pb, pMsg->cb, 4096, &cb, ctxCompress->Compress[i].pbWorkspace); 80 | LeaveCriticalSection(&ctxCompress->Compress[i].Lock); 81 | if(((nt == STATUS_SUCCESS) || (nt == STATUS_BUFFER_ALL_ZEROS)) && (cb <= pMsg->cb)) { 82 | memcpy(pMsg->pb, pb, cb); 83 | pMsg->cbDecompress = pMsg->cb; 84 | pMsg->cb = (DWORD)cb; 85 | pMsg->cbMsg = sizeof(LEECHRPC_MSG_BIN) + (DWORD)cb; 86 | } 87 | LocalFree(pb); 88 | } 89 | } 90 | 91 | _Success_(return) 92 | BOOL LeechRPC_Decompress(_In_ PLEECHRPC_COMPRESS ctxCompress, _In_ PLEECHRPC_MSG_BIN pMsgIn, _Out_ PLEECHRPC_MSG_BIN *ppMsgOut) 93 | { 94 | NTSTATUS nt; 95 | ULONG cb; 96 | PLEECHRPC_MSG_BIN pMsgOut = NULL; 97 | *ppMsgOut = NULL; 98 | if(!pMsgIn->cbDecompress) { return FALSE; } 99 | if(!ctxCompress->fValid || (pMsgIn->cbDecompress > 0x04000000)) { return FALSE; } 100 | if(!(pMsgOut = (PLEECHRPC_MSG_BIN)LocalAlloc(0, sizeof(LEECHRPC_MSG_BIN) + pMsgIn->cbDecompress))) { return FALSE; } 101 | memcpy(pMsgOut, pMsgIn, sizeof(LEECHRPC_MSG_BIN)); 102 | nt = ctxCompress->fn.pfnRtlDecompressBuffer(COMPRESSION_FORMAT_XPRESS, pMsgOut->pb, pMsgOut->cbDecompress, pMsgIn->pb, pMsgIn->cb, &cb); 103 | if((nt != STATUS_SUCCESS) || (cb != pMsgIn->cbDecompress)) { 104 | LocalFree(pMsgOut); 105 | return FALSE; 106 | } 107 | pMsgOut->cb = (DWORD)cb; 108 | pMsgOut->cbMsg = sizeof(LEECHRPC_MSG_BIN) + pMsgOut->cb; 109 | pMsgOut->cbDecompress = 0; 110 | *ppMsgOut = pMsgOut; 111 | return TRUE; 112 | } 113 | 114 | //----------------------------------------------------------------------------- 115 | // GENERAL FUNCTIONALITY BELOW: 116 | //----------------------------------------------------------------------------- 117 | 118 | VOID LeechSvc_GetTimeStamp(_Out_writes_(32) LPSTR szTime) 119 | { 120 | SYSTEMTIME time; 121 | GetLocalTime(&time); 122 | sprintf_s( 123 | szTime, 124 | 32, 125 | "%04i-%02i-%02i %02i:%02i:%02i", 126 | time.wYear, 127 | time.wMonth, 128 | time.wDay, 129 | time.wHour, 130 | time.wMinute, 131 | time.wSecond 132 | ); 133 | } 134 | 135 | #endif /* _WIN32 */ 136 | #if defined(LINUX) || defined(MACOS) 137 | 138 | #include "oscompatibility.h" 139 | 140 | //----------------------------------------------------------------------------- 141 | // COMPRESSION FUNCTIONALITY BELOW: 142 | //----------------------------------------------------------------------------- 143 | 144 | VOID LeechRPC_CompressClose(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 145 | { 146 | if(ctxCompress->lib_mscompress) { 147 | dlclose(ctxCompress->lib_mscompress); 148 | ZeroMemory(ctxCompress, sizeof(LEECHRPC_COMPRESS)); 149 | } 150 | } 151 | 152 | BOOL LeechRPC_CompressInitialize(_Inout_ PLEECHRPC_COMPRESS ctxCompress) 153 | { 154 | CHAR szPathLib[MAX_PATH] = { 0 }; 155 | if(!ctxCompress->fValid) { 156 | Util_GetPathLib(szPathLib); 157 | strncat_s(szPathLib, sizeof(szPathLib), "libMSCompression"LC_LIBRARY_FILETYPE, _TRUNCATE); 158 | ctxCompress->lib_mscompress = dlopen(szPathLib, RTLD_NOW); 159 | if(ctxCompress->lib_mscompress) { 160 | ctxCompress->pfn_xpress_compress = (pfn_xpress_decompress)dlsym(ctxCompress->lib_mscompress, "xpress_compress"); 161 | ctxCompress->pfn_xpress_decompress = (pfn_xpress_decompress)dlsym(ctxCompress->lib_mscompress, "xpress_decompress"); 162 | ctxCompress->fValid = ctxCompress->pfn_xpress_compress && ctxCompress->pfn_xpress_decompress; 163 | } 164 | } 165 | return ctxCompress->fValid; 166 | } 167 | 168 | VOID LeechRPC_Compress(_In_ PLEECHRPC_COMPRESS ctxCompress, _Inout_ PLEECHRPC_MSG_BIN pMsg, _In_ BOOL fCompressDisable) 169 | { 170 | int rc; 171 | PBYTE pb; 172 | SIZE_T cb; 173 | DWORD i; 174 | if(ctxCompress->fValid && (pMsg->cb > 0x1800) && !fCompressDisable) { 175 | if(!(pb = LocalAlloc(0, pMsg->cb))) { return; } 176 | cb = pMsg->cb; 177 | rc = ctxCompress->pfn_xpress_compress(pMsg->pb, pMsg->cb, pb, &cb); 178 | if((rc >= 0) && (cb <= pMsg->cb)) { 179 | memcpy(pMsg->pb, pb, cb); 180 | pMsg->cbDecompress = pMsg->cb; 181 | pMsg->cb = (DWORD)cb; 182 | pMsg->cbMsg = sizeof(LEECHRPC_MSG_BIN) + (DWORD)cb; 183 | } 184 | LocalFree(pb); 185 | } 186 | } 187 | 188 | _Success_(return) 189 | BOOL LeechRPC_Decompress(_In_ PLEECHRPC_COMPRESS ctxCompress, _In_ PLEECHRPC_MSG_BIN pMsgIn, _Out_ PLEECHRPC_MSG_BIN * ppMsgOut) 190 | { 191 | int rc; 192 | DWORD i; 193 | SIZE_T cb; 194 | PLEECHRPC_MSG_BIN pMsgOut = NULL; 195 | *ppMsgOut = NULL; 196 | if(!pMsgIn->cbDecompress) { return FALSE; } 197 | if(!ctxCompress->fValid || (pMsgIn->cbDecompress > 0x04000000)) { return FALSE; } 198 | if(!(pMsgOut = (PLEECHRPC_MSG_BIN)LocalAlloc(0, sizeof(LEECHRPC_MSG_BIN) + pMsgIn->cbDecompress))) { return FALSE; } 199 | memcpy(pMsgOut, pMsgIn, sizeof(LEECHRPC_MSG_BIN)); 200 | cb = pMsgOut->cbDecompress; 201 | rc = ctxCompress->pfn_xpress_decompress(pMsgIn->pb, (SIZE_T)pMsgIn->cb, pMsgOut->pb, &cb); 202 | if((rc < 0) || (cb != pMsgIn->cbDecompress)) { 203 | LocalFree(pMsgOut); 204 | return FALSE; 205 | } 206 | pMsgOut->cb = (DWORD)cb; 207 | pMsgOut->cbMsg = sizeof(LEECHRPC_MSG_BIN) + pMsgOut->cb; 208 | pMsgOut->cbDecompress = 0; 209 | *ppMsgOut = pMsgOut; 210 | return TRUE; 211 | } 212 | 213 | //----------------------------------------------------------------------------- 214 | // GENERAL FUNCTIONALITY BELOW: 215 | //----------------------------------------------------------------------------- 216 | 217 | VOID LeechSvc_GetTimeStamp(_Out_writes_(32) LPSTR szTime) 218 | { 219 | struct tm localTime; 220 | time_t now = time(NULL); 221 | localtime_r(&now, &localTime); 222 | snprintf(szTime, 32, "%04i-%02i-%02i %02i:%02i:%02i", 223 | localTime.tm_year + 1900, 224 | localTime.tm_mon + 1, 225 | localTime.tm_mday, 226 | localTime.tm_hour, 227 | localTime.tm_min, 228 | localTime.tm_sec); 229 | } 230 | 231 | #endif /* LINUX || MACOS */ 232 | -------------------------------------------------------------------------------- /leechcorepyc/oscompatibility.c: -------------------------------------------------------------------------------- 1 | // oscompatibility.c : LeechCore Windows/Linux compatibility layer. 2 | // 3 | // (c) Ulf Frisk, 2017-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifdef _WIN32 7 | 8 | #include "oscompatibility.h" 9 | 10 | VOID usleep(_In_ DWORD us) 11 | { 12 | QWORD tmFreq, tmStart, tmNow, tmThreshold; 13 | if(us == 0) { return; } 14 | QueryPerformanceFrequency((PLARGE_INTEGER)&tmFreq); 15 | tmThreshold = tmFreq * us / (1000 * 1000); // dw_uS uS 16 | QueryPerformanceCounter((PLARGE_INTEGER)&tmStart); 17 | while(QueryPerformanceCounter((PLARGE_INTEGER)&tmNow) && ((tmNow - tmStart) < tmThreshold)) { 18 | ; 19 | } 20 | } 21 | 22 | _Success_(return) 23 | BOOL Util_GetPathExe(_Out_writes_(MAX_PATH) PCHAR szPath) 24 | { 25 | SIZE_T i; 26 | if(GetModuleFileNameA(NULL, szPath, MAX_PATH - 4)) { 27 | for(i = strlen(szPath) - 1; i > 0; i--) { 28 | if(szPath[i] == '/' || szPath[i] == '\\') { 29 | szPath[i + 1] = '\0'; 30 | return TRUE; 31 | } 32 | } 33 | } 34 | return FALSE; 35 | } 36 | 37 | #endif /* _WIN32 */ 38 | #ifdef LINUX 39 | 40 | #include "oscompatibility.h" 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #define INTERNAL_HANDLE_TYPE_THREAD 0xdeadbeeffedfed01 47 | 48 | typedef struct tdINTERNAL_HANDLE { 49 | QWORD type; 50 | HANDLE handle; 51 | } INTERNAL_HANDLE, *PINTERNAL_HANDLE; 52 | 53 | HANDLE LocalAlloc(DWORD uFlags, SIZE_T uBytes) 54 | { 55 | HANDLE h = malloc(uBytes); 56 | if(h && (uFlags & LMEM_ZEROINIT)) { 57 | memset(h, 0, uBytes); 58 | } 59 | return h; 60 | } 61 | 62 | VOID LocalFree(HANDLE hMem) 63 | { 64 | free(hMem); 65 | } 66 | 67 | QWORD GetTickCount64() 68 | { 69 | struct timespec ts; 70 | clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); 71 | return ts.tv_sec * 1000 + ts.tv_nsec / (1000 * 1000); 72 | } 73 | 74 | BOOL QueryPerformanceFrequency(_Out_ LARGE_INTEGER *lpFrequency) 75 | { 76 | *lpFrequency = 1000 * 1000; 77 | return TRUE; 78 | } 79 | 80 | BOOL QueryPerformanceCounter(_Out_ LARGE_INTEGER *lpPerformanceCount) 81 | { 82 | struct timespec ts; 83 | clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); 84 | *lpPerformanceCount = (ts.tv_sec * 1000 * 1000) + (ts.tv_nsec / 1000); // uS resolution 85 | return TRUE; 86 | } 87 | 88 | HANDLE CreateThread( 89 | PVOID lpThreadAttributes, 90 | SIZE_T dwStackSize, 91 | PVOID lpStartAddress, 92 | PVOID lpParameter, 93 | DWORD dwCreationFlags, 94 | PDWORD lpThreadId 95 | ) { 96 | PINTERNAL_HANDLE ph; 97 | pthread_t thread; 98 | int status; 99 | status = pthread_create(&thread, NULL, lpStartAddress, lpParameter); 100 | if(status) { return NULL;} 101 | ph = malloc(sizeof(INTERNAL_HANDLE)); 102 | ph->type = INTERNAL_HANDLE_TYPE_THREAD; 103 | ph->handle = (HANDLE)thread; 104 | return ph; 105 | } 106 | 107 | VOID GetLocalTime(LPSYSTEMTIME lpSystemTime) 108 | { 109 | time_t curtime; 110 | struct tm t = { 0 }; 111 | curtime = time(NULL); 112 | localtime_r(&curtime, &t); 113 | lpSystemTime->wYear = t.tm_year; 114 | lpSystemTime->wMonth = t.tm_mon; 115 | lpSystemTime->wDayOfWeek = t.tm_wday; 116 | lpSystemTime->wDay = t.tm_mday; 117 | lpSystemTime->wHour = t.tm_hour; 118 | lpSystemTime->wMinute = t.tm_min; 119 | lpSystemTime->wSecond = t.tm_sec; 120 | lpSystemTime->wMilliseconds = 0; 121 | } 122 | 123 | HANDLE FindFirstFileA(LPSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData) 124 | { 125 | DWORD i; 126 | DIR *hDir; 127 | CHAR szDirName[MAX_PATH] = { 0 }; 128 | strcpy_s(lpFindFileData->__cExtension, 5, lpFileName + strlen(lpFileName) - 3); 129 | strcpy_s(szDirName, MAX_PATH - 1, lpFileName); 130 | for(i = strlen(szDirName) - 1; i > 0; i--) { 131 | if(szDirName[i] == '/') { 132 | szDirName[i] = 0; 133 | break; 134 | } 135 | } 136 | hDir = opendir(szDirName); 137 | if(!hDir) { return NULL; } 138 | return FindNextFileA((HANDLE)hDir, lpFindFileData) ? (HANDLE)hDir : INVALID_HANDLE_VALUE; 139 | } 140 | 141 | BOOL FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData) 142 | { 143 | DIR *hDir = (DIR*)hFindFile; 144 | struct dirent *dir; 145 | char* sz; 146 | if(!hDir) { return FALSE; } 147 | while ((dir = readdir(hDir)) != NULL) { 148 | sz = dir->d_name; 149 | if((strlen(sz) > 3) && !strcasecmp(sz + strlen(sz) - 3, lpFindFileData->__cExtension)) { 150 | strcpy_s(lpFindFileData->cFileName, MAX_PATH, sz); 151 | return TRUE; 152 | } 153 | } 154 | closedir(hDir); 155 | return FALSE; 156 | } 157 | 158 | DWORD InterlockedAdd(DWORD *Addend, DWORD Value) 159 | { 160 | return __sync_add_and_fetch(Addend, Value); 161 | } 162 | 163 | BOOL IsWow64Process(HANDLE hProcess, PBOOL Wow64Process) 164 | { 165 | if(Wow64Process) { 166 | *Wow64Process = FALSE; 167 | return TRUE; 168 | } 169 | return FALSE; 170 | } 171 | 172 | // ---------------------------------------------------------------------------- 173 | // CRITICAL_SECTION functionality below: 174 | // ---------------------------------------------------------------------------- 175 | 176 | VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) 177 | { 178 | memset(lpCriticalSection, 0, sizeof(CRITICAL_SECTION)); 179 | pthread_mutexattr_init(&lpCriticalSection->mta); 180 | pthread_mutexattr_settype(&lpCriticalSection->mta, PTHREAD_MUTEX_RECURSIVE); 181 | pthread_mutex_init(&lpCriticalSection->mutex, &lpCriticalSection->mta); 182 | } 183 | 184 | VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) 185 | { 186 | pthread_mutex_destroy(&lpCriticalSection->mutex); 187 | memset(lpCriticalSection, 0, sizeof(CRITICAL_SECTION)); 188 | } 189 | 190 | VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) 191 | { 192 | pthread_mutex_lock(&lpCriticalSection->mutex); 193 | } 194 | 195 | VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) 196 | { 197 | pthread_mutex_unlock(&lpCriticalSection->mutex); 198 | } 199 | 200 | // ---------------------------------------------------------------------------- 201 | // EVENT AND CLOSE HANDLE functionality below: 202 | // ---------------------------------------------------------------------------- 203 | 204 | #define OSCOMPATIBILITY_HANDLE_INTERNAL 0x35d91cca 205 | #define OSCOMPATIBILITY_HANDLE_TYPE_EVENTFD 1 206 | 207 | typedef struct tdHANDLE_INTERNAL { 208 | DWORD magic; 209 | DWORD type; 210 | BOOL fEventManualReset; 211 | int handle; 212 | } HANDLE_INTERNAL, *PHANDLE_INTERNAL; 213 | 214 | BOOL CloseHandle(_In_ HANDLE hObject) 215 | { 216 | PHANDLE_INTERNAL hi = (PHANDLE_INTERNAL)hObject; 217 | if(hi->magic != OSCOMPATIBILITY_HANDLE_INTERNAL) { return FALSE; } 218 | if(hi->type == OSCOMPATIBILITY_HANDLE_TYPE_EVENTFD) { 219 | close(hi->handle); 220 | } 221 | LocalFree(hi); 222 | return TRUE; 223 | } 224 | 225 | BOOL SetEvent(_In_ HANDLE hEvent) 226 | { 227 | PHANDLE_INTERNAL hi = (PHANDLE_INTERNAL)hEvent; 228 | uint64_t v = 1; 229 | return -1 != write(hi->handle, &v, sizeof(v)); 230 | } 231 | 232 | // function is not thread-safe, but use case in leechcore is single-threaded 233 | BOOL ResetEvent(_In_ HANDLE hEvent) 234 | { 235 | PHANDLE_INTERNAL hi = (PHANDLE_INTERNAL)hEvent; 236 | uint64_t v; 237 | struct pollfd fds[1]; 238 | fds[0].fd = hi->handle; 239 | fds[0].events = POLLIN; 240 | while((poll(fds, 1, 0) > 0) && (fds[0].revents & POLLIN)) { 241 | read(fds[0].fd, &v, sizeof(v)); 242 | } 243 | return TRUE; 244 | } 245 | 246 | HANDLE CreateEvent(_In_opt_ PVOID lpEventAttributes, _In_ BOOL bManualReset, _In_ BOOL bInitialState, _In_opt_ PVOID lpName) 247 | { 248 | PHANDLE_INTERNAL pi; 249 | pi = malloc(sizeof(HANDLE_INTERNAL)); 250 | pi->magic = OSCOMPATIBILITY_HANDLE_INTERNAL; 251 | pi->type = OSCOMPATIBILITY_HANDLE_TYPE_EVENTFD; 252 | pi->fEventManualReset = bManualReset; 253 | pi->handle = eventfd(0, 0); 254 | if(bInitialState) { SetEvent(pi); } 255 | return pi; 256 | } 257 | 258 | // function is limited and not thread-safe, but use case in leechcore is single-threaded 259 | DWORD WaitForSingleObject(_In_ HANDLE hHandle, _In_ DWORD dwMilliseconds) 260 | { 261 | PHANDLE_INTERNAL hi = (PHANDLE_INTERNAL)hHandle; 262 | uint64_t v; 263 | read(hi->handle, &v, sizeof(v)); 264 | return 0; 265 | } 266 | 267 | // function is limited and not thread-safe, but use case in leechcore is single-threaded 268 | DWORD WaitForMultipleObjects(_In_ DWORD nCount, HANDLE *lpHandles, _In_ BOOL bWaitAll, _In_ DWORD dwMilliseconds) 269 | { 270 | struct pollfd fds[MAXIMUM_WAIT_OBJECTS]; 271 | DWORD i; 272 | uint64_t v; 273 | if(bWaitAll) { 274 | for(i = 0; i < nCount; i++) { 275 | WaitForSingleObject(lpHandles[i], dwMilliseconds); 276 | } 277 | return -1; 278 | } 279 | for(i = 0; i < nCount; i++) { 280 | fds[i].fd = ((PHANDLE_INTERNAL)lpHandles[i])->handle; 281 | fds[i].events = POLLIN; 282 | } 283 | if(poll(fds, 1, -1) > 0) { 284 | for(i = 0; i < nCount; i++) { 285 | if((fds[0].revents & POLLIN)) { 286 | read(fds[i].fd, &v, sizeof(v)); 287 | return i; 288 | } 289 | } 290 | } 291 | return -1; 292 | } 293 | 294 | #endif /* LINUX */ 295 | -------------------------------------------------------------------------------- /leechcore/device_vmware.c: -------------------------------------------------------------------------------- 1 | // device_vmware.c : implementation of the vmware acquisition device. 2 | // 3 | // tested with vmware workstation 16.1.2 4 | // 5 | // (c) Ulf Frisk, 2022-2025 6 | // Author: Ulf Frisk, pcileech@frizk.net 7 | // 8 | #include "leechcore.h" 9 | #include "leechcore_device.h" 10 | #include "leechcore_internal.h" 11 | #include "util.h" 12 | #ifdef _WIN32 13 | 14 | #include 15 | 16 | typedef struct tdDEVICE_CONTEXT_VMWARE { 17 | HANDLE hProcess; 18 | } DEVICE_CONTEXT_VMWARE, *PDEVICE_CONTEXT_VMWARE; 19 | 20 | //----------------------------------------------------------------------------- 21 | // GENERAL FUNCTIONALITY BELOW: 22 | //----------------------------------------------------------------------------- 23 | 24 | VOID DeviceVMWare_ReadScatter(_In_ PLC_CONTEXT ctxLC, _In_ DWORD cpMEMs, _Inout_ PPMEM_SCATTER ppMEMs) 25 | { 26 | PDEVICE_CONTEXT_VMWARE ctx = (PDEVICE_CONTEXT_VMWARE)ctxLC->hDevice; 27 | PMEM_SCATTER pMEM; 28 | DWORD i; 29 | for(i = 0; i < cpMEMs; i++) { 30 | pMEM = ppMEMs[i]; 31 | if(pMEM->f || MEM_SCATTER_ADDR_ISINVALID(pMEM)) { continue; } 32 | pMEM->f = ReadProcessMemory(ctx->hProcess, (LPCVOID)pMEM->qwA, pMEM->pb, pMEM->cb, NULL); 33 | } 34 | } 35 | 36 | VOID DeviceVMWare_WriteScatter(_In_ PLC_CONTEXT ctxLC, _In_ DWORD cpMEMs, _Inout_ PPMEM_SCATTER ppMEMs) 37 | { 38 | PDEVICE_CONTEXT_VMWARE ctx = (PDEVICE_CONTEXT_VMWARE)ctxLC->hDevice; 39 | PMEM_SCATTER pMEM; 40 | DWORD i; 41 | for(i = 0; i < cpMEMs; i++) { 42 | pMEM = ppMEMs[i]; 43 | if(pMEM->f || MEM_SCATTER_ADDR_ISINVALID(pMEM)) { continue; } 44 | pMEM->f = WriteProcessMemory(ctx->hProcess, (LPVOID)pMEM->qwA, pMEM->pb, pMEM->cb, NULL); 45 | } 46 | } 47 | 48 | VOID DeviceVMWare_Close(_Inout_ PLC_CONTEXT ctxLC) 49 | { 50 | PDEVICE_CONTEXT_VMWARE ctx = (PDEVICE_CONTEXT_VMWARE)ctxLC->hDevice; 51 | if(ctx) { 52 | ctxLC->hDevice = 0; 53 | CloseHandle(ctx->hProcess); 54 | LocalFree(ctx); 55 | } 56 | } 57 | 58 | _Success_(return) 59 | BOOL DeviceVMWare_Open_GetRange(_In_ DWORD dwPID, _Out_writes_opt_(42) LPWSTR wszRegion, _Out_opt_ PQWORD pvaRegion, _Out_opt_ PQWORD pcbRegion) 60 | { 61 | DWORD cch; 62 | HANDLE hProcess = 0; 63 | QWORD va = 0x0000000000000000; 64 | WCHAR wsz[MAX_PATH + 1] = { 0 }; 65 | MEMORY_BASIC_INFORMATION BI; 66 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPID); 67 | if(!hProcess) { goto fail; } 68 | while(VirtualQueryEx(hProcess, (LPCVOID)va, &BI, sizeof(MEMORY_BASIC_INFORMATION))) { 69 | va = (QWORD)BI.BaseAddress + BI.RegionSize; 70 | if((QWORD)BI.BaseAddress > 0x00006fffffffffff) { break; } 71 | if(BI.BaseAddress != BI.AllocationBase) { continue; } 72 | if((BI.RegionSize < 0x01000000) || (BI.RegionSize > 0x10000000000)) { continue; } 73 | if((BI.State != MEM_COMMIT) || (BI.Protect != PAGE_READWRITE) || (BI.AllocationProtect != PAGE_READWRITE)) { continue; } 74 | cch = GetMappedFileNameW(hProcess, BI.BaseAddress, wsz, _countof(wsz) - 1); 75 | if(!cch || (cch < 42) || _wcsicmp(L".vmem", wsz + cch - 5)) { continue; } 76 | if(wszRegion) { wcsncpy_s(wszRegion, 42, wsz + cch - 41, _TRUNCATE); } 77 | if(pvaRegion) { *pvaRegion = (QWORD)BI.BaseAddress; } 78 | if(pcbRegion) { *pcbRegion = (QWORD)BI.RegionSize; } 79 | CloseHandle(hProcess); 80 | return TRUE; 81 | } 82 | fail: 83 | if(hProcess) { CloseHandle(hProcess); } 84 | return FALSE; 85 | } 86 | 87 | #define VMWARE_ERRORINFO_MAXCHAR 2048 88 | 89 | VOID DeviceVMWare_Open_List(_Out_ PDWORD pdwSinglePID, _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcCreateErrorInfo) 90 | { 91 | HANDLE hProcess; 92 | QWORD cbRegion; 93 | DWORD cProcessVMWare = 0, iPID, cPIDs, cbPIDs, dwPID, dwPIDs[1024]; 94 | WCHAR wsz[MAX_PATH + 1] = { 0 }, wszInfo[MAX_PATH]; 95 | PLC_CONFIG_ERRORINFO pInfo = NULL; 96 | // 1: init 97 | *pdwSinglePID = 0; 98 | if(ppLcCreateErrorInfo) { *ppLcCreateErrorInfo = NULL; } 99 | if(!EnumProcesses(dwPIDs, sizeof(dwPIDs), &cbPIDs)) { return; } 100 | cPIDs = cbPIDs / sizeof(DWORD); 101 | hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPIDs[0]); 102 | // 2: set up errorinfo (in case it's required later) 103 | if(!(pInfo = LocalAlloc(LMEM_ZEROINIT, sizeof(LC_CONFIG_ERRORINFO) + VMWARE_ERRORINFO_MAXCHAR * sizeof(WCHAR)))) { return; } 104 | pInfo->dwVersion = LC_CONFIG_ERRORINFO_VERSION; 105 | pInfo->cbStruct = sizeof(LC_CONFIG_ERRORINFO) + VMWARE_ERRORINFO_MAXCHAR * sizeof(WCHAR); 106 | pInfo->fUserInputRequest = TRUE; 107 | wcsncat_s(pInfo->wszUserText, VMWARE_ERRORINFO_MAXCHAR - 1, L"Multiple VMWare VMs detected. Select VM-ID.\n VM-ID VM NAME\n=====================\n", _TRUNCATE); 108 | // 3: enumerate 109 | for(iPID = 0; iPID < cPIDs; iPID++) { 110 | dwPID = dwPIDs[iPID]; 111 | if((hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPID))) { 112 | if(GetModuleFileNameEx(hProcess, NULL, wsz, MAX_PATH) && wcsstr(wsz, L"vmware-vmx.exe")) { 113 | if(DeviceVMWare_Open_GetRange(dwPID, wsz, NULL, &cbRegion)) { 114 | *pdwSinglePID = cProcessVMWare ? 0 : dwPID; 115 | cProcessVMWare++; 116 | _snwprintf_s(wszInfo, _countof(wszInfo), _TRUNCATE, L"%6i = %s (%i MB)\n", dwPID, wsz, (DWORD)(cbRegion / (1024 * 1024))); 117 | wcsncat_s(pInfo->wszUserText, VMWARE_ERRORINFO_MAXCHAR - 1, wszInfo, _TRUNCATE); 118 | } 119 | } 120 | CloseHandle(hProcess); 121 | } 122 | } 123 | // 4: finish 124 | if(cProcessVMWare > 1) { 125 | pInfo->cwszUserText = (DWORD)wcslen(pInfo->wszUserText); 126 | *ppLcCreateErrorInfo = pInfo; 127 | } else { 128 | LocalFree(pInfo); 129 | } 130 | } 131 | 132 | /* 133 | * The debug privilege is required to attach to vmware process. 134 | */ 135 | VOID DeviceVMWare_Open_GetSeDebugPrivilege() 136 | { 137 | HANDLE hToken = 0; 138 | LUID luid; 139 | TOKEN_PRIVILEGES tp; 140 | if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { goto fail; } 141 | if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { goto fail; }; 142 | tp.PrivilegeCount = 1; 143 | tp.Privileges[0].Luid = luid; 144 | tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 145 | if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL)) { goto fail; }; 146 | fail: 147 | if(hToken) { CloseHandle(hToken); } 148 | } 149 | 150 | #define VMWARE_PARAMETER_ID "id" 151 | #define VMWARE_PARAMETER_READONLY "ro" 152 | 153 | _Success_(return) 154 | BOOL DeviceVMWare_Open(_Inout_ PLC_CONTEXT ctxLC, _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcCreateErrorInfo) 155 | { 156 | BOOL result = FALSE, fReadOnly; 157 | DWORD dwPID = 0, dwDesiredAccess; 158 | QWORD vaRegion, cbRegion; 159 | PDEVICE_CONTEXT_VMWARE ctx; 160 | if(ppLcCreateErrorInfo) { *ppLcCreateErrorInfo = NULL; } 161 | fReadOnly = LcDeviceParameterGetNumeric(ctxLC, VMWARE_PARAMETER_READONLY) ? TRUE : FALSE; 162 | dwPID = (DWORD)LcDeviceParameterGetNumeric(ctxLC, VMWARE_PARAMETER_ID); 163 | // 1: vm list (if required) 164 | DeviceVMWare_Open_GetSeDebugPrivilege(); 165 | if(!dwPID) { 166 | DeviceVMWare_Open_List(&dwPID, ppLcCreateErrorInfo); 167 | if(!dwPID && !ppLcCreateErrorInfo) { 168 | lcprintfv(ctxLC, "DEVICE: VMWARE: ERROR: no running VMs detected / not running as administrator?\n"); 169 | } 170 | if(!dwPID) { 171 | return FALSE; 172 | } 173 | } 174 | // 2: vm region/range detect 175 | if(!DeviceVMWare_Open_GetRange(dwPID, NULL, &vaRegion, &cbRegion)) { 176 | lcprintfv(ctxLC, "DEVICE: VMWARE: ERROR: running VM not detected in process pid %i / not running as administrator?\n", dwPID); 177 | return FALSE; 178 | } 179 | // 3: initialize core context. 180 | ctx = (PDEVICE_CONTEXT_VMWARE)LocalAlloc(LMEM_ZEROINIT, sizeof(DEVICE_CONTEXT_VMWARE)); 181 | if(!ctx) { return FALSE; } 182 | ctxLC->hDevice = (HANDLE)ctx; 183 | // 4: set callback functions and fix up config 184 | ctxLC->fMultiThread = TRUE; 185 | ctxLC->Config.fVolatile = TRUE; 186 | ctxLC->pfnClose = DeviceVMWare_Close; 187 | ctxLC->pfnReadScatter = DeviceVMWare_ReadScatter; 188 | ctxLC->pfnWriteScatter = fReadOnly ? NULL : DeviceVMWare_WriteScatter; 189 | // 5: connect to vmware vmm process 190 | dwDesiredAccess = fReadOnly ? PROCESS_VM_READ : (PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION); 191 | ctx->hProcess = OpenProcess(dwDesiredAccess, FALSE, dwPID); 192 | if(ctx->hProcess) { 193 | LcMemMap_AddRange(ctxLC, 0, min(0xc0000000, cbRegion), vaRegion); 194 | if(cbRegion > 0xc0000000) { 195 | // account for vmware memory hole at 3-4GB 196 | LcMemMap_AddRange(ctxLC, 0x100000000, cbRegion - 0xc0000000, vaRegion + 0xc0000000); 197 | } 198 | lcprintfv(ctxLC, "DEVICE: VMWARE: Successfully connected to VM %i.\n", dwPID); 199 | return TRUE; 200 | } 201 | DeviceVMWare_Close(ctxLC); 202 | return FALSE; 203 | } 204 | 205 | #endif /* _WIN32 */ 206 | #if defined(LINUX) || defined(MACOS) 207 | 208 | _Success_(return) 209 | BOOL DeviceVMWare_Open(_Inout_ PLC_CONTEXT ctxLC, _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcCreateErrorInfo) 210 | { 211 | lcprintfv(ctxLC, "DEVICE: VMWARE: FAIL: memory acquisition only supported on Windows.\n"); 212 | if(ppLcCreateErrorInfo) { *ppLcCreateErrorInfo = NULL; } 213 | return FALSE; 214 | } 215 | 216 | #endif /* LINUX || MACOS */ 217 | -------------------------------------------------------------------------------- /leechcorepyc/oscompatibility.h: -------------------------------------------------------------------------------- 1 | // oscompatibility.h : LeechCore Windows/Linux compatibility layer. 2 | // 3 | // (c) Ulf Frisk, 2017-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __OSCOMPATIBILITY_H__ 7 | #define __OSCOMPATIBILITY_H__ 8 | #include "leechcore.h" 9 | 10 | #ifdef _WIN32 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define SOCK_NONBLOCK 0 19 | 20 | #pragma warning( disable : 4477) 21 | 22 | #define LC_LIBRARY_FILETYPE ".dll" 23 | #define LINUX_NO_OPTIMIZE 24 | VOID usleep(_In_ DWORD us); 25 | 26 | #endif /* _WIN32 */ 27 | #ifdef LINUX 28 | #define _FILE_OFFSET_BITS 64 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #define LC_LIBRARY_FILETYPE ".so" 48 | 49 | typedef void VOID, *PVOID; 50 | typedef void *HANDLE, **PHANDLE, *HMODULE, *FARPROC; 51 | typedef uint32_t BOOL, *PBOOL; 52 | typedef uint8_t BYTE, *PBYTE; 53 | typedef uint8_t UCHAR, *PUCHAR; 54 | typedef char CHAR, *PCHAR, *PSTR, *LPSTR; 55 | typedef const char *LPCSTR; 56 | typedef uint16_t WORD, *PWORD, USHORT, *PUSHORT; 57 | typedef uint16_t WCHAR, *PWCHAR, *LPWSTR; 58 | typedef const uint16_t *LPCWSTR; 59 | typedef uint32_t DWORD, *PDWORD, ULONG, *PULONG; 60 | typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64; 61 | typedef uint64_t LARGE_INTEGER, *PLARGE_INTEGER, FILETIME; 62 | typedef size_t SIZE_T, *PSIZE_T; 63 | typedef void *OVERLAPPED, *LPOVERLAPPED; 64 | typedef struct tdEXCEPTION_RECORD32 { CHAR sz[80]; } EXCEPTION_RECORD32; 65 | typedef struct tdEXCEPTION_RECORD64 { CHAR sz[152]; } EXCEPTION_RECORD64; 66 | #define TRUE 1 67 | #define FALSE 0 68 | #define MAX_PATH 260 69 | #define LMEM_ZEROINIT 0x0040 70 | #define INVALID_HANDLE_VALUE ((HANDLE)-1) 71 | #define STD_INPUT_HANDLE ((DWORD)-10) 72 | #define STD_OUTPUT_HANDLE ((DWORD)-11) 73 | #define GENERIC_WRITE (0x40000000L) 74 | #define GENERIC_READ (0x80000000L) 75 | #define FILE_SHARE_READ (0x00000001L) 76 | #define CREATE_NEW (0x00000001L) 77 | #define OPEN_EXISTING (0x00000003L) 78 | #define FILE_ATTRIBUTE_NORMAL (0x00000080L) 79 | #define STILL_ACTIVE (0x00000103L) 80 | #define CRYPT_STRING_HEX_ANY (0x00000008L) 81 | #define CRYPT_STRING_HEXASCIIADDR (0x00000008L) 82 | #define STILL_ACTIVE (0x00000103L) 83 | #define INVALID_FILE_SIZE (0xffffffffL) 84 | #define _TRUNCATE ((SIZE_T)-1LL) 85 | #define LPTHREAD_START_ROUTINE PVOID 86 | #define WINUSB_INTERFACE_HANDLE libusb_device_handle* 87 | #define PIPE_TRANSFER_TIMEOUT 0x03 88 | #define CONSOLE_SCREEN_BUFFER_INFO PVOID // TODO: remove this dummy 89 | #define SOCKET int 90 | #define INVALID_SOCKET -1 91 | #define SOCKET_ERROR -1 92 | #define WSAEWOULDBLOCK 10035L 93 | #define WAIT_OBJECT_0 (0x00000000UL) 94 | #define INFINITE (0xFFFFFFFFUL) 95 | #define MAXIMUM_WAIT_OBJECTS 64 96 | 97 | #define _In_ 98 | #define _In_z_ 99 | #define _Out_ 100 | #define _Inout_ 101 | #define _Inout_opt_ 102 | #define _In_opt_ 103 | #define _Out_opt_ 104 | #define _Check_return_opt_ 105 | #define _Frees_ptr_opt_ 106 | #define _Post_ptr_invalid_ 107 | #define _Printf_format_string_ 108 | #define _In_reads_(x) 109 | #define _In_reads_opt_(x) 110 | #define _Out_writes_(x) 111 | #define __bcount(x) 112 | #define _Inout_bytecount_(x) 113 | #define _Inout_updates_opt_(x) 114 | #define _Inout_updates_bytes_(x) 115 | #define _Out_writes_opt_(x) 116 | #define _Success_(x) 117 | #define UNREFERENCED_PARAMETER(x) 118 | 119 | #define max(a, b) (((a) > (b)) ? (a) : (b)) 120 | #define min(a, b) (((a) < (b)) ? (a) : (b)) 121 | #define _byteswap_ushort(v) (bswap_16(v)) 122 | #define _byteswap_ulong(v) (bswap_32(v)) 123 | #define _byteswap_uint64(v) (bswap_64(v)) 124 | #define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) 125 | #define sprintf_s(s, maxcount, ...) (snprintf(s, maxcount, __VA_ARGS__)) 126 | #define strnlen_s(s, maxcount) (strnlen(s, maxcount)) 127 | #define strcpy_s(dst, len, src) (strncpy(dst, src, len)) 128 | #define strncpy_s(dst, len, src, srclen) (strncpy(dst, src, min((QWORD)(max(1, len)) - 1, (QWORD)(srclen)))) 129 | #define strncat_s(dst, dstlen, src, srclen) (strncat(dst, src, min((((strlen(dst) + 1 >= (QWORD)(dstlen)) || ((QWORD)(dstlen) == 0)) ? 0 : ((QWORD)(dstlen) - strlen(dst) - 1)), (QWORD)(srclen)))) 130 | #define strcat_s(dst, dstlen, src) (strncat_s(dst, dstlen, src, _TRUNCATE)) 131 | #define _vsnprintf_s(dst, len, cnt, fmt, a) (vsnprintf(dst, min((QWORD)(len), (QWORD)(cnt)), fmt, a)) 132 | #define _stricmp(s1, s2) (strcasecmp(s1, s2)) 133 | #define _strnicmp(s1, s2, maxcount) (strncasecmp(s1, s2, maxcount)) 134 | #define strtok_s(s, d, c) (strtok_r(s, d, c)) 135 | #define _snprintf_s(s,l,c,...) (snprintf(s,min((QWORD)(l), (QWORD)(c)),__VA_ARGS__)) 136 | #define sscanf_s(s, f, ...) (sscanf(s, f, __VA_ARGS__)) 137 | #define SwitchToThread() (sched_yield()) 138 | #define ExitThread(dwExitCode) (pthread_exit(dwExitCode)) 139 | #define ExitProcess(c) (exit(c ? EXIT_SUCCESS : EXIT_FAILURE)) 140 | #define Sleep(dwMilliseconds) (usleep(1000*dwMilliseconds)) 141 | #define fopen_s(ppFile, szFile, szAttr) ((*ppFile = fopen(szFile, szAttr)) ? 0 : 1) 142 | #define GetModuleFileNameA(m, f, l) (readlink("/proc/self/exe", f, l)) 143 | #define ZeroMemory(pb, cb) (memset(pb, 0, cb)) 144 | #define WinUsb_SetPipePolicy(h, p, t, cb, pb) // TODO: implement this for better USB2 performance. 145 | #define WSAGetLastError() (WSAEWOULDBLOCK) // TODO: remove this dummy when possible. 146 | #define _ftelli64(f) (ftello(f)) 147 | #define _fseeki64(f, o, w) (fseeko(f, o, w)) 148 | #define _chsize_s(fd, cb) (ftruncate64(fd, cb)) 149 | #define _fileno(f) (fileno(f)) 150 | #define InterlockedAdd64(p, v) (__sync_add_and_fetch(p, v)) 151 | #define InterlockedIncrement64(p) (__sync_add_and_fetch(p, 1)) 152 | #define InterlockedIncrement(p) (__sync_add_and_fetch_4(p, 1)) 153 | #define GetCurrentProcess() ((HANDLE)-1) 154 | #define closesocket(s) close(s) 155 | 156 | #ifndef _LINUX_DEF_CRITICAL_SECTION 157 | #define _LINUX_DEF_CRITICAL_SECTION 158 | typedef struct tdCRITICAL_SECTION { 159 | pthread_mutex_t mutex; 160 | pthread_mutexattr_t mta; 161 | } CRITICAL_SECTION, *LPCRITICAL_SECTION; 162 | #endif /* _LINUX_DEF_CRITICAL_SECTION */ 163 | 164 | VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 165 | VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 166 | VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 167 | VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 168 | 169 | typedef struct _SYSTEMTIME { 170 | WORD wYear; 171 | WORD wMonth; 172 | WORD wDayOfWeek; 173 | WORD wDay; 174 | WORD wHour; 175 | WORD wMinute; 176 | WORD wSecond; 177 | WORD wMilliseconds; 178 | } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; 179 | 180 | typedef struct _WIN32_FIND_DATAA { 181 | CHAR __cExtension[5]; 182 | CHAR cFileName[MAX_PATH]; 183 | } WIN32_FIND_DATAA, *PWIN32_FIND_DATAA, *LPWIN32_FIND_DATAA; 184 | 185 | HANDLE FindFirstFileA(LPSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData); 186 | BOOL FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData); 187 | HANDLE LocalAlloc(DWORD uFlags, SIZE_T uBytes); 188 | VOID LocalFree(HANDLE hMem); 189 | QWORD GetTickCount64(); 190 | BOOL QueryPerformanceFrequency(_Out_ LARGE_INTEGER *lpFrequency); 191 | BOOL QueryPerformanceCounter(_Out_ LARGE_INTEGER *lpPerformanceCount); 192 | VOID GetLocalTime(LPSYSTEMTIME lpSystemTime); 193 | DWORD InterlockedAdd(DWORD *Addend, DWORD Value); 194 | BOOL IsWow64Process(HANDLE hProcess, PBOOL Wow64Process); 195 | 196 | HANDLE CreateThread( 197 | PVOID lpThreadAttributes, 198 | SIZE_T dwStackSize, 199 | PVOID lpStartAddress, 200 | PVOID lpParameter, 201 | DWORD dwCreationFlags, 202 | PDWORD lpThreadId 203 | ); 204 | 205 | BOOL CloseHandle(_In_ HANDLE hObject); 206 | BOOL ResetEvent(_In_ HANDLE hEvent); 207 | BOOL SetEvent(_In_ HANDLE hEvent); 208 | HANDLE CreateEvent(_In_opt_ PVOID lpEventAttributes, _In_ BOOL bManualReset, _In_ BOOL bInitialState, _In_opt_ PVOID lpName); 209 | DWORD WaitForMultipleObjects(_In_ DWORD nCount, HANDLE *lpHandles, _In_ BOOL bWaitAll, _In_ DWORD dwMilliseconds); 210 | DWORD WaitForSingleObject(_In_ HANDLE hHandle, _In_ DWORD dwMilliseconds); 211 | 212 | // for some unexplainable reasons the gcc on -O2 will optimize out functionality 213 | // and destroy the proper workings on some functions due to an unexplainable 214 | // reason disable optimization on a function level resolves the issues ... 215 | #define LINUX_NO_OPTIMIZE __attribute__((optimize("O0"))) 216 | 217 | #endif /* LINUX */ 218 | 219 | #endif /* __OSCOMPATIBILITY_H__ */ 220 | -------------------------------------------------------------------------------- /leechagent_linux/oscompatibility.h: -------------------------------------------------------------------------------- 1 | // oscompatibility.h : LeechCore Windows/Linux compatibility layer. 2 | // 3 | // (c) Ulf Frisk, 2017-2025 4 | // Author: Ulf Frisk, pcileech@frizk.net 5 | // 6 | #ifndef __OSCOMPATIBILITY_H__ 7 | #define __OSCOMPATIBILITY_H__ 8 | #include 9 | 10 | #ifdef LINUX 11 | #define LC_LIBRARY_FILETYPE ".so" 12 | // for some unexplainable reasons the gcc on -O2 will optimize out functionality 13 | // and destroy the proper workings on some functions due to an unexplainable 14 | // reason disable optimization on a function level resolves the issues ... 15 | #define LINUX_NO_OPTIMIZE __attribute__((optimize("O0"))) 16 | #endif /* LINUX */ 17 | 18 | #ifdef MACOS 19 | #define SOCK_NONBLOCK 0 20 | #define LC_LIBRARY_FILETYPE ".dylib" 21 | #define LINUX_NO_OPTIMIZE 22 | #endif /* MACOS */ 23 | 24 | #if defined(LINUX) || defined(MACOS) 25 | #define _FILE_OFFSET_BITS 64 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | typedef void VOID, *PVOID; 43 | typedef void *HANDLE, **PHANDLE, *HMODULE, *FARPROC; 44 | typedef uint32_t BOOL, *PBOOL; 45 | typedef uint8_t BYTE, *PBYTE; 46 | typedef uint8_t UCHAR, *PUCHAR; 47 | typedef char CHAR, *PCHAR, *PSTR, *LPSTR; 48 | typedef const char *LPCSTR; 49 | typedef int32_t LONG; 50 | typedef uint16_t WORD, *PWORD, USHORT, *PUSHORT; 51 | typedef uint16_t WCHAR, *PWCHAR, *LPWSTR; 52 | typedef const uint16_t *LPCWSTR; 53 | typedef uint32_t UINT, DWORD, *PDWORD, ULONG, *PULONG; 54 | typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64; 55 | typedef uint64_t LARGE_INTEGER, *PLARGE_INTEGER, FILETIME; 56 | typedef size_t SIZE_T, *PSIZE_T; 57 | typedef void *OVERLAPPED, *LPOVERLAPPED; 58 | typedef struct tdEXCEPTION_RECORD32 { CHAR sz[80]; } EXCEPTION_RECORD32; 59 | typedef struct tdEXCEPTION_RECORD64 { CHAR sz[152]; } EXCEPTION_RECORD64; 60 | typedef int(*_CoreCrtNonSecureSearchSortCompareFunction)(void const *, void const *); 61 | #define __forceinline inline __attribute__((always_inline)) 62 | #define TRUE 1 63 | #define FALSE 0 64 | #define MAX_PATH 260 65 | #define LMEM_ZEROINIT 0x0040 66 | #define INVALID_HANDLE_VALUE ((HANDLE)-1) 67 | #define STD_INPUT_HANDLE ((DWORD)-10) 68 | #define STD_OUTPUT_HANDLE ((DWORD)-11) 69 | #define GENERIC_WRITE (0x40000000L) 70 | #define GENERIC_READ (0x80000000L) 71 | #define FILE_SHARE_READ (0x00000001L) 72 | #define CREATE_NEW (0x00000001L) 73 | #define OPEN_EXISTING (0x00000003L) 74 | #define FILE_ATTRIBUTE_NORMAL (0x00000080L) 75 | #define STILL_ACTIVE (0x00000103L) 76 | #define CRYPT_STRING_HEX_ANY (0x00000008L) 77 | #define CRYPT_STRING_HEXASCIIADDR (0x00000008L) 78 | #define STILL_ACTIVE (0x00000103L) 79 | #define INVALID_FILE_SIZE (0xffffffffL) 80 | #define _TRUNCATE ((SIZE_T)-1LL) 81 | #define LPTHREAD_START_ROUTINE PVOID 82 | #define PIPE_TRANSFER_TIMEOUT 0x03 83 | #define CONSOLE_SCREEN_BUFFER_INFO PVOID // TODO: remove this dummy 84 | #define SOCKET int 85 | #define INVALID_SOCKET -1 86 | #define SOCKET_ERROR -1 87 | #define WSAEWOULDBLOCK 10035L 88 | #define MAXIMUM_WAIT_OBJECTS 64 89 | #define WAIT_OBJECT_0 (0x00000000UL) 90 | #define WAIT_FAILED (0xFFFFFFFFUL) 91 | #define WAIT_TIMEOUT (258L) 92 | #define INFINITE (0xFFFFFFFFUL) 93 | #define E_FAIL (0x80004005UL) 94 | #define error_status_t DWORD 95 | #define SecureZeroMemory(pb, cb) (ZeroMemory(pb, cb)) 96 | #define _itoa_s(n, s, l, b) (snprintf(s, l, "%d", n)) 97 | 98 | #define _In_ 99 | #define _In_z_ 100 | #define _Out_ 101 | #define _Inout_ 102 | #define _Inout_opt_ 103 | #define _In_opt_ 104 | #define _In_opt_z_ 105 | #define _Out_opt_ 106 | #define _Check_return_opt_ 107 | #define _Frees_ptr_opt_ 108 | #define _Post_ptr_invalid_ 109 | #define _Printf_format_string_ 110 | #define _In_reads_(x) 111 | #define _In_reads_opt_(x) 112 | #define _Out_writes_(x) 113 | #define __bcount(x) 114 | #define _Inout_bytecount_(x) 115 | #define _Inout_updates_opt_(x) 116 | #define _Inout_updates_bytes_(x) 117 | #define _Out_writes_opt_(x) 118 | #define _Success_(x) 119 | #define UNREFERENCED_PARAMETER(x) 120 | #define WINAPI 121 | 122 | #define max(a, b) (((a) > (b)) ? (a) : (b)) 123 | #define min(a, b) (((a) < (b)) ? (a) : (b)) 124 | #define _byteswap_ushort(v) (__builtin_bswap16(v)) 125 | #define _byteswap_ulong(v) (__builtin_bswap32(v)) 126 | #define _byteswap_uint64(v) (__builtin_bswap64(v)) 127 | #ifndef _rotr 128 | #define _rotr(v,c) ((((DWORD)v) >> ((DWORD)c) | (DWORD)((DWORD)v) << (32 - (DWORD)c))) 129 | #endif /* _rotr */ 130 | #define _rotr16(v,c) ((((WORD)v) >> ((WORD)c) | (WORD)((WORD)v) << (16 - (WORD)c))) 131 | #define _rotr64(v,c) ((((QWORD)v) >> ((QWORD)c) | (QWORD)((QWORD)v) << (64 - (QWORD)c))) 132 | #define _rotl64(v,c) ((QWORD)(((QWORD)v) << ((QWORD)c)) | (((QWORD)v) >> (64 - (QWORD)c))) 133 | #define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) 134 | #define sprintf_s(s, maxcount, ...) (snprintf(s, maxcount, __VA_ARGS__)) 135 | #define strnlen_s(s, maxcount) (strnlen(s, maxcount)) 136 | #define strcpy_s(dst, len, src) (strncpy(dst, src, len)) 137 | #define strncpy_s(dst, len, src, srclen) (strncpy(dst, src, min((QWORD)(max(1, len)) - 1, (QWORD)(srclen)))) 138 | #define strncat_s(dst, dstlen, src, srclen) (strncat(dst, src, min((((strlen(dst) + 1 >= (QWORD)(dstlen)) || ((QWORD)(dstlen) == 0)) ? 0 : ((QWORD)(dstlen) - strlen(dst) - 1)), (QWORD)(srclen)))) 139 | #define strcat_s(dst, dstlen, src) (strncat_s(dst, dstlen, src, _TRUNCATE)) 140 | #define _vsnprintf_s(dst, len, cnt, fmt, a) (vsnprintf(dst, min((QWORD)(len), (QWORD)(cnt)), fmt, a)) 141 | #define _stricmp(s1, s2) (strcasecmp(s1, s2)) 142 | #define _strnicmp(s1, s2, maxcount) (strncasecmp(s1, s2, maxcount)) 143 | #define strtok_s(s, d, c) (strtok_r(s, d, c)) 144 | #define _snprintf_s(s,l,c,...) (snprintf(s,min((QWORD)(l), (QWORD)(c)),__VA_ARGS__)) 145 | #define sscanf_s(s, f, ...) (sscanf(s, f, __VA_ARGS__)) 146 | #define SwitchToThread() (sched_yield()) 147 | #define ExitThread(dwExitCode) (pthread_exit(dwExitCode)) 148 | #define ExitProcess(c) (exit(c ? EXIT_SUCCESS : EXIT_FAILURE)) 149 | #define Sleep(dwMilliseconds) (usleep(1000*dwMilliseconds)) 150 | #define fopen_s(ppFile, szFile, szAttr) ((*ppFile = fopen(szFile, szAttr)) ? 0 : 1) 151 | #define ZeroMemory(pb, cb) (memset(pb, 0, cb)) 152 | #define WSAGetLastError() (WSAEWOULDBLOCK) // TODO: remove this dummy when possible. 153 | #define _ftelli64(f) (ftello(f)) 154 | #define _fseeki64(f, o, w) (fseeko(f, o, w)) 155 | #define _chsize_s(fd, cb) (ftruncate64(fd, cb)) 156 | #define _fileno(f) (fileno(f)) 157 | #define InterlockedAdd64(p, v) (__sync_add_and_fetch_8(p, v)) 158 | #define InterlockedIncrement64(p) (__sync_add_and_fetch_8(p, 1)) 159 | #define InterlockedIncrement(p) (__sync_add_and_fetch_4(p, 1)) 160 | #define InterlockedDecrement(p) (__sync_sub_and_fetch_4(p, 1)) 161 | #define GetCurrentProcess() ((HANDLE)-1) 162 | #define closesocket(s) close(s) 163 | 164 | #ifndef _LINUX_DEF_CRITICAL_SECTION 165 | #define _LINUX_DEF_CRITICAL_SECTION 166 | typedef struct tdCRITICAL_SECTION { 167 | pthread_mutex_t mutex; 168 | pthread_mutexattr_t mta; 169 | } CRITICAL_SECTION, *LPCRITICAL_SECTION; 170 | #endif /* _LINUX_DEF_CRITICAL_SECTION */ 171 | 172 | VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 173 | VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 174 | VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 175 | BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 176 | VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); 177 | 178 | VOID BusySleep(_In_ DWORD us); 179 | 180 | typedef struct _SYSTEMTIME { 181 | WORD wYear; 182 | WORD wMonth; 183 | WORD wDayOfWeek; 184 | WORD wDay; 185 | WORD wHour; 186 | WORD wMinute; 187 | WORD wSecond; 188 | WORD wMilliseconds; 189 | } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; 190 | 191 | typedef struct _WIN32_FIND_DATAA { 192 | CHAR __cExtension[5]; 193 | CHAR cFileName[MAX_PATH]; 194 | } WIN32_FIND_DATAA, *PWIN32_FIND_DATAA, *LPWIN32_FIND_DATAA; 195 | 196 | HANDLE FindFirstFileA(LPSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData); 197 | BOOL FindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData); 198 | HANDLE LocalAlloc(DWORD uFlags, SIZE_T uBytes); 199 | VOID LocalFree(HANDLE hMem); 200 | QWORD GetTickCount64(); 201 | BOOL QueryPerformanceFrequency(_Out_ LARGE_INTEGER *lpFrequency); 202 | BOOL QueryPerformanceCounter(_Out_ LARGE_INTEGER *lpPerformanceCount); 203 | VOID GetLocalTime(LPSYSTEMTIME lpSystemTime); 204 | DWORD InterlockedAdd(DWORD *Addend, DWORD Value); 205 | BOOL IsWow64Process(HANDLE hProcess, PBOOL Wow64Process); 206 | 207 | HANDLE CreateThread( 208 | PVOID lpThreadAttributes, 209 | SIZE_T dwStackSize, 210 | PVOID lpStartAddress, 211 | PVOID lpParameter, 212 | DWORD dwCreationFlags, 213 | PDWORD lpThreadId 214 | ); 215 | 216 | HMODULE LoadLibraryA(LPSTR lpFileName); 217 | BOOL FreeLibrary(_In_ HMODULE hLibModule); 218 | FARPROC GetProcAddress(HMODULE hModule, LPSTR lpProcName); 219 | 220 | BOOL CloseHandle(_In_ HANDLE hObject); 221 | BOOL ResetEvent(_In_ HANDLE hEvent); 222 | BOOL SetEvent(_In_ HANDLE hEvent); 223 | HANDLE CreateEvent(_In_opt_ PVOID lpEventAttributes, _In_ BOOL bManualReset, _In_ BOOL bInitialState, _In_opt_ PVOID lpName); 224 | DWORD WaitForMultipleObjects(_In_ DWORD nCount, HANDLE *lpHandles, _In_ BOOL bWaitAll, _In_ DWORD dwMilliseconds); 225 | DWORD WaitForSingleObject(_In_ HANDLE hHandle, _In_ DWORD dwMilliseconds); 226 | 227 | VOID Util_GetPathLib(_Out_writes_(MAX_PATH) PCHAR szPath); 228 | 229 | // SRWLOCK 230 | #ifdef LINUX 231 | typedef struct tdSRWLOCK { 232 | uint32_t xchg; 233 | int c; 234 | } SRWLOCK, *PSRWLOCK; 235 | #endif /* LINUX */ 236 | #ifdef MACOS 237 | #include 238 | typedef struct tdSRWLOCK { 239 | union { 240 | QWORD valid; 241 | dispatch_semaphore_t sem; 242 | }; 243 | } SRWLOCK, *PSRWLOCK; 244 | #endif /* MACOS */ 245 | VOID InitializeSRWLock(PSRWLOCK pSRWLock); 246 | VOID AcquireSRWLockExclusive(_Inout_ PSRWLOCK pSRWLock); 247 | VOID ReleaseSRWLockExclusive(_Inout_ PSRWLOCK pSRWLock); 248 | #define AcquireSRWLockShared AcquireSRWLockExclusive 249 | #define ReleaseSRWLockShared ReleaseSRWLockExclusive 250 | #define SRWLOCK_INIT { 0 } 251 | 252 | #endif /* LINUX || MACOS */ 253 | 254 | #endif /* __OSCOMPATIBILITY_H__ */ 255 | --------------------------------------------------------------------------------