Skip to content

Instantly share code, notes, and snippets.

@knightsc
Last active December 15, 2021 01:35
Show Gist options
  • Save knightsc/f5417a577c14125426146be4d9a3864e to your computer and use it in GitHub Desktop.
Save knightsc/f5417a577c14125426146be4d9a3864e to your computer and use it in GitHub Desktop.
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/kern_control.h>
#include <sys/socket.h>
#include <sys/sys_domain.h>
#include <sys/time.h>
#define ENABLE_KERNEL_HOOK 0x01
#define DISABLE_KERNEL_HOOK 0x02
#define PUT_SCAN_RESULT_MSG 0x04
#define PUT_SCAN_TIME_OUT 0x05
#define PING_KEXT 0x06
#define GENERATE_BYPASS 0x07
#define SCAN_RW_POLICY 0x08
#define SCAN_NW_POLICY 0x09
#define ADD_TRUSTED_PROCESS 0x0d
#define FLUSH_TRUSTED_PROCESS 0x0e
#define INVALIDATE_BOOSTER_CACHE 0x0f
#define ENABLE_BOOSTER_CACHE 0x10
#define SET_LOG_LEVEL 0x11
#define CLEAR_DEVICE_ENTRIES 0x12
#define SET_KERNEL_EXCLUSIONS 0x13
#define CLEAR_KERNEL_EXCLUSIONS 0x14
#define KERN_CONTROL_NAME "com.McAfee.AVKext"
#define FILE_SCAN_MESSAGE_SIZE 1080
#define RESULT_ALLOW 1
#define RESULT_DENY 2
#define FC_OPEN_FOR_READ 0x00
#define FC_OPEN_FOR_WRITE 0x01
#define FC_CLOSE 0x02
#define FC_CLOSE_AFTER_MODIFY 0x03
#define FC_DELETE 0x04
#define FC_EXEC 0x05
#define FC_RENAME 0x06
struct FileScanMessage {
int64_t inode;
int32_t pid;
int32_t uid;
int32_t gid;
int32_t devid;
int32_t result;
int32_t action;
int32_t u1;
int32_t u2;
int64_t u3;
char file[1024];
int64_t u4;
};
static int fd;
static volatile bool running = true;
static pthread_t pingKextThread;
void printFileScanMessage(struct FileScanMessage *m)
{
printf("inode: 0x%016llx\n", m->inode);
printf("pid: %d\n", m->pid);
printf("uid: %d\n", m->uid);
printf("gid: %d\n", m->gid);
printf("devid: 0x%08x\n", m->devid);
printf("result: 0x%08x\n", m->result);
printf("action: 0x%08x\n", m->action);
printf("unknown1: 0x%08x\n", m->u1);
printf("unknown2: 0x%08x\n", m->u2);
printf("unknown3: 0x%016llx\n", m->u3);
printf("file: %s\n", m->file);
printf("unknown4: 0x%016llx\n", m->u4);
}
void intHandler(int sig) {
running = false;
}
void* pingKext(void* data)
{
for (;;) {
int result = setsockopt(fd, SYSPROTO_CONTROL, PING_KEXT, NULL, 0);
if (result == -1){
fprintf(stderr, "Unable to ping kext: %s\n", strerror(errno));
}
sleep(55);
}
}
int spawnPingKextThread()
{
int result;
result = pthread_create(&pingKextThread, NULL, pingKext, NULL);
return result;
}
int connectToKext()
{
struct sockaddr_ctl addr;
struct ctl_info info;
fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if (fd == -1) {
fprintf(stderr, "Unable to create socket\n");
return -1;
}
bzero(&addr, sizeof(addr));
addr.sc_len = sizeof(addr);
addr.sc_family = AF_SYSTEM;
addr.ss_sysaddr = AF_SYS_CONTROL;
memset(&info, 0, sizeof(info));
strncpy(info.ctl_name, KERN_CONTROL_NAME, sizeof(info.ctl_name));
if (ioctl(fd, CTLIOCGINFO, &info)) {
fprintf(stderr, "Unable to send IOCTL to Kext.\n");
return -1;
}
addr.sc_id = info.ctl_id;
addr.sc_unit = 0;
int result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
if (result) {
fprintf(stderr, "Unable to connect to Kext\n");
return -1;
}
return 0;
}
int setKextTrustedProcesses()
{
// Error in flushing trusted processes list
// FLUSH_TRUSTED_PROCESS
// Unable to get the trusted process 'path' at the given tIndex.
//Error in setting trusted processes
// ADD_TRUSTED_PROCESS
return 0;
}
int setBoosterCache(int enabled)
{
int result;
result = setsockopt(fd, SYSPROTO_CONTROL, ENABLE_BOOSTER_CACHE, &enabled, sizeof(enabled));
if (result){
fprintf(stderr, "Unable to change booster cache\n");
}
return result;
}
int initializeKext()
{
int result;
result = setKextTrustedProcesses();
result = setBoosterCache(0);
return result;
}
int enableFileWatching()
{
int result;
result = setsockopt(fd, SYSPROTO_CONTROL, ENABLE_KERNEL_HOOK, NULL, 0);
if (result){
fprintf(stderr, "Unable to start OAS in kext\n");
}
return result;
}
void runLoop()
{
int result;
ssize_t count;
struct timeval timeout;
fd_set readset;
char buffer[FILE_SCAN_MESSAGE_SIZE];
char response[sizeof(int64_t) + FILE_SCAN_MESSAGE_SIZE];
timeout.tv_sec = 10;
timeout.tv_usec = 0;
FD_ZERO(&readset);
FD_SET(fd, &readset);
while (running) {
result = select(fd + 1, &readset, NULL, NULL, &timeout);
if (result < 0) {
running = false;
fprintf(stderr, "Error on select(): %s\n", strerror(errno));
break;
}
if (FD_ISSET(fd, &readset)) {
bzero(&buffer, sizeof(buffer));
count = recv(fd, buffer, FILE_SCAN_MESSAGE_SIZE, 0);
if (count < 0) {
// error
running = false;
close(fd);
fprintf(stderr, "recv() error: %s\n", strerror(errno));
break;
} else if (count == 0) {
// socket was closed
running = false;
close(fd);
fprintf(stderr, "Error while receiving requests from kext\n");
break;
} else {
// Process the message
struct FileScanMessage *message = (struct FileScanMessage *)buffer;
printFileScanMessage(message);
printf("\n");
// Inspect file and set a result
if(strstr(message->file, "Clapzok") != NULL) {
message->result = RESULT_DENY;
} else {
message->result = RESULT_ALLOW;
}
// Send the message back to the kext
int64_t n = 1;
memcpy(response, &n, sizeof(n));
memcpy(response+sizeof(n), buffer, FILE_SCAN_MESSAGE_SIZE);
int result = setsockopt(fd, SYSPROTO_CONTROL, PUT_SCAN_RESULT_MSG, response, sizeof(response));
if (result){
fprintf(stderr, "setsockopt failed on PUT_SCAN_RESULT_MSG: %s\n", strerror(errno));
}
}
}
}
}
int main(int argc, const char * argv[]) {
int result;
signal(SIGINT, intHandler);
if ((result = connectToKext()) < 0) {
exit(1);
}
if ((result = initializeKext()) < 0) {
exit(2);
}
if ((result = spawnPingKextThread()) < 0) {
exit(3);
}
if ((result = enableFileWatching()) < 0) {
exit(4);
}
runLoop();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment