____ _ ____ _ _ _ / ___(_)_ __ ___ _ __ ___ ___| _ \ ___| |__ _ _ __ _ __ _| |__ | | | | _| | '_ ` _ \| '_ ` _ \ / _ \ | | |/ _ \ '_ \| | | |/ _` |/ _` | '_ \| | | |_| | | | | | | | | | | | | __/ |_| | __/ |_) | |_| | (_| | (_| | | | |_| \____|_|_| |_| |_|_| |_| |_|\___|____/ \___|_.__/ \__,_|\__, |\__,_|_| |_(_) |___/ GimmeDebugah, a Info.plist injector. Copyright (c) fG!, 2013 - reverser@put.as - http://reverse.put.as All rights reserved. This is a small utility to inject a Info.plist into binaries with enough free space at the Mach-O header. The reason for this is that taskgated has a new default setting in Mountain Lion. Non-privileged binaries that want to execute task_for_pid() for arbitrary applications must be codesigned and have some the SecTaskAccess key set in Info .plist SecTaskAccess. This is easy for bundled binaries but not for isolated binaries. If target binary is compiled from source code, the Info.plist can be embedded in the binary using the compiler option "--sectcreate __TEXT __info_plist path_to/Info.plist". This is not possible if we only have the a binary verstion, for example, the default python install. One possible workaround is to revert taskgated to the old procmod behavior ( man taskgated for details). This is marked as deprecated and who knows when Apple will remove it for good. We can fix this by injecting the required section into the binary. Taskgated binary is linked to the Security framework, which is responsible for reading the embedded Info.plist. Code located at libsecurity_codesigning/lib/machorep.cpp (Security-* package from http://opensource.apple.com) // // Extract an embedded Info.plist from the file. // Returns NULL if none is found. // CFDataRef MachORep::infoPlist() { CFRef<CFDataRef> info; try { auto_ptr<MachO> macho(mainExecutableImage()->architecture()); if (const section *sect = macho->findSection("__TEXT", "__info_plist")) { if (macho->is64()) { const section_64 *sect64 = reinterpret_cast< const section_64 *>(sect); info.take(macho->dataAt(macho->flip(sect64-> offset), macho->flip(sect64->size))); } else { info.take(macho->dataAt(macho->flip(sect-> offset), macho->flip(sect->size))); } } } catch (...) { secdebug("machorep", "exception reading embedded Info.plist"); } return info.yield(); } The framework lookups the __TEXT segment and __info_plist section and reads it. One way to deal with this is to inject a new segment command with the same __TEXT name and with the required section pointing to somewhere in the binary. My solution is to embedded the Info.plist also in the header free space. The reason for this is that codesign doesn't seem to like if we add this data to the end of the binary - it will trigger some check conditions and fail to sign the binary. Because the data is added in the header the target binary must be signed before this util is used. Else the codesign util will see the data located there and complain there is no free space to add the code signature. Workflow is: 1) Sign the target binary, if it's not. 2) Run this util against the target binary. 3) Resign the binary to update the header's modifications. The Info.plist format should be something like this: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple .com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleIdentifier</key> <string>com.apple.taskforpid</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>taskforpid</string> <key>CFBundleVersion</key> <string>1.0</string> <key>SecTaskAccess</key> <array> <string>allowed</string> <string>debug</string> </array> </dict> </plist> CFBundleIdentifier and CFBundleName can be modified to target's name although that's not a requirement. If you are using a self-signed certificate to do the codesigning you need to follow this guide from LLDB to create the certificate, else you will run into annoying problems! https://llvm.org/svn/llvm-project/lldb/trunk/docs/code-signing.txt Two modes of operation are available: - Inject a new segment also called __TEXT with the required section. - Inject only a new section at the existing __TEXT segment. My initial prediction was that the second one wouldn't work but then I decided to give it a try and works without any problem. It's the default mode since it is cleaner than mode #1. Have fun, fG!