ritalin Posted November 19, 2008 Share Posted November 19, 2008 I'm looking for a better (faster) way of removing CPUID checks from OSX binaries. I'm currently using a shellscript with otool and the Maxxuss patcher to do the job. There is a snip from the script I currently use below. It works okay but as you can see it involves creating a temporary configuration using otool and then writing it onto the hard drive for the Maxxuss patcher to use. Ideally I would like to create a simple command line tool to replace otool and the patcher in this instance. Unfortunately my programming skills aren't quite up to the job so I'm asking for help. Alternatively, sticking with the tools I do have, is there any way of speeding up the shellscript I am using. Perhaps there is some way of piping the config file straight into Maxxuss patcher without having to make the slow write to the hard drive? I realize this would be better posted in The X Labs forum but unfortunately, for some reason, I am unable to start a new thread in there. I am also aware of the imminent release of the Voodoo XNU with on-the-fly opcode patching for OSX which should make CPUID patching irrelevant. However I would still like to pursue this. Thanks in advance for any help offered. Link to comment Share on other sites More sharing options...
alicizmar Posted November 19, 2008 Share Posted November 19, 2008 Well all I can give you is a good-luck wish, but... IMO, the voodoo kernel doesn't make this irrelevant. Unless the kernel literally permanently patches every CPUID it runs into on-the-fly, this on-the-fly conversion's going to cause a noticeable performance hit. Or maybe I don't know quite enough about the very kernel I'm using ATM. In which case, never mind me, good luck anyway. Link to comment Share on other sites More sharing options...
ritalin Posted November 21, 2008 Author Share Posted November 21, 2008 Just a thought, would it be possible to use segedit/xxd to remove the CPUIDs rather than the Maxxuss patcher? Link to comment Share on other sites More sharing options...
ritalin Posted November 22, 2008 Author Share Posted November 22, 2008 Okay, this is what I found re segedit and xxd: To use segedit I would need to lipo all the binaries to i386 "segedit only operates on Mach-O files, use lipo(1) on it to get a Mach-O file". This isn't desirable because lipo doesn't preserve set_id bits. To get round that I would have to find some way of then restoring the bit after lipo clears it. Also I wouldn't want to lipo the Frameworks folders as I believe that might screw Rosetta. So segedit is out. I have had much more success with xxd and can now patch CPUIDS ant the command line. I still use otool to find the CPUIDs, but can now pipe the edit straight into xxd with no need to write the config file to hard disk. So now I just need to edit my shellscript accordingly. I would still really like help optimizing the script if anyone feels like lending a hand. Link to comment Share on other sites More sharing options...
ritalin Posted November 24, 2008 Author Share Posted November 24, 2008 My accordingly edited shellscript. #!/bin/sh # AMDbinPatch.sh # # # Created by incompetence and ignorance on a cold day in hell. # Copyright 2008 __MyAss__. All rights reserved. SupportFiles="/Library/Application Support/HexleySupport" #this must hold otool, xxd and apb_decrypt DispLine="----------------------------------------------------------------------------" disptime () { time=`date "+%H:%M:%S"` echo "${time}" return 0 } removeCpuids () # $1 The path to the resource folder - $2 The name of the volume to be patched { if [ ! -d "${1}" ] || [ ! -d "/Volumes/${2}" ] || [ "${2}" = "" ]; then { echo "usage: removeCpuids <\$1> <\$2> \$1 = The path to the resource folder (this folder must contain \"otool\" and \"apb_decrypt\") \$2 = The volume name to be patched" exit 1 } else { echo; echo $DispLine disptime;echo "Removing CPUIDs and decrypting apple-protected binaries for AMD compatibility." echo unset candidateFiles for targets in /Applications /Library /System /bin /private /sbin /usr do find "/Volumes/${2}${targets}" -type f -perm +111 | sed 's/ /_FkgWhiSpc_/g' | while read line do binaryPath=`echo "${line}" | sed 's/_FkgWhiSpc_/ /g'` protected=`"${1}"/otool -lv "${binaryPath}" | grep "flags PROTECTED_VERSION_1"` if [ "${protected}" != "" ];then { echo; echo "Decrypting apple-protected binary:" echo "${binaryPath}" lipo -thin i386 -o "${binaryPath}" "${binaryPath}" >& /dev/null mv "${binaryPath}" "${binaryPath}.original" "${1}"/apb_decrypt "${binaryPath}.original" "${binaryPath}" if [ -f "${binaryPath}" ]; then { rm -rf "${binaryPath}.original" } else { mv "${binaryPath}.original" "${binaryPath}" echo "ERROR: failed to decrypt binary ${binaryPath}" exit 1 } fi } fi cpuids=`"${1}"/otool -tv "${binaryPath}" | grep "cpuid" | awk '{print $1}'` if [ "${cpuids}" != "" ];then { echo; echo "Patching CPUID protected binary:" echo "${binaryPath}" cefaedfe=`"${1}"/xxd -c 16 "${binaryPath}" | grep -m 1 "cefa edfe" | awk '{print $1}' | sed 's/://'`;cefaedfe="0x${cefaedfe}" vmaddr=`"${1}"/otool -l "${binaryPath}" | grep -A 3 "LC_SEGMENT" | grep -A 1 "segname __TEXT" | grep "vmaddr" | awk '{print $2}'` echo "${cefaedfe} cefaedfe address" echo "${vmaddr} vmaddr address" for cpuid in ${cpuids} do cpuid="0x${cpuid}" cpuid=`echo $((${cpuid}-${vmaddr}))` cpuid=`echo "obase=16;ibase=10; $cpuid" | bc` cpuid="0x${cpuid}" cpuid=`echo $((${cpuid}+${cefaedfe}))` cpuid=`echo "obase=16;ibase=10; $cpuid" | bc` cpuidx="0x${cpuid}" currentHex=`"${1}"/xxd -s "${cpuidx}" -ps -l 2 "${binaryPath}"` echo "${cpuidx} value is 0x${currentHex}" if [ "${currentHex}" = "0fa2" ]; then { echo "${cpuid}: cdfb" | "${1}"/xxd -r - "${binaryPath}" currentHex=`"${1}"/xxd -s "${cpuidx}" -ps -l 2 "${binaryPath}"` echo "${cpuidx} value has been patched to 0x${currentHex}" } else { echo "Error: ${cpuidx} value isn't \"0x0fa2\"" } fi done } fi done done echo; echo "Finished decrypting apple-protected binaries and removing CPUID checks." disptime return 0 } fi } removeCpuids "${SupportFiles}" "${1}" exit 0 Urgh! So will someone please help to tidy this thing up. Link to comment Share on other sites More sharing options...
ritalin Posted November 25, 2008 Author Share Posted November 25, 2008 Damn! My method of finding the magic is flawed. Over 4000 files checked and it catches all the cpuids bar one, and that one cpuid stops the system booting on AMD hardware. The cpuid that my script missed was in the following binary- /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation Critical! Luckily I may have already found the answer on the net. Google is amazing. FROM : Jeff JohnsonDATE : Mon Sep 01 05:16:03 2008 Martin, The output of "otool -otV" gives you addresses relative to virtual memory rather than to the object file. Say you're looking at a particular address in the output. Let's call it "addy". The offset in the file will be as follows: (offset of architecture) + (offset of section) + addy - (vmaddr of section) If you do "otool -fv", it will give you file offsets for each architecture. For example, on Mac OS X 10.4.11, "otool -fv /usr/lib/ libobjc.A.dylib" gives offset 4096 (0x1000) for architecture i386. And if you look at 0x1000 in the file, you see "CEFAEDFE", which is little-endian FEEDFACE. Then you can use "size -m -l -x" to find the vmaddr and file offsets of the segments and sections. For example, "size -m -l -x /usr/lib/ libobjc.A.dylib" gives vmaddr 0x90a57fa0 and fileoff 4000 (0xfa0) for section __text, vmaddr 0xa0a6c000 and fileoff 610304 (0x95000) for segment __OBJ. Suppose that addy is 0x90a57fac (__objc_notify_images) in the __text section. In the object file the offset will be as follows: 0x1000 + 0xfa0 + 0x90a57fac - 0x90a57fa0 = 0x1fac -Jeff On Aug 31, 2008, at 9:05 PM, Martin Redington wrote: > Not an Xcode question as such, but this list seemed to be the most > likely forum to get a reply from ... > > I've got an original binary, and a cracked version. I am the > original author. > > If I dump the two binaries with od, and diff the output, I can see > that a few bytes have been changed in two locations, and I have the > addresses for those locations. > > I can see the most likely method call for hacking (to make the > cracker's job somewhat easier, I named the method something like > checkRegistration), which funnily enough, is called from two different > locations. > > But, when I run "otool -otV" on the binary, the addresses I see (after > the hex->octal conversion) don't match up to the locations of the > changes I'm actually seeing in the binary. > > So, to get to my actual question ... > > When I'm looking at the otool output, do the offsets represent > absolute offsets within the binary, or to some kind of internal point > of reference (e.g. the start of the objective-C segment)? > > Assuming that they are not absolute offsets (in the otool output), how > can I convert from the otool output to actual offsets in the binary, > or vice versa. > > cheers, > m. > Finnegan begin again! Link to comment Share on other sites More sharing options...
ritalin Posted November 26, 2008 Author Share Posted November 26, 2008 So, remembering the cpuid check in hex = 0fa2 ritalin$ otool -tv /Users/ritalin/Desktop/CoreFoundation | grep cpuid 000678ad cpuid CPUID addresses relative to virtual memory = 0x000678ad ritalin$ otool -fv /Users/ritalin/Desktop/CoreFoundation | grep -A6 i386 architecture i386 cputype CPU_TYPE_I386 cpusubtype CPU_SUBTYPE_I386_ALL capabilities 0x0 offset 4706304 size 2263376 align 2^12 (4096) Offset of start i386 architecture (the CEFAEDFE magic) = 4706304 = 0x47D000 ritalin$ size -m -l -x /Users/ritalin/Desktop/CoreFoundation | grep -A7 __TEXT Segment __TEXT: 0x133000 (vmaddr 0x0 fileoff 0) Section __text: 0xfcf46 (addr 0xd70 offset 3440) Section __const: 0x3b68 (addr 0xfdcc0 offset 1039552) Section __cstring: 0x17f8b (addr 0x101828 offset 1054760) Section __literal4: 0x48 (addr 0x1197b4 offset 1152948) Section __eh_frame: 0x196b0 (addr 0x1197fc offset 1153020) Section __literal8: 0x150 (addr 0x132eb0 offset 1257136) total 0x132281 Offset of __text section = 3440 = 0xD70 vmaddr of __text section = 0xd70 And the formula is (addresses relative to object file) = (offset of architecture) + (offset of section) + (addresses relative to virtual memory) - (vmaddr of section) So the CPUID address relative to the object file (the binary) = 0x47D000 + 0xD70 + 0x000678ad - 0xD70 = 0x4E48AD Lets check that answer ritalin$ xxd -s 0x4E48AD -ps -l 2 /Users/ritalin/Desktop/CoreFoundation 0fa2 We have a match! Link to comment Share on other sites More sharing options...
ritalin Posted November 29, 2008 Author Share Posted November 29, 2008 Okay, so here is my edited script with the now fully functional method of finding the magic. I've made a another modification in that it now patches cpuids in both 32 and 64bit binaries. This wasn't needed before the release of the voodoo XNU, but now AMD machines can run in 64bit mode. So you can now run OSX on AMD in 64bit using the voodoo XNU with on the fly cpuid patching in conjunction with dsmos.kext (on the fly decrypting) or the like, or you can patch/decrypt using this script and lighten the load a little bit, the choice is yours. To run the script you would need otool, size and apb_decrypt in a directory named /Library/Application Support/HexleySupport. Better just to put them in your PATH and edit the script. otool and size are part of the Xcode Developer Tools and can be downloaded from Apple. apb_decrypt is in my sig, everything else the script uses (grep... etc.)is part of the standard OSX install. #!/bin/sh # AMDbinPatch.sh # # # Created by incompetence and ignorance on a cold day in hell. # Copyright 2008 __MyAss__. All rights reserved. SupportFiles="/Library/Application Support/HexleySupport" DispLine="----------------------------------------------------------------------------" disptime () { time=`date "+%H:%M:%S"` echo "${time}" return 0 } removeCpuids () # $1 The path to the resource folder - $2 The name of the volume to be patched { if [ ! -d "${1}" ] || [ ! -d "/Volumes/${2}" ] || [ "${2}" = "" ]; then { echo "usage: removeCpuids <\$1> <\$2> \$1 = The path to the resource folder (this folder must contain \"otool\" and \"apb_decrypt\") \$2 = The volume name to be patched" return 1 } else { echo; echo $DispLine disptime;echo "Removing CPUIDs and decrypting apple-protected binaries for AMD compatibility." echo for targets in /Applications /Library /System /bin /private /sbin /usr do find "/Volumes/${2}${targets}" -type f -perm +111 | while read binaryPath # Find candidate binaries. do for arch in "i386" "x86_64" # Since the release of the voodoo XNU it is no possible to run AMD in 64 bit, so we now check 32 and 64 bit binaries. do protected="" protected=`"${1}"/otool -arch ${arch} -lv "${binaryPath}" 2>/dev/null | grep "flags PROTECTED_VERSION_1"` # Is the candidate binary encrypted. if [ "${protected}" != "" ];then { if [ "${arch}" = "x86_64" ];then lipo -thin i386 -o "${binaryPath}" "${binaryPath}" >& /dev/null # At the moment apb_decrypt will only decrypt i386 binaries. At the time of writing Apple haven't (to my knowledge) released any binary were the x86_64 object encrypted so this function is unnecessary, but I have included it as a precaution. fi echo; echo "Decrypting apple-protected binary:" echo "${binaryPath}" mv "${binaryPath}" "${binaryPath}.original" "${1}"/apb_decrypt "${binaryPath}.original" "${binaryPath}" # Decrypt the binary. if [ -f "${binaryPath}" ]; then rm -rf "${binaryPath}.original" else { mv "${binaryPath}.original" "${binaryPath}" echo "ERROR: failed to decrypt binary ${binaryPath}" return 1 } fi } fi vmaddrCpuids="" vmaddrCpuids=`"${1}"/otool -arch ${arch} -tv "${binaryPath}" 2>/dev/null | grep "cpuid" | awk '{print $1}'` # If the binary contains cpuids find the offset of virtual memory address of cpuids in base 16 if [ "${vmaddrCpuids}" != "" ];then { echo; echo "Patching CPUID protected binary:" echo "${binaryPath}" cefaedfe=`"${1}"/otool -arch ${arch} -fv "${binaryPath}" | grep -A6 ${arch} | grep offset | awk '{print $2}'` # Offset of start architecture (the CEFAEDFE magic) relative to object file in base 10 (will be zero if the binary isn't FAT) textSection=`"${1}"/size -arch ${arch} -m -l -x "${binaryPath}" | grep -A7 __TEXT | grep __text | awk '{print $7}' | sed 's/)//'` # Offset of __text section relative to object file in base 10 vmaddrTextSection=`"${1}"/size -arch ${arch} -m -l -x "${binaryPath}" | grep -A7 __TEXT | grep __text | awk '{print $5}'` # Offset of virtual memory address of __text section in base 16 for vmaddrCpuid in ${vmaddrCpuids} do vmaddrCpuid="0x${vmaddrCpuid}" # Format the base 16 value with leading 0x cpuid=`echo $((${cefaedfe}+${textSection}+${vmaddrCpuid}-${vmaddrTextSection}))` # Offset of address of CPUID in base 10 cpuid=`echo "obase=16;ibase=10; $cpuid" | bc` # Offset of address of CPUID in base 16 cpuidx="0x${cpuid}" # Format the base 16 value with leading 0x currentHex=`"${1}"/xxd -s "${cpuidx}" -ps -l 2 "${binaryPath}"` if [ "${currentHex}" = "0fa2" ]; then { echo "${cpuid}: cdfb" | "${1}"/xxd -r - "${binaryPath}" currentHex=`"${1}"/xxd -s "${cpuidx}" -ps -l 2 "${binaryPath}"` } else { echo "Error: ${cpuidx} value isn't \"0x0fa2\"" return 1 } fi done } fi done done done echo; echo "Finished decrypting apple-protected binaries and removing CPUID checks." disptime return 0 } fi } removeCpuids "${SupportFiles}" "${1}" exit 0 In case the link gets pulled here is the source for apb_decrypt with the key removed. Its based on apb_encrypt created by Amit Singh. /* keys have been removed and need replacing, you will see where they go... * apb_decrypt.c: Written for Mac OS X 10.5. Compile as follows: * * gcc -Wall -o apb_decrypt apb_decrypt.c -framework IOKit -lcrypto */ #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <sys/types.h> #include <arpa/inet.h> #include <copyfile.h> #include <mach/mach.h> #include <mach/machine.h> #include <mach-o/fat.h> #include <mach-o/loader.h> #include <openssl/aes.h> #include <IOKit/IOKitLib.h> #define APB_UNPROTECTED_HEADER_SIZE (3 * PAGE_SIZE) #define APB_CRYPT_AES_KEY_SIZE (256) #define APB_FAT_MAX_ARCH (5) static char header_page[PAGE_SIZE]; static char data_page[PAGE_SIZE]; static char xcrypted_page[PAGE_SIZE]; static boolean_t apb_initialize(int, AES_KEY*, AES_KEY*); static int apb_decrypt_page(const void*, void*); static void AppleSMC_Read32_0(uint8_t*); static void AppleSMC_Read32_1(uint8_t*); typedef struct { uint32_t key; uint8_t __d0[22]; uint32_t datasize; uint8_t __d1[10]; uint8_t cmd; uint32_t __d2; uint8_t data[32]; } AppleSMCBuffer_t; static void AppleSMC_Read32_0(uint8_t* data32) { (void)memcpy(data32, "1stThirtyTwoLettersOfKeyGoHere..", 32); } static void AppleSMC_Read32_1(uint8_t* data32) { (void)memcpy(data32, "2ndThirtyTwoLettersOfKeyGoHere..", 32); } static boolean_t apb_initialize(__unused int mode, AES_KEY* key1, AES_KEY* key2) { boolean_t result = FALSE; uint8_t data32[32] = { 0 }; AppleSMC_Read32_0(data32); AES_set_decrypt_key(data32, APB_CRYPT_AES_KEY_SIZE, key1); AppleSMC_Read32_1(data32); AES_set_decrypt_key(data32, APB_CRYPT_AES_KEY_SIZE, key2); result = TRUE; return result; } static int apb_decrypt_page(const void* in, void* out) { static AES_KEY key1, key2; static boolean_t initialized = FALSE; if (initialized == FALSE) { initialized = apb_initialize(AES_DECRYPT, &key1, &key2); if (initialized == FALSE) { return -1; } } const unsigned char* _in = (const unsigned char*)in; unsigned char* _out = (unsigned char*)out; unsigned char apb_null_iv1[AES_BLOCK_SIZE] = { 0x0, }; unsigned char apb_null_iv2[AES_BLOCK_SIZE] = { 0x0, }; AES_cbc_encrypt(_in, _out, PAGE_SIZE / 2, &key1, apb_null_iv1, AES_DECRYPT); _in += (PAGE_SIZE / 2); _out += (PAGE_SIZE / 2); AES_cbc_encrypt(_in, _out, PAGE_SIZE / 2, &key2, apb_null_iv2, AES_DECRYPT); return 0; } int main(int argc, char** argv) { int fd_in = -1; int fd_out = -1; if (argc != 3) { fprintf(stderr, "usage: %s <infile> <outfile>\n", argv[0]); exit(1); } fd_in = open(argv[1], O_RDONLY); if (fd_in < 0) { perror("open"); exit(1); } off_t base = (off_t)0; off_t ebase_begin = (off_t)0; off_t ebase_end = (off_t)0; uint32_t n = 0; int ret = 0; ssize_t nbytes = pread(fd_in, header_page, PAGE_SIZE, (off_t)0); if (nbytes != PAGE_SIZE) { ret = -1; goto out; } uint32_t magic = *(uint32_t*)header_page; struct mach_header* mh = (struct mach_header*)0; #ifdef __LITTLE_ENDIAN__ if (magic == FAT_CIGAM) { struct fat_header* fh = (struct fat_header*)header_page; uint32_t nfat_arch = ntohl(fh->nfat_arch); if (nfat_arch > APB_FAT_MAX_ARCH) { fprintf(stderr, "too many architectures in Universal binary\n"); ret = -1; goto out; } struct fat_arch* fa = (struct fat_arch*)((char*)header_page + sizeof(struct fat_header)); for (n = 0; n < nfat_arch; n++, fa++) { if (ntohl(fa->cputype) == CPU_TYPE_X86) { base = (off_t)ntohl(fa->offset); nbytes = pread(fd_in, header_page, PAGE_SIZE, base); if (nbytes != PAGE_SIZE) { fprintf(stderr, "failed to read Universal binary\n"); ret = -1; goto out; } mh = (struct mach_header*)header_page; break; } } } else if (magic == MH_MAGIC) { mh = (struct mach_header*)header_page; if (mh->cputype != CPU_TYPE_X86) { fprintf(stderr, "this program supports only x86 architecture\n"); ret = -1; goto out; } } else { fprintf(stderr, "not an appropriate Mach-O file\n"); ret = -1; goto out; } #else #error This file can only be compiled on Intel. #endif struct segment_command* text = (struct segment_command*)0; uint32_t ncmds = mh->ncmds; struct load_command* lc = (struct load_command*)((char*)mh + sizeof(struct mach_header)); for (n = 0; n < ncmds; n++) { if (lc->cmd == LC_SEGMENT) { struct segment_command* sc = (struct segment_command*)lc; if (strcmp(sc->segname, SEG_TEXT) == 0) { text = sc; break; } } lc = (struct load_command*)((char*)lc + lc->cmdsize); } if (!text) { fprintf(stderr, "failed to find text segment\n"); ret = -1; goto out; } if (text->flags ^ SG_PROTECTED_VERSION_1) { fprintf(stderr, "not encrypted\n"); ret = -1; goto out; } off_t archbase_begin = (off_t)(text->fileoff + APB_UNPROTECTED_HEADER_SIZE); off_t archbase_end = archbase_begin + (off_t)(text->filesize - APB_UNPROTECTED_HEADER_SIZE); ebase_begin = base + archbase_begin; ebase_end = base + archbase_end; fd_out = open(argv[2], O_RDWR | O_CREAT | O_EXCL, 0755); if (fd_out < 0) { perror("open"); ret = -1; goto out; } ret = fcopyfile(fd_in, fd_out, (copyfile_state_t)0, COPYFILE_ALL); if (ret) { perror("copyfile"); ret = -1; goto out; } text->flags ^= SG_PROTECTED_VERSION_1; nbytes = pwrite(fd_out, header_page, PAGE_SIZE, base); if (nbytes != PAGE_SIZE) { perror("pwrite"); ret = -1; goto out; } off_t count = ebase_end - ebase_begin; if (count % PAGE_SIZE) { fprintf(stderr, "text segment not a multiple of page size\n"); ret = -1; goto out; } while (count > 0) { nbytes = pread(fd_in, data_page, PAGE_SIZE, ebase_begin); if (nbytes != PAGE_SIZE) { perror("pread"); ret = -1; goto out; } ret = apb_decrypt_page(data_page, xcrypted_page); if (ret) { fprintf(stderr, "failed to decrypt page\n"); goto out; } nbytes = pwrite(fd_out, xcrypted_page, PAGE_SIZE, ebase_begin); if (nbytes != PAGE_SIZE) { perror("pwrite"); ret = -1; goto out; } ebase_begin += (off_t)PAGE_SIZE; count -= (off_t)PAGE_SIZE; } ret = 0; out: if (fd_in >= 0) { close(fd_in); } if (fd_out >= 0) { close(fd_out); if (ret) { unlink(argv[2]); } } exit(ret); } Link to comment Share on other sites More sharing options...
ritalin Posted December 9, 2008 Author Share Posted December 9, 2008 Just a couple of corrections thanks to zephyroth and a little reformatting to make it more readable (hopefully). #!/bin/sh # AMDbinPatch.sh SUPPORT_FILES="/Library/Application Support/HexleySupport" fnRemoveCpuids () # $1 The path to the resource folder - $2 The name of the volume to be patched - $3 Type { if [ ! -d "${1}" ] || [ ! -d "/Volumes/${2}" ] || [ "" = "${2}" ]; then { echo "usage: fnRemoveCpuids <\$1> <\$2> \$1 = The path to the resource folder (this folder must contain \"otool\" and \"apb_decrypt\") \$2 = The volume name to be patched" >&2 return 1 } else { unset TARGETS TARGETS[0]="/usr" TARGETS[1]="/sbin" TARGETS[2]="/private" TARGETS[3]="/bin" TARGETS[4]="/System" TARGETS[5]="/Library" TARGETS[6]="/Applications" echo; echo $DISPLAY_DASH_LINE fnDispTime;echo "Removing CPUIDs and decrypting apple-protected binaries for AMD compatibility." echo NUMBER_OF_TARGETS=${#TARGETS[*]} for (( i = 0; i < ${NUMBER_OF_TARGETS}; i++ )) do find "/Volumes/${2}${TARGETS[${i}]}" -type f -perm +111 2>/dev/null | while read BINARY_PATH # Find candidate binaries. do for CPU_ARCH in i386 x86_64 # Since the release of the voodoo XNU it is no possible to run AMD in 64 bit, so we now check 32 and 64 bit binaries. do protected="" protected=`"${1}"/otool -arch ${CPU_ARCH} -lv "${BINARY_PATH}" 2>/dev/null | grep "flags PROTECTED_VERSION_1"` # Is the candidate binary encrypted. if [ "${protected}" != "" ];then { if [ "${CPU_ARCH}" = "x86_64" ];then lipo -thin i386 -o "${BINARY_PATH}" "${BINARY_PATH}" >& /dev/null # At the moment apb_decrypt will only decrypt i386 binaries. At the time of writing Apple haven't (to my knowledge) released any binary were the x86_64 object encrypted so this function is unnecessary, but I have included it as a precaution. else { echo; echo "Decrypting ${CPU_ARCH} apple-protected binary:" echo "${BINARY_PATH}" mv "${BINARY_PATH}" "${BINARY_PATH}.original" "${1}"/apb_decrypt "${BINARY_PATH}.original" "${BINARY_PATH}" # Decrypt the binary. if [ -f "${BINARY_PATH}" ]; then rm -rf "${BINARY_PATH}.original" else { mv "${BINARY_PATH}.original" "${BINARY_PATH}" echo "ERROR: failed to decrypt binary ${BINARY_PATH}" >&2 return 1 } fi } fi } fi VM_ADDR_CPUIDS="" VM_ADDR_CPUIDS=`"${1}"/otool -arch ${CPU_ARCH} -tv "${BINARY_PATH}" 2>/dev/null | grep " CPUID" | awk '{print $1}'` # If the binary contains cpuids find the offset of virtual memory address of cpuids in base 16 if [ "${VM_ADDR_CPUIDS}" != "" ];then { echo; echo "Patching ${CPU_ARCH} CPUID protected binary:" echo "${BINARY_PATH}" MAGIC=`"${1}"/otool -arch ${CPU_ARCH} -fv "${BINARY_PATH}" | grep -A6 ${CPU_ARCH} | grep offset | awk '{print $2}'` # Offset of start architecture (the CEFAEDFE magic) relative to object file in base 10 (will be zero if the binary isn't FAT) TEXT_SECTION=`"${1}"/size -arch ${CPU_ARCH} -m -l -x "${BINARY_PATH}" | grep -A7 __TEXT | grep __text: | awk '{print $7}' | sed 's/)//'` # Offset of __text section relative to object file in base 10 VM_ADDR_TEXT_SECTION=`"${1}"/size -arch ${CPU_ARCH} -m -l -x "${BINARY_PATH}" | grep -A7 __TEXT | grep __text: | awk '{print $5}'` # Offset of virtual memory address of __text section in base 16 for VM_ADDR_CPUID in ${VM_ADDR_CPUIDS} do VM_ADDR_CPUID="0x${VM_ADDR_CPUID}" # Format the base 16 value with leading 0x CPUID=`echo $((${MAGIC}+${TEXT_SECTION}+${VM_ADDR_CPUID}-${VM_ADDR_TEXT_SECTION}))` # Offset of address of CPUID in base 10 CPUID=`echo "obase=16;ibase=10; $CPUID" | bc` # Offset of address of CPUID in base 16 CPUID_X="0x${CPUID}" # Format the base 16 value with leading 0x CURRENT_HEX_VALUE=`"${1}"/xxd -s "${CPUID_X}" -ps -l 2 "${BINARY_PATH}"` if [ "${CURRENT_HEX_VALUE}" = "0fa2" ]; then { # echo "${CPUID_X} value is ${CURRENT_HEX_VALUE}" echo "${CPUID}: cdfb" | "${1}"/xxd -r - "${BINARY_PATH}" } else { echo "Error: ${CPUID_X} value isn't \"0x0fa2\"" >&2 return 1 } fi done } fi done done done echo; echo "Finished decrypting apple-protected binaries and removing CPUID checks." } fi return 0 } fnRemoveCpuids "${SUPPORT_FILES}" "${1}" exit 0 So long, and thanks for all the fish. Link to comment Share on other sites More sharing options...
mackerintel Posted December 11, 2008 Share Posted December 11, 2008 Well all I can give you is a good-luck wish, but... IMO, the voodoo kernel doesn't make this irrelevant. Unless the kernel literally permanently patches every CPUID it runs into on-the-fly, this on-the-fly conversion's going to cause a noticeable performance hit. Not at all. CPUID is said to be slow instruction. So emulating it isn't much slower. Additionally it's recommended to run cpuid once per program and store its result. If apple follow this convention then there is no performance hit. I really don't see why an app would want to execute CPUID in a loop Link to comment Share on other sites More sharing options...
Giuly Posted October 15, 2009 Share Posted October 15, 2009 the size-command gave me some errors for SL-binaries, so I edited the script to use otool instead. Also I removed the lipo-part, because I don't want my binaries i386 only. Plus, it didn't work because it searched " CPUID" instead of "cpuid$". #!/bin/sh # AMDbinPatch.sh # As found on InsanelyMac, finely tuned. fnDispTime () { time=`date "+%H:%M:%S"` echo "${time}" return 0 } fnRemoveCpuids () # $1 The path to the resource folder - $2 The name of the volume to be patched - $3 Type { if [ ! -d "${1}" ] || [ ! -d "/Volumes/${2}" ] || [ "" = "${2}" ]; then { echo "usage: fnRemoveCpuids <\$1> <\$2> \$1 = The path to the resource folder (this folder must contain \"otool\" and \"apb_decrypt\") \$2 = The volume name to be patched" >&2 return 1 } else { unset TARGETS TARGETS[0]="/usr" TARGETS[1]="/sbin" TARGETS[2]="/private" TARGETS[3]="/bin" TARGETS[4]="/System" TARGETS[5]="/Library" TARGETS[6]="/Applications" fnDispTime;echo "Removing CPUIDs and decrypting apple-protected binaries for AMD compatibility." NUMBER_OF_TARGETS=${#TARGETS[*]} for (( i = 0; i < ${NUMBER_OF_TARGETS}; i++ )) do find "/Volumes/${2}${TARGETS[${i}]}" -type f -perm +111 2>/dev/null | while read BINARY_PATH # Find candidate binaries. do for CPU_ARCH in i386 x86_64 # Since the release of the voodoo XNU it is no possible to run AMD in 64 bit, so we now check 32 and 64 bit binaries. do protected="" protected=`"${1}"/otool -arch ${CPU_ARCH} -lv "${BINARY_PATH}" 2>/dev/null | grep "flags PROTECTED_VERSION_1"` # Is the candidate binary encrypted. if [ "${protected}" != "" ];then { echo; echo "Decrypting ${CPU_ARCH} apple-protected binary:" echo "${BINARY_PATH}" mv "${BINARY_PATH}" "${BINARY_PATH}.original" "${1}"/apb_decrypt "${BINARY_PATH}.original" "${BINARY_PATH}" # Decrypt the binary. if [ -f "${BINARY_PATH}" ]; then rm -rf "${BINARY_PATH}.original" else { mv "${BINARY_PATH}.original" "${BINARY_PATH}" echo "ERROR: failed to decrypt binary ${BINARY_PATH}" >&2 return 1 } fi } fi VM_ADDR_CPUIDS="" VM_ADDR_CPUIDS=`"${1}"/otool -arch ${CPU_ARCH} -tv "${BINARY_PATH}" 2>/dev/null | grep cpuid$ | awk '{print $1}'` # If the binary contains cpuids find the offset of virtual memory address of cpuids in base 16 if [ "${VM_ADDR_CPUIDS}" != "" ];then { echo; echo "Patching ${CPU_ARCH} CPUID protected binary:" echo "${BINARY_PATH}" MAGIC=`"${1}"/otool -arch ${CPU_ARCH} -fv "${BINARY_PATH}" | grep -A6 ${CPU_ARCH} | grep offset | awk '{print $2}'` # Offset of start architecture (the CEFAEDFE magic) relative to object file in base 10 (will be zero if the binary isn't FAT) #TEXT_SECTION=`"${1}"/size -arch ${CPU_ARCH} -m -l -x "${BINARY_PATH}" | grep -A7 __TEXT | grep __text: | awk '{print $7}' | sed 's/)//'` # Offset of __text section relative to object file in base 10 #VM_ADDR_TEXT_SECTION=`"${1}"/size -arch ${CPU_ARCH} -m -l -x "${BINARY_PATH}" | grep -A7 __TEXT | grep __text: | awk '{print $5}'` # Offset of virtual memory address of __text section in base 16 TEXT_SECTION=`"${1}"/otool -arch ${CPU_ARCH} -lv "${BINARY_PATH}" | grep "sectname __text$" -A 6 | grep offset |awk '{print $2}'` VM_ADDR_TEXT_SECTION=`"${1}"/otool -arch ${CPU_ARCH} -lv "${BINARY_PATH}" | grep "sectname __text$" -A 6 | grep addr |awk '{print $2}'` for VM_ADDR_CPUID in ${VM_ADDR_CPUIDS} do VM_ADDR_CPUID="0x${VM_ADDR_CPUID}" # Format the base 16 value with leading 0x CPUID=`echo $((${MAGIC}+${TEXT_SECTION}+${VM_ADDR_CPUID}-${VM_ADDR_TEXT_SECTION}))` # Offset of address of CPUID in base 10 CPUID=`echo "obase=16;ibase=10; $CPUID" | bc` # Offset of address of CPUID in base 16 CPUID_X="0x${CPUID}" # Format the base 16 value with leading 0x CURRENT_HEX_VALUE=`"${1}"/xxd -s "${CPUID_X}" -ps -l 2 "${BINARY_PATH}"` if [ "${CURRENT_HEX_VALUE}" = "0fa2" ]; then { # echo "${CPUID_X} value is ${CURRENT_HEX_VALUE}" echo "${CPUID}: cdfb" | "${1}"/xxd -r - "${BINARY_PATH}" } else { echo "Error: ${CPUID_X} value isn't \"0x0fa2\"" >&2 return 1 } fi done } fi done done done echo; echo "Finished decrypting apple-protected binaries and removing CPUID checks." } fi return 0 } fnRemoveCpuids "${1}" "${2}" exit 0 Have fun with it Link to comment Share on other sites More sharing options...
Recommended Posts