spotlight meta data, entitlements, improved code signing

-extracts spotlight metadata
-extracts entitlements
-improves code-singing checks (mahalo @midnite_runr)
This commit is contained in:
Patrick Wardle
2018-05-25 11:50:43 -10:00
parent 69316cb68d
commit 40c94d78d5
13 changed files with 787 additions and 212 deletions
BIN
View File
Binary file not shown.
+69 -19
View File
@@ -29,6 +29,24 @@
#define EVENT_EXEC 27
#define EVENT_SPAWN 43190
//signature status
#define KEY_SIGNATURE_STATUS @"signatureStatus"
//signing auths
#define KEY_SIGNING_AUTHORITIES @"signingAuthorities"
//code signing id
#define KEY_SIGNATURE_IDENTIFIER @"signingIdentifier"
//file belongs to apple?
#define KEY_SIGNING_IS_APPLE @"signedByApple"
//file signed with apple dev id
#define KEY_SIGNING_IS_APPLE_DEV_ID @"signedWithDevID"
//from app store
#define KEY_SIGNING_IS_APP_STORE @"fromAppStore"
/* TYPEDEFS */
//block for library
@@ -39,12 +57,12 @@ typedef void (^ProcessCallbackBlock)(Process* _Nonnull);
@interface ProcInfo : NSObject
//init
// flag dictates if CPU intensive signing checks should be performed
-(id _Nullable )init:(BOOL)skipSigningInfo;
//init w/ flag
// flag dictates if CPU-intensive logic (code signing, etc) should be preformed
-(id _Nullable)init:(BOOL)goEasy;
//start monitoring
-(BOOL)start:(ProcessCallbackBlock _Nonnull )callback;
-(void)start:(ProcessCallbackBlock _Nonnull )callback;
//stop monitoring
-(void)stop;
@@ -77,26 +95,26 @@ typedef void (^ProcessCallbackBlock)(Process* _Nonnull);
@property u_int32_t exit;
//path
@property (nonatomic, retain) NSString* _Nullable path;
@property(nonatomic, retain)NSString* _Nullable path;
//args
@property (nonatomic, retain) NSMutableArray* _Nonnull arguments;
@property(nonatomic, retain)NSMutableArray* _Nonnull arguments;
//ancestors
@property (nonatomic, retain) NSMutableArray* _Nonnull ancestors;
@property(nonatomic, retain)NSMutableArray* _Nonnull ancestors;
//Binary object
// has path, hash, etc
@property (nonatomic, retain) Binary* _Nonnull binary;
@property(nonatomic, retain)Binary* _Nonnull binary;
//timestamp
@property (nonatomic, retain) NSDate* _Nonnull timestamp;
@property(nonatomic, retain)NSDate* _Nonnull timestamp;
/* METHODS */
//init with a pid
// method will then (try) fill out rest of object
-(id _Nullable )init:(pid_t)processID;
-(id _Nullable)init:(pid_t)processID;
//set process's path
-(void)pathFromPid;
@@ -119,23 +137,36 @@ typedef void (^ProcessCallbackBlock)(Process* _Nonnull);
/* PROPERTIES */
//path
@property (nonatomic, retain)NSString* _Nonnull path;
@property(nonatomic, retain)NSString* _Nonnull path;
//name
@property (nonatomic, retain)NSString* _Nonnull name;
@property(nonatomic, retain)NSString* _Nonnull name;
//icon
@property (nonatomic, retain)NSImage* _Nonnull icon;
@property(nonatomic, retain)NSImage* _Nonnull icon;
//file attributes
@property (nonatomic, retain)NSDictionary* _Nullable attributes;
@property(nonatomic, retain)NSDictionary* _Nullable attributes;
//spotlight meta data
@property(nonatomic, retain)NSDictionary* _Nullable metadata;
//bundle
// nil for non-apps
@property (nonatomic, retain)NSBundle* _Nullable bundle;
@property(nonatomic, retain)NSBundle* _Nullable bundle;
//signing info
@property (nonatomic, retain)NSDictionary* _Nonnull signingInfo;
@property(nonatomic, retain)NSDictionary* _Nonnull signingInfo;
//entitlements
@property(nonatomic, retain)NSDictionary* _Nonnull entitlements;
//hash
@property(nonatomic, retain)NSString* _Nonnull sha256;
//identifier
// either signing id or sha256 hash
@property(nonatomic, retain)NSString* _Nonnull identifier;
//flag indicating binary belongs to Apple OS
@property BOOL isApple;
@@ -145,13 +176,32 @@ typedef void (^ProcessCallbackBlock)(Process* _Nonnull);
/* METHODS */
//init w/ an info dictionary
-(id _Nonnull )init:(NSString* _Nonnull)path;
//init w/ a path
-(id _Nonnull)init:(NSString* _Nonnull)path;
/* the following methods are rather CPU-intensive
as such, if the proc monitoring is run with the 'goEasy' option, they aren't automatically invoked
*/
//get an icon for a process
// for apps, this will be app's icon, otherwise just a standard system one
-(void)getIcon;
//generate signing info
// also classifies if Apple/from App Store/etc.
-(void)generateSigningInfo;
-(void)generateSigningInfo:(SecCSFlags)flags entitlements:(BOOL)entitlements;
//generate entitlements
// note: can also call 'generateSigningInfo' w/ 'entitlements:YES'
-(void)generateEntitlements;
//generate hash
-(void)generateHash;
//generate id
// eithersigning id, or sha256 hash
// note: will generate signing info if needed
-(void)generateIdentifier;
@end
+1 -1
View File
@@ -98,7 +98,7 @@ static const SecAsn1Template kSetOfReceiptAttributeTemplate[] =
/* METHODS */
//init with app path
// ->locate/load receipt, etc
// locate/load receipt, etc
-(instancetype)init:(NSBundle *)bundle;
/* PROPERTIES */
+11 -11
View File
@@ -13,7 +13,7 @@
#import "AppReceipt.h"
//helper function from [1]
// ->extract an int from ASN.1 data
// extract an int from ASN.1 data
inline static int getIntValueFromASN1Data(const ASN1_Data *asn1Data)
{
int ret = 0;
@@ -25,7 +25,7 @@ inline static int getIntValueFromASN1Data(const ASN1_Data *asn1Data)
}
//helper function from [1]
// ->decode string from ASN.1 data
// decode string from ASN.1 data
inline static NSString *decodeUTF8StringFromASN1Data(SecAsn1CoderRef decoder, ASN1_Data srcData)
{
//data struct
@@ -61,7 +61,7 @@ bail:
@synthesize decodedData;
//init with app path
// ->locate/load/decode receipt, etc
// locate/load/decode receipt, etc
-(instancetype)init:(NSBundle *)bundle
{
//init
@@ -101,7 +101,7 @@ bail:
}
//parse out values
// ->bundle id, app version, etc
// bundle id, app version, etc
self.components = [self parse];
if( (nil == self.components) ||
(0 == self.components.count) )
@@ -120,7 +120,7 @@ bail:
}
//decode receipt data
// ->some validations performed here too
// some validations performed here too
-(NSData*)decode
{
//decoded data
@@ -183,7 +183,7 @@ bail:
}
//CHECK 1:
// ->make sure there is a signer
// make sure there is a signer
status = CMSDecoderGetNumSigners(decoder, &signers);
if( (noErr != status) ||
(0 == signers) )
@@ -193,7 +193,7 @@ bail:
}
//CHECK 2:
// ->make sure signer status is ok
// make sure signer status is ok
status = CMSDecoderCopySignerStatus(decoder, 0, policy, TRUE, &signerStatus, &trust, &certVerifyResult);
if( (noErr != status) ||
(kCMSSignerValid != signerStatus) )
@@ -259,7 +259,7 @@ bail:
}
//parse decoded receipt
// ->extract out items such as bundle id, app version, etc.
// extract out items such as bundle id, app version, etc.
-(NSMutableDictionary*)parse
{
//decoder
@@ -297,14 +297,14 @@ bail:
items = [NSMutableDictionary dictionary];
//extact attributes
// ->save those of interest
// save those of interest
for(int i = 0; (attribute = payload.attrs[i]); i++)
{
//process each type
switch(getIntValueFromASN1Data(&attribute->type))
{
//bundle id
// ->save bundle id and data
// save bundle id and data
case RECEIPT_ATTR_BUNDLE_ID:
{
//save bundle id
@@ -345,7 +345,7 @@ bail:
}
//default
// ->ignore
// ignore
default:
{
break;
+115 -14
View File
@@ -19,12 +19,15 @@
@synthesize path;
@synthesize bundle;
@synthesize isApple;
@synthesize metadata;
@synthesize attributes;
@synthesize identifier;
@synthesize isAppStore;
@synthesize signingInfo;
@synthesize entitlements;
//init binary object
// generates signing info, classifies binary, etc
// note: CPU-intensive logic (code signing, etc) called manually
-(id)init:(NSString*)binaryPath
{
//init super
@@ -57,11 +60,11 @@
//get name
[self getName];
//get icon
[self getIcon];
//get attributes
//get file attributes
[self getAttributes];
//get meta data (spotlight)
[self getMetadata];
}
return self;
@@ -89,17 +92,17 @@
// either via app bundle, or from path
-(void)getName
{
//found app bundle?
// grab name from 'CFBundleName'
//first try get name from app bundle
// specifically, via grab name from 'CFBundleName'
if(nil != self.bundle)
{
//extract name
self.name = [self.bundle infoDictionary][@"CFBundleName"];
}
//no app bundle
//no app bundle || no 'CFBundleName'
// just use last component from path
else
if(nil == self.name)
{
//set name
self.name = [self.path lastPathComponent];
@@ -108,7 +111,7 @@
return;
}
//get attributes
//get file attributes
-(void)getAttributes
{
//grab (file) attributes
@@ -117,6 +120,53 @@
return;
}
//get (spotlight) meta data
-(void)getMetadata
{
//md item ref
MDItemRef mdItem = nil;
//attributes names
CFArrayRef attributeNames = nil;
//create
mdItem = MDItemCreate(kCFAllocatorDefault, (CFStringRef)self.path);
if(nil == mdItem)
{
//bail
goto bail;
}
//copy names
attributeNames = MDItemCopyAttributeNames(mdItem);
if(nil == attributeNames)
{
//bail
goto bail;
}
//get metadata
self.metadata = CFBridgingRelease(MDItemCopyAttributes(mdItem, attributeNames));
bail:
//release names
if(nil != attributeNames)
{
//release
CFRelease(attributeNames);
}
//release item
if(nil != mdItem)
{
//release
CFRelease(mdItem);
}
return;
}
//get an icon for a process
// for apps, this will be app's icon, otherwise just a standard system one
-(void)getIcon
@@ -153,7 +203,7 @@
iconExtension = [iconFile pathExtension];
//if its blank (i.e. not specified)
// ->go with 'icns'
// go with 'icns'
if(YES == [iconExtension isEqualTo:@""])
{
//set type
@@ -176,7 +226,7 @@
self.icon = [[NSWorkspace sharedWorkspace] iconForFile:self.path];
//load system document icon
// ->static var, so only load once
// static var, so only load once
if(nil == documentIcon)
{
//load
@@ -204,11 +254,11 @@ bail:
//generate signing info
// also classifies if Apple/from App Store/etc.
-(void)generateSigningInfo
-(void)generateSigningInfo:(SecCSFlags)flags entitlements:(BOOL)entitlements
{
//extract signing info (do this first!)
// from Apple, App Store, signing authorities, etc
self.signingInfo = extractSigningInfo(self.path);
self.signingInfo = extractSigningInfo(self.path, flags, entitlements);
//perform more signing checks and lists
// gotta be happily signed for checks though
@@ -229,6 +279,57 @@ bail:
return;
}
//generate hash
-(void)generateHash
{
//hash
self.sha256 = PI_hashFile(self.path);
return;
}
//generate id
// either signing id, or sha256 hash
// note: will generate signing info if needed
-(void)generateIdentifier
{
//generate signing info?
if(nil == self.signingInfo)
{
//generate
[self generateSigningInfo:kSecCSDefaultFlags entitlements:NO];
}
//validly signed binary?
// use its signing identifier
if( (noErr == [self.signingInfo[KEY_SIGNATURE_STATUS] intValue]) &&
(0 != [self.signingInfo[KEY_SIGNING_AUTHORITIES] count]) &&
(nil != self.signingInfo[KEY_SIGNATURE_IDENTIFIER]) )
{
//use signing id
self.identifier = self.signingInfo[KEY_SIGNATURE_IDENTIFIER];
}
//not validly signed or unsigned
// generate sha256 hash for identifier
else
{
//hash
self.identifier = PI_hashFile(self.path);
}
return;
}
//generate entitlements
// note: can also call 'generateSigningInfo' w/ 'entitlements:YES'
-(void)generateEntitlements
{
//call into helper function
self.entitlements = extractEntitlements(self.path);
return;
}
//for pretty printing
-(NSString *)description
{
+10 -13
View File
@@ -28,22 +28,19 @@
//audit class for exec events
#define AUDIT_CLASS_EXEC 0x40000000
//signature status
#define KEY_SIGNATURE_STATUS @"signatureStatus"
//key for stdout output
#define STDOUT @"stdOutput"
//signing auths
#define KEY_SIGNING_AUTHORITIES @"signingAuthorities"
//file belongs to apple?
#define KEY_SIGNING_IS_APPLE @"signedByApple"
//file signed with apple dev id
#define KEY_SIGNING_IS_APPLE_DEV_ID @"signedWithDevID"
//from app store
#define KEY_SIGNING_IS_APP_STORE @"fromAppStore"
//key for stderr output
#define STDERR @"stdError"
//key for exit code
#define EXIT_CODE @"exitCode"
//path to codesign
#define CODE_SIGN @"/usr/bin/codesign"
//entitlements
#define KEY_SIGNING_ENTITLEMENTS @"entitlements"
#endif /* Consts_h */
+16 -17
View File
@@ -102,7 +102,7 @@ bail:
}
//get uid
// ->sets 'user' instance var
// sets 'user' instance var
-(void)getUser
{
//kinfo_proc struct
@@ -156,7 +156,7 @@ bail:
currentPID = self.ppid;
}
//don't know parent
// ->just start with self
// just start with self
else
{
//start w/ self
@@ -164,7 +164,7 @@ bail:
}
//add until we get to to end (pid 0)
// ->or error out during the traversal
// or error out during the traversal
while(YES)
{
//get parent pid
@@ -300,7 +300,7 @@ bail:
int signalStatus = -1;
//send kill with 0 to determine if alive
// -> see: http://stackoverflow.com/questions/9152979/check-if-process-exists-given-its-pid
// see: http://stackoverflow.com/questions/9152979/check-if-process-exists-given-its-pid
signalStatus = kill(self.pid, 0);
//is alive?
@@ -315,7 +315,7 @@ bail:
}
//extract commandline args
// ->saves into 'arguments' ivar
// saves into 'arguments' ivar
-(void)getArgs
{
//'management info base' array
@@ -340,7 +340,7 @@ bail:
char* parser = NULL;
//init mib
// ->want system's size for max args
// want system's size for max args
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
@@ -363,7 +363,7 @@ bail:
}
//init mib
// ->want process args
// want process args
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = pid;
@@ -379,7 +379,7 @@ bail:
}
//sanity check
// ->ensure buffer is somewhat sane
// ensure buffer is somewhat sane
if(size <= sizeof(int))
{
//bail
@@ -387,12 +387,11 @@ bail:
}
//extract number of args
// ->at start of buffer
// at start of buffer
memcpy(&numberOfArgs, processArgs, sizeof(numberOfArgs));
//init pointer to start of args
// ->they start right after # of args
// they start right after # of args
parser = processArgs + sizeof(numberOfArgs);
//scan until end of process's NULL-terminated path
@@ -410,7 +409,7 @@ bail:
}
//sanity check
// ->make sure end-of-buffer wasn't reached
// make sure end-of-buffer wasn't reached
if(parser == &processArgs[size])
{
//bail
@@ -418,7 +417,7 @@ bail:
}
//skip all trailing NULLs
// ->scan will end when non-NULL is found
// scan will end when non-NULL is found
while(parser < &processArgs[size])
{
//scan till NULL-terminator
@@ -433,7 +432,7 @@ bail:
}
//sanity check
// ->(again), make sure end-of-buffer wasn't reached
// (again), make sure end-of-buffer wasn't reached
if(parser == &processArgs[size])
{
//bail
@@ -441,15 +440,15 @@ bail:
}
//parser should now point to argv[0], process name
// ->init arg start
// init arg start
argStart = parser;
//keep scanning until all args are found
// ->each is NULL-terminated
// each is NULL-terminated
while(parser < &processArgs[size])
{
//each arg is NULL-terminated
// ->so scan till NULL, then save into array
// so scan till NULL, then save into array
if(*parser == '\0')
{
//save arg
+26 -19
View File
@@ -8,7 +8,7 @@
//
//disable incomplete/umbrella warnings
// ->otherwise complains about 'audit_kevents.h'
// otherwise complains about 'audit_kevents.h'
#pragma clang diagnostic ignored "-Wincomplete-umbrella"
#import "Consts.h"
@@ -30,8 +30,8 @@
/* INSTANCE VARIABLES */
//do signing checks?
@property BOOL skipSigningInfo;
//skip CPU-intensive logic
@property BOOL goEasy;
//callback block
@property(nonatomic, copy)ProcessCallbackBlock processCallback;
@@ -72,8 +72,8 @@ bail:
}
//init w/ flag
// flag dictates if CPU intensive signing checks should be performed
-(id _Nullable )init:(BOOL)skipSigningInfo;
// flag dictates if CPU-intensive logic (code signing, etc) should be preformed
-(id _Nullable )init:(BOOL)goEasy;
{
//init
// calls 'super' too
@@ -81,7 +81,7 @@ bail:
if(self)
{
//save mode
self.skipSigningInfo = skipSigningInfo;
self.goEasy = goEasy;
}
bail:
@@ -91,7 +91,7 @@ bail:
//start monitoring
// note: requires root/macOS 10.12.4+ for full monitoring
-(BOOL)start:(ProcessCallbackBlock)callback
-(void)start:(ProcessCallbackBlock)callback
{
//OS version info
NSDictionary* osVersionInfo = nil;
@@ -103,7 +103,7 @@ bail:
osVersionInfo = PI_getOSVersion();
//do basic (app) monitoring
// ->if not root, or OS version is < 10.12.4 (due to kernel bug)
// if not root, or OS version is < 10.12.4 (due to kernel bug)
if( (0 != getuid()) ||
([osVersionInfo[@"minorVersion"] intValue] < OS_MINOR_VERSION_SIERRA) ||
(([osVersionInfo[@"minorVersion"] intValue] == OS_MINOR_VERSION_SIERRA) && ([osVersionInfo[@"bugfixVersion"] intValue] < 4)) )
@@ -125,7 +125,7 @@ bail:
});
}
return NO;
return;
}
//stop monitoring
@@ -136,7 +136,7 @@ bail:
[[NSNotificationCenter defaultCenter] removeObserver: self];
//set 'stop' monitor bool
// ->is checked in 'monitor' method as termination condition
// is checked in 'monitor' method as termination condition
self.shouldStop = YES;
return;
@@ -231,7 +231,7 @@ bail:
}
//set preselect flags
// ->event classes we're interested in
// event classes we're interested in
status = ioctl(auditFileDescriptor, AUDITPIPE_SET_PRESELECT_FLAGS, &eventClasses);
if(-1 == status)
{
@@ -240,7 +240,7 @@ bail:
}
//set non-attributable flags
// ->event classes we're interested in
// event classes we're interested in
status = ioctl(auditFileDescriptor, AUDITPIPE_SET_PRESELECT_NAFLAGS, &eventClasses);
if(-1 == status)
{
@@ -249,7 +249,7 @@ bail:
}
//forever
// ->read/parse/process audit records
// read/parse/process audit records
while(YES)
{
@autoreleasepool
@@ -293,7 +293,7 @@ bail:
processedLength = 0;
//parse record
// ->read all tokens/process
// read all tokens/process
while(0 != recordBalance)
{
//extract token
@@ -301,7 +301,7 @@ bail:
if(-1 == au_fetch_tok(&tokenStruct, recordBuffer + processedLength, recordBalance))
{
//error
// ->skip record
// skip record
break;
}
@@ -311,7 +311,7 @@ bail:
(YES != [self shouldProcessRecord:process.type]) )
{
//bail
// ->skips rest of record
// skips rest of record
break;
}
@@ -700,11 +700,15 @@ bail:
goto bail;
}
//automatically generate signing info?
if(YES != self.skipSigningInfo)
//automatically generate signing info/icon?
// these can be skipped for performance reasons
if(YES != self.goEasy)
{
//generate signing info
[process.binary generateSigningInfo];
[process.binary generateSigningInfo:kSecCSDefaultFlags entitlements:NO];
//set icon
[process.binary getIcon];
}
//invoke user callback
@@ -756,6 +760,9 @@ bail:
continue;
}
//generate signing info
[currentProcess.binary generateSigningInfo:kSecCSDefaultFlags entitlements:NO];
//add
[processes addObject:currentProcess];
}
+10 -6
View File
@@ -16,20 +16,24 @@
/* FUNCTIONS */
//get the signing info of a file
NSDictionary* extractSigningInfo(NSString* path);
NSMutableDictionary* extractSigningInfo(NSString* path, SecCSFlags flags, BOOL entitlements);
//determine if a file is signed by Apple proper
BOOL isApple(NSString* path, SecCSFlags flags);
//determine if file is signed with Apple Dev ID/cert
BOOL isSignedDevID(NSString* binary);
BOOL isSignedDevID(NSString* path, SecCSFlags flags);
//determine if a file is from the app store
// ->gotta be signed w/ Apple Dev ID & have valid app receipt
// gotta be signed w/ Apple Dev ID & have valid app receipt
BOOL fromAppStore(NSString* path);
//get GUID (really just computer's MAC address)
// ->from Apple's 'Get the GUID in OS X' (see: 'Validating Receipts Locally')
// from Apple's 'Get the GUID in OS X' (see: 'Validating Receipts Locally')
NSData* getGUID(void);
//determine if a file is signed by Apple proper
BOOL isApple(NSString* path);
//extact entitlements
// note: execs apple's 'codesign' binary
NSDictionary* extractEntitlements(NSString* path);
#endif
+290 -78
View File
@@ -9,19 +9,130 @@
#import "Consts.h"
#import "Signing.h"
#import "procInfo.h"
#import "Utilities.h"
#import "AppReceipt.h"
#import <mach-o/fat.h>
#import <mach-o/arch.h>
#import <mach-o/swap.h>
#import <sys/sysctl.h>
#import <Security/Security.h>
#import <CommonCrypto/CommonDigest.h>
#import <SystemConfiguration/SystemConfiguration.h>
//determine the offset (if any)
// of the 'best' architecture in a (fat) binary
uint32_t bestArchOffset(NSString* path)
{
//offset of best architecture
uint32_t offset = 0;
//pool
@autoreleasepool
{
//binary
NSMutableData* binary = nil;
//le bytez
const void* binaryBytes = NULL;
//fat header
struct fat_header* fatHeader = NULL;
//number of fat architectures
uint32_t fatArchitectureCount = 0;
//fat architectures
void *fatArchitectures = NULL;
//local architecture
const NXArchInfo *localArchitecture = NULL;
//best matching architecture
struct fat_arch *bestArchitecture = NULL;
//load binary into memory
binary = [NSMutableData dataWithContentsOfFile:path];
if(binary.length < sizeof(struct fat_header))
{
//bail
goto bail;
}
//grab bytes
binaryBytes = binary.bytes;
//not universal (fat)
if( (FAT_MAGIC != *(const uint32_t *)binaryBytes) &&
(FAT_CIGAM != *(const uint32_t *)binaryBytes) )
{
//bail
goto bail;
}
//binary is fat
// init pointer to fat header
fatHeader = (struct fat_header*)binaryBytes;
//swap size?
if(fatHeader->magic == OSSwapHostToBigInt32(FAT_MAGIC))
{
//swap
fatArchitectureCount = OSSwapBigToHostInt32(fatHeader->nfat_arch);
}
//sanity check
if(binary.length <= sizeof(struct fat_header) + fatArchitectureCount * sizeof(struct fat_arch))
{
//bail
goto bail;
}
//init pointer to fat architectures
fatArchitectures = (char*)binaryBytes + sizeof(struct fat_header);
//get local architecture
localArchitecture = NXGetLocalArchInfo();
//swap fat architectures?
if(fatHeader->magic == OSSwapHostToBigInt32(FAT_MAGIC))
{
//swap
swap_fat_arch(fatArchitectures, fatArchitectureCount, localArchitecture->byteorder);
}
//find best architecture
bestArchitecture = NXFindBestFatArch(localArchitecture->cputype, localArchitecture->cpusubtype, fatArchitectures, fatArchitectureCount);
if(NULL == bestArchitecture)
{
//bail
goto bail;
}
//init offset
offset = bestArchitecture->offset;
bail:
;
}//autorelease
return offset;
}
//get the signing info of a item
NSDictionary* extractSigningInfo(NSString* path)
NSMutableDictionary* extractSigningInfo(NSString* path, SecCSFlags flags, BOOL entitlements)
{
//info dictionary
NSMutableDictionary* signingStatus = nil;
NSMutableDictionary* signingInfo = nil;
//offset of best architecture
// for universal/fat binary, need to check correct arch
uint32_t offset = 0;
//code
SecStaticCodeRef staticCode = NULL;
@@ -30,7 +141,7 @@ NSDictionary* extractSigningInfo(NSString* path)
OSStatus status = -1;
//signing information
CFDictionaryRef signingInformation = NULL;
CFDictionaryRef signingDetails = NULL;
//cert chain
NSArray* certificateChain = nil;
@@ -45,23 +156,27 @@ NSDictionary* extractSigningInfo(NSString* path)
CFStringRef commonName = NULL;
//init signing status
signingStatus = [NSMutableDictionary dictionary];
signingInfo = [NSMutableDictionary dictionary];
//sanity check
if(nil == path)
{
//set err
signingStatus[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:errSecCSObjectRequired];
signingInfo[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:errSecCSObjectRequired];
//bail
goto bail;
}
//get offset of 'best' architecute
// this is what loader will run, and thus, what we should validate!
offset = bestArchOffset(path);
//create static code
status = SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:path]), kSecCSDefaultFlags, &staticCode);
status = SecStaticCodeCreateWithPathAndAttributes((__bridge CFURLRef)([NSURL fileURLWithPath:path]), kSecCSDefaultFlags, (__bridge CFDictionaryRef)@{(__bridge NSString *)kSecCodeAttributeUniversalFileOffset : [NSNumber numberWithUnsignedInt:offset]}, &staticCode);
//save signature status
signingStatus[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
signingInfo[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
if(noErr != status)
{
//bail
@@ -69,60 +184,59 @@ NSDictionary* extractSigningInfo(NSString* path)
}
//check signature
status = SecStaticCodeCheckValidityWithErrors(staticCode, kSecCSDoNotValidateResources, NULL, NULL);
status = SecStaticCodeCheckValidity(staticCode, flags, NULL);
//(re)save signature status
signingStatus[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
//if file is signed
// ->grab signing authorities
if(noErr == status)
{
//grab signing authorities
status = SecCodeCopySigningInformation(staticCode, kSecCSSigningInformation, &signingInformation);
if(noErr != status)
{
//bail
goto bail;
}
//determine if binary is signed by Apple
signingStatus[KEY_SIGNING_IS_APPLE] = [NSNumber numberWithBool:isApple(path)];
//not apple proper
// ->is signed with Apple Dev ID?
if(YES != [signingStatus[KEY_SIGNING_IS_APPLE] boolValue])
{
//determine if binary is Apple Dev ID
signingStatus[KEY_SIGNING_IS_APPLE_DEV_ID] = [NSNumber numberWithBool:isSignedDevID(path)];
//if dev id
// ->from app store?
if(YES == [signingStatus[KEY_SIGNING_IS_APPLE_DEV_ID] boolValue])
{
//from app store?
signingStatus[KEY_SIGNING_IS_APP_STORE] = [NSNumber numberWithBool:fromAppStore(path)];
}
}
}
//error
// ->not signed, or something else, so no need to check cert's names
else
signingInfo[KEY_SIGNATURE_STATUS] = [NSNumber numberWithInt:status];
if(noErr != status)
{
//bail
goto bail;
}
//grab signing info
status = SecCodeCopySigningInformation(staticCode, kSecCSSigningInformation, &signingDetails);
if(noErr != status)
{
//bail
goto bail;
}
//grab signing ID
signingInfo[KEY_SIGNATURE_IDENTIFIER] = [(__bridge NSDictionary*)signingDetails objectForKey:(__bridge NSString*)kSecCodeInfoIdentifier];
//determine if binary is signed by Apple
signingInfo[KEY_SIGNING_IS_APPLE] = [NSNumber numberWithBool:isApple(path, flags)];
//not apple proper
// is signed with Apple Dev ID?
if(YES != [signingInfo[KEY_SIGNING_IS_APPLE] boolValue])
{
//determine if binary is Apple Dev ID
signingInfo[KEY_SIGNING_IS_APPLE_DEV_ID] = [NSNumber numberWithBool:isSignedDevID(path, flags)];
//if dev id
// from app store?
if(YES == [signingInfo[KEY_SIGNING_IS_APPLE_DEV_ID] boolValue])
{
//from app store?
signingInfo[KEY_SIGNING_IS_APP_STORE] = [NSNumber numberWithBool:fromAppStore(path)];
}
}
//init array for certificate names
signingStatus[KEY_SIGNING_AUTHORITIES] = [NSMutableArray array];
signingInfo[KEY_SIGNING_AUTHORITIES] = [NSMutableArray array];
//get cert chain
certificateChain = [(__bridge NSDictionary*)signingInformation objectForKey:(__bridge NSString*)kSecCodeInfoCertificates];
certificateChain = [(__bridge NSDictionary*)signingDetails objectForKey:(__bridge NSString*)kSecCodeInfoCertificates];
//get name of all certs
// ->add each to list
// add each to list
for(index = 0; index < certificateChain.count; index++)
{
//reset
commonName = NULL;
//extract cert
certificate = (__bridge SecCertificateRef)([certificateChain objectAtIndex:index]);
@@ -133,28 +247,41 @@ NSDictionary* extractSigningInfo(NSString* path)
if( (noErr != status) ||
(NULL == commonName))
{
//release
if(NULL != commonName)
{
//release
CFRelease(commonName);
}
//skip
continue;
}
//save
[signingStatus[KEY_SIGNING_AUTHORITIES] addObject:(__bridge NSString*)commonName];
[signingInfo[KEY_SIGNING_AUTHORITIES] addObject:(__bridge NSString*)commonName];
//release name
CFRelease(commonName);
}
//add entitlements?
if(YES == entitlements)
{
//extract entitlements via Apple's 'codesign'
signingInfo[KEY_SIGNING_ENTITLEMENTS] = extractEntitlements(path);
}
bail:
//free signing info
if(NULL != signingInformation)
if(NULL != signingDetails)
{
//free
CFRelease(signingInformation);
CFRelease(signingDetails);
//unset
signingInformation = NULL;
signingDetails = NULL;
}
//free static code
@@ -167,11 +294,11 @@ bail:
staticCode = NULL;
}
return signingStatus;
return signingInfo;
}
//determine if a file is signed by Apple proper
BOOL isApple(NSString* path)
BOOL isApple(NSString* path, SecCSFlags flags)
{
//flag
BOOL isApple = NO;
@@ -205,17 +332,17 @@ BOOL isApple(NSString* path)
//check if file is signed by apple by checking if it conforms to req string
// note: ignore 'errSecCSBadResource' as lots of signed apple files return this issue :/
status = SecStaticCodeCheckValidity(staticCode, kSecCSDefaultFlags, requirementRef);
status = SecStaticCodeCheckValidity(staticCode, flags, requirementRef);
if( (noErr != status) &&
(errSecCSBadResource != status) )
{
//bail
// ->just means app isn't signed by apple
// just means isn't signed by apple
goto bail;
}
//ok, happy (SecStaticCodeCheckValidity() didn't fail)
// ->file is signed by Apple
// file is signed by Apple
isApple = YES;
bail:
@@ -244,7 +371,7 @@ bail:
}
//verify the receipt
// ->check bundle ID, app version, and receipt's hash
// check bundle ID, app version, and receipt's hash
BOOL verifyReceipt(NSBundle* appBundle, AppReceipt* receipt)
{
//flag
@@ -280,7 +407,7 @@ BOOL verifyReceipt(NSBundle* appBundle, AppReceipt* receipt)
[digestData appendData:receipt.bundleIdentifierData];
//CHECK 1:
// ->app's bundle ID should match receipt's bundle ID
// app's bundle ID should match receipt's bundle ID
if(YES != [receipt.bundleIdentifier isEqualToString:appBundle.bundleIdentifier])
{
//bail
@@ -288,7 +415,7 @@ BOOL verifyReceipt(NSBundle* appBundle, AppReceipt* receipt)
}
//CHECK 2:
// ->app's version should match receipt's version
// app's version should match receipt's version
if(YES != [receipt.appVersion isEqualToString:appBundle.infoDictionary[@"CFBundleShortVersionString"]])
{
//bail
@@ -296,7 +423,7 @@ BOOL verifyReceipt(NSBundle* appBundle, AppReceipt* receipt)
}
//CHECK 3:
// ->verify receipt's hash (UUID)
// verify receipt's hash (UUID)
//init SHA 1 hash
CC_SHA1(digestData.bytes, (CC_LONG)digestData.length, digestBuffer);
@@ -317,7 +444,7 @@ bail:
}
//get GUID (really just computer's MAC address)
// ->from Apple's 'Get the GUID in OS X' (see: 'Validating Receipts Locally')
// from Apple's 'Get the GUID in OS X' (see: 'Validating Receipts Locally')
NSData* getGUID()
{
//status var
@@ -346,7 +473,7 @@ NSData* getGUID()
//only init guid once
dispatch_once(&onceToken,
^{
^{
//get master port
kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
@@ -404,7 +531,7 @@ NSData* getGUID()
IOObjectRelease(iterator);
//convert guid to NSData*
// ->also release registry property
// also release registry property
if(NULL != registryProperty)
{
//convert
@@ -415,7 +542,7 @@ NSData* getGUID()
}
bail:
;
;
});//only once
@@ -423,7 +550,7 @@ bail:
}
//determine if file is signed with Apple Dev ID/cert
BOOL isSignedDevID(NSString* binary)
BOOL isSignedDevID(NSString* path, SecCSFlags flags)
{
//flag
BOOL signedOK = NO;
@@ -438,7 +565,7 @@ BOOL isSignedDevID(NSString* binary)
OSStatus status = -1;
//create static code
status = SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:binary]), kSecCSDefaultFlags, &staticCode);
status = SecStaticCodeCreateWithPath((__bridge CFURLRef)([NSURL fileURLWithPath:path]), kSecCSDefaultFlags, &staticCode);
if(noErr != status)
{
//bail
@@ -455,16 +582,16 @@ BOOL isSignedDevID(NSString* binary)
}
//check if file is signed w/ apple dev id by checking if it conforms to req string
status = SecStaticCodeCheckValidity(staticCode, kSecCSDefaultFlags, requirementRef);
status = SecStaticCodeCheckValidity(staticCode, flags, requirementRef);
if(noErr != status)
{
//bail
// ->just means app isn't signed by apple dev id
// just means app isn't signed by apple dev id
goto bail;
}
//ok, happy
// ->file is signed by Apple Dev ID
// file is signed by Apple Dev ID
signedOK = YES;
bail:
@@ -493,8 +620,8 @@ bail:
}
//determine if a file is from the app store
// ->gotta be signed w/ Apple Dev ID & have valid app receipt
// note: here, assume this function is only called on Apps signed with Apple Dev ID!
// gotta be signed w/ Apple Dev ID & have valid app receipt
// note: here, assume this function is only called on Apps signed with Apple Dev ID!
BOOL fromAppStore(NSString* path)
{
//flag
@@ -504,16 +631,16 @@ BOOL fromAppStore(NSString* path)
AppReceipt* appReceipt = nil;
//path to app bundle
// ->just have binary
// just have binary
NSBundle* appBundle = nil;
//if it's an app
// ->can directly load app bundle
// can directly load app bundle
appBundle = [NSBundle bundleWithPath:path];
if(nil == appBundle)
{
//find app bundle from binary
// ->likely not an application if this fails
// likely not an application if this fails
appBundle = PI_findAppBundle(path);
if(nil == appBundle)
{
@@ -523,7 +650,7 @@ BOOL fromAppStore(NSString* path)
}
//bail if it doesn't have an receipt
// ->done here, since checking signature is expensive!
// done here, since checking signature is expensive!
if( (nil == appBundle.appStoreReceiptURL) ||
(YES != [[NSFileManager defaultManager] fileExistsAtPath:appBundle.appStoreReceiptURL.path]) )
{
@@ -532,7 +659,7 @@ BOOL fromAppStore(NSString* path)
}
//init
// ->will parse/decode, etc
// will parse/decode, etc
appReceipt = [[AppReceipt alloc] init:appBundle];
if(nil == appReceipt)
{
@@ -548,10 +675,95 @@ BOOL fromAppStore(NSString* path)
}
//happy
// ->app is signed w/ dev ID & its receipt is solid
// app is signed w/ dev ID & its receipt is solid
appStoreApp = YES;
bail:
return appStoreApp;
}
//extact entitlements
// note: execs apple's 'codesign' binary
NSDictionary* extractEntitlements(NSString* path)
{
//entitlements
NSDictionary* entitlements = nil;
//results
NSMutableDictionary* results = nil;
//entitlements at bytes
unsigned char* entitlementBytes = nil;
//entitlements as data
NSData* entitlementsData = nil;
//entitlements as xml
NSString* entitlementsXML = nil;
//if path is '/usr/bin/codesign'
// this isn't entitled, and to avoid recursive calling, just bail
if(YES == [path isEqualToString:CODE_SIGN])
{
//bail
goto bail;
}
//exec 'codesign'
results = PI_execTask(CODE_SIGN, @[@"-d", @"--entitlements", @"-", path], YES, YES);
if(noErr != [results[EXIT_CODE] intValue])
{
//bail
goto bail;
}
//not entitled?
// could just check for nil, but use offset below
if([results[STDOUT] length] < 0x10)
{
//bail
goto bail;
}
//grab bytes
entitlementBytes = (unsigned char*)[results[STDOUT] bytes];
//codesign has a bug where it returns some (encoding?) bytes first
// check for that here, and if found, start string conversion at offset 0x8
if(0xFA == entitlementBytes[0])
{
//convert to string
entitlementsXML = [[NSString alloc] initWithData:[results[STDOUT] subdataWithRange:NSMakeRange(0x8, [results[STDOUT] length] - 0x8)] encoding:NSUTF8StringEncoding];
}
//other just convert as is
else
{
//convert to string
entitlementsXML = [[NSString alloc] initWithData:results[STDOUT] encoding:NSUTF8StringEncoding];
}
//sanity check
// make sure conversion to string ok
if(0 == [entitlementsXML length])
{
//bail
goto bail;
}
//convert to data
entitlementsData = [entitlementsXML dataUsingEncoding:NSUTF8StringEncoding];
if(nil == entitlementsData)
{
//bail
goto bail;
}
//convert to dictionary
entitlements = [NSPropertyListSerialization propertyListWithData:entitlementsData options:NSPropertyListImmutable format:nil error:nil];
bail:
return entitlements;
}
+5 -2
View File
@@ -17,7 +17,7 @@
NSBundle* PI_findAppBundle(NSString* binaryPath);
//check if current OS version is supported
// ->for now, just...?
// for now, just...?
BOOL PI_isSupportedOS(void);
//get OS version
@@ -27,7 +27,7 @@ NSDictionary* PI_getOSVersion(void);
NSMutableArray* PI_enumerateProcesses(void);
//given a bundle
// ->find its executable
// find its executable
NSString* PI_findAppBinary(NSString* appPath);
//sha256 a file
@@ -37,4 +37,7 @@ NSString* PI_hashFile(NSString* filePath);
// find the full path by scanning $PATH
NSString* PI_which(NSString* processName);
//exec a process with args
NSMutableDictionary* PI_execTask(NSString* binaryPath, NSArray* arguments, BOOL shouldWait, BOOL grabOutput);
#endif
+165 -13
View File
@@ -15,7 +15,7 @@
#import <sys/sysctl.h>
//disable deprecated warnings
// ->use 'Gestalt' as this code may run on old OS X vers.
// use 'Gestalt' as this code may run on old OS X vers.
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
//get OS version
@@ -81,7 +81,7 @@ bail:
}
//is current OS version supported?
// ->for now, just OS X 10.8+
// for now, just OS X 10.8+
BOOL PI_isSupportedOS()
{
//support flag
@@ -158,7 +158,7 @@ NSMutableArray* PI_enumerateProcesses()
}
//iterate over all pids
// ->save pid into return array
// save pid into return array
for(int i = 0; i < numberOfProcesses; ++i)
{
//save each pid
@@ -185,7 +185,7 @@ bail:
}
//given a path to binary
// ->parse it back up to find app's bundle
// parse it back up to find app's bundle
NSBundle* PI_findAppBundle(NSString* binaryPath)
{
//app's bundle
@@ -204,24 +204,24 @@ NSBundle* PI_findAppBundle(NSString* binaryPath)
appBundle = [NSBundle bundleWithPath:appPath];
//check for match
// ->binary path's match
// binary path's match
if( (nil != appBundle) &&
(YES == [appBundle.executablePath isEqualToString:binaryPath]))
(YES == [appBundle.executablePath isEqualToString:binaryPath]))
{
//all done
break;
}
//always unset bundle var since it's being returned
// ->and at this point, its not a match
// and at this point, its not a match
appBundle = nil;
//remove last part
// ->will try this next
// will try this next
appPath = [appPath stringByDeletingLastPathComponent];
//scan until we get to root
// ->of course, loop will be exited if app info dictionary is found/loaded
// of course, loop will be exited if app info dictionary is found/loaded
} while( (nil != appPath) &&
(YES != [appPath isEqualToString:@"/"]) &&
(YES != [appPath isEqualToString:@""]) );
@@ -229,7 +229,8 @@ NSBundle* PI_findAppBundle(NSString* binaryPath)
return appBundle;
}
//sha256 a file
//hash a file
// algorithm: sha256
NSString* PI_hashFile(NSString* filePath)
{
//file's contents
@@ -258,7 +259,7 @@ NSString* PI_hashFile(NSString* filePath)
CC_SHA256(fileContents.bytes, (unsigned int)fileContents.length, digestSHA256);
//convert to NSString
// ->iterate over each bytes in computed digest and format
// iterate over each bytes in computed digest and format
for(index=0; index < CC_SHA256_DIGEST_LENGTH; index++)
{
//format/append
@@ -293,11 +294,11 @@ NSString* PI_which(NSString* processName)
pathComponents = [path componentsSeparatedByString:@":"];
//iterate over all path components
// ->build candidate path and check if it exists
// build candidate path and check if it exists
for(NSString* pathComponent in pathComponents)
{
//build candidate path
// ->current path component + process name
// current path component + process name
candidateBinary = [pathComponent stringByAppendingPathComponent:processName];
//check if it exists
@@ -318,3 +319,154 @@ NSString* PI_which(NSString* processName)
return fullPath;
}
//exec a process with args
NSMutableDictionary* PI_execTask(NSString* binaryPath, NSArray* arguments, BOOL shouldWait, BOOL grabOutput)
{
//task
NSTask* task = nil;
//output pipe for stdout
NSPipe* stdOutPipe = nil;
//output pipe for stderr
NSPipe* stdErrPipe = nil;
//read handle for stdout
NSFileHandle* stdOutReadHandle = nil;
//read handle for stderr
NSFileHandle* stdErrReadHandle = nil;
//results dictionary
NSMutableDictionary* results = nil;
//output for stdout
NSMutableData *stdOutData = nil;
//output for stderr
NSMutableData *stdErrData = nil;
//init dictionary for results
results = [NSMutableDictionary dictionary];
//init task
task = [[NSTask alloc] init];
//only setup pipes if wait flag is set
if(YES == grabOutput)
{
//init stdout pipe
stdOutPipe = [NSPipe pipe];
//init stderr pipe
stdErrPipe = [NSPipe pipe];
//init stdout read handle
stdOutReadHandle = [stdOutPipe fileHandleForReading];
//init stderr read handle
stdErrReadHandle = [stdErrPipe fileHandleForReading];
//init stdout output buffer
stdOutData = [NSMutableData data];
//init stderr output buffer
stdErrData = [NSMutableData data];
//set task's stdout
task.standardOutput = stdOutPipe;
//set task's stderr
task.standardError = stdErrPipe;
}
//set task's path
task.launchPath = binaryPath;
//set task's args
if(nil != arguments)
{
//set
task.arguments = arguments;
}
//wrap task launch
@try
{
//launch
[task launch];
}
@catch(NSException *exception)
{
//bail
goto bail;
}
//no need to wait
// can just bail w/ no output
if( (YES != shouldWait) &&
(YES != grabOutput) )
{
//bail
goto bail;
}
//wait
// ...but no output
else if( (YES == shouldWait) &&
(YES != grabOutput) )
{
//wait
[task waitUntilExit];
//add exit code
results[EXIT_CODE] = [NSNumber numberWithInteger:task.terminationStatus];
//bail
goto bail;
}
//grab output?
// even if wait not set, still will wait!
else
{
//read in stdout/stderr
while(YES == [task isRunning])
{
//accumulate stdout
[stdOutData appendData:[stdOutReadHandle readDataToEndOfFile]];
//accumulate stderr
[stdErrData appendData:[stdErrReadHandle readDataToEndOfFile]];
}
//grab any leftover stdout
[stdOutData appendData:[stdOutReadHandle readDataToEndOfFile]];
//grab any leftover stderr
[stdErrData appendData:[stdErrReadHandle readDataToEndOfFile]];
//add stdout
if(0 != stdOutData.length)
{
//add
results[STDOUT] = stdOutData;
}
//add stderr
if(0 != stdErrData.length)
{
//add
results[STDERR] = stdErrData;
}
//add exit code
results[EXIT_CODE] = [NSNumber numberWithInteger:task.terminationStatus];
}
bail:
return results;
}
+69 -19
View File
@@ -29,6 +29,24 @@
#define EVENT_EXEC 27
#define EVENT_SPAWN 43190
//signature status
#define KEY_SIGNATURE_STATUS @"signatureStatus"
//signing auths
#define KEY_SIGNING_AUTHORITIES @"signingAuthorities"
//code signing id
#define KEY_SIGNATURE_IDENTIFIER @"signingIdentifier"
//file belongs to apple?
#define KEY_SIGNING_IS_APPLE @"signedByApple"
//file signed with apple dev id
#define KEY_SIGNING_IS_APPLE_DEV_ID @"signedWithDevID"
//from app store
#define KEY_SIGNING_IS_APP_STORE @"fromAppStore"
/* TYPEDEFS */
//block for library
@@ -39,12 +57,12 @@ typedef void (^ProcessCallbackBlock)(Process* _Nonnull);
@interface ProcInfo : NSObject
//init
// flag dictates if CPU intensive signing checks should be performed
-(id _Nullable )init:(BOOL)skipSigningInfo;
//init w/ flag
// flag dictates if CPU-intensive logic (code signing, etc) should be preformed
-(id _Nullable)init:(BOOL)goEasy;
//start monitoring
-(BOOL)start:(ProcessCallbackBlock _Nonnull )callback;
-(void)start:(ProcessCallbackBlock _Nonnull )callback;
//stop monitoring
-(void)stop;
@@ -77,26 +95,26 @@ typedef void (^ProcessCallbackBlock)(Process* _Nonnull);
@property u_int32_t exit;
//path
@property (nonatomic, retain) NSString* _Nullable path;
@property(nonatomic, retain)NSString* _Nullable path;
//args
@property (nonatomic, retain) NSMutableArray* _Nonnull arguments;
@property(nonatomic, retain)NSMutableArray* _Nonnull arguments;
//ancestors
@property (nonatomic, retain) NSMutableArray* _Nonnull ancestors;
@property(nonatomic, retain)NSMutableArray* _Nonnull ancestors;
//Binary object
// has path, hash, etc
@property (nonatomic, retain) Binary* _Nonnull binary;
@property(nonatomic, retain)Binary* _Nonnull binary;
//timestamp
@property (nonatomic, retain) NSDate* _Nonnull timestamp;
@property(nonatomic, retain)NSDate* _Nonnull timestamp;
/* METHODS */
//init with a pid
// method will then (try) fill out rest of object
-(id _Nullable )init:(pid_t)processID;
-(id _Nullable)init:(pid_t)processID;
//set process's path
-(void)pathFromPid;
@@ -119,23 +137,36 @@ typedef void (^ProcessCallbackBlock)(Process* _Nonnull);
/* PROPERTIES */
//path
@property (nonatomic, retain)NSString* _Nonnull path;
@property(nonatomic, retain)NSString* _Nonnull path;
//name
@property (nonatomic, retain)NSString* _Nonnull name;
@property(nonatomic, retain)NSString* _Nonnull name;
//icon
@property (nonatomic, retain)NSImage* _Nonnull icon;
@property(nonatomic, retain)NSImage* _Nonnull icon;
//file attributes
@property (nonatomic, retain)NSDictionary* _Nullable attributes;
@property(nonatomic, retain)NSDictionary* _Nullable attributes;
//spotlight meta data
@property(nonatomic, retain)NSDictionary* _Nullable metadata;
//bundle
// nil for non-apps
@property (nonatomic, retain)NSBundle* _Nullable bundle;
@property(nonatomic, retain)NSBundle* _Nullable bundle;
//signing info
@property (nonatomic, retain)NSDictionary* _Nonnull signingInfo;
@property(nonatomic, retain)NSDictionary* _Nonnull signingInfo;
//entitlements
@property(nonatomic, retain)NSDictionary* _Nonnull entitlements;
//hash
@property(nonatomic, retain)NSString* _Nonnull sha256;
//identifier
// either signing id or sha256 hash
@property(nonatomic, retain)NSString* _Nonnull identifier;
//flag indicating binary belongs to Apple OS
@property BOOL isApple;
@@ -145,13 +176,32 @@ typedef void (^ProcessCallbackBlock)(Process* _Nonnull);
/* METHODS */
//init w/ an info dictionary
-(id _Nonnull )init:(NSString* _Nonnull)path;
//init w/ a path
-(id _Nonnull)init:(NSString* _Nonnull)path;
/* the following methods are rather CPU-intensive
as such, if the proc monitoring is run with the 'goEasy' option, they aren't automatically invoked
*/
//get an icon for a process
// for apps, this will be app's icon, otherwise just a standard system one
-(void)getIcon;
//generate signing info
// also classifies if Apple/from App Store/etc.
-(void)generateSigningInfo;
-(void)generateSigningInfo:(SecCSFlags)flags entitlements:(BOOL)entitlements;
//generate entitlements
// note: can also call 'generateSigningInfo' w/ 'entitlements:YES'
-(void)generateEntitlements;
//generate hash
-(void)generateHash;
//generate id
// eithersigning id, or sha256 hash
// note: will generate signing info if needed
-(void)generateIdentifier;
@end