Add objc hooking utilities

This commit is contained in:
altalk23 2023-08-18 10:51:00 +03:00
parent 409815acb3
commit a31d07237f
5 changed files with 103 additions and 4 deletions
VERSION
loader
include/Geode
src/platform
mac
windows

View file

@ -1 +1 @@
1.1.1
1.2.0

View file

@ -11,3 +11,4 @@
#include "utils/general.hpp"
#include "utils/timer.hpp"
#include "utils/MiniFunction.hpp"
#include "utils/ObjcHook.hpp"

View file

@ -0,0 +1,68 @@
#pragma once
#include "../loader/Hook.hpp"
#include "Result.hpp"
namespace geode {
namespace hook {
/**
* Add a new Objective-C method to a class. This method will be created
* using the imp provided. If the method already exists, it won't do
* anything.
* @param className The name of the class to add the method to
* @param selectorName The name of the method to add
* @param imp The implementation of the method
* @returns Ok() if the method was added successfully, or an error.
*/
Result<> addObjcMethod(std::string const& className, std::string const& selectorName, void* imp);
/**
* Get the implementation of an Objective-C method.
* @param className The name of the class whose method to get
* @param selectorName The name of the method to get
* @returns The implementation of the method, or an error.
*/
Result<void*> getObjcMethodImp(std::string const& className, std::string const& selectorName);
}
class ObjcHook {
public:
/**
* Create a hook for an Objective-C method
* @param className The name of the class whose method to hook
* @param selectorName The name of the method to hook
* @param function The detour to run when the method is called
* @returns The created hook, or an error.
*/
template <class Func>
static Result<Hook*> create(std::string const& className, std::string const& selectorName, Func function, tulip::hook::HookMetadata const& metadata = tulip::hook::HookMetadata()) {
GEODE_UNWRAP_INTO(auto imp, geode::hook::getObjcMethodImp(className, selectorName));
return Ok(Hook::create(
getMod(),
imp,
function,
className + "::" + selectorName,
tulip::hook::TulipConvention::Default,
metadata
));
}
/**
* Create a hook for a new Objective-C method. This method will be
* created with a dummy implementation that does nothing.
* @param className The name of the class whose method to hook
* @param selectorName The name of the method to hook
* @param function The detour to run when the method is called
* @param empty A function that takes no arguments and returns nothing.
* This is used to create a dummy method that can be hooked.
* @returns The created hook, or an error.
*/
template <class Func>
static Result<Hook*> create(std::string const& className, std::string const& selectorName, Func function, void(*empty)(), tulip::hook::HookMetadata const& metadata = tulip::hook::HookMetadata()) {
GEODE_UNWRAP(geode::hook::addObjcMethod(className, selectorName, (void*)empty));
return ObjcHook::create(className, selectorName, function, metadata);
}
};
}

View file

@ -7,9 +7,7 @@ using namespace geode::prelude;
#include <Geode/loader/Dirs.hpp>
#import <AppKit/AppKit.h>
#include <Geode/utils/web.hpp>
#include <Geode/utils/file.hpp>
#include <Geode/utils/cocos.hpp>
#include <Geode/Utils.hpp>
#include <Geode/binding/GameManager.hpp>
bool utils::clipboard::write(std::string const& data) {
@ -235,4 +233,29 @@ void geode::utils::game::restart() {
), CCDirector::get()->getRunningScene(), false);
}
Result<> geode::hook::addObjcMethod(std::string const& className, std::string const& selectorName, void* imp) {
auto cls = objc_getClass(className.c_str());
if (!cls)
return Err("Class not found");
auto sel = sel_registerName(selectorName.c_str());
class_addMethod(cls, sel, (IMP)imp, "v@:");
return Ok();
}
Result<void*> geode::hook::getObjcMethodImp(std::string const& className, std::string const& selectorName) {
auto cls = objc_getClass(className.c_str());
if (!cls)
return Err("Class not found");
auto sel = sel_registerName(selectorName.c_str());
auto method = class_getInstanceMethod(cls, sel);
if (!method)
return Err("Method not found");
return Ok((void*)method_getImplementation(method));
}
#endif

View file

@ -184,4 +184,11 @@ void geode::utils::game::restart() {
exit(0);
}
Result<> geode::hook::addObjcMethod(std::string const& className, std::string const& selectorName, void* imp) {
return Err("Wrong platform");
}
Result<void*> geode::hook::getObjcMethodImp(std::string const& className, std::string const& selectorName) {
return Err("Wrong platform");
}
#endif