summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Marc Lenoir2022-03-12 12:16:25 +0100
committerJean-Marc Lenoir2022-03-12 12:16:25 +0100
commit1a9cfc692141619c665da33bcf9013d2c66e2c99 (patch)
tree543444f82f2700348f9dd9f39e13c51561ff318b
parent9340abb70178f0a81b43a6deb77eaf09e222c66a (diff)
downloadaur-1a9cfc692141619c665da33bcf9013d2c66e2c99.tar.gz
Include unlocker files
These files are not available anymore on Internet
-rw-r--r--PKGBUILD12
-rw-r--r--efi-patches.txt25
-rw-r--r--unlocker.py387
3 files changed, 417 insertions, 7 deletions
diff --git a/PKGBUILD b/PKGBUILD
index ec2b7c22a139..b6532ad1b772 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -114,8 +114,6 @@ _vmware_fusion_buildver=19436697
_vmware_fusion_ver_full=${_vmware_fusion_ver}_${_vmware_fusion_buildver}
# List of VMware Fusion versions: https://softwareupdate.vmware.com/cds/vmw-desktop/fusion/
-_unlocker_ver=3.0.7
-
makedepends+=(
python
dmg2img
@@ -125,8 +123,8 @@ makedepends+=(
source+=(
"https://download3.vmware.com/software/FUS-${_vmware_fusion_ver//./}-New/VMware-Fusion-${_vmware_fusion_ver_full/_/-}_x86.dmg"
- "unlocker-${_unlocker_ver}.py::https://raw.githubusercontent.com/DrDonk/unlocker/v${_unlocker_ver}/unlocker.py"
- "efi-patches-${_unlocker_ver}.txt::https://raw.githubusercontent.com/DrDonk/unlocker/v${_unlocker_ver}/uefipatch/efi-patches.txt"
+ "unlocker.py"
+ "efi-patches.txt"
)
sha256sums+=(
'8cd01bd0e7d18b32bfa159bcce54bd885151e3d92d97e5d4a20bcbc09a1c3f4b'
@@ -173,7 +171,7 @@ if [ -n "$_enable_macOS_guests" ]; then
dmg2img -s VMware-Fusion-${_vmware_fusion_ver_full/_/-}_x86.dmg VMware-Fusion-${_vmware_fusion_ver_full/_/-}_x86.iso
7z e -y VMware-Fusion-${_vmware_fusion_ver_full/_/-}_x86.iso VMware\ Fusion/VMware\ Fusion.app/Contents/Library/isoimages/\* -o"fusion-isoimages" > /dev/null 2>&1 || true
- sed -i -e "s|/usr/lib/vmware/|${pkgdir}/usr/lib/vmware/|" "$srcdir/unlocker-${_unlocker_ver}.py"
+ sed -i -e "s|/usr/lib/vmware/|${pkgdir}/usr/lib/vmware/|" "$srcdir/unlocker.py"
fi
}
@@ -400,7 +398,7 @@ fi
if [ -n "$_enable_macOS_guests" ]; then
msg "Patching VMware to enable macOS guest support"
- python3 "$srcdir/unlocker-${_unlocker_ver}.py" > /dev/null
+ python3 "$srcdir/unlocker.py" > /dev/null
for isoimage in ${_fusion_isoimages[@]}
do
@@ -411,7 +409,7 @@ if [ -n "$_enable_macOS_guests" ]; then
_efi_arch=(32 64)
for arch in ${_efi_arch[@]}
do
- UEFIPatch "$pkgdir/usr/lib/vmware/roms/EFI${arch}.ROM" "$srcdir/efi-patches-${_unlocker_ver}.txt" -o "$pkgdir/usr/lib/vmware/roms/EFI${arch}.ROM" > /dev/null
+ UEFIPatch "$pkgdir/usr/lib/vmware/roms/EFI${arch}.ROM" "$srcdir/efi-patches.txt" -o "$pkgdir/usr/lib/vmware/roms/EFI${arch}.ROM" > /dev/null
done
fi
diff --git a/efi-patches.txt b/efi-patches.txt
new file mode 100644
index 000000000000..6451d1db0315
--- /dev/null
+++ b/efi-patches.txt
@@ -0,0 +1,25 @@
+# Patch string format
+# FileGuid SectionType PatchType:FindPatternOrOffset:ReplacePattern
+# Please ensure that the latest symbol in patch string is space
+
+# Possible section types:
+# PE32 image 10
+# Position-independent code 11
+# TE Image 12
+# DXE Dependency 13
+# Version information 14
+# User interface string 15
+# 16-bit code 16
+# Guided freeform 18
+# Raw data 19
+# PEI Dependency 1B
+# SMM Dependency 1C
+# Please do not try another section types, it can make the resulting image broken
+
+# Possible patch types:
+# P - pattern-based, first parameter is a pattern to find, second - a pattern to replace
+# O - offset-based, first parameter is hexadecimal offset, second - a pattern to replace
+# Patterns can have . as "any possible value" symbol
+
+# VMware remove macOS Server check ServerVersion.plist -> SystemVersion.plist
+961578FE-B6B7-44C3-AF35-6BC705CD3B3F 10 P:530065007200760065007200560065007200730069006F006E002E0070006C00690073007400:530079007300740065006D00560065007200730069006F006E002E0070006C00690073007400
diff --git a/unlocker.py b/unlocker.py
new file mode 100644
index 000000000000..8ac86cb92951
--- /dev/null
+++ b/unlocker.py
@@ -0,0 +1,387 @@
+#!/usr/bin/env python3
+"""
+vSMC Header Structure
+Offset Length Struct Type Description
+----------------------------------------
+0x00/00 0x08/08 Q ptr Offset to key table
+0x08/08 0x04/4 I int Number of private keys
+0x0C/12 0x04/4 I int Number of public keys
+
+vSMC Key Data Structure
+Offset Length Struct Type Description
+----------------------------------------
+0x00/00 0x04/04 4s int Key name (byte reversed e.g. #KEY is YEK#)
+0x04/04 0x01/01 B byte Length of returned data
+0x05/05 0x04/04 4s int Data type (byte reversed e.g. ui32 is 23iu)
+0x09/09 0x01/01 B byte Flag R/W
+0x0A/10 0x06/06 6x byte Padding
+0x10/16 0x08/08 Q ptr Internal VMware routine
+0x18/24 0x30/48 48B byte Data
+"""
+
+import codecs
+import os
+import re
+import struct
+import sys
+
+if sys.version_info < (3, 6):
+ sys.stderr.write('You need Python 3.6 or later\n')
+ sys.exit(1)
+
+# Setup imports depending on whether IronPython or CPython
+if sys.platform in ('cli', 'win32'):
+ # noinspection PyUnresolvedReferences
+ from winreg import *
+
+
+def bytetohex(data):
+ return ''.join('{:02X} '.format(c) for c in data)
+
+
+def joinpath(folder, filename):
+ return os.path.join(folder, filename)
+
+
+def printkey(i, offset, smc_key, smc_data):
+ print(str(i + 1).zfill(3)
+ + ' ' + hex(offset)
+ + ' ' + smc_key[0][::-1].decode('UTF-8')
+ + ' ' + str(smc_key[1]).zfill(2)
+ + ' ' + smc_key[2][::-1].replace(b'\x00', b' ').decode('UTF-8')
+ + ' ' + '{0:#0{1}x}'.format(smc_key[3], 4)
+ + ' ' + hex(smc_key[4])
+ + ' ' + bytetohex(smc_data))
+
+
+def set_bit(value, bit):
+ return value | (1 << bit)
+
+
+def clear_bit(value, bit):
+ return value & ~(1 << bit)
+
+
+def test_bit(value, bit):
+ return value & bit
+
+
+E_CLASS64 = 2
+E_SHT_RELA = 4
+
+
+# noinspection PyUnusedLocal
+def patchelf(f, oldoffset, newoffset):
+ f.seek(0)
+ magic = f.read(4)
+ if not magic == b'\x7fELF':
+ raise Exception('Magic number does not match')
+
+ ei_class = struct.unpack('=B', f.read(1))[0]
+ if ei_class != E_CLASS64:
+ raise Exception('Not 64bit elf header: ' + ei_class)
+
+ f.seek(40)
+ e_shoff = struct.unpack('=Q', f.read(8))[0]
+ f.seek(58)
+ e_shentsize = struct.unpack('=H', f.read(2))[0]
+ e_shnum = struct.unpack('=H', f.read(2))[0]
+ e_shstrndx = struct.unpack('=H', f.read(2))[0]
+
+ print('e_shoff: 0x{:x} e_shentsize: 0x{:x} e_shnum:0x{:x} e_shstrndx:0x{:x}'.format(e_shoff, e_shentsize,
+ e_shnum, e_shstrndx))
+
+ for i in range(0, e_shnum):
+ f.seek(e_shoff + i * e_shentsize)
+ e_sh = struct.unpack('=LLQQQQLLQQ', f.read(e_shentsize))
+ e_sh_name = e_sh[0]
+ e_sh_type = e_sh[1]
+ e_sh_offset = e_sh[4]
+ e_sh_size = e_sh[5]
+ e_sh_entsize = e_sh[9]
+ if e_sh_type == E_SHT_RELA:
+ e_sh_nument = int(e_sh_size / e_sh_entsize)
+ print('RELA at 0x{:x} with {:d} entries'.format(e_sh_offset, e_sh_nument))
+ for j in range(0, e_sh_nument):
+ f.seek(e_sh_offset + e_sh_entsize * j)
+ rela = struct.unpack('=QQq', f.read(e_sh_entsize))
+ r_offset = rela[0]
+ r_info = rela[1]
+ r_addend = rela[2]
+ if r_addend == oldoffset:
+ r_addend = newoffset
+ f.seek(e_sh_offset + e_sh_entsize * j)
+ f.write(struct.pack('=QQq', r_offset, r_info, r_addend))
+ print('Relocation modified at: ' + hex(e_sh_offset + e_sh_entsize * j))
+
+
+def patchkeys(f, key):
+ # Setup struct pack string
+ key_pack = '=4sB4sB6xQ'
+ smc_old_memptr = 0
+ smc_new_memptr = 0
+
+ # Do Until OSK1 read
+ i = 0
+ while True:
+
+ # Read key into struct str and data byte str
+ offset = key + (i * 72)
+ f.seek(offset)
+ smc_key = struct.unpack(key_pack, f.read(24))
+ smc_data = f.read(smc_key[1])
+
+ # Reset pointer to beginning of key entry
+ f.seek(offset)
+
+ if smc_key[0] == b'SKL+':
+ # Use the +LKS data routine for OSK0/1
+ smc_new_memptr = smc_key[4]
+ print('+LKS Key: ')
+ printkey(i, offset, smc_key, smc_data)
+
+ elif smc_key[0] == b'0KSO':
+ # Write new data routine pointer from +LKS
+ print('OSK0 Key Before:')
+ printkey(i, offset, smc_key, smc_data)
+ smc_old_memptr = smc_key[4]
+ f.seek(offset)
+ f.write(struct.pack(key_pack, smc_key[0], smc_key[1], smc_key[2], smc_key[3], smc_new_memptr))
+ f.flush()
+
+ # Write new data for key
+ f.seek(offset + 24)
+ smc_new_data = codecs.encode('bheuneqjbexolgurfrjbeqfthneqrqcy', 'rot_13')
+ f.write(smc_new_data.encode('UTF-8'))
+ f.flush()
+
+ # Re-read and print key
+ f.seek(offset)
+ smc_key = struct.unpack(key_pack, f.read(24))
+ smc_data = f.read(smc_key[1])
+ print('OSK0 Key After:')
+ printkey(i, offset, smc_key, smc_data)
+
+ elif smc_key[0] == b'1KSO':
+ # Write new data routine pointer from +LKS
+ print('OSK1 Key Before:')
+ printkey(i, offset, smc_key, smc_data)
+ smc_old_memptr = smc_key[4]
+ f.seek(offset)
+ f.write(struct.pack(key_pack, smc_key[0], smc_key[1], smc_key[2], smc_key[3], smc_new_memptr))
+ f.flush()
+
+ # Write new data for key
+ f.seek(offset + 24)
+ smc_new_data = codecs.encode('rnfrqbagfgrny(p)NccyrPbzchgreVap', 'rot_13')
+ f.write(smc_new_data.encode('UTF-8'))
+ f.flush()
+
+ # Re-read and print key
+ f.seek(offset)
+ smc_key = struct.unpack(key_pack, f.read(24))
+ smc_data = f.read(smc_key[1])
+ print('OSK1 Key After:')
+ printkey(i, offset, smc_key, smc_data)
+
+ # Finished so get out of loop
+ break
+
+ # elif smc_key[0] == b'WPPK':
+ # # Set the old SMC password as an addtional marker that vmx has been patched
+ # # This has no functional value except for checking status
+ # print('KPPW Key Before:')
+ # printkey(i, offset, smc_key, smc_data)
+ # f.seek(offset + 24)
+ # f.write('SpecialisRevelio'.encode('UTF-8'))
+ #
+ # # Re-read and print key
+ # f.seek(offset)
+ # smc_key = struct.unpack(key_pack, f.read(24))
+ # smc_data = f.read(smc_key[1])
+ # print('KPPW Key After:')
+ # printkey(i, offset, smc_key, smc_data)
+
+ else:
+ pass
+
+ i += 1
+ return smc_old_memptr, smc_new_memptr
+
+
+def patchsmc(name, sharedobj):
+ with open(name, 'r+b') as f:
+
+ smc_old_memptr = 0
+ smc_new_memptr = 0
+
+ # Read file into string variable
+ vmx = f.read()
+
+ print('File: ' + name + '\n')
+
+ # Setup hex string for vSMC headers
+ # These are the private and public key counts
+ smc_header_v0 = b'\xF2\x00\x00\x00\xF0\x00\x00\x00'
+ smc_header_v1 = b'\xB4\x01\x00\x00\xB0\x01\x00\x00'
+
+ # Setup hex string for #KEY key
+ key_key = b'\x59\x45\x4B\x23\x04\x32\x33\x69\x75'
+
+ # Setup hex string for $Adr key
+ adr_key = b'\x72\x64\x41\x24\x04\x32\x33\x69\x75'
+
+ # Find the vSMC headers
+ smc_header_v0_offset = vmx.find(smc_header_v0) - 8
+ smc_header_v1_offset = vmx.find(smc_header_v1) - 8
+
+ # Find '#KEY' keys
+ smc_key0 = vmx.find(key_key)
+ smc_key1 = vmx.rfind(key_key)
+
+ # Find '$Adr' key table
+ smc_adr = vmx.find(adr_key)
+
+ # Print vSMC0 tables and keys
+ print('appleSMCTableV0 (smc.version = "0")')
+ print('appleSMCTableV0 Address : ' + hex(smc_header_v0_offset))
+ print('appleSMCTableV0 Private Key #: 0xF2/242')
+ print('appleSMCTableV0 Public Key #: 0xF0/240')
+
+ if (smc_adr - smc_key0) != 72:
+ print('appleSMCTableV0 Table : ' + hex(smc_key0))
+ smc_old_memptr, smc_new_memptr = patchkeys(f, smc_key0)
+ elif (smc_adr - smc_key1) != 72:
+ print('appleSMCTableV0 Table : ' + hex(smc_key1))
+ smc_old_memptr, smc_new_memptr = patchkeys(f, smc_key1)
+
+ print()
+
+ # Print vSMC1 tables and keys
+ print('appleSMCTableV1 (smc.version = "1")')
+ print('appleSMCTableV1 Address : ' + hex(smc_header_v1_offset))
+ print('appleSMCTableV1 Private Key #: 0x01B4/436')
+ print('appleSMCTableV1 Public Key #: 0x01B0/432')
+
+ if (smc_adr - smc_key0) == 72:
+ print('appleSMCTableV1 Table : ' + hex(smc_key0))
+ smc_old_memptr, smc_new_memptr = patchkeys(f, smc_key0)
+ elif (smc_adr - smc_key1) == 72:
+ print('appleSMCTableV1 Table : ' + hex(smc_key1))
+ smc_old_memptr, smc_new_memptr = patchkeys(f, smc_key1)
+
+ print()
+
+ # Find matching RELA record in .rela.dyn in ESXi ELF files
+ # This is temporary code until proper ELF parsing written
+ if sharedobj:
+ print('Modifying RELA records from: ' + hex(smc_old_memptr) + ' to ' + hex(smc_new_memptr))
+ patchelf(f, smc_old_memptr, smc_new_memptr)
+
+ # Tidy up
+ f.flush()
+ f.close()
+
+
+def patchbase(name):
+ # Patch file
+ print('GOS Patching: ' + name)
+ f = open(name, 'r+b')
+
+ # Entry to search for in GOS table
+ # Should work for Workstation 12-15...
+ darwin = re.compile(
+ b'\x10\x00\x00\x00[\x10|\x20]\x00\x00\x00[\x01|\x02]\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+
+ # Read file into string variable
+ base = f.read()
+
+ # Loop through each entry and set top bit
+ # 0xBE --> 0xBF (WKS 12/13)
+ # 0x3E --> 0x3F (WKS 14+)
+ for m in darwin.finditer(base):
+ offset = m.start()
+ f.seek(offset + 32)
+ flag = ord(f.read(1))
+ flag = set_bit(flag, 0)
+ # flag = chr(flag)
+ f.seek(offset + 32)
+ f.write(bytes([flag]))
+ print('GOS Patched flag @: ' + hex(offset))
+
+ # Tidy up
+ f.flush()
+ f.close()
+ print('GOS Patched: ' + name)
+
+
+def patchvmkctl(name):
+ # Patch file
+ print('smcPresent Patching: ' + name)
+ f = open(name, 'r+b')
+
+ # Read file into string variable
+ vmkctl = f.read()
+ applesmc = vmkctl.find(b'applesmc')
+ f.seek(applesmc)
+ f.write(b'vmkernel')
+
+ # Tidy up
+ f.flush()
+ f.close()
+ print('smcPresent Patched: ' + name)
+
+
+# noinspection PyUnresolvedReferences
+def main():
+ # Work around absent Platform module on VMkernel
+ if os.name == 'nt' or os.name == 'cli':
+ osname = 'windows'
+ else:
+ osname = os.uname()[0].lower()
+
+ # vmwarebase = ''
+ vmx_so = False
+
+ # Setup default paths
+ if osname == 'linux':
+ # TODO: Dynamically find Linux installation
+ # Path the install is stored in /etc/vmware/config
+ # libdir = "/usr/lib/vmware"
+ vmx_path = '/usr/lib/vmware/bin/'
+ vmx = joinpath(vmx_path, 'vmware-vmx')
+ vmx_debug = joinpath(vmx_path, 'vmware-vmx-debug')
+ vmx_stats = joinpath(vmx_path, 'vmware-vmx-stats')
+ vmx_so = True
+ if os.path.isfile('/usr/lib/vmware/lib/libvmwarebase.so/libvmwarebase.so'):
+ vmwarebase = '/usr/lib/vmware/lib/libvmwarebase.so/libvmwarebase.so'
+ else:
+ vmwarebase = '/usr/lib/vmware/lib/libvmwarebase.so.0/libvmwarebase.so.0'
+
+ elif osname == 'windows':
+ reg = ConnectRegistry(None, HKEY_LOCAL_MACHINE)
+ key = OpenKey(reg, r'SOFTWARE\Wow6432Node\VMware, Inc.\VMware Workstation')
+ vmwarebase_path = QueryValueEx(key, 'InstallPath')[0]
+ vmx_path = QueryValueEx(key, 'InstallPath64')[0]
+ vmx = joinpath(vmx_path, 'vmware-vmx.exe')
+ vmx_debug = joinpath(vmx_path, 'vmware-vmx-debug.exe')
+ vmx_stats = joinpath(vmx_path, 'vmware-vmx-stats.exe')
+ vmwarebase = joinpath(vmwarebase_path, 'vmwarebase.dll')
+
+ else:
+ print('Unknown Operating System: ' + osname)
+ return
+
+ # Patch the vmx executables skipping stats version for Player
+ patchsmc(vmx, vmx_so)
+ patchsmc(vmx_debug, vmx_so)
+ if os.path.isfile(vmx_stats):
+ patchsmc(vmx_stats, vmx_so)
+
+ # Patch vmwarebase for Workstation and Player
+ patchbase(vmwarebase)
+
+
+if __name__ == '__main__':
+ main()