diff options
| author | daniel <daniel@planethacker.net> | 2025-05-06 16:57:32 -0700 |
|---|---|---|
| committer | daniel <daniel@planethacker.net> | 2025-05-06 16:57:32 -0700 |
| commit | 2278df1493e064c197913e49b5d1935942d83448 (patch) | |
| tree | 42f06ab2f76e2ddf228bafbb03f79621975a4534 /include | |
initial import
Diffstat (limited to 'include')
| -rw-r--r-- | include/agent_context.h | 23 | ||||
| -rw-r--r-- | include/aho-corasick.h | 30 | ||||
| -rw-r--r-- | include/av_rules.h | 86 | ||||
| -rw-r--r-- | include/base64.h | 4 | ||||
| -rw-r--r-- | include/djb2.h | 5 | ||||
| -rw-r--r-- | include/dns.h | 15 | ||||
| -rw-r--r-- | include/entropy.h | 12 | ||||
| -rw-r--r-- | include/error.h | 8 | ||||
| -rw-r--r-- | include/fanotify.h | 6 | ||||
| -rw-r--r-- | include/hash_ledger.h | 59 | ||||
| -rw-r--r-- | include/json.h | 54 | ||||
| -rw-r--r-- | include/md5.h | 6 | ||||
| -rw-r--r-- | include/net.h | 9 | ||||
| -rw-r--r-- | include/output.h | 4 | ||||
| -rw-r--r-- | include/proc.h | 49 | ||||
| -rw-r--r-- | include/proc_connector.h | 24 | ||||
| -rw-r--r-- | include/proc_ledger.h | 61 | ||||
| -rw-r--r-- | include/sha256.h | 40 | ||||
| -rw-r--r-- | include/sniffer.h | 44 | ||||
| -rw-r--r-- | include/string_common.h | 6 | ||||
| -rw-r--r-- | include/time_common.h | 4 |
21 files changed, 549 insertions, 0 deletions
diff --git a/include/agent_context.h b/include/agent_context.h new file mode 100644 index 0000000..01bd3d0 --- /dev/null +++ b/include/agent_context.h @@ -0,0 +1,23 @@ +#pragma once + +#include <limits.h> + +//#include <linux/limits.h> + +#include "proc_ledger.h" +#include "hash_ledger.h" +#include "aho-corasick.h" +#include "av_rules.h" + +struct agent_context { + struct proc_ledger *proc_ledger; + struct hash_ledger *hash_ledger; + rule_set_t rules; + ac_context_t *ac; + char hostname[HOST_NAME_MAX]; + long ticks; + unsigned long boot_time; + size_t maxsize; +}; + +typedef struct agent_context agent_context_t; diff --git a/include/aho-corasick.h b/include/aho-corasick.h new file mode 100644 index 0000000..a468256 --- /dev/null +++ b/include/aho-corasick.h @@ -0,0 +1,30 @@ +#pragma once + +#include <stddef.h> +#include <stdint.h> + +#define AC_BUF_SIZE 65536 +#define AC_ALPHABET_SIZE 256 + +// forward declaration to allow users to define context +struct ac_context; + +typedef struct ac_match { + const char *id; + size_t offset; + size_t len; +} ac_match_t; + +typedef struct ac_context ac_context_t; +typedef struct pattern_node ac_node_t; +typedef struct pattern_entry ac_pattern_t; + +typedef void (*ac_callback)(const ac_match_t *match, void *user_data); + +ac_context_t *ac_new(void); +void ac_free(ac_context_t *ctx); +int ac_add_pattern(ac_context_t *ctx, const char *id, const uint8_t *pattern, size_t len); +int ac_build(ac_context_t *ctx); +int ac_match(ac_context_t *ctx, const uint8_t *data, size_t len, ac_callback cb, void *user_data); +int ac_match_fd(ac_context_t *ctx, int fd, ac_callback cb, void *user_data); +int ac_match_path(ac_context_t *ctx, const char *path, ac_callback cb, void *user_data); diff --git a/include/av_rules.h b/include/av_rules.h new file mode 100644 index 0000000..8e55a54 --- /dev/null +++ b/include/av_rules.h @@ -0,0 +1,86 @@ +#pragma once + +#include <stddef.h> +#include <stdbool.h> +#include <stdint.h> + +#define MAX_RULE_CONDITIONS 16 +#define MAX_RULES 128 +#define MAX_PATTERNS 512 +#define MAX_MATCH_OFFSETS 64 +#define PATTERN_TABLE_SIZE 1024 + +typedef struct { + const char *id; + uint8_t *bytes; + size_t len; + + size_t match_offsets[MAX_MATCH_OFFSETS]; + size_t match_count; +} pattern_t; + +/* typedef struct { */ +/* const char *id; */ +/* pattern_t *entry; */ +/* } pattern_bucket_t; */ + +typedef struct pattern_bucket { + const char *id; + pattern_t *entry; + struct pattern_bucket *next; +} pattern_bucket_t; + +//pattern_bucket_t *buckets[PATTERN_TABLE_SIZE]; + +typedef struct { + pattern_t patterns[MAX_PATTERNS]; + size_t count; + + pattern_bucket_t *buckets[PATTERN_TABLE_SIZE]; +} pattern_table_t; + + +typedef enum { + RULE_BLOCK, + RULE_ALLOW, + RULE_QUARANTINE, + RULE_INFORMATIONAL +} rule_action_t; + +typedef enum { + COND_TYPE_REQUIRED, // and + COND_TYPE_OPTIONAL, // or + COND_TYPE_NEGATED // not +} condition_type_t; + +typedef struct { + const char *pattern_id; + size_t offset; + bool has_offset; + condition_type_t type; +} rule_condition_t; + +typedef struct { + const char *id; + rule_action_t action; + rule_condition_t conditions[MAX_RULE_CONDITIONS]; + size_t condition_count; +} rule_t; + +typedef struct { + rule_t rules[MAX_RULES]; + size_t rule_count; + pattern_table_t patterns; +} rule_set_t; + + +pattern_t *pattern_table_find(pattern_table_t *table, const char *id); +int pattern_table_add(pattern_table_t *table, const char *id, const uint8_t *bytes, size_t len); +void pattern_table_clear_matches(pattern_table_t *table); +void pattern_table_free(pattern_table_t *table); + +int load_rules(const char *path, rule_set_t *out_ruleset); +rule_action_t parse_action(const char *s); +bool evaluate_rule(const rule_t *rule, pattern_table_t *patterns); +void dump_rule(const rule_t *r); +void free_rules(rule_set_t *rules); diff --git a/include/base64.h b/include/base64.h new file mode 100644 index 0000000..7938980 --- /dev/null +++ b/include/base64.h @@ -0,0 +1,4 @@ +#pragma once + +unsigned char *base64_encode(const unsigned char *, size_t, size_t *); +unsigned char *base64_decode(const unsigned char *, size_t, size_t *); diff --git a/include/djb2.h b/include/djb2.h new file mode 100644 index 0000000..fda01f9 --- /dev/null +++ b/include/djb2.h @@ -0,0 +1,5 @@ +#pragma once + +#include <stdint.h> + +uint32_t djb2(const char *str); diff --git a/include/dns.h b/include/dns.h new file mode 100644 index 0000000..eb8f125 --- /dev/null +++ b/include/dns.h @@ -0,0 +1,15 @@ +#pragma once + +#include <stdint.h> +#include <stddef.h> + +#define MAX_DNS_NAME_LEN 256 +#define MAX_DNS_QUESTIONS 8 + +struct dns_question { + char name[MAX_DNS_NAME_LEN]; + uint16_t qtype; +}; + +const char *dns_type_to_string(uint16_t type); +size_t parse_dns_udp(const uint8_t *payload, size_t len, struct dns_question *out, size_t max_qs); diff --git a/include/entropy.h b/include/entropy.h new file mode 100644 index 0000000..e246682 --- /dev/null +++ b/include/entropy.h @@ -0,0 +1,12 @@ +#include <stddef.h> + +#pragma once + +typedef struct entropy_ctx { + size_t freq[256]; + size_t total_bytes; +} entropy_ctx; + +void entropy_init(entropy_ctx *ctx); +void entropy_update(entropy_ctx *ctx, const unsigned char *buf, size_t len); +double entropy_final(entropy_ctx *ctx); diff --git a/include/error.h b/include/error.h new file mode 100644 index 0000000..5ae9b0d --- /dev/null +++ b/include/error.h @@ -0,0 +1,8 @@ +#pragma once + +#include <string.h> +#include <errno.h> + + +void error(const char *, ...); +void error_fatal(const char *, ...); diff --git a/include/fanotify.h b/include/fanotify.h new file mode 100644 index 0000000..d58109f --- /dev/null +++ b/include/fanotify.h @@ -0,0 +1,6 @@ +#pragma once + +#include "agent_context.h" + +int setup_fanotify(void); +void select_fanotify(int fan_fd, agent_context_t *ctx); diff --git a/include/hash_ledger.h b/include/hash_ledger.h new file mode 100644 index 0000000..24e2ac3 --- /dev/null +++ b/include/hash_ledger.h @@ -0,0 +1,59 @@ +#pragma once + +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <stddef.h> +#include <stdbool.h> +#include <limits.h> + +#define MAX_MATCHED_PATTERNS 32 +#define MAX_MATCHED_RULES 16 + +typedef enum { + VERDICT_UNKNOWN = 0, + VERDICT_ALLOW, + VERDICT_BLOCK, + VERDICT_QUARANTINE, + VERDICT_INFORMATIONAL +} scan_verdict_t; + +struct hash_entry { + char path[PATH_MAX]; + char md5[33]; + char sha256[65]; + double entropy; + struct stat sb; + time_t last_scanned; + size_t scan_count; + + scan_verdict_t verdict; + const char *matched_patterns[MAX_MATCHED_PATTERNS]; + size_t matched_pattern_count; + const char *matched_rules[MAX_MATCHED_RULES]; + size_t matched_rule_count; + + struct hash_entry *next; // collision handling +}; + +struct hash_ledger { + size_t num_buckets; + struct hash_entry **buckets; +}; + +// structure to hold output for multihash() +struct multihash { + char md5[33]; + char sha256[65]; + double entropy; +}; + +// TODO hash_ledger_t +struct hash_ledger *hash_ledger_init(size_t num_buckets); +void hash_ledger_destroy(struct hash_ledger *ledger); +size_t hash_ledger_bucket(struct hash_ledger *ledger, const char *path); +struct hash_entry *hash_ledger_find(struct hash_ledger *ledger, const char *path); +struct hash_entry *hash_ledger_add_or_update(struct hash_ledger *ledger, + const char *path, + struct stat *sb); +bool multihash_file(const char *path, struct multihash *out); diff --git a/include/json.h b/include/json.h new file mode 100644 index 0000000..db508df --- /dev/null +++ b/include/json.h @@ -0,0 +1,54 @@ +#pragma once + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +#define JSON_MAX_DEPTH 8 + +typedef enum { + JSON_CONTEXT_OBJECT, + JSON_CONTEXT_ARRAY +} json_context_t; + +typedef struct { + char *data; + size_t length; + size_t capacity; + json_context_t context_stack[JSON_MAX_DEPTH]; + int context_depth; + bool needs_comma[JSON_MAX_DEPTH]; +} json_t; + +void json_init(json_t *buf); +void json_free(json_t *buf); +const char *json_get(json_t *buf); + +void json_start_object(json_t *buf); +void json_end_object(json_t *buf); +void json_set_needs_comma(json_t *buf); +bool json_needs_comma(json_t *buf); + +void json_append(json_t *buf, const char *fmt, ...); +void json_escape_string(json_t *buf, const char *input); + +void json_add_string(json_t *buf, const char *key, const char *value); +void json_add_string_or_null(json_t *buf, const char *key, const char *value); +void json_add_int(json_t *buf, const char *key, int value); +void json_add_int64(json_t *buf, const char *key, int64_t value); +void json_add_uint64(json_t *buf, const char *key, uint64_t value); +void json_add_double(json_t *buf, const char *key, double value); +void json_add_bool(json_t *buf, const char *key, bool value); +void json_add_null(json_t *buf, const char *key); + +void json_start_array(json_t *buf); +void json_end_array(json_t *buf); +void json_add_array_start(json_t *buf, const char *key); + +void json_array_add_string(json_t *buf, const char *value); +void json_array_add_int(json_t *buf, int value); +void json_array_add_int64(json_t *buf, int64_t value); +void json_array_add_uint64(json_t *buf, uint64_t value); +void json_array_add_double(json_t *buf, double value); +void json_array_add_bool(json_t *buf, bool value); +void json_array_add_null(json_t *buf); diff --git a/include/md5.h b/include/md5.h new file mode 100644 index 0000000..dedb0d1 --- /dev/null +++ b/include/md5.h @@ -0,0 +1,6 @@ +#pragma once + +#define MD5_DIGEST_LENGTH 16 +#define MD5_TOO_LARGE "TOOLARGETOHASH" + +char *md5_digest_file(const char *); diff --git a/include/net.h b/include/net.h new file mode 100644 index 0000000..83e1c47 --- /dev/null +++ b/include/net.h @@ -0,0 +1,9 @@ +#pragma once + +typedef int sock_t; +typedef unsigned short port_t; + +int sockprintf(int, const char *, ...); +bool validate_ip(const char *); +bool validate_ipv4(const char *); +char *get_default_iface(void); diff --git a/include/output.h b/include/output.h new file mode 100644 index 0000000..cb59956 --- /dev/null +++ b/include/output.h @@ -0,0 +1,4 @@ +#pragma once + +void output(const char *); +void msg(const char *, ...); diff --git a/include/proc.h b/include/proc.h new file mode 100644 index 0000000..be737a6 --- /dev/null +++ b/include/proc.h @@ -0,0 +1,49 @@ +#pragma once + +// /proc/PID/status +struct proc_status { + char name[17]; + char state; + pid_t pid; + pid_t tgid; + pid_t ppid; + pid_t tracer_pid; + uid_t uid; + uid_t euid; + uid_t ssuid; + uid_t fsuid; + gid_t gid; + gid_t egid; + gid_t ssgid; + gid_t fsgid; + unsigned int fdsize; + unsigned int threads; + unsigned long cap_inh; + unsigned long cap_prm; + unsigned long cap_eff; + unsigned long cap_bnd; + unsigned long cap_amb; + int no_new_privs; + int seccomp; +}; + +// /proc/PID/stat +struct proc_stat { + char state; + unsigned long starttime; + unsigned long utime; // user time + unsigned long stime; // kernel time + long priority; + long nice; + unsigned long vsize; + long rss; + int tty_nr; +}; + +char *proc_cwd(pid_t); +char *proc_environ(pid_t); +char *proc_exe_path(pid_t); +char *proc_get_exe_path(pid_t); +char *proc_get_cmdline(pid_t); +struct proc_stat proc_parse_stat(pid_t); +struct proc_status proc_get_status(pid_t); diff --git a/include/proc_connector.h b/include/proc_connector.h new file mode 100644 index 0000000..10a20ff --- /dev/null +++ b/include/proc_connector.h @@ -0,0 +1,24 @@ +#pragma once + +#include <linux/connector.h> +#include <linux/cn_proc.h> + +#include "agent_context.h" +#include "proc_ledger.h" +#include "json.h" +#include "net.h" + +sock_t setup_proc_connector(void); +void select_proc_connector(sock_t, agent_context_t *); + +json_t handle_PROC_EVENT_SID(struct proc_event *, agent_context_t *); +json_t handle_PROC_EVENT_COMM(struct proc_event *, agent_context_t *, const char *); +json_t handle_PROC_EVENT_COREDUMP(struct proc_event *, agent_context_t *); +json_t handle_PROC_EVENT_FORK(struct proc_event *, agent_context_t *); +json_t handle_PROC_EVENT_EXEC(struct proc_event *, agent_context_t *); +json_t handle_PROC_EVENT_EXEC_environment(struct proc_event *, agent_context_t *); +json_t handle_PROC_EVENT_EXIT(struct proc_event *, agent_context_t *); +json_t handle_PROC_EVENT_UID(struct proc_event *, agent_context_t *, int, int); +json_t handle_PROC_EVENT_GID(struct proc_event *, agent_context_t *, int, int); +json_t handle_PROC_EVENT_PTRACE(struct proc_event *, agent_context_t *); +json_t handle_PROC_EVENT_UNKNOWN(struct proc_event *, agent_context_t *); diff --git a/include/proc_ledger.h b/include/proc_ledger.h new file mode 100644 index 0000000..d715384 --- /dev/null +++ b/include/proc_ledger.h @@ -0,0 +1,61 @@ +#pragma once + +#include <stddef.h> +#include <stdbool.h> +#include <sys/types.h> +#include <time.h> +#include <limits.h> +//#include <pthread.h> // for the future..maybe... + +#include "json.h" + +struct agent_context; +typedef struct agent_context agent_context_t; + +struct proc_ledger_entry { + pid_t pid; + pid_t tgid; + pid_t ppid; + char exe[PATH_MAX]; + char comm[17]; + char cmdline[4096]; + char cwd[PATH_MAX]; + uid_t uid; + uid_t euid; + gid_t gid; + gid_t egid; + time_t start_time; + unsigned long cpu_user_ticks; + unsigned long cpu_kernel_ticks; + long rss; + unsigned long vsize; + bool daemonized; + bool is_traced; + pid_t tracer_pid; + char state; + int seccomp; + unsigned long cap_eff; + unsigned int threads; + bool has_tty; + struct proc_ledger_entry *next; // for hash collisions +}; + +struct proc_ledger { + size_t num_buckets; + struct proc_ledger_entry **buckets; + //pthread_mutex_t lock; // for the future..maybe... +}; + +struct proc_ledger *proc_ledger_init(size_t num_buckets); +void proc_ledger_destroy(struct proc_ledger *ledger); + +struct proc_ledger_entry *proc_ledger_find(struct proc_ledger *ledger, pid_t pid); +struct proc_ledger_entry *proc_ledger_entry_create(pid_t pid, agent_context_t *ctx); +bool proc_ledger_add(struct proc_ledger *ledger, struct proc_ledger_entry *entry); +bool proc_ledger_remove(struct proc_ledger *ledger, pid_t pid); +bool proc_ledger_replace(struct proc_ledger *ledger, struct proc_ledger_entry *new_entry); +json_t proc_ledger_entry_to_json(struct proc_ledger_entry *entry, + const char *event_type, + struct agent_context *ctx); +void proc_ledger_hydrate(agent_context_t *ctx); +size_t proc_ledger_bucket(struct proc_ledger *ledger, pid_t pid); diff --git a/include/sha256.h b/include/sha256.h new file mode 100644 index 0000000..72cf9c3 --- /dev/null +++ b/include/sha256.h @@ -0,0 +1,40 @@ +/********************************************************************* +* Filename: sha256.h +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Defines the API for the corresponding SHA256 implementation. +*********************************************************************/ + +#ifndef SHA256_H +#define SHA256_H + +/*************************** HEADER FILES ***************************/ +#include <stddef.h> +#include <stdint.h> + +/****************************** MACROS ******************************/ +#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest +#define SHA256_DIGEST_LENGTH SHA256_BLOCK_SIZE +#define SHA256_TOO_LARGE "TOOLARGETOHASH" + +#undef SHA256_SHOW_ERRORS // for debugging + +/**************************** DATA TYPES ****************************/ +typedef unsigned char BYTE; // 8-bit byte +typedef uint32_t WORD; // 32-bit word + +typedef struct { + BYTE data[64]; + WORD datalen; + uint64_t bitlen; + //unsigned long long bitlen; + WORD state[8]; +} SHA256_CTX; + +/*********************** FUNCTION DECLARATIONS **********************/ +void sha256_init(SHA256_CTX *); +void sha256_update(SHA256_CTX *, const BYTE [], size_t); +void sha256_final(SHA256_CTX *, BYTE []); +char *sha256_digest_file(const char *); +#endif // SHA256_H diff --git a/include/sniffer.h b/include/sniffer.h new file mode 100644 index 0000000..8b85100 --- /dev/null +++ b/include/sniffer.h @@ -0,0 +1,44 @@ +#pragma once + +#include <stdbool.h> +#include <stdint.h> + +#include "agent_context.h" +#include "net.h" + +#ifndef TH_FIN +#define TH_FIN 0x01 +#endif + +#ifndef TH_SYN +#define TH_SYN 0x02 +#endif + +#ifndef TH_RST +#define TH_RST 0x04 +#endif + +#ifndef TH_PUSH +#define TH_PUSH 0x08 +#endif + +#ifndef TH_ACK +#define TH_ACK 0x10 +#endif + +#ifndef TH_URG +#define TH_URG 0x20 +#endif + +#ifndef TH_ECE +#define TH_ECE 0x40 +#endif + +#ifndef TH_CWR +#define TH_CWR 0x80 +#endif + +sock_t sniffer_init_interface(const char *interface, bool promisc); +void sniffer_handle_packet(sock_t sniffer, agent_context_t *ctx); + +pid_t match_udp_inode(uint32_t ip_be, uint16_t port_be); diff --git a/include/string_common.h b/include/string_common.h new file mode 100644 index 0000000..bca8985 --- /dev/null +++ b/include/string_common.h @@ -0,0 +1,6 @@ +#pragma once + +#include <stdbool.h> + +bool startswith(const char *, const char *); +bool endswith(const char *, const char *); diff --git a/include/time_common.h b/include/time_common.h new file mode 100644 index 0000000..9f39eef --- /dev/null +++ b/include/time_common.h @@ -0,0 +1,4 @@ +#pragma once + +double timestamp(void); +unsigned long get_boot_time(void); |
