diff --git a/NightShiftUnlocker.xcodeproj/project.pbxproj b/NightShiftUnlocker.xcodeproj/project.pbxproj index d99160c..d32615c 100644 --- a/NightShiftUnlocker.xcodeproj/project.pbxproj +++ b/NightShiftUnlocker.xcodeproj/project.pbxproj @@ -176,7 +176,7 @@ D51ED55F1ECDF7F10084868D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1000; ORGANIZATIONNAME = FireWolf; TargetAttributes = { D51ED5671ECDF7F10084868D = { @@ -239,6 +239,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -246,6 +247,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -293,6 +295,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -300,6 +303,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; diff --git a/NightShiftUnlocker/Headers/capstone/arm.h b/NightShiftUnlocker/Headers/capstone/arm.h old mode 100755 new mode 100644 diff --git a/NightShiftUnlocker/Headers/capstone/arm64.h b/NightShiftUnlocker/Headers/capstone/arm64.h old mode 100755 new mode 100644 index 8814709..87504ba --- a/NightShiftUnlocker/Headers/capstone/arm64.h +++ b/NightShiftUnlocker/Headers/capstone/arm64.h @@ -659,8 +659,8 @@ typedef enum arm64_reg { //> alias registers - ARM64_REG_IP1 = ARM64_REG_X16, - ARM64_REG_IP0 = ARM64_REG_X17, + ARM64_REG_IP0 = ARM64_REG_X16, + ARM64_REG_IP1 = ARM64_REG_X17, ARM64_REG_FP = ARM64_REG_X29, ARM64_REG_LR = ARM64_REG_X30, } arm64_reg; diff --git a/NightShiftUnlocker/Headers/capstone/capstone.h b/NightShiftUnlocker/Headers/capstone/capstone.h old mode 100755 new mode 100644 index 72fd1d1..172c7b8 --- a/NightShiftUnlocker/Headers/capstone/capstone.h +++ b/NightShiftUnlocker/Headers/capstone/capstone.h @@ -8,10 +8,6 @@ extern "C" { #endif -#ifdef CAPSTONE_HAS_OSXKERNEL -#include -#endif - #if !defined(_MSC_VER) || !defined(_KERNEL_MODE) #include #endif diff --git a/NightShiftUnlocker/Headers/capstone/mips.h b/NightShiftUnlocker/Headers/capstone/mips.h old mode 100755 new mode 100644 diff --git a/NightShiftUnlocker/Headers/capstone/platform.h b/NightShiftUnlocker/Headers/capstone/platform.h old mode 100755 new mode 100644 diff --git a/NightShiftUnlocker/Headers/capstone/ppc.h b/NightShiftUnlocker/Headers/capstone/ppc.h old mode 100755 new mode 100644 diff --git a/NightShiftUnlocker/Headers/capstone/sparc.h b/NightShiftUnlocker/Headers/capstone/sparc.h old mode 100755 new mode 100644 diff --git a/NightShiftUnlocker/Headers/capstone/systemz.h b/NightShiftUnlocker/Headers/capstone/systemz.h old mode 100755 new mode 100644 diff --git a/NightShiftUnlocker/Headers/capstone/x86.h b/NightShiftUnlocker/Headers/capstone/x86.h old mode 100755 new mode 100644 diff --git a/NightShiftUnlocker/Headers/capstone/xcore.h b/NightShiftUnlocker/Headers/capstone/xcore.h old mode 100755 new mode 100644 diff --git a/NightShiftUnlocker/Headers/kern_api.hpp b/NightShiftUnlocker/Headers/kern_api.hpp index 5aaa976..15711b1 100644 --- a/NightShiftUnlocker/Headers/kern_api.hpp +++ b/NightShiftUnlocker/Headers/kern_api.hpp @@ -23,12 +23,12 @@ class LiluAPI { * Initialise lilu api */ void init(); - + /** * Deinitialise lilu api */ void deinit(); - + /** * Errors returned by functions */ @@ -42,13 +42,13 @@ class LiluAPI { TooLate, Offline }; - + /** * Minimal API version that guarantees forward ABI compatibility * Present due to lack of OSBundleCompatibleVersion at kext injection */ static constexpr size_t CompatibilityVersion {parseModuleVersion("1.2.0")}; - + /** * Obtains api access by holding a lock, which is required when accessing out of the main context * @@ -58,7 +58,7 @@ class LiluAPI { * @return Error::NoError on success */ EXPORT Error requestAccess(size_t version=CompatibilityVersion, bool check=false); - + /** * Releases api lock * @@ -71,12 +71,24 @@ class LiluAPI { * It is assumed that single user mode is equal to normal, because it is generally * used to continue the load of a complete OS, and by default Lilu itself ignores it. */ - enum Requirements : uint32_t { - AllowNormal = 1, - AllowInstallerRecovery = 2, - AllowSafeMode = 4 + enum RunningMode : uint32_t { + RunningNormal = 1, + AllowNormal = RunningNormal, + RunningInstallerRecovery = 2, + AllowInstallerRecovery = RunningInstallerRecovery, + RunningSafeMode = 4, + AllowSafeMode = RunningSafeMode }; + /** + * Obtain current run mode similarly to requirements + * + * @return run mode mask (RunningMode) + */ + inline uint32_t getRunMode() { + return currentRunMode; + } + /** * Decides whether you are eligible to continue * @@ -96,7 +108,7 @@ class LiluAPI { * @return Error::NoError on success */ EXPORT Error shouldLoad(const char *product, size_t version, uint32_t runmode, const char **disableArg, size_t disableArgNum, const char **debugArg, size_t debugArgNum, const char **betaArg, size_t betaArgNum, KernelVersion min, KernelVersion max, bool &printDebug); - + /** * Kernel patcher loaded callback * @@ -104,7 +116,7 @@ class LiluAPI { * @param patcher kernel patcher instance */ using t_patcherLoaded = void (*)(void *user, KernelPatcher &patcher); - + /** * Registers custom provided callbacks for later invocation on kernel patcher initialisation * @@ -114,7 +126,22 @@ class LiluAPI { * @return Error::NoError on success */ EXPORT Error onPatcherLoad(t_patcherLoaded callback, void *user=nullptr); - + + /** + * Registers custom provided callbacks for later invocation on kernel patcher initialisation + * Enforced version, which panics on registration failure (assuming your code cannot continue otherwise) + * + * @param callback your callback function + * @param user your pointer that will be passed to the callback function + * + * @return Error::NoError on success + */ + inline void onPatcherLoadForce(t_patcherLoaded callback, void *user=nullptr) { + auto err = onPatcherLoad(callback, user); + if (err != Error::NoError) + PANIC("api", "onPatcherLoad failed with code %d", err); + } + /** * Kext loaded callback * Note that you will get notified of all the requested kexts for speed reasons @@ -126,21 +153,53 @@ class LiluAPI { * @param size loaded memory size */ using t_kextLoaded = void (*)(void *user, KernelPatcher &patcher, size_t id, mach_vm_address_t slide, size_t size); - + /** * Registers custom provided callbacks for later invocation on kext load * * @param infos your kext list (make sure to point to const memory) * @param num number of provided kext entries - * @param callback your callback function + * @param callback your callback function (optional) + * @param user your pointer that will be passed to the callback function (optional) + * + * @return Error::NoError on success + */ + EXPORT Error onKextLoad(KernelPatcher::KextInfo *infos, size_t num=1, t_kextLoaded callback=nullptr, void *user=nullptr); + + /** + * Registers custom provided callbacks for later invocation on kext load + * Enforced version, which panics on registration failure (assuming your code cannot continue otherwise) + * + * @param infos your kext list (make sure to point to const memory) + * @param num number of provided kext entries + * @param callback your callback function (optional) + * @param user your pointer that will be passed to the callback function (optional) + * + * @return Error::NoError on success + */ + inline void onKextLoadForce(KernelPatcher::KextInfo *infos, size_t num=1, t_kextLoaded callback=nullptr, void *user=nullptr) { + auto err = onKextLoad(infos, num, callback, user); + if (err != Error::NoError) + PANIC("api", "onKextLoad failed with code %d", err); + } + + /** + * Registers custom provided callbacks for later invocation on binary load + * + * @param infos your binary list (make sure to point to const memory) + * @param num number of provided binary entries + * @param callback your callback function (could be null) * @param user your pointer that will be passed to the callback function + * @param mods optional mod list (make sure to point to const memory) + * @param modnum number of provided mod entries * * @return Error::NoError on success */ - EXPORT Error onKextLoad(KernelPatcher::KextInfo *infos, size_t num, t_kextLoaded callback, void *user=nullptr); - + EXPORT Error onProcLoad(UserPatcher::ProcInfo *infos, size_t num=1, UserPatcher::t_BinaryLoaded callback=nullptr, void *user=nullptr, UserPatcher::BinaryModInfo *mods=nullptr, size_t modnum=0); + /** * Registers custom provided callbacks for later invocation on binary load + * Enforced version, which panics on registration failure (assuming your code cannot continue otherwise) * * @param infos your binary list (make sure to point to const memory) * @param num number of provided binary entries @@ -151,7 +210,47 @@ class LiluAPI { * * @return Error::NoError on success */ - EXPORT Error onProcLoad(UserPatcher::ProcInfo *infos, size_t num, UserPatcher::t_BinaryLoaded callback, void *user=nullptr, UserPatcher::BinaryModInfo *mods=nullptr, size_t modnum=0); + inline void onProcLoadForce(UserPatcher::ProcInfo *infos, size_t num=1, UserPatcher::t_BinaryLoaded callback=nullptr, void *user=nullptr, UserPatcher::BinaryModInfo *mods=nullptr, size_t modnum=0) { + auto err = onProcLoad(infos, num, callback, user, mods, modnum); + if (err != Error::NoError) + PANIC("api", "onProcLoad failed with code %d", err); + } + + /** + * Kext loaded callback + * Note that you will get notified of all the requested kexts for speed reasons + * + * @param user user provided pointer at registering + * @param task task + * @param entitlement loaded kinfo id + * @param original original entitlement value + */ + using t_entitlementRequested = void (*)(void *user, task_t task, const char *entitlement, OSObject *&original); + + /** + * Registers custom provided callbacks for later invocation on entitlement registration + * + * @param callback your callback function + * @param user your pointer that will be passed to the callback function + * + * @return Error::NoError on success + */ + EXPORT Error onEntitlementRequest(t_entitlementRequested callback, void *user=nullptr); + + /** + * Registers custom provided callbacks for later invocation on entitlement registration + * Enforced version, which panics on registration failure (assuming your code cannot continue otherwise) + * + * @param callback your callback function + * @param user your pointer that will be passed to the callback function + * + * @return Error::NoError on success + */ + inline void onEntitlementRequestForce(t_entitlementRequested callback, void *user=nullptr) { + auto err = onEntitlementRequest(callback, user); + if (err != Error::NoError) + PANIC("api", "onEntitlementRequest failed with code %d", err); + } /** * Processes all the registered patcher load callbacks @@ -170,14 +269,14 @@ class LiluAPI { * @param reloadable kinfo could be unloaded */ void processKextLoadCallbacks(KernelPatcher &patcher, size_t id, mach_vm_address_t slide, size_t size, bool reloadable); - + /** * Processes all the registered user patcher load callbacks * * @param patcher user patcher instance */ void processUserLoadCallbacks(UserPatcher &patcher); - + /** * Processes all the registered binary load callbacks * @@ -187,7 +286,7 @@ class LiluAPI { * @param len path length excluding null terminator */ void processBinaryLoadCallbacks(UserPatcher &patcher, vm_map_t map, const char *path, size_t len); - + /** * Activates patchers * @@ -195,9 +294,9 @@ class LiluAPI { * @param upatcher user patcher instance */ void activate(KernelPatcher &kpatcher, UserPatcher &upatcher); - + private: - + /** * Api lock */ @@ -212,48 +311,68 @@ class LiluAPI { * No longer accept any requests */ bool apiRequestsOver {false}; - + /** * Stores call function and user pointer */ template using stored_pair = ppair; - + /** * Stores multiple callbacks */ template using stored_vector = evector *, stored_pair::deleter>; - + /** * List of patcher callbacks */ stored_vector patcherLoadedCallbacks; - + /** * List of kext callbacks */ stored_vector kextLoadedCallbacks; - + /** * List of binary callbacks */ stored_vector binaryLoadedCallbacks; - + + /** + * List of entitlement callbacks + */ + stored_vector entitlementRequestedCallbacks; + /** * List of processed kexts */ stored_vector storedKexts; - + /** * List of processed procs */ evector storedProcs; - + /** * List of processed binary mods */ evector storedBinaryMods; + + /** + * Copy client entitlement type (see IOUserClient) + */ + using t_copyClientEntitlement = OSObject *(*)(task_t, const char *); + + /** + * Hooked entitlement copying method + */ + static OSObject *copyClientEntitlement(task_t task, const char *entitlement); + + /** + * Trampoline for original entitlement copying method + */ + t_copyClientEntitlement orgCopyClientEntitlement {nullptr}; }; EXPORT extern LiluAPI lilu; diff --git a/NightShiftUnlocker/Headers/kern_cpu.hpp b/NightShiftUnlocker/Headers/kern_cpu.hpp new file mode 100644 index 0000000..31e4d70 --- /dev/null +++ b/NightShiftUnlocker/Headers/kern_cpu.hpp @@ -0,0 +1,409 @@ +// +// kern_cpu.hpp +// Lilu +// +// Copyright © 2018 vit9696. All rights reserved. +// + +#ifndef kern_cpu_h +#define kern_cpu_h + +#include +#include +#include + +#include + +/** + * XNU CPU-related exports missing from headers + */ +extern "C" { + int cpu_number(void); + void mp_rendezvous_no_intrs(void (*action_func)(void *), void *arg); +}; + +namespace CPUInfo { + /** + * Keep this in sync to XNU MAX_CPUS from osfmk/i386/mp.h + */ + static constexpr size_t MaxCpus {64}; + + /** + * Contents of CPUID(1) eax register contents describing model version + */ + struct CpuVersion { + uint32_t stepping : 4; + uint32_t model : 4; + uint32_t family : 4; + uint32_t type : 2; + uint32_t reserved1 : 2; + uint32_t extendedModel : 4; + uint32_t extendedFamily : 8; + uint32_t reserved2 : 4; + }; + + static_assert(sizeof(CpuVersion) == sizeof(uint32_t), "CpuVersion size mismatch!"); + + /** + * Intel CPU models as returned by CPUID + * The list is synchronised and updated with XNU source code (osfmk/i386/cpuid.h). + * Names are altered to avoid conflicts just in case. + * Last update: xnu-4570.41.2 + * Some details could be found on http://instlatx64.atw.hu and https://en.wikichip.org/wiki/64-bit_architecture#x86 + */ + enum CpuModel { + CPU_MODEL_UNKNOWN = 0x00, + CPU_MODEL_PENRYN = 0x17, + CPU_MODEL_NEHALEM = 0x1A, + CPU_MODEL_FIELDS = 0x1E, /* Lynnfield, Clarksfield */ + CPU_MODEL_DALES = 0x1F, /* Havendale, Auburndale */ + CPU_MODEL_NEHALEM_EX = 0x2E, + CPU_MODEL_DALES_32NM = 0x25, /* Clarkdale, Arrandale */ + CPU_MODEL_WESTMERE = 0x2C, /* Gulftown, Westmere-EP/-WS */ + CPU_MODEL_WESTMERE_EX = 0x2F, + CPU_MODEL_SANDYBRIDGE = 0x2A, + CPU_MODEL_JAKETOWN = 0x2D, + CPU_MODEL_IVYBRIDGE = 0x3A, + CPU_MODEL_IVYBRIDGE_EP = 0x3E, + CPU_MODEL_CRYSTALWELL = 0x46, + CPU_MODEL_HASWELL = 0x3C, + CPU_MODEL_HASWELL_EP = 0x3F, + CPU_MODEL_HASWELL_ULT = 0x45, + CPU_MODEL_BROADWELL = 0x3D, + CPU_MODEL_BROADWELL_ULX = 0x3D, + CPU_MODEL_BROADWELL_ULT = 0x3D, + CPU_MODEL_BRYSTALWELL = 0x47, + CPU_MODEL_SKYLAKE = 0x4E, + CPU_MODEL_SKYLAKE_ULT = 0x4E, + CPU_MODEL_SKYLAKE_ULX = 0x4E, + CPU_MODEL_SKYLAKE_DT = 0x5E, + CPU_MODEL_SKYLAKE_W = 0x55, + CPU_MODEL_KABYLAKE = 0x8E, + CPU_MODEL_KABYLAKE_ULT = 0x8E, + CPU_MODEL_KABYLAKE_ULX = 0x8E, + CPU_MODEL_KABYLAKE_DT = 0x9E, + CPU_MODEL_COFFEELAKE = 0x9E, + CPU_MODEL_COFFEELAKE_ULT = 0x9E, + CPU_MODEL_COFFEELAKE_ULX = 0x9E, + CPU_MODEL_COFFEELAKE_DT = 0x9E, + CPU_MODEL_CANNONLAKE = 0x66, + CPU_MODEL_ICELAKE = 0x7E + }; + + /** + * Known CPU vendors + */ + enum class CpuVendor { + Unknown, + AMD, + Intel + /* Add more processors here if needed */ + }; + + /** + * Intel CPU generations (starting from 0) + */ + enum class CpuGeneration { + Unknown, + Penryn, + Nehalem, + Westmere, + SandyBridge, + IvyBridge, + Haswell, + Broadwell, + Skylake, + KabyLake, + CoffeeLake, + CannonLake, + IceLake, + MaxGeneration + }; + + /* Responses identification request with %eax 0 */ + /* AMD: "AuthenticAMD" */ + static constexpr uint32_t signature_AMD_ebx = 0x68747541; + static constexpr uint32_t signature_AMD_edx = 0x69746e65; + static constexpr uint32_t signature_AMD_ecx = 0x444d4163; + /* CENTAUR: "CentaurHauls" */ + static constexpr uint32_t signature_CENTAUR_ebx = 0x746e6543; + static constexpr uint32_t signature_CENTAUR_edx = 0x48727561; + static constexpr uint32_t signature_CENTAUR_ecx = 0x736c7561; + /* CYRIX: "CyrixInstead" */ + static constexpr uint32_t signature_CYRIX_ebx = 0x69727943; + static constexpr uint32_t signature_CYRIX_edx = 0x736e4978; + static constexpr uint32_t signature_CYRIX_ecx = 0x64616574; + /* INTEL: "GenuineIntel" */ + static constexpr uint32_t signature_INTEL_ebx = 0x756e6547; + static constexpr uint32_t signature_INTEL_edx = 0x49656e69; + static constexpr uint32_t signature_INTEL_ecx = 0x6c65746e; + /* TM1: "TransmetaCPU" */ + static constexpr uint32_t signature_TM1_ebx = 0x6e617254; + static constexpr uint32_t signature_TM1_edx = 0x74656d73; + static constexpr uint32_t signature_TM1_ecx = 0x55504361; + /* TM2: "GenuineTMx86" */ + static constexpr uint32_t signature_TM2_ebx = 0x756e6547; + static constexpr uint32_t signature_TM2_edx = 0x54656e69; + static constexpr uint32_t signature_TM2_ecx = 0x3638784d; + /* NSC: "Geode by NSC" */ + static constexpr uint32_t signature_NSC_ebx = 0x646f6547; + static constexpr uint32_t signature_NSC_edx = 0x43534e20; + static constexpr uint32_t signature_NSC_ecx = 0x79622065; + /* NEXGEN: "NexGenDriven" */ + static constexpr uint32_t signature_NEXGEN_ebx = 0x4778654e; + static constexpr uint32_t signature_NEXGEN_edx = 0x72446e65; + static constexpr uint32_t signature_NEXGEN_ecx = 0x6e657669; + /* RISE: "RiseRiseRise" */ + static constexpr uint32_t signature_RISE_ebx = 0x65736952; + static constexpr uint32_t signature_RISE_edx = 0x65736952; + static constexpr uint32_t signature_RISE_ecx = 0x65736952; + /* SIS: "SiS SiS SiS " */ + static constexpr uint32_t signature_SIS_ebx = 0x20536953; + static constexpr uint32_t signature_SIS_edx = 0x20536953; + static constexpr uint32_t signature_SIS_ecx = 0x20536953; + /* UMC: "UMC UMC UMC " */ + static constexpr uint32_t signature_UMC_ebx = 0x20434d55; + static constexpr uint32_t signature_UMC_edx = 0x20434d55; + static constexpr uint32_t signature_UMC_ecx = 0x20434d55; + /* VIA: "VIA VIA VIA " */ + static constexpr uint32_t signature_VIA_ebx = 0x20414956; + static constexpr uint32_t signature_VIA_edx = 0x20414956; + static constexpr uint32_t signature_VIA_ecx = 0x20414956; + /* VORTEX: "Vortex86 SoC" */ + static constexpr uint32_t signature_VORTEX_ebx = 0x74726f56; + static constexpr uint32_t signature_VORTEX_edx = 0x36387865; + static constexpr uint32_t signature_VORTEX_ecx = 0x436f5320; + + /* Features in %ecx for leaf 1 */ + static constexpr uint32_t bit_SSE3 = 0x00000001; + static constexpr uint32_t bit_PCLMULQDQ = 0x00000002; + static constexpr uint32_t bit_DTES64 = 0x00000004; + static constexpr uint32_t bit_MONITOR = 0x00000008; + static constexpr uint32_t bit_DSCPL = 0x00000010; + static constexpr uint32_t bit_VMX = 0x00000020; + static constexpr uint32_t bit_SMX = 0x00000040; + static constexpr uint32_t bit_EIST = 0x00000080; + static constexpr uint32_t bit_TM2 = 0x00000100; + static constexpr uint32_t bit_SSSE3 = 0x00000200; + static constexpr uint32_t bit_CNXTID = 0x00000400; + static constexpr uint32_t bit_FMA = 0x00001000; + static constexpr uint32_t bit_CMPXCHG16B = 0x00002000; + static constexpr uint32_t bit_xTPR = 0x00004000; + static constexpr uint32_t bit_PDCM = 0x00008000; + static constexpr uint32_t bit_PCID = 0x00020000; + static constexpr uint32_t bit_DCA = 0x00040000; + static constexpr uint32_t bit_SSE41 = 0x00080000; + static constexpr uint32_t bit_SSE42 = 0x00100000; + static constexpr uint32_t bit_x2APIC = 0x00200000; + static constexpr uint32_t bit_MOVBE = 0x00400000; + static constexpr uint32_t bit_POPCNT = 0x00800000; + static constexpr uint32_t bit_TSCDeadline = 0x01000000; + static constexpr uint32_t bit_AESNI = 0x02000000; + static constexpr uint32_t bit_XSAVE = 0x04000000; + static constexpr uint32_t bit_OSXSAVE = 0x08000000; + static constexpr uint32_t bit_AVX = 0x10000000; + static constexpr uint32_t bit_F16C = 0x20000000; + static constexpr uint32_t bit_RDRND = 0x40000000; + + /* Features in %edx for leaf 1 */ + static constexpr uint32_t bit_FPU = 0x00000001; + static constexpr uint32_t bit_VME = 0x00000002; + static constexpr uint32_t bit_DE = 0x00000004; + static constexpr uint32_t bit_PSE = 0x00000008; + static constexpr uint32_t bit_TSC = 0x00000010; + static constexpr uint32_t bit_MSR = 0x00000020; + static constexpr uint32_t bit_PAE = 0x00000040; + static constexpr uint32_t bit_MCE = 0x00000080; + static constexpr uint32_t bit_CX8 = 0x00000100; + static constexpr uint32_t bit_APIC = 0x00000200; + static constexpr uint32_t bit_SEP = 0x00000800; + static constexpr uint32_t bit_MTRR = 0x00001000; + static constexpr uint32_t bit_PGE = 0x00002000; + static constexpr uint32_t bit_MCA = 0x00004000; + static constexpr uint32_t bit_CMOV = 0x00008000; + static constexpr uint32_t bit_PAT = 0x00010000; + static constexpr uint32_t bit_PSE36 = 0x00020000; + static constexpr uint32_t bit_PSN = 0x00040000; + static constexpr uint32_t bit_CLFSH = 0x00080000; + static constexpr uint32_t bit_DS = 0x00200000; + static constexpr uint32_t bit_ACPI = 0x00400000; + static constexpr uint32_t bit_MMX = 0x00800000; + static constexpr uint32_t bit_FXSR = 0x01000000; + static constexpr uint32_t bit_SSE = 0x02000000; + static constexpr uint32_t bit_SSE2 = 0x04000000; + static constexpr uint32_t bit_SS = 0x08000000; + static constexpr uint32_t bit_HTT = 0x10000000; + static constexpr uint32_t bit_TM = 0x20000000; + static constexpr uint32_t bit_PBE = 0x80000000; + + /* Features in %ebx for leaf 7 sub-leaf 0 */ + static constexpr uint32_t bit_FSGSBASE = 0x00000001; + static constexpr uint32_t bit_SGX = 0x00000004; + static constexpr uint32_t bit_BMI = 0x00000008; + static constexpr uint32_t bit_HLE = 0x00000010; + static constexpr uint32_t bit_AVX2 = 0x00000020; + static constexpr uint32_t bit_SMEP = 0x00000080; + static constexpr uint32_t bit_BMI2 = 0x00000100; + static constexpr uint32_t bit_ENH_MOVSB = 0x00000200; + static constexpr uint32_t bit_RTM = 0x00000800; + static constexpr uint32_t bit_MPX = 0x00004000; + static constexpr uint32_t bit_AVX512F = 0x00010000; + static constexpr uint32_t bit_AVX512DQ = 0x00020000; + static constexpr uint32_t bit_RDSEED = 0x00040000; + static constexpr uint32_t bit_ADX = 0x00080000; + static constexpr uint32_t bit_AVX512IFMA = 0x00200000; + static constexpr uint32_t bit_CLFLUSHOPT = 0x00800000; + static constexpr uint32_t bit_CLWB = 0x01000000; + static constexpr uint32_t bit_AVX512PF = 0x04000000; + static constexpr uint32_t bit_AVX51SER = 0x08000000; + static constexpr uint32_t bit_AVX512CD = 0x10000000; + static constexpr uint32_t bit_SHA = 0x20000000; + static constexpr uint32_t bit_AVX512BW = 0x40000000; + static constexpr uint32_t bit_AVX512VL = 0x80000000; + + /* Features in %ecx for leaf 7 sub-leaf 0 */ + static constexpr uint32_t bit_PREFTCHWT1 = 0x00000001; + static constexpr uint32_t bit_AVX512VBMI = 0x00000002; + static constexpr uint32_t bit_PKU = 0x00000004; + static constexpr uint32_t bit_OSPKE = 0x00000010; + static constexpr uint32_t bit_AVX512VPOPCNTDQ = 0x00004000; + static constexpr uint32_t bit_RDPID = 0x00400000; + + /* Features in %edx for leaf 7 sub-leaf 0 */ + static constexpr uint32_t bit_AVX5124VNNIW = 0x00000004; + static constexpr uint32_t bit_AVX5124FMAPS = 0x00000008; + + /* Features in %eax for leaf 13 sub-leaf 1 */ + static constexpr uint32_t bit_XSAVEOPT = 0x00000001; + static constexpr uint32_t bit_XSAVEC = 0x00000002; + static constexpr uint32_t bit_XSAVES = 0x00000008; + + /* Features in %ecx for leaf = 0x80000001 */; + static constexpr uint32_t bit_LAHF_LM = 0x00000001; + static constexpr uint32_t bit_ABM = 0x00000020; + static constexpr uint32_t bit_SSE4a = 0x00000040; + static constexpr uint32_t bit_PRFCHW = 0x00000100; + static constexpr uint32_t bit_XOP = 0x00000800; + static constexpr uint32_t bit_LWP = 0x00008000; + static constexpr uint32_t bit_FMA4 = 0x00010000; + static constexpr uint32_t bit_TBM = 0x00200000; + static constexpr uint32_t bit_MWAITX = 0x20000000; + + /* Features in %edx for leaf = 0x80000001 */; + static constexpr uint32_t bit_MMXEXT = 0x00400000; + static constexpr uint32_t bit_LM = 0x20000000; + static constexpr uint32_t bit_3DNOWP = 0x40000000; + static constexpr uint32_t bit_3DNOW = 0x80000000; + + /* Features in %ebx for leaf = 0x80000001 */; + static constexpr uint32_t bit_CLZERO = 0x00000001; + + /** + * Reads CPU information and other data. + */ + void loadCpuInformation(); + + /** + * Installed CPU information mapping + */ + struct CpuTopology { + /** + * Number of physical processors installed + */ + uint8_t packageCount {0}; + + /** + * Number of physical cores per package + */ + uint8_t physicalCount[MaxCpus] {}; + + /** + * Number of logical cores per package + */ + uint8_t logicalCount[MaxCpus] {}; + + /** + * Total number of physical cores + */ + inline uint8_t totalPhysical() { + uint8_t count = physicalCount[0]; + for (uint8_t i = 1; i < packageCount; i++) + count += physicalCount[i]; + return count; + } + + /** + * Total number of logical cores + */ + inline uint8_t totalLogical() { + uint8_t count = logicalCount[0]; + for (uint8_t i = 1; i < packageCount; i++) + count += logicalCount[i]; + return count; + } + + /** + * Mapping of cpu_number() to CPU package from 0 to packageCount + */ + uint8_t numberToPackage[MaxCpus] {}; + + /** + * Mapping of cpu_number() to physical core from 0 to physicalCount in package + */ + uint8_t numberToPhysical[MaxCpus] {}; + + /** + * Mapping of cpu_number() to physical cores from 0 to totalPhysical. + */ + inline uint8_t numberToPhysicalUnique(uint8_t i) { + uint8_t num = 0; + uint8_t package = numberToPackage[i]; + for (uint8_t i = 0; i < package; i++) + num += physicalCount[i]; + return num + numberToPhysical[i]; + } + + /** + * Mapping of cpu_number() to logical thread from 0 to logicalCount in package + * Note, that the list is sorted, and the first physicalCount logical threads + * correspond to their corresponding physical cores. + */ + uint8_t numberToLogical[MaxCpus] {}; + }; + + /** + * Get running CPU generation. + * + * @param ofamily a pointer to store CPU family in + * @param omodel a pointer to store CPU model in + * @param ostepping a pointer to store CPU stepping in + * + * @return detected Intel CPU generation + */ + EXPORT CpuGeneration getGeneration(uint32_t *ofamily=nullptr, uint32_t *omodel=nullptr, uint32_t *ostepping=nullptr); + + /** + * Obtain CPU topology. + * + * @param topology parsed cpu topology, must be passed zeroed. + * + * @return true on success + */ + EXPORT bool getCpuTopology(CpuTopology &topology); + + /** + * Obtain cpuid registers + * + * @param no cpuid number + * @param count cpuid count + * @param a eax output pointer (optional) + * @param b ebx output pointer (optional) + * @param c ecx output pointer (optional) + * @param d edx output pointer (optional) + * + * @return true if supported + */ + EXPORT bool getCpuid(uint32_t no, uint32_t count, uint32_t *a, uint32_t *b=nullptr, uint32_t *c=nullptr, uint32_t *d=nullptr); +} + +#endif /* kern_cpu_h */ diff --git a/NightShiftUnlocker/Headers/kern_devinfo.hpp b/NightShiftUnlocker/Headers/kern_devinfo.hpp new file mode 100644 index 0000000..0271a76 --- /dev/null +++ b/NightShiftUnlocker/Headers/kern_devinfo.hpp @@ -0,0 +1,272 @@ +// +// kern_devinfo.hpp +// Lilu +// +// Copyright © 2018 vit9696. All rights reserved. +// + +#ifndef kern_devinfo_h +#define kern_devinfo_h + +#include +#include +#include + +/** + * Obtain installed devices split into categories. + * Should be used from onPatcherLoad and onwards. + */ +class DeviceInfo { + /** + * Updates reportedLayoutId + */ + void updateLayoutId(); + + /** + * Updates reportedFramebufferId + */ + void updateFramebufferId(); + + /** + * Updates firmwareVendor + */ + void updateFirmwareVendor(); + + /** + * Obtains devices from PCI root + * + * @param pciRoot PCI root instance (commonly PCI0@0 device) + */ + void grabDevicesFromPciRoot(IORegistryEntry *pciRoot); + +public: + /** + * Obtains autodetected legacy framebuffer if applicable + * + * @return framebuffer or 0xFFFFFFFF + */ + static uint32_t getLegacyFramebufferId(); + + /** + * Checks whether the framebuffer has connectors or not. + * + * @return true if the framebuffer has no connectors + */ + static bool isConnectorLessPlatformId(uint32_t id); + + /** + * Common external GPU parameter list + */ + struct ExternalVideo { + /** + * Aka GFX0 device + */ + IORegistryEntry *video {nullptr}; + + /** + * Aka HDAU device + */ + IORegistryEntry *audio {nullptr}; + + /** + * External GPU vendor + */ + uint32_t vendor {0}; + }; + + /** + * Aka HDEF device + */ + IORegistryEntry *audioBuiltinAnalog {nullptr}; + + /** + * Aka HDAU device for builtin GPU + */ + IORegistryEntry *audioBuiltinDigital {nullptr}; + + /** + * Aka IGPU device + */ + IORegistryEntry *videoBuiltin {nullptr}; + + /** + * Aka IMEI device + */ + IORegistryEntry *managementEngine {nullptr}; + + /** + * Aka GFX0 devices (kept in sync with audioExternal) + */ + evector videoExternal; + +private: + /** + * This is the default reported layout-id passed to reportedLayoutId. + * The reason for choosing 7 is its presence in 10.14 and the fact + * Apple frameworks still communicate to the files present on disk. + * For information purposes only! Use reportedLayoutId! + */ + static constexpr uint32_t DefaultReportedLayoutId = 7; + + /** + * The boot-arg to override the reported layout-id to AppleHDA. + * For user configuration only! Use reportedLayoutId! + */ + static constexpr const char *ReportedLayoutIdArg = "alcapplid"; + + /** + * The property to override the reported layout-id to AppleHDA. + * For user configuration only! Use reportedLayoutId! + */ + static constexpr const char *ReportedLayoutIdName = "apple-layout-id"; + +public: + /** + * Layout id to be reported by all audio devices (you must update it yourself). + * This follows the standard convention initially found in AppleALC: + * alcapplid=X boot-arg has highest priority and overrides any other value. + * apple-layout-id HDEF prop has normal priority, you may use it if you need. + * DefaultReportedLayoutId will be used if both of the above are not set. + */ + uint32_t reportedLayoutId {0}; + +private: + /** + * The boot-arg to override the reported AAPL,ig-platform-id to Intel drivers. + * For user configuration only! Use reportedFramebufferId! + */ + static constexpr const char *ReportedFrameIdArg = "igfxframe"; + + /** + * The boot-arg to override the reported AAPL,ig-platform-id to Intel drivers. + * Sets VESA framebuffer id (0xFFFFFFFF). + * For user configuration only! Use reportedFramebufferId! + */ + static constexpr const char *ReportedVesaIdArg = "-igfxvesa"; + + /** + * The boot-arg to force-disable any external GPU if found. + * For user configuration only! Use requestedExternalSwitchOff! + */ + static constexpr const char *RequestedExternalSwitchOffArg {"-wegnoegpu"}; + + /** + * The property to set your platform id for Intel drivers (Ivy and newer). + * For user configuration only! Use reportedFramebufferName! + */ + static constexpr const char *ReportedFrameIdName = "AAPL,ig-platform-id"; + + /** + * The property to set your platform id for Intel drivers (Sandy). + * For user configuration only! Use reportedFramebufferName! + */ + static constexpr const char *ReportedFrameIdLegacyName = "AAPL,snb-platform-id"; + + /** + * The IGPU property to force-disable any external GPU if found. + * For user configuration only! Use requestedExternalSwitchOff! + */ + static constexpr const char *RequestedExternalSwitchOffName {"disable-external-gpu"}; + + /** + * Known platform ids used by Intel GPU kexts + * For user configuration only! + */ + static constexpr uint32_t DefaultAppleSkylakePlatformId {0x19120000}; + static constexpr uint32_t DefaultAppleKabyLakePlatformId {0x59160000}; + static constexpr uint32_t DefaultAppleCoffeeLakePlatformId {0x3EA50000}; + static constexpr uint32_t DefaultAppleCannonLakePlatformId {0x5A520000}; + static constexpr uint32_t DefaultAppleIceLakeRealPlatformId {0x8A520000}; + static constexpr uint32_t DefaultAppleIceLakeSimulatorPlatformId {0xFF050000}; + + /** + * Framebuffers without any ports used for hardware acceleration only + * Note 1: Broadwell framebuffers all have connectors added. + * Note 2: Coffee Lake framebuffers without connectors are only present in 10.14. + * Note 3: prerelease Cannon Lake and Ice Lake framebuffers are without connectors. + * For user configuration only! + */ + static constexpr uint32_t ConnectorLessSandyBridgePlatformId1 {0x00030030}; + static constexpr uint32_t ConnectorLessSandyBridgePlatformId2 {0x00050000}; + static constexpr uint32_t ConnectorLessIvyBridgePlatformId1 {0x01620006}; + static constexpr uint32_t ConnectorLessIvyBridgePlatformId2 {0x01620007}; + static constexpr uint32_t ConnectorLessHaswellPlatformId1 {0x04120004}; + static constexpr uint32_t ConnectorLessHaswellPlatformId2 {0x0412000B}; + static constexpr uint32_t ConnectorLessSkylakePlatformId1 {0x19020001}; + static constexpr uint32_t ConnectorLessSkylakePlatformId2 {0x19170001}; + static constexpr uint32_t ConnectorLessSkylakePlatformId3 {0x19120001}; + static constexpr uint32_t ConnectorLessSkylakePlatformId4 {0x19320001}; + static constexpr uint32_t ConnectorLessKabyLakePlatformId1 {0x59180002}; + static constexpr uint32_t ConnectorLessKabyLakePlatformId2 {0x59120003}; + static constexpr uint32_t ConnectorLessCoffeeLakePlatformId1 {0x3E920003}; + static constexpr uint32_t ConnectorLessCoffeeLakePlatformId2 {0x3E910003}; + +public: + /** + * Vesa framebuffer identifier + */ + static constexpr uint32_t DefaultVesaPlatformId {0xFFFFFFFF}; + + /** + * Framebuffer id to be reported to IGPU. + * This follows the standard convention initially found in IntelGraphicsFixup: + * igfxframe=X boot-arg has highest priority and overrides any other value. + * -igfxvesa forces 0xFFFFFFFF frame to get into VESA mode. + * Manually specified AAPL,ig-platform-id or AAPL,snb-platform-id go next. + * On Sandy Bridge processors a default AAPL,snb-platform-id will be tried afterwards. + * On Skylake and Kaby Lake processors some default id will be tried afterwards. + */ + uint32_t reportedFramebufferId {0}; + + /** + * Compatible platform id property name for this IGPU + */ + const char *reportedFramebufferName {nullptr}; + + /** + * Set to true if the framebuffer has no connectors + */ + bool reportedFramebufferIsConnectorLess {false}; + + /** + * Known variants of firmware vendors + * Please note, that it may not be possible to always detect the right vendor + */ + enum class FirmwareVendor { + Unknown, + Apple, + VMware, + EDKII, + Parallels, + AMI, + Insyde, + Phoenix, + HP + }; + + /** + * Firmware vendor manufacturer + */ + FirmwareVendor firmwareVendor {FirmwareVendor::Unknown}; + + /** + * Requested external GPU switchoff + */ + bool requestedExternalSwitchOff {false}; + + /** + * Allocate and initialise the device list. + * + * @return device list or nullptr + */ + EXPORT static DeviceInfo *create(); + + /** + * Release initialised device list. + * + * @param d device list + */ + EXPORT static void deleter(DeviceInfo *d); +}; + +#endif /* kern_devinfo_h */ diff --git a/NightShiftUnlocker/Headers/kern_disasm.hpp b/NightShiftUnlocker/Headers/kern_disasm.hpp index ba1b9ca..fbabac7 100644 --- a/NightShiftUnlocker/Headers/kern_disasm.hpp +++ b/NightShiftUnlocker/Headers/kern_disasm.hpp @@ -22,6 +22,7 @@ #include class Disassembler { +#ifdef LILU_ADVANCED_DISASSEMBLY /** * Because captsone handle can be 0 */ @@ -30,7 +31,8 @@ class Disassembler { /** * Internal capstone handle */ - size_t handle; + size_t handle {}; +#endif /** * Max instruction size @@ -38,10 +40,22 @@ class Disassembler { static constexpr size_t MaxInstruction {15}; public: + /** + * Return the real instruction size contained within min bytes + * Unlike instructionSize this uses HDE engine and at the cost of reduced compatibility it is much faster + * Note: instruction pointer should point to at least min + 32 valid bytes. + * + * @param ptr instruction pointer + * @param min minimal possible size + * + * @return instruction size >= min on success or 0 + */ + EXPORT static size_t quickInstructionSize(mach_vm_address_t ptr, size_t min); + #ifdef LILU_ADVANCED_DISASSEMBLY /** - * Initialise dissassembling framework + * Initialise advanced dissassembling framework * * @param detailed debugging output necessity * @@ -50,25 +64,10 @@ class Disassembler { EXPORT bool init(bool detailed=false); /** - * Deinitialise dissassembling framework, must be called regardless of the init error + * Deinitialise advanced dissassembling framework, must be called regardless of the init error */ EXPORT void deinit(); -#endif /* LILU_ADVANCED_DISASSEMBLY */ - - /** - * Return the real instruction size contained within min bytes - * Unlike instructionSize this uses HDE engine and at the cost of reduced compatibility it is much faster - * - * @param ptr instruction pointer - * @param min minimal possible size - * - * @return instruction size >= min on success or 0 - */ - EXPORT static size_t quickInstructionSize(mach_vm_address_t ptr, size_t min); - -#ifdef LILU_ADVANCED_DISASSEMBLY - /** * Reads size bytes from addr and disassembles them. * diff --git a/NightShiftUnlocker/Headers/kern_efi.hpp b/NightShiftUnlocker/Headers/kern_efi.hpp new file mode 100644 index 0000000..48c6fa5 --- /dev/null +++ b/NightShiftUnlocker/Headers/kern_efi.hpp @@ -0,0 +1,86 @@ +// +// kern_efi.hpp +// Lilu +// +// Copyright © 2018 vit9696. All rights reserved. +// + +#ifndef kern_efi_h +#define kern_efi_h + +#include + +#include + +/** + * Convert 32-bit EFI errors provided by Apple to 64-bit EFI errors + */ +#define EFI_ERROR64(x) (((x) & ~(1ULL << 31)) | (1ULL << 63)) +static_assert(EFI_LOAD_ERROR == 0x80000001 && EFI_ERROR64(EFI_LOAD_ERROR) == 0x8000000000000001, + "Apple has finally upgraded EFI headers!"); + +class EfiRuntimeServices { + IOLock *accessLock {nullptr}; + static EfiRuntimeServices *instance; +public: + /** + * Activates EFI Runtime Services + */ + static void activate(); + + /** + * Lilu custom GUIDs exports, see Headers/Guid/LiluVariables.h + */ + EXPORT static const EFI_GUID LiluNormalGuid; + EXPORT static const EFI_GUID LiluReadOnlyGuid; + EXPORT static const EFI_GUID LiluWriteOnlyGuid; + + /** + * Get EFI Runtime Services wrapper if supported + * + * @param lock lock instance during the run, must be put back + * + * @return wrapper instance + */ + EXPORT static EfiRuntimeServices *get(bool lock=false); + + /** + * Put EFI Runtime Services wrapper to unlock + */ + EXPORT void put(); + + /** + * Perform system reset (does not return on success) + * + * @param type reset type + */ + EXPORT void resetSystem(EFI_RESET_TYPE type); + + /** + * Obtain EFI variable, invokes EFI_RUNTIME_SERVICES::GetVariable. + * + * @param name variable name + * @param guid vendor guid + * @param attr variable attributes + * @param size data buffer size updated on read + * @param data read data + * + * @return EFI_STATUS code + */ + EXPORT uint64_t getVariable(const char16_t *name, const EFI_GUID *guid, uint32_t *attr, uint64_t *size, void *data); + + /** + * Set EFI variable, invokes EFI_RUNTIME_SERVICES::SetVariable. + * + * @param name variable name + * @param guid vendor guid + * @param attr variable attributes + * @param size data buffer size + * @param data data to write + * + * @return EFI_STATUS code + */ + EXPORT uint64_t setVariable(const char16_t *name, const EFI_GUID *guid, uint32_t attr, uint64_t size, void *data); +}; + +#endif /* kern_efi_h */ diff --git a/NightShiftUnlocker/Headers/kern_iokit.hpp b/NightShiftUnlocker/Headers/kern_iokit.hpp index 7958311..dc31b77 100644 --- a/NightShiftUnlocker/Headers/kern_iokit.hpp +++ b/NightShiftUnlocker/Headers/kern_iokit.hpp @@ -34,7 +34,7 @@ namespace WIOKit { * @return true on success */ template - bool getOSDataValue(const OSObject *obj, const char *name, T &value) { + inline bool getOSDataValue(const OSObject *obj, const char *name, T &value) { if (obj) { auto data = OSDynamicCast(OSData, obj); if (data && data->getLength() == sizeof(T)) { @@ -49,27 +49,67 @@ namespace WIOKit { } return false; } - + + /** + * Read typed OSData through a temp type + * + * @param obj read object + * @param value read value + * @param name propert name + * + * @return true on success + */ + template + inline bool getOSDataValue(const OSObject *obj, const char *name, T &value) { + AS tmp; + if (getOSDataValue(obj, name, tmp)) { + value = static_cast(tmp); + return true; + } + + return false; + } + /** * Read typed OSData from IORegistryEntry * * @see getOSDataValue */ template - bool getOSDataValue(const IORegistryEntry *sect, const char *name, T &value) { + inline bool getOSDataValue(const IORegistryEntry *sect, const char *name, T &value) { return getOSDataValue(sect->getProperty(name), name, value); } - + + /** + * Read typed OSData from IORegistryEntry + * + * @see getOSDataValue + */ + template + inline bool getOSDataValue(const IORegistryEntry *sect, const char *name, T &value) { + return getOSDataValue(sect->getProperty(name), name, value); + } + /** * Read typed OSData from IORegistryEntry * * @see getOSDataValue */ template - bool getOSDataValue(const OSDictionary *dict, const char *name, T &value) { + inline bool getOSDataValue(const OSDictionary *dict, const char *name, T &value) { return getOSDataValue(dict->getObject(name), name, value); } + /** + * Read typed OSData from IORegistryEntry + * + * @see getOSDataValue + */ + template + inline bool getOSDataValue(const OSDictionary *dict, const char *name, T &value) { + return getOSDataValue(dict->getObject(name), name, value); + } + /** * Retrieve property object * @@ -79,7 +119,7 @@ namespace WIOKit { * @return property object (must be released) or nullptr */ EXPORT OSSerialize *getProperty(IORegistryEntry *entry, const char *property); - + /** * Model variants */ @@ -91,14 +131,123 @@ namespace WIOKit { ComputerAny = ComputerLaptop | ComputerDesktop }; }; - + + /** + * PCI GPU Vendor identifiers + */ + struct VendorID { + enum : uint16_t { + ATIAMD = 0x1002, + NVIDIA = 0x10de, + Intel = 0x8086 + }; + }; + + /** + * PCI class codes + */ + struct ClassCode { + enum : uint32_t { + VGAController = 0x030000, + DisplayController = 0x038000, + PCIBridge = 0x060400, + // Watch out for PCISubclassMask, 0x040380 is common on laptops. + HDADevice = 0x040300, + // This does not seem to be documented. It works on Haswell at least. + IMEI = 0x078000, + // To ignore device subclasses. + PCISubclassMask = 0xFFFF00, + }; + }; + + /** + * Definitions of PCI Config Registers + */ + enum PCIRegister : uint8_t { + kIOPCIConfigVendorID = 0x00, + kIOPCIConfigDeviceID = 0x02, + kIOPCIConfigCommand = 0x04, + kIOPCIConfigStatus = 0x06, + kIOPCIConfigRevisionID = 0x08, + kIOPCIConfigClassCode = 0x09, + kIOPCIConfigCacheLineSize = 0x0C, + kIOPCIConfigLatencyTimer = 0x0D, + kIOPCIConfigHeaderType = 0x0E, + kIOPCIConfigBIST = 0x0F, + kIOPCIConfigBaseAddress0 = 0x10, + kIOPCIConfigBaseAddress1 = 0x14, + kIOPCIConfigBaseAddress2 = 0x18, + kIOPCIConfigBaseAddress3 = 0x1C, + kIOPCIConfigBaseAddress4 = 0x20, + kIOPCIConfigBaseAddress5 = 0x24, + kIOPCIConfigCardBusCISPtr = 0x28, + kIOPCIConfigSubSystemVendorID = 0x2C, + kIOPCIConfigSubSystemID = 0x2E, + kIOPCIConfigExpansionROMBase = 0x30, + kIOPCIConfigCapabilitiesPtr = 0x34, + kIOPCIConfigInterruptLine = 0x3C, + kIOPCIConfigInterruptPin = 0x3D, + kIOPCIConfigMinimumGrant = 0x3E, + kIOPCIConfigMaximumLatency = 0x3F + }; + + /** + * Fixed offsets for PCI Config I/O virtual methods + */ + struct PCIConfigOffset { + enum : size_t { + ConfigRead32 = 0x10A, + ConfigWrite32 = 0x10B, + ConfigRead16 = 0x10C, + ConfigWrite16 = 0x10D, + ConfigRead8 = 0x10E, + ConfigWrite8 = 0x10F, + GetBusNumber = 0x11D, + GetDeviceNumber = 0x11E, + GetFunctionNumber = 0x11F + }; + }; + + /** + * PCI Config I/O method prototypes + */ + using t_PCIConfigRead32 = uint32_t (*)(IORegistryEntry *service, uint32_t space, uint8_t offset); + using t_PCIConfigRead16 = uint16_t (*)(IORegistryEntry *service, uint32_t space, uint8_t offset); + using t_PCIConfigRead8 = uint8_t (*)(IORegistryEntry *service, uint32_t space, uint8_t offset); + using t_PCIConfigWrite32 = void (*)(IORegistryEntry *service, uint32_t space, uint8_t offset, uint32_t data); + using t_PCIConfigWrite16 = void (*)(IORegistryEntry *service, uint32_t space, uint8_t offset, uint16_t data); + using t_PCIConfigWrite8 = void (*)(IORegistryEntry *service, uint32_t space, uint8_t offset, uint8_t data); + using t_PCIGetBusNumber = uint8_t (*)(IORegistryEntry *service); + using t_PCIGetDeviceNumber = uint8_t (*)(IORegistryEntry *service); + using t_PCIGetFunctionNumber = uint8_t (*)(IORegistryEntry *service); + + /** + * Read PCI Config register + * + * @param service IOPCIDevice-compatible service. + * @param reg PCI config register + * @param space adress space + * @param size read size for reading custom registers + */ + EXPORT uint32_t readPCIConfigValue(IORegistryEntry *service, uint32_t reg, uint32_t space = 0, uint32_t size = 0); + + /** + * Retrieve PCI device address + * + * @param service IOPCIDevice-compatible service. + * @param bus bus address + * @param device device address + * @param function function address + */ + EXPORT void getDeviceAddress(IORegistryEntry *service, uint8_t &bus, uint8_t &device, uint8_t &function); + /** * Retrieve the computer type * * @return valid computer type or ComputerAny */ EXPORT int getComputerModel(); - + /** * Retrieve computer model and/or board-id properties * @@ -110,7 +259,7 @@ namespace WIOKit { * @return true if relevant properties already are available, otherwise buffers are unchanged */ EXPORT bool getComputerInfo(char *model, size_t modelsz, char *board, size_t boardsz); - + /** * Retrieve an ioreg entry by path/prefix * @@ -124,7 +273,7 @@ namespace WIOKit { * @return entry pointer (must NOT be released) or nullptr (on failure or in proc mode) */ EXPORT IORegistryEntry *findEntryByPrefix(const char *path, const char *prefix, const IORegistryPlane *plane, bool (*proc)(void *, IORegistryEntry *)=nullptr, bool brute=false, void *user=nullptr); - + /** * Retrieve an ioreg entry by path/prefix * @@ -138,6 +287,24 @@ namespace WIOKit { * @return entry pointer (must NOT be released) or nullptr (on failure or in proc mode) */ EXPORT IORegistryEntry *findEntryByPrefix(IORegistryEntry *entry, const char *prefix, const IORegistryPlane *plane, bool (*proc)(void *, IORegistryEntry *)=nullptr, bool brute=false, void *user=nullptr); + + /** + * Check if we are using prelinked kernel/kexts or not + * + * @return true when confirmed that we definitely are + */ + EXPORT bool usingPrelinkedCache(); + + /** + * Properly rename the device + * + * @param entry device to rename + * @param name new name + * @param compat correct compatible + * + * @return true on success + */ + EXPORT bool renameDevice(IORegistryEntry *entry, const char *name, bool compat=true); } #endif /* kern_iokit_hpp */ diff --git a/NightShiftUnlocker/Headers/kern_mach.hpp b/NightShiftUnlocker/Headers/kern_mach.hpp index a31b754..d582c79 100644 --- a/NightShiftUnlocker/Headers/kern_mach.hpp +++ b/NightShiftUnlocker/Headers/kern_mach.hpp @@ -41,42 +41,30 @@ class MachInfo { bool kaslr_slide_set {false}; // kaslr can be null, used for disambiguation bool allow_decompress {true}; // allows mach decompression bool prelink_slid {false}; // assume kaslr-slid kext addresses + uint64_t self_uuid[2] {}; // saved uuid of the loaded kext or kernel /** - * 16 byte IDT descriptor, used for 32 and 64 bits kernels (64 bit capable cpus!) + * Kernel slide is aligned by 20 bits */ - struct descriptor_idt { - uint16_t offset_low; - uint16_t seg_selector; - uint8_t reserved; - uint8_t flag; - uint16_t offset_middle; - uint32_t offset_high; - uint32_t reserved2; - }; - + static constexpr size_t KASLRAlignment {0x100000}; + /** - * Retrieve the address of the IDT + * Retrieve LC_UUID command value from a mach header * - * @return always returns the IDT address - */ - mach_vm_address_t getIDTAddress(); - - /** - * Calculate the address of the kernel int80 handler + * @param header mach header pointer * - * @return always returns the int80 handler address + * @return UUID or nullptr */ - mach_vm_address_t calculateInt80Address(); - + uint64_t *getUUID(void *header); + /** - * Retrieve LC_UUID command value from a mach header + * Retrieve and preserve LC_UUID command value from a mach header * * @param header mach header pointer * - * @return UUID or nullptr + * @return true on success */ - uint64_t *getUUID(void *header); + bool loadUUID(void *header); /** * Enable/disable the Write Protection bit in CR0 register @@ -140,7 +128,26 @@ class MachInfo { } MachInfo(const MachInfo &) = delete; MachInfo &operator =(const MachInfo &) = delete; - + + /** + * Resolve mach data in the kernel via prelinked cache + * + * @param prelink prelink information source (i.e. Kernel MachInfo) + * + * @return KERN_SUCCESS if loaded + */ + kern_return_t initFromPrelinked(MachInfo *prelink); + + /** + * Resolve mach data in the kernel via filesystem access + * + * @param paths filesystem paths for lookup + * @param num the number of paths passed + * + * @return KERN_SUCCESS if loaded + */ + kern_return_t initFromFileSystem(const char * const paths[], size_t num); + public: /** @@ -187,7 +194,7 @@ class MachInfo { EXPORT void deinit(); /** - * retrieve the mach header and __TEXT addresses + * Retrieve the mach header and __TEXT addresses * * @param slide load slide if calculating for kexts * @param size memory size @@ -208,7 +215,7 @@ class MachInfo { EXPORT kern_return_t setRunningAddresses(mach_vm_address_t slide=0, size_t size=0); /** - * retrieve running mach positions + * Retrieve running mach positions * * @param header pointer to header * @param size file size @@ -216,7 +223,7 @@ class MachInfo { EXPORT void getRunningPosition(uint8_t * &header, size_t &size); /** - * solve a mach symbol (running addresses must be calculated) + * Solve a mach symbol (running addresses must be calculated) * * @param symbol symbol to solve * @@ -225,15 +232,23 @@ class MachInfo { EXPORT mach_vm_address_t solveSymbol(const char *symbol); /** - * find the kernel base address (mach-o header) - * by searching backwards using the int80 handler as starting point + * Find the kernel base address (mach-o header) * * @return kernel base address or 0 */ EXPORT mach_vm_address_t findKernelBase(); /** - * enable/disable interrupt handling + * Compare the loaded kernel with the current UUID (see loadUUID) + * + * @param base image base, pass 0 to use kernel base + * + * @return true if image uuids match + */ + EXPORT bool isCurrentBinary(mach_vm_address_t base=0); + + /** + * Enable/disable interrupt handling * this is similar to ml_set_interrupts_enabled except the return value * * @param enable the desired value @@ -243,7 +258,7 @@ class MachInfo { EXPORT static bool setInterrupts(bool enable); /** - * enable/disable kernel memory write protection + * Enable/disable kernel memory write protection * * @param enable the desired value * @param lock use spinlock to disable cpu preemption (see KernelPatcher::kernelWriteLock) @@ -252,28 +267,20 @@ class MachInfo { */ EXPORT static kern_return_t setKernelWriting(bool enable, IOSimpleLock *lock); - /** - * Compare the loaded kernel with the passed kernel header - * - * @param kernel_header 64-bit mach header of at least HeaderSize size - * - * @return true if the kernel uuids match - */ - EXPORT bool isCurrentKernel(void *kernelHeader); - /** * Find section bounds in a passed binary for provided cpu * - * @param ptr pointer to a complete mach binary + * @param ptr pointer to a complete mach-o binary + * @param sourceSize size of the mach-o binary * @param vmsegment returned vm segment pointer * @param vmsection returned vm section pointer * @param sectionptr returned section pointer - * @param size returned section size or 0 on failure + * @param sectionSize returned section size or 0 on failure * @param segmentName segment name * @param sectionName section name * @param cpu cpu to look for in case of fat binaries */ - EXPORT static void findSectionBounds(void *ptr, vm_address_t &vmsegment, vm_address_t &vmsection, void *§ionptr, size_t &size, const char *segmentName="__TEXT", const char *sectionName="__text", cpu_type_t cpu=CPU_TYPE_X86_64); + EXPORT static void findSectionBounds(void *ptr, size_t sourceSize, vm_address_t &vmsegment, vm_address_t &vmsection, void *§ionptr, size_t §ionSize, const char *segmentName="__TEXT", const char *sectionName="__text", cpu_type_t cpu=CPU_TYPE_X86_64); /** * Request to free file buffer resources (not including linkedit symtable) diff --git a/NightShiftUnlocker/Headers/kern_nvram.hpp b/NightShiftUnlocker/Headers/kern_nvram.hpp index 941f75c..2dcb07d 100644 --- a/NightShiftUnlocker/Headers/kern_nvram.hpp +++ b/NightShiftUnlocker/Headers/kern_nvram.hpp @@ -8,9 +8,10 @@ #ifndef kern_nvram_hpp #define kern_nvram_hpp +#include #include #include -#include +#include #include /** @@ -22,6 +23,14 @@ #define NVRAM_APPLE_FILEVAULT_GUID "8D63D4FE-BD3C-4AAD-881D-86FD974BC1DF" #define NVRAM_APPLE_PASSWORD_UI_GUID "9EBA2D25-BBE3-4AC2-A2C6-C87F44A1278C" +/** + * Custom GUIDs used for Lilu preferences + * Must be kept in sync to Headers/Guid/LiluVariables.h + */ +#define LILU_NORMAL_GUID "2660DD78-81D2-419D-8138-7B1F363F79A6" +#define LILU_READ_ONLY_GUID "E09B9297-7928-4440-9AAB-D1F8536FBF0A" +#define LILU_WRITE_ONLY_GUID "F0B9AF8F-2222-4840-8A37-ECF7CC8C12E1" + /** * Prefix variable name with a GUID */ @@ -56,7 +65,6 @@ class NVStorage { */ EXPORT uint8_t *decompress(const uint8_t *src, uint32_t &size, bool sensitive=false); -public: /** * Value storage options */ @@ -85,7 +93,7 @@ class NVStorage { uint16_t magic {Magic}; uint8_t version {MaxVer}; - uint8_t opts; + uint8_t opts {OptAuto}; }; /** diff --git a/NightShiftUnlocker/Headers/kern_patcher.hpp b/NightShiftUnlocker/Headers/kern_patcher.hpp index ff66f39..1ca78e1 100644 --- a/NightShiftUnlocker/Headers/kern_patcher.hpp +++ b/NightShiftUnlocker/Headers/kern_patcher.hpp @@ -41,7 +41,8 @@ class KernelPatcher { PointerRange, AlreadyDone, LockError, - Unsupported + Unsupported, + InvalidSymbolFound }; /** @@ -88,8 +89,8 @@ class KernelPatcher { FSFallback, // perform fs fallback if kextcache failed Reserved, SysFlagNum, - UserFlagNum = sizeof(size_t)-SysFlagNum }; + static constexpr size_t UserFlagNum {sizeof(size_t)-SysFlagNum}; static_assert(UserFlagNum > 0, "There should be at least one user flag"); const char *id {nullptr}; const char **paths {nullptr}; @@ -97,6 +98,14 @@ class KernelPatcher { bool sys[SysFlagNum] {}; bool user[UserFlagNum] {}; size_t loadIndex {Unloaded}; // Updated after loading + + /** + * Disable this info from being used + * May be called from onPatcherLoad callbacks to disable certain kexts + */ + void switchOff() { + sys[KernelPatcher::KextInfo::Disabled] = true; + } }; static_assert(sizeof(KextInfo) == 5 * sizeof(size_t), "KextInfo is no longer ABI compatible"); @@ -166,7 +175,36 @@ class KernelPatcher { * @return running symbol address or 0 */ EXPORT mach_vm_address_t solveSymbol(size_t id, const char *symbol); - + + /** + * Solve a kinfo symbol in range with designated type + * + * @param id loaded kinfo id + * @param symbol symbol to solve + * @param start start address range + * @param size address range size + * @param crash kernel panic on invalid non-zero address + * + * @return running symbol address or 0 casted to type T (mach_vm_address_t) + */ + template + inline T solveSymbol(size_t id, const char *symbol, mach_vm_address_t start, size_t size, bool crash=false) { + auto addr = solveSymbol(id, symbol); + if (addr) { + if (addr >= start && addr < start + size) + return (T)addr; + + code = Error::InvalidSymbolFound; + SYSTRACE("patcher", "address " PRIKADDR " is out of range " PRIKADDR " with size %lX", + CASTKADDR(addr), CASTKADDR(start), size); + + PANIC_COND(crash, "patcher", "address " PRIKADDR " is out of range " PRIKADDR " with size %lX", + CASTKADDR(addr), CASTKADDR(start), size); + } + + return (T)nullptr; + } + /** * Hook kext loading and unloading to access kexts at early stage */ @@ -239,6 +277,15 @@ class KernelPatcher { * @param patch patch to apply */ EXPORT void applyLookupPatch(const LookupPatch *patch); + + /** + * Apply a find/replace patch with additional constraints + * + * @param patch patch to apply + * @param startingAddress start with this address (or kext/kernel lowest address) + * @param maxSize maximum size to look for (or kext/kernel max size) + */ + EXPORT void applyLookupPatch(const LookupPatch *patch, uint8_t *startingAddress, size_t maxSize); #endif /* LILU_KEXTPATCH_SUPPORT */ /** @@ -267,6 +314,98 @@ class KernelPatcher { */ EXPORT mach_vm_address_t routeBlock(mach_vm_address_t from, const uint8_t *opcodes, size_t opnum, bool buildWrapper=false, bool kernelRoute=true); + /** + * Route virtual function to function + * + * @param obj OSObject-compatible instance + * @param off function offset in a virtual table (arch-neutral, i.e. divided by sizeof(uintptr_t) + * @param func function to replace with + * @param orgFunc pointer to store the original function + * + * @return true on success + */ + template + static inline bool routeVirtual(void *obj, size_t off, T func, T *orgFunc=nullptr) { + // First OSObject (and similar) field is its virtual table. + auto vt = obj ? reinterpret_cast(obj)[0] : nullptr; + if (vt) { + // Do not try to replace twice! + if (vt[off] == func) + return false; + if (orgFunc) *orgFunc = vt[off]; + vt[off] = func; + return true; + } + return false; + } + + /** + * Route request to simplify casting and error handling + * See routeMultiple. + * + * symbol symbol to lookup + * from solved symbol (assigned by routeMultiple) + * to destination address + * org trampoline storage to the original symbol + */ + struct RouteRequest { + const char *symbol {nullptr}; + mach_vm_address_t from {0}; + const mach_vm_address_t to {0}; + mach_vm_address_t *org {nullptr}; + + /** + * Construct RouteRequest for wrapping a function + * @param s symbol to lookup + * @param t destination address + * @param o trampoline storage to the original symbol + */ + template + RouteRequest(const char *s, T t, mach_vm_address_t &o) : + symbol(s), to(reinterpret_cast(t)), org(&o) { } + + /** + * Construct RouteRequest for routing a function + * @param s symbol to lookup + * @param t destination address + */ + template + RouteRequest(const char *s, T t) : + symbol(s), to(reinterpret_cast(t)) { } + }; + + /** + * Simple route multiple functions with basic error handling + * + * @param id kernel item identifier + * @param requests an array of requests to replace + * @param num requests array size + * @param start start address range + * @param size address range size + * @param kernelRoute kernel change requiring memory protection changes and patch reverting at unload + * @param force continue on first error + * + * @return false if it at least one error happened + */ + EXPORT bool routeMultiple(size_t id, RouteRequest *requests, size_t num, mach_vm_address_t start=0, size_t size=0, bool kernelRoute=true, bool force=false); + + /** + * Simple route multiple functions with basic error handling + * + * @param id kernel item identifier + * @param requests an array of requests to replace + * @param start start address range + * @param size address range size + * @param kernelRoute kernel change requiring memory protection changes and patch reverting at unload + * @param force continue on first error + * + * @return false if it at least one error happened + */ + template + inline bool routeMultiple(size_t id, RouteRequest (&requests)[N], mach_vm_address_t start=0, size_t size=0, bool kernelRoute=true, bool force=false) { + return routeMultiple(id, requests, N, start, size, kernelRoute, force); + } + private: /** @@ -282,7 +421,7 @@ class KernelPatcher { /** * Offset to tempExecutableMemory that is safe to use */ - off_t tempExecutableMemoryOff {0}; + size_t tempExecutableMemoryOff {0}; /** * Patcher status @@ -328,9 +467,9 @@ class KernelPatcher { #endif /* LILU_KEXTPATCH_SUPPORT */ /** - * Local disassmebler instance, initialised on demand + * Kernel prelink image in case prelink is used */ - Disassembler disasm; + MachInfo *prelinkInfo {nullptr}; /** * Loaded kernel items @@ -370,31 +509,28 @@ class KernelPatcher { * Jump instruction sizes */ static constexpr size_t SmallJump {1 + sizeof(int32_t)}; - static constexpr size_t LongJump {2 * sizeof(uint64_t)}; + static constexpr size_t LongJump {6 + sizeof(uint64_t)}; /** * Possible kernel paths */ #ifdef LILU_COMPRESSION_SUPPORT - static constexpr size_t kernelPathsNum {10}; -#else - static constexpr size_t kernelPathsNum {4}; -#endif /* LILU_COMPRESSION_SUPPORT */ - const char *kernelPaths[kernelPathsNum] { -#ifdef LILU_COMPRESSION_SUPPORT + const char *prelinkKernelPaths[6] { + // This is the usual kernel cache place, which often the best thing to use "/System/Library/Caches/com.apple.kext.caches/Startup/kernelcache", - "/System/Library/PrelinkedKernels/prelinkedkernel", -#endif /* LILU_COMPRESSION_SUPPORT */ + // Otherwise fallback to one of the prelinked kernels + // Since we always verify the LC_UUID value, trying the kernels could be done in any order. + "/System/Library/PrelinkedKernels/prelinkedkernel", // normal + "/macOS Install Data/Locked Files/Boot Files/prelinkedkernel", // 10.13 installer + "/com.apple.boot.R/prelinkedkernel", // 10.12+ fusion drive installer + "/com.apple.boot.S/System/Library/PrelinkedKernels/prelinkedkernel", // 10.11 fusion drive installer + "/com.apple.recovery.boot/prelinkedkernel" // recovery + }; +#endif + + const char *kernelPaths[2] { "/System/Library/Kernels/kernel", //since 10.10 - "/mach_kernel", -#ifdef LILU_COMPRESSION_SUPPORT - "/System/Library/Caches/com.apple.kext.caches/Startup/kernelcache.debug", - "/System/Library/Caches/com.apple.kext.caches/Startup/kernelcache.development", - "/System/Library/PrelinkedKernels/prelinkedkernel.debug", - "/System/Library/PrelinkedKernels/prelinkedkernel.development", -#endif /* LILU_COMPRESSION_SUPPORT */ - "/System/Library/Kernels/kernel.debug", - "/System/Library/Kernels/kernel.development" + "/mach_kernel" }; }; diff --git a/NightShiftUnlocker/Headers/kern_rtc.hpp b/NightShiftUnlocker/Headers/kern_rtc.hpp new file mode 100644 index 0000000..c4bd831 --- /dev/null +++ b/NightShiftUnlocker/Headers/kern_rtc.hpp @@ -0,0 +1,229 @@ +// +// kern_rtc.hpp +// Lilu +// +// Copyright © 2018 vit9696. All rights reserved. +// + +#ifndef kern_rtc_h +#define kern_rtc_h + +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#include +#pragma clang diagnostic pop + +class RTCStorage { + /** + * General access RTC ports on x86 systems. + */ + static constexpr uint8_t R_PCH_RTC_INDEX = 0x70; + static constexpr uint8_t R_PCH_RTC_TARGET = 0x71; + static constexpr uint8_t R_PCH_RTC_EXT_INDEX = 0x72; + static constexpr uint8_t R_PCH_RTC_EXT_TARGET = 0x73; + + /** + * RTC has N banks (we support up to 2) of memory. + */ + static constexpr uint8_t RTC_BANK_SIZE = 0x80; + + /** + * Non-ext RTC index register uses higher bit for nmi. + */ + static constexpr uint8_t RTC_DATA_MASK = 0x7F; + static constexpr uint8_t RTC_NMI_MASK = 0x80; + + /** + * Apple-specific RTC checksum addresses + */ + static constexpr uint8_t APPLERTC_HASHED_ADDR = 0x0E; + static constexpr uint8_t APPLERTC_CHECKSUM_ADDR1 = 0x58; + static constexpr uint8_t APPLERTC_CHECKSUM_ADDR2 = 0x59; + + /** + * AppleRTC service handle + */ + IOService *rtcSrv {nullptr}; + + /** + * Low-level RTC read (does not check memory availability). + * + * @param dev RTC ACPI device + * @param offset offset + * + * @result read value + */ + static uint8_t readByte(IOACPIPlatformDevice *dev, uint8_t offset); + + /** + * Low-level RTC write (does not check memory availability). + * + * @param dev RTC ACPI device + * @param offset offset + * @param value value + */ + static void writeByte(IOACPIPlatformDevice *dev, uint8_t offset, uint8_t value); +public: + /** + * Attempt to connect to active RTC service + * + * @param wait wait for service availability + * + * @return true on success + */ + EXPORT bool init(bool wait=true); + + /** + * Release obtained RTC service + */ + EXPORT void deinit(); + + /** + * Check whether extended (higher 128 bytes) is available + * + * @return true on success + */ + EXPORT bool checkExtendedMemory(); + + /** + * Read memory from RTC + * + * @param off offset to read data from + * @param size data size + * @param buffer data buffer to read to + * + * @return true on success + */ + EXPORT bool read(uint64_t off, uint32_t size, uint8_t *buffer); + + /** + * Write memory to RTC + * + * @param off offset to write data to + * @param size data size + * @param buffer data buffer to write from + * + * @return true on success + */ + EXPORT bool write(uint64_t off, uint32_t size, uint8_t *buffer); + + /** + * Obtain RTC device for direct writing. + * Written as inline to avoid IOACPIPlatformDevice dependency. + * + * @param name device name + * + * @return RTC ACPI device for I/O access, must be released + */ + static inline IOACPIPlatformDevice *getRTCDevice(const char *name = "PNP0B00") { + IOService *rtcDev = nullptr; + auto matching = IOService::nameMatching(name); + if (matching) { + rtcDev = IOService::waitForMatchingService(matching); + matching->release(); + } else { + SYSLOG("rtc", "failed to allocate rtc device matching"); + } + + if (rtcDev) { + DBGLOG("rtc", "got rtc device"); + auto acpiDev = OSDynamicCast(IOACPIPlatformDevice, rtcDev); + if (acpiDev) { + DBGLOG("rtc", "got rtc acpi device"); + return acpiDev; + } else { + SYSLOG("rtc", "failed to obtain rtc acpi device"); + rtcDev->release(); + } + } + + SYSLOG("rtc", "failed to get rtc device"); + return nullptr; + } + + /** + * Directly read RTC memory (UNSAFE, usage with caution!) + * + * @param dev RTC device + * @param off offset to read data from + * @param size data size + * @param buffer data buffer to read to + * @param introff turn interrupts off + * + * @return true on success + */ + EXPORT static void readDirect(IOACPIPlatformDevice *dev, uint8_t off, uint16_t size, uint8_t *buffer, bool introff); + + /** + * Directly write RTC memory (UNSAFE, usage with caution!) + * + * @param dev RTC device + * @param off offset to read data from + * @param size data size + * @param buffer data buffer to read to + * @param updatecrc recalculate crc on write + * @param introff turn interrupts off + * + * @return true on success + */ + EXPORT static void writeDirect(IOACPIPlatformDevice *dev, uint8_t off, uint16_t size, uint8_t *buffer, bool updatecrc, bool introff); + + + /** + * Directly read RTC memory (UNSAFE, usage with caution!), this is just a compatibility function. + * + * @param off offset to read data from + * @param size data size + * @param buffer data buffer to read to + * @param introff turn interrupts off + * + * @return true on success + */ + static inline bool readDirect(uint8_t off, uint16_t size, uint8_t *buffer, bool introff) { + if (size > RTC_BANK_SIZE*2 - off) { + SYSLOG("rtc", "reading unsupported size"); + return false; + } + + auto rtc = getRTCDevice(); + if (rtc) { + readDirect(rtc, off, size, buffer, introff); + rtc->release(); + return true; + } + + return false; + } + + /** + * Directly write RTC memory (UNSAFE, usage with caution!), this is just a compatibility function. + * + * @param off offset to read data from + * @param size data size + * @param buffer data buffer to read to + * @param updatecrc recalculate crc on write + * @param introff turn interrupts off + * + * @return true on success + */ + static inline bool writeDirect(uint8_t off, uint16_t size, uint8_t *buffer, bool updatecrc, bool introff) { + if (size > RTC_BANK_SIZE*2 - off) { + SYSLOG("rtc", "writing unsupported size"); + return false; + } + + auto rtc = getRTCDevice(); + if (rtc) { + writeDirect(rtc, off, size, buffer, updatecrc, introff); + rtc->release(); + return true; + } + + return false; + } +}; + +#endif /* kern_rtc_h */ diff --git a/NightShiftUnlocker/Headers/kern_time.hpp b/NightShiftUnlocker/Headers/kern_time.hpp new file mode 100644 index 0000000..41d2f91 --- /dev/null +++ b/NightShiftUnlocker/Headers/kern_time.hpp @@ -0,0 +1,135 @@ +// +// kern_time.hpp +// Lilu +// +// Copyright © 2018 vit9696. All rights reserved. +// + +#ifndef kern_time_hpp +#define kern_time_hpp + +#include + +/** + * Obtain current system time in nanoseconds + * + * @return current time + */ +inline uint64_t getCurrentTimeNs() { + uint64_t currt = 0; + absolutetime_to_nanoseconds(mach_absolute_time(), &currt); + return currt; +} + +/** + * Obtain current calendar system time in nanoseconds + * + * @return current time + */ +inline uint64_t getCalendarTimeNs() { + clock_sec_t sc; + clock_nsec_t ns; + clock_get_calendar_nanotime(&sc, &ns); + return static_cast(sc) * NSEC_PER_SEC + ns; +} + +/** + * Obtain time passed since some timestamp in nanoseconds + * + * @param start starting timestamp + * @param current timestamp to check against (pass 0 for current time) + * + * @return delta or 0 (if current time equals or precedeces the start) + */ +inline uint64_t getTimeSinceNs(uint64_t start, uint64_t current = 0) { + if (current == 0) + current = getCurrentTimeNs(); + if (current > start) + return current - start; + return 0; +} + +/** + * Obtain time left till a timestamp in the future in nanoseconds + * + * @param start starting timestamp + * @param timeout timeout for the event + * @param current timestamp to check against (pass 0 for current time) + * + * @return delta or 0 (if the timeout is over) + */ +inline uint64_t getTimeLeftNs(uint64_t start, uint64_t timeout, uint64_t current = 0) { + if (current == 0) + current = getCurrentTimeNs(); + if (start + timeout > current) + return start + timeout - current; + return 0; +} + +/** + * Convert from nanoseconds to milliseconds + * + * @param t timestamp in ns + * + * @return timestamp in ms + */ +constexpr uint64_t convertNsToMs(uint64_t t) { + return t / 1000000; +} + +/** + * Convert from nanoseconds to seconds + * + * @param t timestamp in ns + * + * @return timestamp in s + */ +constexpr uint64_t convertNsToSc(uint64_t t) { + return t / 1000000000; +} + +/** + * Convert from milliseconds to seconds + * + * @param t timestamp in ms + * + * @return timestamp in s + */ +constexpr uint64_t convertMsToSc(uint64_t t) { + return t / 1000; +} + +/** + * Convert from milliseconds to nanoseconds + * + * @param t timestamp in ms + * + * @return timestamp in ns + */ +constexpr uint64_t convertMsToNs(uint64_t t) { + return t * 1000000; +} + +/** + * Convert from seconds to nanoseconds + * + * @param t timestamp in s + * + * @return timestamp in ns + */ +constexpr uint64_t convertScToNs(uint64_t t) { + return t * 1000000000; +} + +/** + * Convert from seconds to milliseconds + * + * @param t timestamp in s + * + * @return timestamp in ms + */ +constexpr uint64_t convertScToMs(uint64_t t) { + return t * 1000; +} + +#endif /* kern_time_hpp */ diff --git a/NightShiftUnlocker/Headers/kern_user.hpp b/NightShiftUnlocker/Headers/kern_user.hpp index 7a81aa3..26df5a0 100644 --- a/NightShiftUnlocker/Headers/kern_user.hpp +++ b/NightShiftUnlocker/Headers/kern_user.hpp @@ -130,9 +130,14 @@ class UserPatcher { MatchMask = MatchExact | MatchAny | MatchPrefix | MatchSuffix }; - const char *path; - uint32_t len; - uint32_t section; + /** + * Unused (aka disabled) proc info section + */ + static constexpr uint32_t SectionDisabled {0}; + + const char *path {nullptr}; + uint32_t len {0}; + uint32_t section {SectionDisabled}; uint32_t flags {MatchExact}; }; @@ -158,7 +163,51 @@ class UserPatcher { * @param user pointer that will be passed to the callback function */ bool registerPatches(ProcInfo **procs, size_t procNum, BinaryModInfo **mods, size_t modNum, t_BinaryLoaded callback, void *user); - + + /** + * Reads current process header + * + * @param map vm map + * @param header Mach-O header + * + * @return false on failure + */ + EXPORT bool getTaskHeader(vm_map_t map, mach_header_64 &header); + + /** + * Disables dyld_shared_cache for the current process + * + * @param map vm map + * + * @return false on mach image failure + */ + EXPORT bool injectRestrict(vm_map_t map); + + /** + * Injects payload into the process right after the header with EP replacement. + * + * @param map vm map + * @param payload code + * @param size code size (up to PAGE_SIZE) + * @param ep original entrypoint (may be written to code before copying) + * + * @return false on mach image failure + */ + EXPORT bool injectPayload(vm_map_t map, uint8_t *payload, size_t size, void *ep=nullptr); + + /** + * Allocates a new segment in the process. + * + * @param map vm map + * @param addr allocation address (e.g. a little below SHARED_REGION_BASE_X86_64) + * @param payload code + * @param size code size (must be PAGE_SIZE-aligned) + * @param prot segment protection + * + * @return allocated address or 0 on failure + */ + EXPORT vm_address_t injectSegment(vm_map_t taskPort, vm_address_t addr, uint8_t *payload, size_t size, vm_prot_t prot); + /** * Activates monitoring functions if necessary */ @@ -175,6 +224,7 @@ class UserPatcher { using t_codeSignValidateRangeWrapper = boolean_t (*)(void *, memory_object_t, memory_object_offset_t, const void *, memory_object_size_t, unsigned *); using t_vmSharedRegionMapFile = kern_return_t (*)(vm_shared_region_t, unsigned int, shared_file_mapping_np *, memory_object_control_t, memory_object_size_t, void *, uint32_t, user_addr_t slide_start, user_addr_t); using t_vmSharedRegionSlide = int (*)(uint32_t, mach_vm_offset_t, mach_vm_size_t, mach_vm_offset_t, mach_vm_size_t, memory_object_control_t); + using t_vmSharedRegionSlideMojave = int (*)(uint32_t, mach_vm_offset_t, mach_vm_size_t, mach_vm_offset_t, mach_vm_size_t, mach_vm_offset_t, memory_object_control_t); using t_currentMap = vm_map_t (*)(void); using t_getTaskMap = vm_map_t (*)(task_t); using t_getMapMin = vm_map_offset_t (*)(vm_map_t); @@ -190,6 +240,7 @@ class UserPatcher { t_codeSignValidateRangeWrapper orgCodeSignValidateRangeWrapper {nullptr}; t_vmSharedRegionMapFile orgVmSharedRegionMapFile {nullptr}; t_vmSharedRegionSlide orgVmSharedRegionSlide {nullptr}; + t_vmSharedRegionSlideMojave orgVmSharedRegionSlideMojave {nullptr}; t_currentMap orgCurrentMap {nullptr}; t_getMapMin orgGetMapMin {nullptr}; t_getTaskMap orgGetTaskMap {nullptr}; @@ -208,6 +259,7 @@ class UserPatcher { static kern_return_t vmSharedRegionMapFile(vm_shared_region_t shared_region, unsigned int mappings_count, shared_file_mapping_np *mappings, memory_object_control_t file_control, memory_object_size_t file_size, void *root_dir, uint32_t slide, user_addr_t slide_start, user_addr_t slide_size); static void execsigs(proc_t p, thread_t thread); static int vmSharedRegionSlide(uint32_t slide, mach_vm_offset_t entry_start_address, mach_vm_size_t entry_size, mach_vm_offset_t slide_start, mach_vm_size_t slide_size, memory_object_control_t sr_file_control); + static int vmSharedRegionSlideMojave(uint32_t slide, mach_vm_offset_t entry_start_address, mach_vm_size_t entry_size, mach_vm_offset_t slide_start, mach_vm_size_t slide_size, mach_vm_offset_t slid_mapping, memory_object_control_t sr_file_control); static proc_t procExecSwitchTask(proc_t p, task_t current_task, task_t new_task, thread_t new_thread); /** @@ -305,7 +357,7 @@ class UserPatcher { /** * Provided global callback for on proc invocation */ - ppair userCallback; + ppair userCallback {}; /** * Applies dyld shared cache patches @@ -363,7 +415,7 @@ class UserPatcher { }; struct Lookup { - uint32_t offs[4]; + uint32_t offs[4] {}; static constexpr size_t matchNum {4}; evector c[matchNum]; }; @@ -379,7 +431,7 @@ class UserPatcher { sizeof(segment_command_64), "__RESTRICT", SHARED_REGION_BASE_X86_64, - 1 + 1, 0, 0, 0, 0, 0, 0 }; /** @@ -390,14 +442,14 @@ class UserPatcher { sizeof(segment_command), "__RESTRICT", SHARED_REGION_BASE_I386, - 1 + 1, 0, 0, 0, 0, 0, 0 }; /** - * Temporary header for reading data + * Temporary buffer for reading image data */ - mach_header_64 tmpHeader; - + uint8_t tmpBufferData[PAGE_SIZE*3] {}; + /** * Kernel auth listener handle */ @@ -411,7 +463,7 @@ class UserPatcher { /** * Validation cookie */ - void *cookie = {reinterpret_cast(0xB16B00B5)}; + void *cookie {nullptr}; /** * Exec callback @@ -463,16 +515,7 @@ class UserPatcher { * @return true on success */ bool hookMemoryAccess(); - - /** - * Disables dyld_shared_cache for the current process - * - * @param map vm map - * - * @return false on mach image failure - */ - bool injectRestrict(vm_map_t map); - + /** * Peforms the actual binary patching * @@ -483,13 +526,14 @@ class UserPatcher { void patchBinary(vm_map_t map, const char *path, uint32_t len); /** - * Possible dyld shared cache map paths + * Dyld shared cache map path for 10.10+ on Haswell */ - static constexpr size_t sharedCacheMapPathsNum {2}; - const char *sharedCacheMap[sharedCacheMapPathsNum] { - "/private/var/db/dyld/dyld_shared_cache_x86_64h.map", //since 10.10 - "/private/var/db/dyld/dyld_shared_cache_x86_64.map" - }; + static constexpr const char *SharedCacheMapHaswell {"/private/var/db/dyld/dyld_shared_cache_x86_64h.map"}; + + /** + * Dyld shared cache map path for all other systems and older CPUs + */ + static constexpr const char *SharedCacheMapLegacy {"/private/var/db/dyld/dyld_shared_cache_x86_64.map"}; }; diff --git a/NightShiftUnlocker/Headers/kern_util.hpp b/NightShiftUnlocker/Headers/kern_util.hpp index a80616b..17e627f 100644 --- a/NightShiftUnlocker/Headers/kern_util.hpp +++ b/NightShiftUnlocker/Headers/kern_util.hpp @@ -34,6 +34,13 @@ */ extern bool ADDPR(debugEnabled); +/** + * Debugging print delay used as an ugly hack around printf bufferisation, + * which results in messages not appearing in the boot log. + * Use liludelay=1000 (1 second) boot-arg to put a second after each message. + */ +extern uint32_t ADDPR(debugPrintDelay); + /** * Kernel version major */ @@ -54,16 +61,21 @@ extern vm_map_t kernel_map; */ extern proc_t kernproc; +/** + * For noreturn failures + */ +#define UNREACHABLE() do { __builtin_unreachable(); } while (0) + /** * Conditional logging to system log prefixed with you plugin name * * @param cond precondition * @param str printf-like string */ -#define SYSLOG_COND(cond, module, str, ...) \ - do { \ - if (cond) \ - IOLog( "%s%10s" str "\n", xStringify(PRODUCT_NAME) ": ", module " @ ", ## __VA_ARGS__); \ +#define SYSLOG_COND(cond, module, str, ...) \ + do { \ + if (cond) \ + lilu_os_log( "%s%10s" str "\n", xStringify(PRODUCT_NAME) ": ", module " @ ", ## __VA_ARGS__); \ } while (0) /** @@ -83,8 +95,10 @@ extern proc_t kernproc; */ #define SYSTRACE_COND(cond, module, str, ...) \ do { \ - if (cond) \ - OSReportWithBacktrace( "%s%10s" str "\n", xStringify(PRODUCT_NAME) ": ", module " @ ", ## __VA_ARGS__); \ + if (cond) { \ + SYSLOG(module, str, ## __VA_ARGS__); \ + OSReportWithBacktrace( "%s%10s" str "\n", xStringify(PRODUCT_NAME) ": ", module " @ ", ## __VA_ARGS__); \ + } \ } while (0) /** @@ -104,8 +118,10 @@ extern proc_t kernproc; */ #define PANIC_COND(cond, module, str, ...) \ do { \ - if (cond) \ - (panic)( "%s%10s" str "\n", xStringify(PRODUCT_NAME) ": ", module " @ ", ## __VA_ARGS__); \ + if (cond) { \ + (panic)( "%s%10s" str "\n", xStringify(PRODUCT_NAME) ": ", module " @ ", ## __VA_ARGS__); \ + UNREACHABLE(); \ + } \ } while (0) /** @@ -127,7 +143,7 @@ extern proc_t kernproc; */ #define DBGLOG_COND(cond, module, str, ...) \ do { \ - SYSLOG_COND(ADDPR(debugEnabled) && (cond), module, "%s" str, "(DBG) ", ## __VA_ARGS__); \ + SYSLOG_COND(ADDPR(debugEnabled) && (cond), module, "%s" str, "(DBG) ", ## __VA_ARGS__); \ } while (0) /** @@ -147,7 +163,7 @@ extern proc_t kernproc; */ #define DBGTRACE_COND(cond, module, str, ...) \ do { \ - SYSTRACE_COND(ADDPR(debugEnabled) && (cond), module, "%s" str, "(DBG) ", ## __VA_ARGS__); \ + SYSTRACE_COND(ADDPR(debugEnabled) && (cond), module, "%s" str, "(DBG) ", ## __VA_ARGS__); \ } while (0) /** @@ -167,6 +183,47 @@ extern proc_t kernproc; #endif +/** + * Deprecate the interface + */ +#define DEPRECATE(x) __attribute__((deprecated(x))) + +/** + * Macros to bypass kernel address printing protection + */ +#define PRIKADDR "0x%08X%08X" +#define CASTKADDR(x) \ + static_cast(reinterpret_cast(x) >> 32), \ + static_cast(reinterpret_cast(x)) + +/** + * Ugly floating point printing macros + */ +#define PRIFRAC "%lld.%04lld" +#define CASTFRAC(x) static_cast(x), static_cast(((x) - static_cast(x)) * 10000) + +/** + * Macros to print the UUID + */ +#define PRIUUID "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X" +#define CASTUUID(uuid) \ + reinterpret_cast(uuid)[0], \ + reinterpret_cast(uuid)[1], \ + reinterpret_cast(uuid)[2], \ + reinterpret_cast(uuid)[3], \ + reinterpret_cast(uuid)[4], \ + reinterpret_cast(uuid)[5], \ + reinterpret_cast(uuid)[6], \ + reinterpret_cast(uuid)[7], \ + reinterpret_cast(uuid)[8], \ + reinterpret_cast(uuid)[9], \ + reinterpret_cast(uuid)[10], \ + reinterpret_cast(uuid)[11], \ + reinterpret_cast(uuid)[12], \ + reinterpret_cast(uuid)[13], \ + reinterpret_cast(uuid)[14], \ + reinterpret_cast(uuid)[15] + /** * Export function or symbol for linking */ @@ -177,6 +234,14 @@ extern proc_t kernproc; */ #define PACKED __attribute__((packed)) +/** + * This function is supposed to workaround missing entries in the system log. + * By providing its own buffer for logging data. + * + * @param format formatted string + */ +EXPORT extern "C" void lilu_os_log(const char *format, ...); + /** * Two-way substring search * @@ -198,6 +263,16 @@ EXPORT const char *strstr(const char *stack, const char *needle, size_t len=0); */ EXPORT char *strrchr(const char *stack, int ch); +/** + * XNU kernel implementation of a C-standard qsort function normally not exported by the kernel. + * + * @param a array to sort + * @param n array length + * @param es array element size + * @param cmp array element comparator + */ +EXPORT void qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *)); + /** * Count array elements * @@ -218,6 +293,7 @@ extern "C" { void *kern_os_calloc(size_t num, size_t size); void kern_os_free(void *addr); void *kern_os_realloc(void *addr, size_t nsize); + // kern_os_free does not check its argument for nullptr EXPORT void lilu_os_free(void *addr); } @@ -232,7 +308,8 @@ enum KernelVersion { Yosemite = 14, ElCapitan = 15, Sierra = 16, - HighSierra = 17 + HighSierra = 17, + Mojave = 18, }; /** @@ -258,6 +335,18 @@ inline KernelMinorVersion getKernelMinorVersion() { return static_cast(version_minor); } +/** + * Check whether kernel boot argument is passed ignoring the value (e.g. -arg or arg). + * + * @param name argument name + * + * @return true if argument was passed + */ +inline bool checkKernelArgument(const char *name) { + int val[16]; + return PE_parse_boot_argn(name, val, sizeof(val)); +} + /** * Parse apple version at compile time * @@ -269,18 +358,159 @@ constexpr size_t parseModuleVersion(const char *version) { return (version[0] - '0') * 100 + (version[2] - '0') * 10 + (version[4] - '0'); } +/** + * Access struct member by its offset + * + * @param T pointer to the field you need + * @param that pointer to struct + * @param off offset in bytes to the member + * + * @return reference to the struct member + */ +template +inline T &getMember(void *that, size_t off) { + return *reinterpret_cast(static_cast(that) + off); +} + +/** + * Align value by align (page size by default) + * + * @param size value + * + * @return algined value + */ +template +inline T alignValue(T size, T align = 4096) { + return (size + align - 1) & (~(align - 1)); +} + +/** + * Check pointer alignment for type T + * + * @param p pointer + * + * @return true if properly aligned + */ +template +inline bool isAligned(T *p) { + return reinterpret_cast(p) % alignof(T) == 0; +} + +/** + * Obtain bit value of size sizeof(T) + * Warning, you are suggested to always pass the type explicitly! + * + * @param n bit no + * + * @return bit value + */ +template +constexpr T getBit(T n) { + return static_cast(1U) << n; +} + +/** + * Obtain bit mask of size sizeof(T) + * Warning, you are suggested to always pass the type explicitly! + * + * @param hi starting high bit + * @param lo ending low bit + * + * @return bit mask + */ +template +constexpr T getBitMask(T hi, T lo) { + return (getBit(hi)|(getBit(hi)-1U)) & ~(getBit(lo)-1U); +} + +/** + * Obtain bit field of size sizeof(T) + * Warning, you are suggested to always pass the type explicitly! + * + * @param so source + * @param hi starting high bit + * @param lo ending low bit + * + * @return bit field value + */ +template +constexpr T getBitField(T so, T hi, T lo) { + return (so & getBitMask(hi, lo)) >> lo; +} + +/** + * Set bit field of size sizeof(T) + * Warning, you are suggested to always pass the type explicitly! + * + * @param va value + * @param hi starting high bit + * @param lo ending low bit + * + * @return bit field value + */ +template +constexpr T setBitField(T so, T hi, T lo) { + return (so << lo) & getBitMask(hi, lo); +} + +/** + * This is an ugly replacement to std::find_if, allowing you + * to check whether a container consists only of value values. + * + * @param in container + * @param size container size + * @param value value to look for + * + * @return true if an element different from value was found + */ +template +inline bool findNotEquals(T &in, size_t size, Y value) { + for (size_t i = 0; i < size; i++) + if (in[i] != value) + return true; + return false; +} + +/** + * Returns non-null string when they can be null + * + * @param str original string + * + * @return non-null string + */ +inline const char *safeString(const char *str) { + return str ? str : "(null)"; +} + +/** + * A shorter form of writing reinterpret_cast(ptr) + */ +template +inline T FunctionCast(T org, mach_vm_address_t ptr) { + return reinterpret_cast(ptr); +} + /** * Typed buffer allocator */ namespace Buffer { + /** + * Allocating more than 1 GB is unreasonable for stability purposes. + */ + static constexpr size_t BufferMax = 1024*1024*1024; + template - T *create(size_t size) { - return static_cast(kern_os_malloc(sizeof(T) * size)); + inline T *create(size_t size) { + size_t s = sizeof(T) * size; + if (s > BufferMax) return nullptr; + return static_cast(kern_os_malloc(s)); } template - bool resize(T *&buf, size_t size) { - auto nbuf = static_cast(kern_os_realloc(buf, sizeof(T) * size)); + inline bool resize(T *&buf, size_t size) { + size_t s = sizeof(T) * size; + if (s > BufferMax) return false; + auto nbuf = static_cast(kern_os_realloc(buf, s)); if (nbuf) { buf = nbuf; return true; @@ -290,7 +520,7 @@ namespace Buffer { } template - void deleter(T *buf) { + inline void deleter(T *buf) { lilu_os_free(buf); } } @@ -376,7 +606,7 @@ class evector { * * @return element count */ - const size_t size() const { + size_t size() const { return cnt; } @@ -395,7 +625,7 @@ class evector { * * @return element id */ - const size_t last() const { + size_t last() const { return cnt-1; } @@ -449,12 +679,12 @@ class evector { * * @return true on success */ - bool erase(size_t index) { + bool erase(size_t index, bool free=true) { deleter(ptr[index]); if (--cnt != index) lilu_os_memmove(&ptr[index], &ptr[index + 1], (cnt - index) * sizeof(T)); - if (cnt == 0) { + if (free && cnt == 0) { kern_os_free(ptr); ptr = nullptr; rsvd = 0; @@ -517,4 +747,55 @@ class evector { } }; +/** + * Slightly non-standard helpers to get the date in a YYYY-MM-DD format. + */ +template +inline constexpr char getBuildYear() { + static_assert(i < 4, "Year consists of four digits"); + return __DATE__[7+i]; +} + +template +inline constexpr char getBuildMonth() { + static_assert(i < 2, "Month consists of two digits"); + auto mon = *reinterpret_cast(__DATE__); + switch (mon) { + case ' naJ': + return "01"[i]; + case ' beF': + return "02"[i]; + case ' raM': + return "03"[i]; + case ' rpA': + return "04"[i]; + case ' yaM': + return "05"[i]; + case ' nuJ': + return "06"[i]; + case ' luJ': + return "07"[i]; + case ' guA': + return "08"[i]; + case ' peS': + return "09"[i]; + case ' tcO': + return "10"[i]; + case ' voN': + return "11"[i]; + case ' ceD': + return "12"[i]; + } + + return '0'; +} + +template +inline constexpr char getBuildDay() { + static_assert(i < 2, "Day consists of two digits"); + if (i == 0 && __DATE__[4+i] == ' ') + return '0'; + return __DATE__[4+i]; +} + #endif /* kern_util_hpp */ diff --git a/NightShiftUnlocker/Headers/plugin_start.hpp b/NightShiftUnlocker/Headers/plugin_start.hpp index 0f190b1..7920882 100644 --- a/NightShiftUnlocker/Headers/plugin_start.hpp +++ b/NightShiftUnlocker/Headers/plugin_start.hpp @@ -46,6 +46,8 @@ class EXPORT PRODUCT_NAME : public IOService { void stop(IOService *provider) override; }; +extern PRODUCT_NAME *ADDPR(selfInstance); + #endif /* LILU_CUSTOM_IOKIT_INIT */ #endif /* kern_start_hpp */ diff --git a/NightShiftUnlocker/Library/plugin_start.cpp b/NightShiftUnlocker/Library/plugin_start.cpp index 3f3fe18..db14db0 100644 --- a/NightShiftUnlocker/Library/plugin_start.cpp +++ b/NightShiftUnlocker/Library/plugin_start.cpp @@ -17,17 +17,34 @@ bool ADDPR(startSuccess) = true; #endif bool ADDPR(debugEnabled) = false; +uint32_t ADDPR(debugPrintDelay) = 0; #ifndef LILU_CUSTOM_IOKIT_INIT +static const char kextVersion[] { +#ifdef DEBUG + 'D', 'B', 'G', '-', +#else + 'R', 'E', 'L', '-', +#endif + xStringify(MODULE_VERSION)[0], xStringify(MODULE_VERSION)[2], xStringify(MODULE_VERSION)[4], '-', + getBuildYear<0>(), getBuildYear<1>(), getBuildYear<2>(), getBuildYear<3>(), '-', + getBuildMonth<0>(), getBuildMonth<1>(), '-', getBuildDay<0>(), getBuildDay<1>(), '\0' +}; + OSDefineMetaClassAndStructors(PRODUCT_NAME, IOService) +PRODUCT_NAME *ADDPR(selfInstance) = nullptr; + IOService *PRODUCT_NAME::probe(IOService *provider, SInt32 *score) { + ADDPR(selfInstance) = this; + setProperty("VersionInfo", kextVersion); auto service = IOService::probe(provider, score); return ADDPR(startSuccess) ? service : nullptr; } bool PRODUCT_NAME::start(IOService *provider) { + ADDPR(selfInstance) = this; if (!IOService::start(provider)) { SYSLOG("init", "failed to start the parent"); return false; @@ -37,6 +54,7 @@ bool PRODUCT_NAME::start(IOService *provider) { } void PRODUCT_NAME::stop(IOService *provider) { + ADDPR(selfInstance) = nullptr; IOService::stop(provider); } @@ -45,7 +63,10 @@ void PRODUCT_NAME::stop(IOService *provider) { #ifndef LILU_CUSTOM_KMOD_INIT EXPORT extern "C" kern_return_t ADDPR(kern_start)(kmod_info_t *, void *) { - LiluAPI::Error error = lilu.requestAccess(); + // This is an ugly hack necessary on some systems where buffering kills most of debug output. + PE_parse_boot_argn("liludelay", &ADDPR(debugPrintDelay), sizeof(ADDPR(debugPrintDelay))); + + auto error = lilu.requestAccess(); if (error == LiluAPI::Error::NoError) { error = lilu.shouldLoad(ADDPR(config).product, ADDPR(config).version, ADDPR(config).runmode, ADDPR(config).disableArg, ADDPR(config).disableArgNum, ADDPR(config).debugArg, ADDPR(config).debugArgNum, ADDPR(config).betaArg, ADDPR(config).betaArgNum, ADDPR(config).minKernel, diff --git a/NightShiftUnlocker/kern_start.cpp b/NightShiftUnlocker/kern_start.cpp index 87db307..1a163a1 100644 --- a/NightShiftUnlocker/kern_start.cpp +++ b/NightShiftUnlocker/kern_start.cpp @@ -195,7 +195,7 @@ static void generatePatches(void* unused, KernelPatcher &patcher) return; } - IOLog("NightShiftUnlocker::generatePatches() Found symbol @ %02X.\n", address); + IOLog("NightShiftUnlocker::generatePatches() Found symbol @ %02llX.\n", address); size_t length = numBytesBufferAA; @@ -203,14 +203,14 @@ static void generatePatches(void* unused, KernelPatcher &patcher) if (buffer != NULL) { - IOLog("NightShiftUnlocker::generatePatches() %d bytes have been read.\n", length); + IOLog("NightShiftUnlocker::generatePatches() %zu bytes have been read.\n", length); // TODO: Future: Multiple Patches??? size_t offset = numBytesPatchAA; - memcpy(&findBytesAA[0], buffer, length); + lmemcpy(&findBytesAA[0], buffer, length); - memcpy(&replBytesAA[offset], buffer + offset, length - offset); + lmemcpy(&replBytesAA[offset], buffer + offset, length - offset); IOLog("NightShiftUnlocker::generatePatches() Binary patches have been generated.\n"); @@ -269,7 +269,7 @@ PluginConfiguration ADDPR(config) = parseModuleVersion(xStringify(MODULE_VERSION)), - LiluAPI::Requirements::AllowNormal, + LiluAPI::RunningMode::AllowNormal, bootArgDisable, @@ -285,7 +285,7 @@ PluginConfiguration ADDPR(config) = KernelVersion::Sierra, - KernelVersion::HighSierra, - + KernelVersion::Mojave, + startUnlocker };