1.cocoa 自带的进程查看信息太少 RDProcess增强版它可以检查一个进程是否被沙箱化,搜索其包含路径等
//apple_sandbox.h
/*
* Copyright (c) 2006-2010 Apple Inc. All rights reserved.
*
* @[email protected]
*
* 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.
*
* @[email protected]
*/
#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]);
}
原文地址:http://blog.51cto.com/haidragon/2115713
时间: 2025-01-03 01:50:40