Jump to content

Removing CPUID checks and decrypting OSX binaries


  • Please log in to reply
10 replies to this topic

#1
ritalin

ritalin

    InsanelyMac Protégé

  • Members
  • PipPip
  • 67 posts
  • Gender:Male
  • Location:A dull, bluish green, planet
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. :(
Posted ImagePosted Image

#2
alicizmar

alicizmar

    InsanelyMac Protégé

  • Members
  • Pip
  • 37 posts
  • Gender:Female
  • Location:Middle of Nowhere, TX
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. ;)

#3
ritalin

ritalin

    InsanelyMac Protégé

  • Members
  • PipPip
  • 67 posts
  • Gender:Male
  • Location:A dull, bluish green, planet
Just a thought, would it be possible to use segedit/xxd to remove the CPUIDs rather than the Maxxuss patcher?

#4
ritalin

ritalin

    InsanelyMac Protégé

  • Members
  • PipPip
  • 67 posts
  • Gender:Male
  • Location:A dull, bluish green, planet
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.

#5
ritalin

ritalin

    InsanelyMac Protégé

  • Members
  • PipPip
  • 67 posts
  • Gender:Male
  • Location:A dull, bluish green, planet
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.

#6
ritalin

ritalin

    InsanelyMac Protégé

  • Members
  • PipPip
  • 67 posts
  • Gender:Male
  • Location:A dull, bluish green, planet
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 Johnson
DATE : 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! :rolleyes:

#7
ritalin

ritalin

    InsanelyMac Protégé

  • Members
  • PipPip
  • 67 posts
  • Gender:Male
  • Location:A dull, bluish green, planet
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! ;)

#8
ritalin

ritalin

    InsanelyMac Protégé

  • Members
  • PipPip
  • 67 posts
  • Gender:Male
  • Location:A dull, bluish green, planet
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);
}

:rolleyes:

#9
ritalin

ritalin

    InsanelyMac Protégé

  • Members
  • PipPip
  • 67 posts
  • Gender:Male
  • Location:A dull, bluish green, planet
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.

#10
mackerintel

mackerintel

    InsanelyMac Geek

  • Members
  • PipPipPip
  • 128 posts

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

#11
Giuly

Giuly

    InsanelyMac Protégé

  • Members
  • Pip
  • 19 posts
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 ;)





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

© 2014 InsanelyMac  |   News  |   Forum  |   Downloads  |   OSx86 Wiki  |   Mac Netbook  |   PHP hosting by CatN  |   Designed by Ed Gain  |   Logo by irfan  |   Privacy Policy