├── 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 |
--------------------------------------------------------------------------------