Files

168 lines
4.0 KiB
Objective-C

//
// ProcessMonitor.m
// ProcessMonitor
//
// Created by Patrick Wardle on 9/1/19.
// Copyright © 2020 Objective-See. All rights reserved.
//
// Inspired by https://gist.github.com/Omar-Ikram/8e6721d8e83a3da69b31d4c2612a68ba
// NOTE: requires a) root b) the 'com.apple.developer.endpoint-security.client' entitlement
#import "utilities.h"
#import "ProcessMonitor.h"
#import <Foundation/Foundation.h>
#import <EndpointSecurity/EndpointSecurity.h>
//endpoint client
es_client_t* endpointClient = nil;
//pointer to function
// responsibility_get_pid_responsible_for_pid()
pid_t (*getRPID)(pid_t pid) = NULL;
@implementation ProcessMonitor
//start monitoring
// pass in events of interest, count of said events, flag for codesigning, flag for environment variable collection, and callback
-(BOOL)start:(es_event_type_t*)events count:(uint32_t)count csOption:(NSUInteger)csOption parseEnv:(BOOL)parseEnv callback:(ProcessCallbackBlock)callback
{
//flag
BOOL started = NO;
//result
es_new_client_result_t result = 0;
//sync
@synchronized (self)
{
//create client
// callback invokes (user) callback for new processes
result = es_new_client(&endpointClient, ^(es_client_t *client, const es_message_t *message)
{
//new process event
Process* process = nil;
//init process obj
// do static check as well
process = [[Process alloc] init:(es_message_t* _Nonnull)message csOption:csOption parseEnv:parseEnv];
if(nil != process)
{
//invoke user callback
callback(process);
}
});
//error?
if(ES_NEW_CLIENT_RESULT_SUCCESS != result)
{
//err msg
NSLog(@"ERROR: es_new_client() failed");
//provide more info
switch (result) {
//not entitled
case ES_NEW_CLIENT_RESULT_ERR_NOT_ENTITLED:
NSLog(@"ES_NEW_CLIENT_RESULT_ERR_NOT_ENTITLED: \"The caller is not properly entitled to connect\"");
break;
//not permitted
case ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED:
NSLog(@"ES_NEW_CLIENT_RESULT_ERR_NOT_PERMITTED: \"The caller is not permitted to connect. They lack Transparency, Consent, and Control (TCC) approval form the user.\"");
break;
//not privileged
case ES_NEW_CLIENT_RESULT_ERR_NOT_PRIVILEGED:
NSLog(@"ES_NEW_CLIENT_RESULT_ERR_NOT_PRIVILEGED: \"The caller is not running as root\"");
break;
default:
break;
}
//bail
goto bail;
}
//clear cache
if(ES_CLEAR_CACHE_RESULT_SUCCESS != es_clear_cache(endpointClient))
{
//err msg
NSLog(@"ERROR: es_clear_cache() failed");
//bail
goto bail;
}
//subscribe
if(ES_RETURN_SUCCESS != es_subscribe(endpointClient, events, count))
{
//err msg
NSLog(@"ERROR: es_subscribe() failed");
//bail
goto bail;
}
} //sync
//happy
started = YES;
bail:
return started;
}
//stop
-(BOOL)stop
{
//flag
BOOL stopped = NO;
//sync
@synchronized (self)
{
//unsubscribe & delete
if(NULL != endpointClient)
{
//unsubscribe
if(ES_RETURN_SUCCESS != es_unsubscribe_all(endpointClient))
{
//err msg
NSLog(@"ERROR: es_unsubscribe_all() failed");
//bail
goto bail;
}
//delete client
if(ES_RETURN_SUCCESS != es_delete_client(endpointClient))
{
//err msg
NSLog(@"ERROR: es_delete_client() failed");
//bail
goto bail;
}
//unset
endpointClient = NULL;
//happy
stopped = YES;
}
} //sync
bail:
return stopped;
}
@end