2022-03-29 10:26:33 +03:00

383 lines
12 KiB
C++
Executable File

//
// kern_api.hpp
// Lilu
//
// Copyright © 2016-2017 vit9696. All rights reserved.
//
#ifndef kern_api_h
#define kern_api_h
#include <Headers/kern_config.hpp>
#include <Headers/kern_patcher.hpp>
#include <Headers/kern_user.hpp>
#include <Headers/kern_util.hpp>
#include <stdint.h>
#include <sys/types.h>
#include <libkern/OSAtomic.h>
#include <Availability.h>
#ifndef __ACIDANTHERA_MAC_SDK
#error "This kext SDK is unsupported. Download from https://github.com/acidanthera/MacKernelSDK"
#endif
class LiluAPI {
public:
/**
* Initialise lilu api
*/
void init();
/**
* Deinitialise lilu api
*/
void deinit();
/**
* Errors returned by functions
*/
enum class Error {
NoError,
LockError,
MemoryError,
UnsupportedFeature,
IncompatibleOS,
Disabled,
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
*
* @param version api compatibility version
* @param check do not wait on the lock but return Error::LockError on failure
*
* @return Error::NoError on success
*/
EXPORT Error requestAccess(size_t version=CompatibilityVersion, bool check=false);
/**
* Releases api lock
*
* @return Error::NoError on success
*/
EXPORT Error releaseAccess();
/**
* You are supposed declare that your plugins work in at least one of these modes
* 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 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
*
* @param product product name
* @param version product version
* @param runmode bitmask of allowed enviornments
* @param disableArg pointer to disabling boot arguments array
* @param disableArgNum number of disabling boot arguments
* @param debugArg pointer to debug boot arguments array
* @param debugArgNum number of debug boot arguments
* @param betaArg pointer to beta boot arguments array
* @param betaArgNum number of beta boot arguments
* @param min minimal required kernel version
* @param max maximum supported kernel version
* @param printDebug returns debug printing status (based on debugArg)
*
* @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
*
* @param user user provided pointer at registering
* @param patcher kernel patcher instance
*/
using t_patcherLoaded = void (*)(void *user, KernelPatcher &patcher);
/**
* Registers custom provided callbacks for later invocation on kernel patcher initialisation
*
* @param callback your callback function
* @param user your pointer that will be passed to the callback function
*
* @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
*/
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
*
* @param user user provided pointer at registering
* @param patcher kernel patcher instance
* @param id loaded kinfo id
* @param slide loaded slide
* @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 (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)
*/
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 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
* @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
*/
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
*/
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);
}
/**
* Complete plugin registration and perform regulatory actions
*/
void finaliseRequests();
/**
* Processes all the registered patcher load callbacks
*
* @param patcher kernel patcher instance
*/
void processPatcherLoadCallbacks(KernelPatcher &patcher);
/**
* Processes all the registered kext load callbacks
*
* @param patcher kernel patcher instance
* @param id loaded kinfo id
* @param slide loaded slide
* @param size loaded memory size
* @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
*
* @param patcher kernel patcher instance
* @param map process image vm_map
* @param path path to the binary absolute or relative
* @param len path length excluding null terminator
*/
void processBinaryLoadCallbacks(UserPatcher &patcher, vm_map_t map, const char *path, size_t len);
/**
* Activates patchers
*
* @param kpatcher kernel patcher instance
* @param upatcher user patcher instance
*/
void activate(KernelPatcher &kpatcher, UserPatcher &upatcher);
private:
/**
* Api lock
*/
IOLock *access {nullptr};
/**
* Defines current running modes
*/
uint32_t currentRunMode {};
/**
* No longer accept any requests
*/
bool apiRequestsOver {false};
/**
* Stores call function and user pointer
*/
template <typename T, typename Y=void *>
using stored_pair = ppair<T, Y>;
/**
* Stores multiple callbacks
*/
template <typename T, typename Y=void *>
using stored_vector = evector<stored_pair<T, Y> *, stored_pair<T, Y>::deleter>;
/**
* List of patcher callbacks
*/
stored_vector<t_patcherLoaded> patcherLoadedCallbacks;
/**
* List of kext callbacks
*/
stored_vector<t_kextLoaded> kextLoadedCallbacks;
/**
* List of binary callbacks
*/
stored_vector<UserPatcher::t_BinaryLoaded> binaryLoadedCallbacks;
/**
* List of entitlement callbacks
*/
stored_vector<t_entitlementRequested> entitlementRequestedCallbacks;
/**
* List of processed kexts
*/
stored_vector<KernelPatcher::KextInfo *, size_t> storedKexts;
/**
* List of processed procs
*/
evector<UserPatcher::ProcInfo *> storedProcs;
/**
* List of processed binary mods
*/
evector<UserPatcher::BinaryModInfo *> 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;
#endif /* kern_api_h */