Jump to content

Removing CPUID checks and decrypting OSX binaries


ritalin
 Share

11 posts in this topic

Recommended Posts

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. :(

removecpuidsxx5.th.pngthpix.gif

Link to comment
Share on other sites

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

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

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

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:

Link to comment
Share on other sites

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

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:

Link to comment
Share on other sites

  • 2 weeks later...

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

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

  • 10 months later...

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

 Share

×
×
  • Create New...