initial checkin
This commit is contained in:
@@ -61,3 +61,4 @@ fastlane/test_output
|
||||
# https://github.com/johnno1962/injectionforxcode
|
||||
|
||||
iOSInjectionProject/
|
||||
FileMonitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
CE56C7ED231DAAD10046EDA3 /* File.m in Sources */ = {isa = PBXBuildFile; fileRef = CE56C7EC231DAAD10046EDA3 /* File.m */; };
|
||||
CE91B743231A0E6D003273AF /* FileMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = CE91B742231A0E6D003273AF /* FileMonitor.h */; };
|
||||
CE91B745231A0E6D003273AF /* FileMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91B744231A0E6D003273AF /* FileMonitor.m */; };
|
||||
CE91B74E231A129D003273AF /* Process.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91B74C231A129D003273AF /* Process.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
CE56C7EC231DAAD10046EDA3 /* File.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = File.m; sourceTree = "<group>"; };
|
||||
CE91B73F231A0E6D003273AF /* libFileMonitor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFileMonitor.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
CE91B742231A0E6D003273AF /* FileMonitor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FileMonitor.h; sourceTree = "<group>"; };
|
||||
CE91B744231A0E6D003273AF /* FileMonitor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FileMonitor.m; sourceTree = "<group>"; };
|
||||
CE91B74C231A129D003273AF /* Process.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Process.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
CE91B73D231A0E6D003273AF /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
CE91B736231A0E6D003273AF = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CE91B741231A0E6D003273AF /* Source */,
|
||||
CE91B740231A0E6D003273AF /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CE91B740231A0E6D003273AF /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CE91B73F231A0E6D003273AF /* libFileMonitor.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CE91B741231A0E6D003273AF /* Source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CE91B742231A0E6D003273AF /* FileMonitor.h */,
|
||||
CE91B744231A0E6D003273AF /* FileMonitor.m */,
|
||||
CE91B74C231A129D003273AF /* Process.m */,
|
||||
CE56C7EC231DAAD10046EDA3 /* File.m */,
|
||||
);
|
||||
path = Source;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
CE91B73B231A0E6D003273AF /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CE91B743231A0E6D003273AF /* FileMonitor.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
CE91B73E231A0E6D003273AF /* FileMonitor */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = CE91B748231A0E6D003273AF /* Build configuration list for PBXNativeTarget "FileMonitor" */;
|
||||
buildPhases = (
|
||||
CE91B73B231A0E6D003273AF /* Headers */,
|
||||
CE91B73C231A0E6D003273AF /* Sources */,
|
||||
CE91B73D231A0E6D003273AF /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = FileMonitor;
|
||||
productName = processMonitor;
|
||||
productReference = CE91B73F231A0E6D003273AF /* libFileMonitor.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
CE91B737231A0E6D003273AF /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1100;
|
||||
ORGANIZATIONNAME = "Objective-See";
|
||||
TargetAttributes = {
|
||||
CE91B73E231A0E6D003273AF = {
|
||||
CreatedOnToolsVersion = 11.0;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = CE91B73A231A0E6D003273AF /* Build configuration list for PBXProject "FileMonitor" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = CE91B736231A0E6D003273AF;
|
||||
productRefGroup = CE91B740231A0E6D003273AF /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
CE91B73E231A0E6D003273AF /* FileMonitor */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
CE91B73C231A0E6D003273AF /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CE56C7ED231DAAD10046EDA3 /* File.m in Sources */,
|
||||
CE91B745231A0E6D003273AF /* FileMonitor.m in Sources */,
|
||||
CE91B74E231A129D003273AF /* Process.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
CE91B746231A0E6D003273AF /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
CE91B747231A0E6D003273AF /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
CE91B749231A0E6D003273AF /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
CE91B74A231A0E6D003273AF /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
EXECUTABLE_PREFIX = lib;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
CE91B73A231A0E6D003273AF /* Build configuration list for PBXProject "FileMonitor" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
CE91B746231A0E6D003273AF /* Debug */,
|
||||
CE91B747231A0E6D003273AF /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
CE91B748231A0E6D003273AF /* Build configuration list for PBXNativeTarget "FileMonitor" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
CE91B749231A0E6D003273AF /* Debug */,
|
||||
CE91B74A231A0E6D003273AF /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = CE91B737231A0E6D003273AF /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// Process.m
|
||||
// ProcessMonitor
|
||||
//
|
||||
// Created by Patrick Wardle on 9/1/19.
|
||||
// Copyright © 2019 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#import <libproc.h>
|
||||
#import <bsm/libbsm.h>
|
||||
#import <sys/sysctl.h>
|
||||
|
||||
#import "utilities.h"
|
||||
#import "FileMonitor.h"
|
||||
|
||||
//events
|
||||
extern NSDictionary* eventsOfInterest;
|
||||
|
||||
/* FUNCTIONS */
|
||||
|
||||
@implementation File
|
||||
|
||||
@synthesize process;
|
||||
@synthesize sourcePath;
|
||||
@synthesize destinationPath;
|
||||
|
||||
//init
|
||||
-(id)init:(es_message_t*)message
|
||||
{
|
||||
//init super
|
||||
self = [super init];
|
||||
if(nil != self)
|
||||
{
|
||||
//set type
|
||||
self.event = message->event_type;
|
||||
|
||||
//set process
|
||||
self.process = [[Process alloc] init:message];
|
||||
|
||||
//extract path(s)
|
||||
// logic is specific to event
|
||||
[self extractPaths:message];
|
||||
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
//extract source & destination path
|
||||
// this requires event specific logic
|
||||
-(void)extractPaths:(es_message_t*)message
|
||||
{
|
||||
//event specific logic
|
||||
switch (message->event_type) {
|
||||
|
||||
//create
|
||||
case ES_EVENT_TYPE_NOTIFY_CREATE:
|
||||
|
||||
//set path
|
||||
self.destinationPath = convertStringToken(&message->event.create.target->path);
|
||||
|
||||
break;
|
||||
|
||||
//open
|
||||
case ES_EVENT_TYPE_NOTIFY_OPEN:
|
||||
|
||||
//set path
|
||||
self.destinationPath = convertStringToken(&message->event.open.file->path);
|
||||
|
||||
break;
|
||||
|
||||
//write
|
||||
case ES_EVENT_TYPE_NOTIFY_WRITE:
|
||||
|
||||
//set path
|
||||
self.destinationPath = convertStringToken(&message->event.write.target->path);
|
||||
|
||||
break;
|
||||
|
||||
//close
|
||||
case ES_EVENT_TYPE_NOTIFY_CLOSE:
|
||||
|
||||
//set path
|
||||
self.destinationPath = convertStringToken(&message->event.close.target->path);
|
||||
|
||||
break;
|
||||
|
||||
//link
|
||||
case ES_EVENT_TYPE_NOTIFY_LINK:
|
||||
|
||||
//set (src) path
|
||||
self.sourcePath = convertStringToken(&message->event.link.source->path);
|
||||
|
||||
//set (dest) path
|
||||
// combine dest dir + dest file
|
||||
self.destinationPath = [convertStringToken(&message->event.link.target_dir->path) stringByAppendingPathComponent:convertStringToken(&message->event.link.target_filename)];
|
||||
|
||||
break;
|
||||
|
||||
//rename
|
||||
case ES_EVENT_TYPE_NOTIFY_RENAME:
|
||||
|
||||
//set (src) path
|
||||
self.sourcePath = convertStringToken(&message->event.rename.source->path);
|
||||
|
||||
//existing file ('ES_DESTINATION_TYPE_EXISTING_FILE')
|
||||
if(ES_DESTINATION_TYPE_EXISTING_FILE == message->event.rename.destination_type)
|
||||
{
|
||||
//set (dest) file
|
||||
self.destinationPath = convertStringToken(&message->event.rename.destination.existing_file->path);
|
||||
}
|
||||
//new path ('ES_DESTINATION_TYPE_NEW_PATH')
|
||||
else
|
||||
{
|
||||
//set (dest) path
|
||||
// combine dest dir + dest file
|
||||
self.destinationPath = [convertStringToken(&message->event.rename.destination.new_path.dir->path) stringByAppendingPathComponent:convertStringToken(&message->event.rename.destination.new_path.filename)];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//unlink
|
||||
case ES_EVENT_TYPE_NOTIFY_UNLINK:
|
||||
|
||||
//set path
|
||||
self.destinationPath = convertStringToken(&message->event.unlink.target->path);
|
||||
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//for pretty printing
|
||||
-(NSString *)description
|
||||
{
|
||||
//pretty print
|
||||
return [NSString stringWithFormat: @"%@: \nsource path: %@\ndestination path: %@\nprocess: %@", eventsOfInterest[[NSNumber numberWithInt:self.event]], self.sourcePath, self.destinationPath, process];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// FileMonitor.h
|
||||
// FileMonitor
|
||||
//
|
||||
// Created by Patrick Wardle on 9/1/19.
|
||||
// Copyright © 2019 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <EndpointSecurity/EndpointSecurity.h>
|
||||
|
||||
/* CONSTS */
|
||||
|
||||
//code signing keys
|
||||
#define KEY_SIGNATURE_CDHASH @"cdHash"
|
||||
#define KEY_SIGNATURE_FLAGS @"csFlags"
|
||||
#define KEY_SIGNATURE_IDENTIFIER @"signatureIdentifier"
|
||||
#define KEY_SIGNATURE_TEAM_IDENTIFIER @"teamIdentifier"
|
||||
#define KEY_SIGNATURE_PLATFORM_BINARY @"isPlatforBinary"
|
||||
|
||||
/* CLASSES */
|
||||
@class File;
|
||||
@class Process;
|
||||
|
||||
/* TYPEDEFS */
|
||||
|
||||
//block for library
|
||||
typedef void (^FileCallbackBlock)(File* _Nonnull);
|
||||
|
||||
@interface FileMonitor : NSObject
|
||||
|
||||
//start monitoring
|
||||
-(BOOL)start:(FileCallbackBlock _Nonnull )callback;
|
||||
|
||||
//stop monitoring
|
||||
-(BOOL)stop;
|
||||
|
||||
@end
|
||||
|
||||
/* OBJECT: FILE */
|
||||
|
||||
@interface File : NSObject
|
||||
|
||||
/* PROPERTIES */
|
||||
|
||||
//event
|
||||
// create, write, etc...
|
||||
@property u_int32_t event;
|
||||
|
||||
//src path
|
||||
@property(nonatomic, retain)NSString* _Nullable sourcePath;
|
||||
|
||||
//dest path
|
||||
@property(nonatomic, retain)NSString* _Nullable destinationPath;
|
||||
|
||||
//process
|
||||
@property(nonatomic, retain)Process* _Nullable process;
|
||||
|
||||
/* METHODS */
|
||||
|
||||
//init
|
||||
-(id _Nullable)init:(es_message_t* _Nonnull)message;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/* OBJECT: PROCESS */
|
||||
|
||||
@interface Process : NSObject
|
||||
|
||||
/* PROPERTIES */
|
||||
|
||||
//pid
|
||||
@property pid_t pid;
|
||||
|
||||
//ppid
|
||||
@property pid_t ppid;
|
||||
|
||||
//user id
|
||||
@property uid_t uid;
|
||||
|
||||
//event
|
||||
// exec, fork, exit
|
||||
@property u_int32_t event;
|
||||
|
||||
//exit code
|
||||
@property u_int32_t exit;
|
||||
|
||||
//path
|
||||
@property(nonatomic, retain)NSString* _Nullable path;
|
||||
|
||||
//args
|
||||
@property(nonatomic, retain)NSMutableArray* _Nonnull arguments;
|
||||
|
||||
//ancestors
|
||||
@property(nonatomic, retain)NSMutableArray* _Nonnull ancestors;
|
||||
|
||||
//signing info
|
||||
@property(nonatomic, retain)NSMutableDictionary* _Nonnull signingInfo;
|
||||
|
||||
//timestamp
|
||||
@property(nonatomic, retain)NSDate* _Nonnull timestamp;
|
||||
|
||||
/* METHODS */
|
||||
|
||||
//init
|
||||
-(id _Nullable)init:(es_message_t* _Nonnull)message;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,230 @@
|
||||
//
|
||||
// FileMonitor.m
|
||||
// FileMonitor
|
||||
//
|
||||
// Created by Patrick Wardle on 9/1/19.
|
||||
// Copyright © 2019 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 "FileMonitor.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <EndpointSecurity/EndpointSecurity.h>
|
||||
|
||||
//endpoint
|
||||
es_client_t *endpointClient = nil;
|
||||
|
||||
//file events of interest
|
||||
NSDictionary* eventsOfInterest = nil;
|
||||
|
||||
@implementation FileMonitor
|
||||
|
||||
//init
|
||||
-(id)init
|
||||
{
|
||||
//init super
|
||||
self = [super init];
|
||||
if(nil != self)
|
||||
{
|
||||
//init events of interest
|
||||
eventsOfInterest = @{[NSNumber numberWithInt:ES_EVENT_TYPE_NOTIFY_CREATE]:@"ES_EVENT_TYPE_NOTIFY_CREATE",
|
||||
[NSNumber numberWithInt:ES_EVENT_TYPE_NOTIFY_OPEN]:@"ES_EVENT_TYPE_NOTIFY_OPEN",
|
||||
[NSNumber numberWithInt:ES_EVENT_TYPE_NOTIFY_WRITE]:@"ES_EVENT_TYPE_NOTIFY_WRITE",
|
||||
[NSNumber numberWithInt:ES_EVENT_TYPE_NOTIFY_CLOSE]:@"ES_EVENT_TYPE_NOTIFY_CLOSE",
|
||||
[NSNumber numberWithInt:ES_EVENT_TYPE_NOTIFY_RENAME]:@"ES_EVENT_TYPE_NOTIFY_RENAME",
|
||||
[NSNumber numberWithInt:ES_EVENT_TYPE_NOTIFY_LINK]:@"ES_EVENT_TYPE_NOTIFY_LINK",
|
||||
[NSNumber numberWithInt:ES_EVENT_TYPE_NOTIFY_UNLINK]:@"ES_EVENT_TYPE_NOTIFY_UNLINK"};
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
//start monitoring
|
||||
-(BOOL)start:(FileCallbackBlock)callback
|
||||
{
|
||||
//flag
|
||||
BOOL started = NO;
|
||||
|
||||
//events (as array)
|
||||
es_event_type_t* events = NULL;
|
||||
|
||||
//result
|
||||
es_new_client_result_t result = 0;
|
||||
|
||||
//alloc events
|
||||
events = malloc(sizeof(es_event_type_t) * eventsOfInterest.count);
|
||||
|
||||
//init events
|
||||
// es_* APIs expect a C-array...
|
||||
for(int i = 0; i < eventsOfInterest.count; i++)
|
||||
{
|
||||
//add event
|
||||
events[i] = [eventsOfInterest.allKeys[i] intValue];
|
||||
}
|
||||
|
||||
//sync
|
||||
@synchronized (self)
|
||||
{
|
||||
|
||||
//create client
|
||||
// callback invokes (user) callback for new processes
|
||||
result = es_new_client(&endpointClient, ^(es_client_t *cleint, const es_message_t *message)
|
||||
{
|
||||
//new file event
|
||||
File* file = nil;
|
||||
|
||||
//ignore non-notify messages
|
||||
if(ES_ACTION_TYPE_NOTIFY != message->action_type)
|
||||
{
|
||||
//ignore
|
||||
return;
|
||||
}
|
||||
|
||||
//ignore non-msg's of interest
|
||||
if(nil == [eventsOfInterest objectForKey:[NSNumber numberWithInt:message->event_type]])
|
||||
{
|
||||
//ignore
|
||||
return;
|
||||
}
|
||||
|
||||
//init process obj
|
||||
file = [[File alloc] init:(es_message_t* _Nonnull)message];
|
||||
if(nil != file)
|
||||
{
|
||||
//invoke user callback
|
||||
callback(file);
|
||||
}
|
||||
});
|
||||
|
||||
//error?
|
||||
if(ES_NEW_CLIENT_RESULT_SUCCESS != result)
|
||||
{
|
||||
//err msg
|
||||
NSLog(@"ERROR: es_new_client() failed with %d", result);
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
//mute self
|
||||
// note: you might not want this, but for a cmdline-based filemonitor
|
||||
// this ensures we don't constantly report writes to /dev/tty
|
||||
es_mute_path_literal(endpointClient, [NSProcessInfo.processInfo.arguments[0] UTF8String]);
|
||||
|
||||
//subscribe
|
||||
if(ES_RETURN_SUCCESS != es_subscribe(endpointClient, events, (u_int32_t)eventsOfInterest.count))
|
||||
{
|
||||
//err msg
|
||||
NSLog(@"ERROR: es_subscribe() failed");
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
} //sync
|
||||
|
||||
//happy
|
||||
started = YES;
|
||||
|
||||
bail:
|
||||
|
||||
//free events
|
||||
if(NULL != events)
|
||||
{
|
||||
//free
|
||||
free(events);
|
||||
events = NULL;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
//helper function
|
||||
// convert es_string_token_t to string
|
||||
NSString* convertStringToken(es_string_token_t* stringToken)
|
||||
{
|
||||
//string
|
||||
NSString* string = nil;
|
||||
|
||||
//init to empty string
|
||||
string = [NSString string];
|
||||
|
||||
//sanity check(s)
|
||||
if( (NULL == stringToken) ||
|
||||
(0 == stringToken->length) ||
|
||||
(NULL == stringToken->data) )
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//convert to data, then to string
|
||||
string = [NSString stringWithUTF8String:[[NSData dataWithBytes:stringToken->data length:stringToken->length] bytes]];
|
||||
|
||||
bail:
|
||||
|
||||
return string;
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
//
|
||||
// Process.m
|
||||
// ProcessMonitor
|
||||
//
|
||||
// Created by Patrick Wardle on 9/1/19.
|
||||
// Copyright © 2019 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#import <libproc.h>
|
||||
#import <bsm/libbsm.h>
|
||||
#import <sys/sysctl.h>
|
||||
|
||||
#import "utilities.h"
|
||||
#import "FileMonitor.h"
|
||||
|
||||
/* FUNCTIONS */
|
||||
|
||||
//helper function
|
||||
// get parent of arbitrary process
|
||||
pid_t getParentID(pid_t child);
|
||||
|
||||
@implementation Process
|
||||
|
||||
@synthesize pid;
|
||||
@synthesize exit;
|
||||
@synthesize path;
|
||||
@synthesize ppid;
|
||||
@synthesize event;
|
||||
@synthesize ancestors;
|
||||
@synthesize arguments;
|
||||
@synthesize timestamp;
|
||||
@synthesize signingInfo;
|
||||
|
||||
//init
|
||||
-(id)init:(es_message_t*)message
|
||||
{
|
||||
//init super
|
||||
self = [super init];
|
||||
if(nil != self)
|
||||
{
|
||||
//process from msg
|
||||
es_process_t* process = NULL;
|
||||
|
||||
//alloc array for args
|
||||
self.arguments = [NSMutableArray array];
|
||||
|
||||
//alloc array for parents
|
||||
self.ancestors = [NSMutableArray array];
|
||||
|
||||
//alloc dictionary for signing info
|
||||
self.signingInfo = [NSMutableDictionary dictionary];
|
||||
|
||||
//init exit
|
||||
self.exit = -1;
|
||||
|
||||
//init user id
|
||||
self.uid = -1;
|
||||
|
||||
//init event
|
||||
self.event = -1;
|
||||
|
||||
//set start time
|
||||
self.timestamp = [NSDate date];
|
||||
|
||||
//set type
|
||||
self.event = message->event_type;
|
||||
|
||||
//event specific logic
|
||||
// set type
|
||||
// extract (relevant) process object, etc
|
||||
switch (message->event_type) {
|
||||
|
||||
//exec
|
||||
case ES_EVENT_TYPE_NOTIFY_EXEC:
|
||||
|
||||
//set process (target)
|
||||
process = message->event.exec.target;
|
||||
|
||||
//extract/format args
|
||||
[self extractArgs:&message->event];
|
||||
|
||||
break;
|
||||
|
||||
//fork
|
||||
case ES_EVENT_TYPE_NOTIFY_FORK:
|
||||
|
||||
//set process (child)
|
||||
process = message->event.fork.child;
|
||||
|
||||
break;
|
||||
|
||||
//exit
|
||||
case ES_EVENT_TYPE_NOTIFY_EXIT:
|
||||
|
||||
//set process
|
||||
process = message->process;
|
||||
|
||||
//set exit code
|
||||
self.exit = message->event.exit.stat;
|
||||
|
||||
break;
|
||||
|
||||
//default
|
||||
default:
|
||||
|
||||
//set process
|
||||
process = message->process;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//init pid
|
||||
self.pid = audit_token_to_pid(process->audit_token);
|
||||
|
||||
//init ppid
|
||||
self.ppid = process->ppid;
|
||||
|
||||
//init uuid
|
||||
self.uid = audit_token_to_euid(process->audit_token);
|
||||
|
||||
//init path
|
||||
self.path = convertStringToken(&process->executable->path);
|
||||
|
||||
//extract/format code signing info
|
||||
[self extractSigningInfo:process];
|
||||
|
||||
//enum ancestors
|
||||
[self enumerateAncestors];
|
||||
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
//extract/format args
|
||||
-(void)extractArgs:(es_events_t *)event
|
||||
{
|
||||
//number of args
|
||||
uint32_t count = 0;
|
||||
|
||||
//get # of args
|
||||
count = es_exec_arg_count(&event->exec);
|
||||
if(0 == count)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//extact all args
|
||||
for(uint32_t i = 0; i < count; i++)
|
||||
{
|
||||
//current arg
|
||||
es_string_token_t currentArg = {0};
|
||||
|
||||
//extract current arg
|
||||
currentArg = es_exec_arg(&event->exec, i);
|
||||
|
||||
//append
|
||||
[self.arguments addObject:convertStringToken(¤tArg)];
|
||||
}
|
||||
|
||||
bail:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//extract/format signing info
|
||||
-(void)extractSigningInfo:(es_process_t *)process
|
||||
{
|
||||
//cd hash
|
||||
NSMutableString* cdHash = nil;
|
||||
|
||||
//alloc string for hash
|
||||
cdHash = [NSMutableString string];
|
||||
|
||||
//add flags
|
||||
self.signingInfo[KEY_SIGNATURE_FLAGS] = [NSNumber numberWithUnsignedInt:process->codesigning_flags];
|
||||
|
||||
//add signing id
|
||||
self.signingInfo[KEY_SIGNATURE_IDENTIFIER] = convertStringToken(&process->signing_id);
|
||||
|
||||
//add team id
|
||||
self.signingInfo[KEY_SIGNATURE_TEAM_IDENTIFIER] = convertStringToken(&process->team_id);
|
||||
|
||||
//add platform binary
|
||||
self.signingInfo[KEY_SIGNATURE_PLATFORM_BINARY] = [NSNumber numberWithBool:process->is_platform_binary];
|
||||
|
||||
//format cdhash
|
||||
for(uint32_t i = 0; i<CS_CDHASH_LEN; i++)
|
||||
{
|
||||
//append
|
||||
[cdHash appendFormat:@"%X", process->cdhash[i]];
|
||||
}
|
||||
|
||||
//add cdhash
|
||||
self.signingInfo[KEY_SIGNATURE_CDHASH] = cdHash;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//generate list of ancestors
|
||||
-(void)enumerateAncestors
|
||||
{
|
||||
//current process id
|
||||
pid_t currentPID = -1;
|
||||
|
||||
//parent pid
|
||||
pid_t parentPID = -1;
|
||||
|
||||
//add parent
|
||||
if(-1 != self.ppid)
|
||||
{
|
||||
//add
|
||||
[self.ancestors addObject:[NSNumber numberWithInt:self.ppid]];
|
||||
|
||||
//set current to parent
|
||||
currentPID = self.ppid;
|
||||
}
|
||||
//don't know parent
|
||||
// just start with self
|
||||
else
|
||||
{
|
||||
//start w/ self
|
||||
currentPID = self.pid;
|
||||
}
|
||||
|
||||
//complete ancestry
|
||||
while(YES)
|
||||
{
|
||||
//get parent pid
|
||||
parentPID = getParentID(currentPID);
|
||||
if( (0 == parentPID) ||
|
||||
(-1 == parentPID) ||
|
||||
(currentPID == parentPID) )
|
||||
{
|
||||
//bail
|
||||
break;
|
||||
}
|
||||
|
||||
//update
|
||||
currentPID = parentPID;
|
||||
|
||||
//add
|
||||
[self.ancestors addObject:[NSNumber numberWithInt:parentPID]];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//for pretty printing
|
||||
-(NSString *)description
|
||||
{
|
||||
//description
|
||||
NSString* description = nil;
|
||||
|
||||
//exec/fork events
|
||||
// don't add exit code...
|
||||
if(ES_EVENT_TYPE_NOTIFY_EXIT != self.event)
|
||||
{
|
||||
//pretty print
|
||||
description = [NSString stringWithFormat: @"pid: %d\npath: %@\nuid: %d\nargs: %@\nancestors: %@\nsigning info: %@", self.pid, self.path, self.uid, self.arguments, self.ancestors, self.signingInfo];
|
||||
}
|
||||
//exit event
|
||||
// add exit code
|
||||
else
|
||||
{
|
||||
description = [NSString stringWithFormat: @"pid: %d\npath: %@\nuid: %d\nargs: %@\nancestors: %@\nsigning info: %@\nexit code: %d", self.pid, self.path, self.uid, self.arguments, self.ancestors, self.signingInfo, self.exit];
|
||||
}
|
||||
|
||||
return description;
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
//helper function
|
||||
// get parent of arbitrary process
|
||||
pid_t getParentID(pid_t child)
|
||||
{
|
||||
//parent id
|
||||
pid_t parentID = -1;
|
||||
|
||||
//kinfo_proc struct
|
||||
struct kinfo_proc processStruct = {0};
|
||||
|
||||
//size
|
||||
size_t procBufferSize = 0;
|
||||
|
||||
//mib
|
||||
const u_int mibLength = 4;
|
||||
|
||||
//syscall result
|
||||
int sysctlResult = -1;
|
||||
|
||||
//init buffer length
|
||||
procBufferSize = sizeof(processStruct);
|
||||
|
||||
//init mib
|
||||
int mib[mibLength] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, child};
|
||||
|
||||
//make syscall
|
||||
sysctlResult = sysctl(mib, mibLength, &processStruct, &procBufferSize, NULL, 0);
|
||||
|
||||
//check if got ppid
|
||||
if( (noErr == sysctlResult) &&
|
||||
(0 != procBufferSize) )
|
||||
{
|
||||
//save ppid
|
||||
parentID = processStruct.kp_eproc.e_ppid;
|
||||
}
|
||||
|
||||
return parentID;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// utilities.h
|
||||
// ProcessMonitor
|
||||
//
|
||||
// Created by Patrick Wardle on 9/1/19.
|
||||
// Copyright © 2019 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef utilities_h
|
||||
#define utilities_h
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <EndpointSecurity/EndpointSecurity.h>
|
||||
|
||||
//convert es_string_token_t to string
|
||||
NSString* convertStringToken(es_string_token_t* stringToken);
|
||||
|
||||
#endif /* utilities_h */
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// utilities.m
|
||||
// ProcessMonitor
|
||||
//
|
||||
// Created by Patrick Wardle on 9/1/19.
|
||||
// Copyright © 2019 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#import "utilities.h"
|
||||
|
||||
//convert es_string_token_t to string
|
||||
NSString* convertStringToken(es_string_token_t* stringToken)
|
||||
{
|
||||
//string
|
||||
NSString* string = nil;
|
||||
|
||||
//init to empty string
|
||||
string = [NSString string];
|
||||
|
||||
//sanity check(s)
|
||||
if( (NULL == stringToken) ||
|
||||
(0 == stringToken->length) ||
|
||||
(NULL == stringToken->data) )
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//convert to data, then to string
|
||||
string = [NSString stringWithUTF8String:[[NSData dataWithBytes:stringToken->data length:stringToken->length] bytes]];
|
||||
|
||||
bail:
|
||||
|
||||
return string;
|
||||
}
|
||||
Reference in New Issue
Block a user