mac中增強版進程查看類(RDProcess)
阿新 • • 發佈:2018-05-13
cocoa1.cocoa 自帶的進程查看信息太少 RDProcess增強版它可以檢查一個進程是否被沙箱化,搜索其包含路徑等
//apple_sandbox.h
//apple_sandbox.h
/* * Copyright (c) 2006-2010 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the ‘License‘). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an ‘AS IS‘ basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef _SANDBOX_H_ #define _SANDBOX_H_ #include <sys/cdefs.h> #include <stdint.h> #include <unistd.h> __BEGIN_DECLS /* * @function sandbox_init * Places the current process in a sandbox with a profile as * specified. If the process is already in a sandbox, the new profile * is ignored and sandbox_init() returns an error. * * @param profile (input) The Sandbox profile to be used. The format * and meaning of this parameter is modified by the `flags‘ parameter. * * @param flags (input) Must be SANDBOX_NAMED. All other * values are reserved. * * @param errorbuf (output) In the event of an error, sandbox_init * will set `*errorbuf` to a pointer to a NUL-terminated string * describing the error. This string may contain embedded newlines. * This error information is suitable for developers and is not * intended for end users. * * If there are no errors, `*errorbuf` will be set to NULL. The * buffer `*errorbuf` should be deallocated with `sandbox_free_error`. * * @result 0 on success, -1 otherwise. */ int sandbox_init(const char *profile, uint64_t flags, char **errorbuf); /* * @define SANDBOX_NAMED The `profile‘ argument specifies a Sandbox * profile named by one of the kSBXProfile* string constants. */ #define SANDBOX_NAMED 0x0001 #ifdef __APPLE_API_PRIVATE /* The following flags are reserved for Mac OS X. Developers should not * depend on their availability. */ /* * @define SANDBOX_NAMED_BUILTIN The `profile‘ argument specifies the * name of a builtin profile that is statically compiled into the * system. */ #define SANDBOX_NAMED_BUILTIN 0x0002 /* * @define SANDBOX_NAMED_EXTERNAL The `profile‘ argument specifies the * pathname of a Sandbox profile. The pathname may be abbreviated: If * the name does not start with a `/‘ it is treated as relative to * /usr/share/sandbox and a `.sb‘ suffix is appended. */ #define SANDBOX_NAMED_EXTERNAL 0x0003 /* * @define SANDBOX_NAMED_MASK Mask for name types: 4 bits, 15 possible * name types, 3 currently defined. */ #define SANDBOX_NAMED_MASK 0x000f #endif /* __APPLE_API_PRIVATE */ /* * Available Sandbox profiles. */ /* TCP/IP networking is prohibited. */ extern const char kSBXProfileNoInternet[]; /* All sockets-based networking is prohibited. */ extern const char kSBXProfileNoNetwork[]; /* File system writes are prohibited. */ extern const char kSBXProfileNoWrite[]; /* File system writes are restricted to temporary folders /var/tmp and * confstr(_CS_DARWIN_USER_DIR, ...). */ extern const char kSBXProfileNoWriteExceptTemporary[]; /* All operating system services are prohibited. */ extern const char kSBXProfilePureComputation[]; /* * @function sandbox_free_error * Deallocates an error string previously allocated by sandbox_init. * * @param errorbuf (input) The buffer to be freed. Must be a pointer * previously returned by sandbox_init in the `errorbuf‘ argument, or NULL. * * @result void */ void sandbox_free_error(char *errorbuf); #ifdef __APPLE_API_PRIVATE /* The following definitions are reserved for Mac OS X. Developers should not * depend on their availability. */ int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf); int sandbox_init_with_extensions(const char *profile, uint64_t flags, const char *const extensions[], char **errorbuf); enum sandbox_filter_type { SANDBOX_FILTER_NONE, SANDBOX_FILTER_PATH, SANDBOX_FILTER_GLOBAL_NAME, SANDBOX_FILTER_LOCAL_NAME, SANDBOX_FILTER_APPLEEVENT_DESTINATION, SANDBOX_FILTER_RIGHT_NAME, }; extern const enum sandbox_filter_type SANDBOX_CHECK_NO_REPORT __attribute__((weak_import)); enum sandbox_extension_flags { FS_EXT_DEFAULTS = 0, FS_EXT_FOR_PATH = (1 << 0), FS_EXT_FOR_FILE = (1 << 1), FS_EXT_READ = (1 << 2), FS_EXT_WRITE = (1 << 3), FS_EXT_PREFER_FILEID = (1 << 4), }; int sandbox_check(pid_t pid, const char *operation, enum sandbox_filter_type type, ...); int sandbox_note(const char *note); int sandbox_suspend(pid_t pid); int sandbox_unsuspend(void); int sandbox_issue_extension(const char *path, char **ext_token); int sandbox_issue_fs_extension(const char *path, uint64_t flags, char **ext_token); int sandbox_issue_fs_rw_extension(const char *path, char **ext_token); int sandbox_issue_mach_extension(const char *name, char **ext_token); int sandbox_consume_extension(const char *path, const char *ext_token); int sandbox_consume_fs_extension(const char *ext_token, char **path); int sandbox_consume_mach_extension(const char *ext_token, char **name); int sandbox_release_fs_extension(const char *ext_token); int sandbox_container_path_for_pid(pid_t pid, char *buffer, size_t bufsize); int sandbox_wakeup_daemon(char **errorbuf); const char *_amkrtemp(const char *); #endif /* __APPLE_API_PRIVATE */ __END_DECLS #endif /* _SANDBOX_H_ */
//RDProcess.h
#import <Foundation/Foundation.h> #import <AppKit/AppKit.h> typedef void (^RDProcessEnumerator)(id process, NSString *bundleID, BOOL *stop); @interface RDProcess : NSObject #pragma mark Initialization with PID - (instancetype)init __attribute__((unavailable("use -initWithPID: instead"))); /** * Returns a process for specified PID with following fields pre-initiated: * - PID value * - Process name (via either LaunchServices API or argv[0]-based value) * - Bundle ID * - Executable path (via either LaunchServices API or proc_pidpath() or, if nothing else, argv[0]-based value) * * @param {(pid_t} aPid the PID of a target process */ - (instancetype)initWithPID: (pid_t)aPid; #pragma mark Creation with Bundle ID + (instancetype)oldestProcessWithBundleID: (NSString *)bundleID; + (instancetype)youngestProcessWithBundleID: (NSString *)bundleID; + (void)enumerateProcessesWithBundleID: (NSString *)bundleID usingBlock: (RDProcessEnumerator)block; + (NSArray *)allProcessesWithBundleID: (NSString *)bundleID; - (pid_t)pid; /** * A name of the process (using either LaunchServices API or argv[0]-based value) * * @return this method should not return `nil` value, but the value may be invalid any other way, * so it‘s up to you to verify it. */ - (NSString *)processName; /** * Sets a new title for the process. * * @brief * This method sets a new value for LaunchServices‘ "Display Name" key of the process; * Please, note that some utils like `ps` or `top` rather depend on an argv[0] value than * on the "Display Name". * @param * {NSString *} new title for the process * @return * {BOOL} Always NO (0) */ - (BOOL)setProcessName: (NSString *)new_proc_name; /** * These methods will return (obviously) `nil` for non-bundled applications. */ - (NSString *)bundleID; - (NSURL *)bundleURL; - (NSString *)bundlePath; - (NSURL *)executableURL; - (NSString *)executablePath; /** * UID, name and full name for a user who owns this process. */ - (uid_t)ownerUserID; - (NSString *)ownerUserName; - (NSString *)ownerFullUserName; /** * List of groups of which the user is member of. * * @format: Keys are groupd ids, values are groups names; */ - (NSDictionary *)ownerGroups; /** * Check if the process is sanboxed by OS X. * * @note * this method returns YES for any process with invalid PID, so you should also check if * [proc sandboxContainerPath] is not nil. * * @return {BOOL} YES or NO, or neither. */ - (BOOL)isSandboxedByOSX; /** * Sandbox container path for the process (if it has one). * @return * {NSString *} containter path or `nil` if the process is not sandboxed. */ - (NSString *)sandboxContainerPath; - (NSURL *)sandboxContainerURL; - (BOOL)canWriteToFileAtPath: (NSString *)file_path; - (BOOL)canWriteToFileAtURL: (NSURL *)file_url; - (BOOL)canReadFileAtPath: (NSString *)file_path; - (BOOL)canReadFileAtURL: (NSURL *)file_url; /** * ARGV and ENV values of a process * * @brief * Until the current user is not a member of `procmod` group, these method will work only for * processes owned by this user (for other‘s processes they return `nil`). */ - (NSArray *)launchArguments; /* @note variable values are percent escaped */ - (NSDictionary *)environmentVariables; /* ------------------------{ NOT IMPLEMENTED YET }------------------------ */ /** * More sandbox stuff */ - (int)_enableSandbox __attribute__((unavailable("not implemented yet"))); - (BOOL)_isSandboxedByUser __attribute__((unavailable("not implemented yet"))); // gonna crash it down - (int)_disableSandbox __attribute__((unavailable("not implemented yet"))); // Intel - (NSString *)architectureString __attribute__((unavailable("not implemented yet"))); // smth like "Intel (64 bit)" - (NSString *)kindString __attribute__((unavailable("not implemented yet"))); - (BOOL)is64bit __attribute__((unavailable("not implemented yet"))); // 0-100% - (NSUInteger)CPUUsagePercentages __attribute__((unavailable("not implemented yet"))); // msec - (NSUInteger)CPUTimeMsec __attribute__((unavailable("not implemented yet"))); - (NSUInteger)threadsCount __attribute__((unavailable("not implemented yet"))); - (NSUInteger)activeThreadsCount __attribute__((unavailable("not implemented yet"))); - (NSUInteger)inactiveThreadsCount __attribute__((unavailable("not implemented yet"))); - (NSUInteger)openPortsCount __attribute__((unavailable("not implemented yet"))); - (NSUInteger)memoryUsageRealBytes __attribute__((unavailable("not implemented yet"))); - (NSUInteger)memoryUsageRealPrivateBytes __attribute__((unavailable("not implemented yet"))); - (NSUInteger)memoryUsageRealSharedBytes __attribute__((unavailable("not implemented yet"))); - (NSUInteger)memoryUsageVirtualPrivateBytes __attribute__((unavailable("not implemented yet"))); - (NSUInteger)messagesSent __attribute__((unavailable("not implemented yet"))); - (NSUInteger)messagesReceived __attribute__((unavailable("not implemented yet"))); @end
//RDProcess.m
#import <grp.h> #import <pwd.h> #import <unistd.h> #import <libproc.h> #import <sys/sysctl.h> #import <mach-o/dyld.h> #import <sys/proc_info.h> #import "RDProcess.h" #import "apple_sandbox.h" #define RDSymbolNameStr(symbol) (CFSTR("_"#symbol)) #define kPasswdBufferSize (128) #define kSandboxContainerPathBufferSize (2024) #define kLaunchServicesMagicConstant (-2) // or (-1), the difference is unknown static CFTypeRef (*LSCopyApplicationInformation)(int, const void*, CFArrayRef) = NULL; static CFTypeRef (*LSSetApplicationInformation)(int, CFTypeRef, CFDictionaryRef, void *) = NULL; static CFTypeRef (*LSASNCreateWithPid)(CFAllocatorRef, pid_t) = NULL; static CFStringRef (kLSDisplayNameKey) = NULL; static CFStringRef (kLSPIDKey) = NULL; static CFStringRef (kLSBundlePathKey) = NULL; static CFStringRef (kLSExecutablePathKey) = NULL; typedef NS_ENUM(NSUInteger, RDProcessForBundleIDEnumerationOption) { kRDProcessForBundleIDYoungest = 0, kRDProcessForBundleIDOldest, kRDProcessForBundleIDAll }; static const CFStringRef kLaunchServicesBundleID = CFSTR("com.apple.LaunchServices"); @interface RDProcess() { /* General *dynamic* info */ pid_t _pid; NSString *_process_name; NSString *_bundle_id, *_bundle_path; NSString *_executable_path; uid_t _uid; NSString *_owner_user_name, *_owner_full_user_name; /* Sanboxing */ BOOL _sandboxed; // sandboxed by OS X BOOL _sandboxed_by_user; NSString *_sandbox_container_path; /* stuff */ NSArray *_launch_args; NSDictionary *_env_variables; /* Not implemented yet */ NSString *kind_string; NSUInteger cpu_usage, cpu_time_msec; NSUInteger threads_count, open_ports_count; NSUInteger memory_real_bytes, memory_real_private_bytes, memory_real_shared_bytes, memory_virtual_private_bytes; NSUInteger messages_sent, messages_received; NSLock *lock; } + (BOOL)_checkIfWeCanAccessPIDAtTheMoment: (pid_t)a_pid; + (NSArray *)_lookupForProcessesWithBundleID: (NSString *)bundleID options: (RDProcessForBundleIDEnumerationOption)option; - (void)_requestOwnerNames; - (BOOL)_requestProcessArgumentsAndEnvironment; - (BOOL)_checkSandboxOperation: (const char *)operation forItemAtPath: (NSString *)item_path; - (BOOL)_findLSPrivateSymbols; - (void)_fetchNewDataFromLaunchServicesWithAtLeastOneKey: (CFStringRef)key; - (void)_updateWithLSDictionary: (CFDictionaryRef)dictionary; @end @implementation RDProcess - (instancetype)initWithPID: (pid_t)a_pid { BOOL pid_is_available = [[self class] _checkIfWeCanAccessPIDAtTheMoment: a_pid]; if (NO == pid_is_available) { return (nil); } if ((self = [super init])) { _pid = a_pid; _uid = -1; _owner_user_name = nil; _owner_full_user_name = nil; [self _fetchNewDataFromLaunchServicesWithAtLeastOneKey: NULL]; } return (self); } + (instancetype)oldestProcessWithBundleID: (NSString *)bundleID { return [[self _lookupForProcessesWithBundleID: bundleID option: kRDProcessForBundleIDOldest] lastObject]; } + (instancetype)youngestProcessWithBundleID: (NSString *)bundleID { return [[self _lookupForProcessesWithBundleID: bundleID option: kRDProcessForBundleIDYoungest] lastObject]; } + (void)enumerateProcessesWithBundleID: (NSString *)bundleID usingBlock: (RDProcessEnumerator)block { if (!block) { return; } NSArray *procs = [self allProcessesWithBundleID: bundleID]; if (!procs) { return; } [procs enumerateObjectsUsingBlock: ^(id process, NSUInteger idx, BOOL *stop){ block(process, bundleID, stop); }]; } + (NSArray *)allProcessesWithBundleID: (NSString *)bundleID { return [self _lookupForProcessesWithBundleID: bundleID option: kRDProcessForBundleIDAll]; } + (BOOL)_checkIfWeCanAccessPIDAtTheMoment: (pid_t)a_pid { if (a_pid < 0) return NO; /** * kill(0) here is an indicator that we have a process with * such PID and can access it. */ int err = kill(a_pid, 0); switch (err) { case (-1): { NSLog(@"Could not access pid (%d)", a_pid); return (errno != ESRCH); } case (0): { return YES; } default: { NSLog(@"Pid %d doesn‘t exist", a_pid); return NO; } } } + (NSArray *)_lookupForProcessesWithBundleID: (NSString *)bundleID option: (RDProcessForBundleIDEnumerationOption)option { if (bundleID.length == 0) { return (nil); } ProcessSerialNumber psn = {0, kNoProcess}; UInt32 oldest_proc_launch_date = UINT32_MAX, youngest_proc_launch_date = 0; NSMutableArray *procs = nil; BOOL find_youngest = (option == kRDProcessForBundleIDYoungest); BOOL find_oldest = (option == kRDProcessForBundleIDOldest); pid_t target_pid = (-1); BOOL find_all = !(find_youngest || find_oldest); if (find_all) { procs = [[NSMutableArray alloc] init]; } /** * Seems like the only *public* way to iterate over all running processes is GetNextProcess() * which is a simple wrapper for LSCopyRunningApplicationArray(). * * So, @todo: use LSCopyRunningApplicationArray() directly. */ while (KERN_SUCCESS == GetNextProcess(&psn)) { struct ProcessInfoRec info = {0}; info.processInfoLength = sizeof(&info); int err = GetProcessInformation(&psn, &info); if (err != KERN_SUCCESS) { NSLog(@"GetProcessInformation returned %d: %@", err, [NSError errorWithDomain: NSOSStatusErrorDomain code: err userInfo: nil]); continue; } pid_t pid = 0; GetProcessPID(&psn, &pid); CFTypeRef asn = LSASNCreateWithPid(kCFAllocatorDefault, pid); CFDictionaryRef proc_info = LSCopyApplicationInformation(kLaunchServicesMagicConstant, asn, NULL); CFRelease(asn); if (!proc_info) { continue; } CFStringRef found_bundle_id = CFDictionaryGetValue(proc_info, kCFBundleIdentifierKey); if (!found_bundle_id) { CFRelease(proc_info); continue; } BOOL (^checkIfBundleIDMatches)(CFStringRef, CFStringRef) = ^BOOL(CFStringRef a, CFStringRef b) { return (CFStringCompare(a, b, 0) == kCFCompareEqualTo); }; if (find_oldest && info.processLaunchDate < oldest_proc_launch_date) { if (checkIfBundleIDMatches(found_bundle_id, (__bridge CFStringRef)bundleID)) { oldest_proc_launch_date = info.processLaunchDate; target_pid = pid; } } if (find_youngest && info.processLaunchDate > youngest_proc_launch_date) { if (checkIfBundleIDMatches(found_bundle_id, (__bridge CFStringRef)bundleID)) { youngest_proc_launch_date = info.processLaunchDate; target_pid = pid; } } if (find_all) { if (checkIfBundleIDMatches(found_bundle_id, (__bridge CFStringRef)bundleID)) { [procs addObject: [[RDProcess alloc] initWithPID: pid]]; } } CFRelease(proc_info); } if (find_all) { NSArray *result = [NSArray arrayWithArray: procs]; // [procs release]; return (result); } else { if (target_pid == (-1)) { return nil; } else { return @[[[RDProcess alloc] initWithPID: target_pid]]; } } } - (NSString *)description { return [NSString stringWithFormat: @"<%@: %@ (%@/%d) owned by %@ (%d)>", NSStringFromClass([self class]), self.processName, self.bundleID, self.pid, self.ownerUserName, self.ownerUserID]; } - (NSString *)processName { if (!_process_name) { [self _fetchNewDataFromLaunchServicesWithAtLeastOneKey: kLSDisplayNameKey]; if (!_process_name) { //_process_name = [[self.executablePath lastPathComponent] retain]; } } return _process_name; } - (BOOL)setProcessName: (NSString *)new_proc_name { if (self.processName.length == 0 || new_proc_name.length == 0) { return NO; } const char *pConstChar = [new_proc_name UTF8String]; // CFDictionaryRef tmp_dict = CFDictionaryCreate(kCFAllocatorDefault, // (const void **)&kLSDisplayNameKey, (const void **)&new_proc_name, // 1, // &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryRef tmp_dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&kLSDisplayNameKey, (const void **)&pConstChar, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); LSSetApplicationInformation(kLaunchServicesMagicConstant, LSASNCreateWithPid(kCFAllocatorDefault, self.pid), tmp_dict, NULL); CFRelease(tmp_dict); /* Force updating the process name value via LaunchServices */ [self _fetchNewDataFromLaunchServicesWithAtLeastOneKey: kLSDisplayNameKey]; return NO; } - (pid_t)pid { /** * I‘m not sure * 1) if PID is likely to change during a process lifetime and * 2) if we should ask LS for a PID every time this method gets called; * * @todo: make sure about both points above. */ [self _fetchNewDataFromLaunchServicesWithAtLeastOneKey: kLSPIDKey]; return _pid; } - (NSString *)bundleID { if (!_bundle_id) { [self _fetchNewDataFromLaunchServicesWithAtLeastOneKey: kCFBundleIdentifierKey]; if (!_bundle_id && _executable_path) { /* Maybe we have a bundle even if Launch Services said no? */ NSString *path = [_executable_path stringByDeletingLastPathComponent]; // remove executable name path = [path stringByReplacingOccurrencesOfString: @"/Contents/MacOS" withString: @""]; NSBundle *lasthope = [NSBundle bundleWithPath: path]; _bundle_id = [lasthope bundleIdentifier]; /* Let‘s also fix the bundle path */ if (!_bundle_path) { // _bundle_path = [path retain]; } } } return _bundle_id; } - (NSURL *)bundleURL { if (!self.bundlePath) { return (nil); } return [NSURL fileURLWithPath: self.bundlePath]; } - (NSString *)bundlePath { if (!_bundle_path) { [self _fetchNewDataFromLaunchServicesWithAtLeastOneKey: kLSBundlePathKey]; } return _bundle_path; } - (NSURL *)executableURL { if (!self.executablePath) { return (nil); } return [NSURL fileURLWithPath: self.executablePath]; } - (NSString *)executablePath { if (!_executable_path) { /* First we ask LaunchServies API */ [self _fetchNewDataFromLaunchServicesWithAtLeastOneKey: kLSExecutablePathKey]; /* If it fails, ask for argv[0] */ if (!_executable_path) { // _executable_path = [[self.launchArguments objectAtIndex: 0] retain]; } /* If argv[0] doesn‘t exist (which is unlikely to happen, but anyway), use `proc_pidpath()`*/ if (!_executable_path) { char *buf = malloc(sizeof(*buf) * kSandboxContainerPathBufferSize); int err = proc_pidpath(self.pid, buf, kSandboxContainerPathBufferSize); if (err) { _executable_path = [NSString stringWithUTF8String: buf]; } free(buf); } } return _executable_path; } - (uid_t)ownerUserID { if (_uid == -1) { pid_t current_pid = self.pid; struct kinfo_proc process_info; int ctl_args[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, current_pid }; size_t info_size = sizeof(process_info); int err = sysctl(ctl_args, 4, &process_info, &info_size, NULL, 0); if (err == KERN_SUCCESS && info_size > 0) { _uid = process_info.kp_eproc.e_ucred.cr_uid; } } return _uid; } - (void)_requestOwnerNames { if (_owner_user_name && _owner_full_user_name) { return; } struct passwd user_data, *tmp = NULL; uid_t user_id = [self ownerUserID]; if (user_id == -1) { return; } char* buffer = malloc(sizeof(*buffer) * kPasswdBufferSize); int err = getpwuid_r(user_id, &user_data, buffer, kPasswdBufferSize, &tmp); if (err != KERN_SUCCESS) { free(buffer); return; } _owner_full_user_name = [[NSString stringWithUTF8String: user_data.pw_gecos] copy]; _owner_user_name = [[NSString stringWithUTF8String: user_data.pw_name] copy]; free(buffer); } - (NSString *)ownerUserName { [self _requestOwnerNames]; return (_owner_user_name); } - (NSString *)ownerFullUserName { [self _requestOwnerNames]; return (_owner_full_user_name); } - (NSDictionary *)ownerGroups { NSDictionary *result = nil; int ngroups = NGROUPS_MAX; int *gr_bytes = malloc(sizeof(*gr_bytes) * ngroups); const char *user_name = [self.ownerUserName UTF8String]; if (!user_name) { return result; } getgrouplist(user_name, 12, gr_bytes, &ngroups); if (ngroups == 0) { /* will it ever happen? */ return result; } NSMutableDictionary *tmp_dict = [[NSMutableDictionary alloc] initWithCapacity: ngroups]; for (int i = 0; i < ngroups; i++) { struct group *some_group = getgrgid(gr_bytes[i]); if (!some_group) { continue; } [tmp_dict setObject: [NSString stringWithUTF8String: some_group->gr_name] forKey: [NSNumber numberWithUnsignedInt: gr_bytes[i]]]; } result = [NSDictionary dictionaryWithDictionary: tmp_dict]; free(gr_bytes); // [tmp_dict release]; return result; } #pragma mark #pragma mark Inspecting process #pragma mark - (BOOL)_requestProcessArgumentsAndEnvironment { /* Max size of arguments (KERN_ARGMAX) */ int request_argmax[2] = { CTL_KERN, KERN_ARGMAX }; int argmax = 0; size_t size = sizeof(argmax); int err = sysctl(request_argmax, 2, &argmax, &size, NULL, 0); if (err != KERN_SUCCESS) { NSLog(@"[%d] sysctl failed in method %s", __LINE__, __PRETTY_FUNCTION__); return (NO); } /* Request arguments pointer */ uint8_t *arguments = malloc(argmax); if (!arguments) { return (NO); } pid_t current_pid = self.pid; int request_args[3] = { CTL_KERN, KERN_PROCARGS2, current_pid }; size = argmax; err = sysctl(request_args, 3, arguments, &size, NULL, 0); if (err != KERN_SUCCESS) { free(arguments); NSLog(@"[%d] sysctl failed in method %s", __LINE__, __PRETTY_FUNCTION__); return (NO); } int argc = *arguments; int counter = 0; uint8_t *arguments_ptr = arguments; // skip `argc` arguments += sizeof(argc); // skip `exec_path` which is a duplicate of argv[0] arguments += strlen((const char *)arguments); if (argc <= 0) { free(arguments_ptr); NSLog(@"argc <= 0; weird :("); return (NO); } NSMutableArray *tmp_argv = [[NSMutableArray alloc] initWithCapacity: argc]; NSMutableDictionary *tmp_env = [[NSMutableDictionary alloc] init]; for (int i = 0; i < size;) { if ((*(arguments+i)) == ‘\0‘) { i++; } const char *arg = (const char *)(arguments+i); if (strlen(arg) > 0) { if (counter < argc) { [tmp_argv addObject: [NSString stringWithUTF8String: arg]]; } else { /* Parse env vars */ NSArray *parts = [[NSString stringWithUTF8String: arg] componentsSeparatedByString: @"="]; /** * Sometimes environment variable pair contains only the key, so * let‘s handle it correctly. */ NSString *value = (parts.count > 1) ? parts[1] : @""; [tmp_env setObject: [value stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding] forKey: parts[0]]; } ++counter; i += strlen(arg); } else { i++; } } if (_launch_args) { // [_launch_args release]; } _launch_args = [[NSArray alloc] initWithArray: tmp_argv copyItems: NO]; // [tmp_argv release]; if (_env_variables) { // [_env_variables release]; } _env_variables = [[NSDictionary alloc] initWithDictionary: tmp_env]; // [tmp_env release]; free(arguments_ptr); return (YES); } - (NSArray *)launchArguments { if (!_launch_args) { [self _requestProcessArgumentsAndEnvironment]; } return (_launch_args); } - (NSDictionary *)environmentVariables { if (!_env_variables) { [self _requestProcessArgumentsAndEnvironment]; } return (_env_variables); } #pragma mark #pragma mark Sandbox #pragma mark /** * Returns YES if a proccess is living in Sandbox environment. * * NOTE: this may return wrong result if the process was sandboxed by user, not by OS X. * Use `_isSandboxedByUser` to make sure you get corrent results; * * NOTE: this method also returns YES for any process with *invalid* PID, so it may be * better to check if `-sandboxContainerPath` is not equal to `nil` to find out that * the process is actually sandboxed. */ - (BOOL)isSandboxedByOSX { static pid_t old_pid = -1; pid_t new_pid = self.pid; if (old_pid != new_pid) { old_pid = new_pid; _sandboxed = sandbox_check(self.pid, NULL, SANDBOX_FILTER_NONE); } return (_sandboxed); } - (NSString *)sandboxContainerPath { if (!_sandbox_container_path) { char *buf = malloc(sizeof(*buf) * kSandboxContainerPathBufferSize); int err = sandbox_container_path_for_pid(_pid, buf, kSandboxContainerPathBufferSize); if (err == KERN_SUCCESS && strlen(buf) > 0) { // _sandbox_container_path = [[NSString stringWithUTF8String: buf] retain]; } free(buf); } return (_sandbox_container_path); } - (NSURL *)sandboxContainerURL { return [NSURL fileURLWithPath: self.sandboxContainerPath]; } - (BOOL)_checkSandboxOperation: (const char *)operation forItemAtPath: (NSString *)item_path { BOOL result = NO; if (strlen(operation) == 0 || item_path.length == 0) { return result; } result = (KERN_SUCCESS == sandbox_check(self.pid, operation, (SANDBOX_FILTER_PATH | SANDBOX_CHECK_NO_REPORT), [item_path UTF8String])); return (result); } /* @todo: "job-creation", anyone? */ - (BOOL)canReadFileAtPath: (NSString *)file_path { return [self _checkSandboxOperation: "file-read-data" forItemAtPath: file_path]; } - (BOOL)canReadFileAtURL: (NSURL *)file_url { return [self canReadFileAtPath: [file_url path]]; } - (BOOL)canWriteToFileAtPath: (NSString *)file_path { return [self _checkSandboxOperation: "file-write-data" forItemAtPath: file_path]; } - (BOOL)canWriteToFileAtURL: (NSURL *)file_url { return [self canWriteToFileAtPath: [file_url path]]; } /** * Enable or disable(?) custom sanbox for the process. */ #pragma mark Custom Sandboxing /** * to be implemented * @return {int} [description] */ - (int)_enableSandbox { if ([self isSandboxedByOSX]) { return KERN_FAILURE; } if ([self _isSandboxedByUser]) { return KERN_SUCCESS; } return KERN_FAILURE; } /** * to be implemented * @return {int} [description] */ - (BOOL)_isSandboxedByUser { return NO; } /** * to be implemented * @return {int} [description] */ - (int)_disableSandbox { return KERN_FAILURE; } #pragma mark #pragma mark LaunchServices Magic #pragma mark - (void)_fetchNewDataFromLaunchServicesWithAtLeastOneKey: (CFStringRef)key { [lock lock]; if (!LSCopyApplicationInformation) { if ( ! [self _findLSPrivateSymbols]) { goto done; } } CFArrayRef request_array = NULL; if (key) { request_array = CFArrayCreate(NULL, (const void **)key, 1, NULL); } CFDictionaryRef ls_update = LSCopyApplicationInformation(kLaunchServicesMagicConstant, LSASNCreateWithPid(NULL, _pid), request_array); if (!ls_update) { goto done; } [self _updateWithLSDictionary: ls_update]; CFRelease(ls_update); done: { [lock unlock]; return; } } - (void)_updateWithLSDictionary: (CFDictionaryRef)dictionary { CFTypeRef tmp = NULL; if (CFDictionaryGetValueIfPresent(dictionary, kLSPIDKey, &tmp)) { CFNumberGetValue(tmp, kCFNumberIntType, &_pid); } tmp = NULL; if (CFDictionaryGetValueIfPresent(dictionary, kLSDisplayNameKey, &tmp)) { // if (_process_name) [_process_name release]; // _process_name = [[NSString stringWithString: tmp] retain]; } tmp = NULL; if (CFDictionaryGetValueIfPresent(dictionary, kCFBundleIdentifierKey, &tmp)) { // if (_bundle_id) [_bundle_id release]; // _bundle_id = [[NSString stringWithString: tmp] retain]; } tmp = NULL; if (CFDictionaryGetValueIfPresent(dictionary, kLSBundlePathKey, &tmp)) { // if (_bundle_path) [_bundle_path release]; // _bundle_path = [[NSString stringWithString: tmp] retain]; } tmp = NULL; if (CFDictionaryGetValueIfPresent(dictionary, kLSExecutablePathKey, &tmp)) { // if (_executable_path) [_executable_path release]; // _executable_path = [[NSString stringWithString: tmp] retain]; } } - (BOOL)_findLSPrivateSymbols { CFBundleRef launch_services_bundle = CFBundleGetBundleWithIdentifier(kLaunchServicesBundleID); if (!launch_services_bundle) { return NO; } LSCopyApplicationInformation = CFBundleGetFunctionPointerForName(launch_services_bundle, RDSymbolNameStr(LSCopyApplicationInformation)); if (!LSCopyApplicationInformation) { return NO; } NSLog(@"LSCopyApplicationInformation = %p", LSCopyApplicationInformation); LSASNCreateWithPid = CFBundleGetFunctionPointerForName(launch_services_bundle, RDSymbolNameStr(LSASNCreateWithPid)); if (!LSASNCreateWithPid) { return NO; } NSLog(@"LSASNCreateWithPid = %p", LSASNCreateWithPid); LSSetApplicationInformation = CFBundleGetFunctionPointerForName(launch_services_bundle, RDSymbolNameStr(LSSetApplicationInformation)); if (!LSSetApplicationInformation) { return NO; } kLSDisplayNameKey = *(CFStringRef *)CFBundleGetDataPointerForName(launch_services_bundle, RDSymbolNameStr(kLSDisplayNameKey)); if (!kLSDisplayNameKey) { return NO; } NSLog(@"kLSDisplayNameKey = %p (%@)", kLSDisplayNameKey, (__bridge id)kLSDisplayNameKey); kLSPIDKey = *(CFStringRef *)CFBundleGetDataPointerForName(launch_services_bundle, RDSymbolNameStr(kLSPIDKey)); if (!kLSPIDKey) { return NO; } NSLog(@"kLSPIDKey = %p (%@)", kLSPIDKey, (__bridge id)kLSPIDKey); kLSBundlePathKey = *(CFStringRef *)CFBundleGetDataPointerForName(launch_services_bundle, RDSymbolNameStr(kLSBundlePathKey)); if (!kLSBundlePathKey) { return NO; } NSLog(@"kLSBundlePathKey = %p (%@)", kLSBundlePathKey, (__bridge id)kLSBundlePathKey); kLSExecutablePathKey = *(CFStringRef *)CFBundleGetDataPointerForName(launch_services_bundle, RDSymbolNameStr(kLSExecutablePathKey)); if (!kLSExecutablePathKey) { return NO; } NSLog(@"kLSExecutablePathKey = %p (%@)", kLSExecutablePathKey, (__bridge id)kLSExecutablePathKey); /******************************************************/ return YES; } @end
//main.m
//
// main.m
// testmac
//
// Created by Allenboy on 2018/5/13.
// Copyright ? 2018年 Allenboy. All rights reserved.
//
#import "RDProcess.h"
#include <mach-o/dyld.h>
#import <Cocoa/Cocoa.h>
static void print_usage(const char *prog_name)
{
printf("Usage: %s [pid]\nIf no pid specified, getpid() is used\n\n", prog_name);
}
void pid( pid_t pid);
int main(int argc, const char * argv[]) {
NSArray *runningApps = [[NSWorkspace sharedWorkspace] runningApplications];
for(int i=0;i<runningApps.count;i++){
NSRunningApplication *app = [runningApps objectAtIndex:i];
//進程 pid
NSLog(@"----------------------------------------進程 pid:%d--------------------------------------", app.processIdentifier);
pid(app.processIdentifier);
// //進程的url
// NSLog(@"進程 bundleURL:%@", app.bundleURL);
// NSLog(@"進程 bundleIdentifier:%@", app.bundleIdentifier);
// // 可執行文件 url
// NSLog(@"進程 executableURL:%@", app.executableURL);
// NSLog(@"進程 executableArchitecture:%ld", (long)app.executableArchitecture);
// //進程名稱
// NSLog(@"進程 name:%@", app.localizedName);
}
// pid_t pid = (-1);
// if (argc < 2) {
// print_usage(argv[0]);
// pid = getpid();
// } else {
// // pid = strtol(argv[1], NULL, 10); //字符串轉 類型為 long int 型 最後一個為幾進制
// }
//
// [proc release];
//return NSApplicationMain(argc, argv);
}
void pid( pid_t pid){
RDProcess *proc = [[RDProcess alloc] initWithPID: 75712];
if (!proc) {
NSLog(@"Could not create RDProcess with invalid PID (%d)", pid);
return;
}
NSLog(@"Proc general: %@", proc);
NSLog(@"PID: %d", proc.pid);
NSLog(@"Name: %@", proc.processName);
NSLog(@"Bundle ID: %@", proc.bundleID);
NSLog(@"Bundle URL: %@", proc.bundleURL);
NSLog(@"Executable URL: %@", proc.executableURL);
NSLog(@"Owner: %@, %@ (%d)", proc.ownerUserName, proc.ownerFullUserName, proc.ownerUserID);
NSDictionary *tmp = proc.ownerGroups;
if (tmp.count > 0) {
NSMutableString *owner_groups = [[NSMutableString alloc] init];
[tmp enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
[owner_groups appendFormat:@"%@(%@), ", obj, key];
}];
NSLog(@"Owner groups (%lu): %@",
[tmp allKeys].count, [owner_groups substringToIndex: owner_groups.length-2]);
// [owner_groups release];
}
NSLog(@"Sandboxed by OS X (unreliable): %@", proc.isSandboxedByOSX ? @"YES" : @"NO");
NSLog(@"Sandbox container: %@", proc.sandboxContainerPath);
NSArray *paths = @[
@"/usr/bin",
@"~/Library/Fonts",
@"~/Library/Colors",
@"~/Desktop",
@"/",
@"~/Library/Container/com.apple.Preview/Data/Library",
proc.executablePath
];
if (proc.sandboxContainerPath) {
paths = [paths arrayByAddingObject: proc.sandboxContainerPath];
}
[paths enumerateObjectsUsingBlock: ^(id path, NSUInteger idx, BOOL *stop){
NSLog(@"Sandbox file permissions {%@%@} for [%@]:\t",
[proc canReadFileAtPath: [path stringByExpandingTildeInPath]] ? @"R" : @"-",
[proc canWriteToFileAtPath: [path stringByExpandingTildeInPath]] ? @"W" : @"-",
path);
}];
NSLog(@"Arguments: %@", proc.launchArguments);
NSLog(@"Environment: %@", proc.environmentVariables);
// proc.processName = [proc.processName stringByAppendingString: @" (RDProcess)"];
NSLog(@"All processes with the same Bundle ID:");
[RDProcess enumerateProcessesWithBundleID: proc.bundleID
usingBlock:^(id process, NSString *bundleID, BOOL *stop){
NSLog(@"\t* %@", process);
}];
NSLog(@"And again, here they are:");
NSLog(@"%@", [RDProcess allProcessesWithBundleID: proc.bundleID]);
NSLog(@"The youngest process: %@", [RDProcess youngestProcessWithBundleID: proc.bundleID]);
NSLog(@"The oldest process: %@", [RDProcess oldestProcessWithBundleID: proc.bundleID]);
}
mac中增強版進程查看類(RDProcess)