diff --git a/loader/include/Geode/loader/Hook.hpp b/loader/include/Geode/loader/Hook.hpp
index da6e42e6..1f79e9c6 100644
--- a/loader/include/Geode/loader/Hook.hpp
+++ b/loader/include/Geode/loader/Hook.hpp
@@ -16,13 +16,14 @@ namespace geode {
     private:
         class Impl;
         std::shared_ptr<Impl> m_impl;
-        explicit Hook(std::shared_ptr<Impl>&& impl);
         ~Hook();
 
         friend class Mod;
         friend class Loader;
 
     public:
+        explicit Hook(std::shared_ptr<Impl>&& impl);
+
         /**
          * Create a hook at an address. The hook is enabled immediately. By 
          * default, the hook is placed at the end of the detour list; however, 
@@ -37,7 +38,7 @@ namespace geode {
          * @returns The created hook, or an error. Make sure to add the created 
          * hook to the mod that owns it using mod->claimHook!
          */
-        static Hook* create(
+        static std::shared_ptr<Hook> create(
             void* address,
             void* detour,
             std::string const& displayName,
@@ -46,7 +47,7 @@ namespace geode {
         );
 
         template<class DetourType>
-        static Hook* create(
+        static std::shared_ptr<Hook> create(
             void* address,
             DetourType detour,
             std::string const& displayName,
@@ -144,14 +145,15 @@ namespace geode {
     private:
         class Impl;
         std::shared_ptr<Impl> m_impl;
-        explicit Patch(std::shared_ptr<Impl>&& impl);
         ~Patch();
 
         friend class Mod;
         friend class Loader;
 
     public:
-        static Patch* create(void* address, const ByteVector& patch);
+        explicit Patch(std::shared_ptr<Impl>&& impl);
+
+        static std::shared_ptr<Patch> create(void* address, const ByteVector& patch);
 
         Patch(Patch const&) = delete;
         Patch operator=(Patch const&) = delete;
diff --git a/loader/include/Geode/loader/Mod.hpp b/loader/include/Geode/loader/Mod.hpp
index 82320363..14aa1959 100644
--- a/loader/include/Geode/loader/Mod.hpp
+++ b/loader/include/Geode/loader/Mod.hpp
@@ -251,8 +251,8 @@ namespace geode {
             tulip::hook::HookMetadata const& hookMetadata = tulip::hook::HookMetadata()
         ) {
             auto hook = Hook::create(address, detour, displayName, convention, hookMetadata);
-            GEODE_UNWRAP(this->claimHook(hook));
-            return Ok(hook);
+            GEODE_UNWRAP_INTO(auto ptr, this->claimHook(std::move(hook)));
+            return Ok(ptr);
         }
 
         Result<Hook*> hook(
@@ -261,11 +261,11 @@ namespace geode {
             tulip::hook::HookMetadata const& hookMetadata
         ) {
             auto hook = Hook::create(address, detour, displayName, handlerMetadata, hookMetadata);
-            GEODE_UNWRAP(this->claimHook(hook));
-            return Ok(hook);
+            GEODE_UNWRAP_INTO(auto ptr, this->claimHook(std::move(hook)));
+            return Ok(ptr);
         }
 
-        Result<> claimHook(Hook* hook);
+        Result<Hook*> claimHook(std::shared_ptr<Hook>&& hook);
 
         Result<> disownHook(Hook* hook);
 
@@ -284,11 +284,11 @@ namespace geode {
          */
         Result<Patch*> patch(void* address, ByteVector const& data) {
             auto patch = Patch::create(address, data);
-            GEODE_UNWRAP(this->claimPatch(patch));
-            return Ok(patch);
+            GEODE_UNWRAP_INTO(auto ptr, this->claimPatch(std::move(patch)));
+            return Ok(ptr);
         }
 
-        Result<> claimPatch(Patch* patch);
+        Result<Patch*> claimPatch(std::shared_ptr<Patch>&& patch);
 
         Result<> disownPatch(Patch* patch);
 
diff --git a/loader/include/Geode/modify/Modify.hpp b/loader/include/Geode/modify/Modify.hpp
index 504d2988..32e27459 100644
--- a/loader/include/Geode/modify/Modify.hpp
+++ b/loader/include/Geode/modify/Modify.hpp
@@ -70,13 +70,13 @@ namespace geode::modifier {
     template <class ModifyDerived>
     class ModifyBase {
     public:
-        std::map<std::string, Hook*> m_hooks;
+        std::map<std::string, std::shared_ptr<Hook>> m_hooks;
 
         Result<Hook*> getHook(std::string const& name) {
             if (m_hooks.find(name) == m_hooks.end()) {
                 return Err("Hook not in this modify");
             }
-            return Ok(m_hooks[name]);
+            return Ok(m_hooks[name].get());
         }
 
         Result<> setHookPriority(std::string const& name, int32_t priority) {
@@ -94,11 +94,18 @@ namespace geode::modifier {
             auto test = static_cast<ModifyDerived*>(this);
             test->ModifyDerived::apply();
             ModifyDerived::Derived::onModify(*this);
+            std::vector<std::string> added;
             for (auto& [uuid, hook] : m_hooks) {
-                auto res = Mod::get()->claimHook(hook);
+                auto res = Mod::get()->claimHook(std::move(hook));
                 if (!res) {
                     log::error("Failed to claim hook {}: {}", hook->getDisplayName(), res.error());
                 }
+                else {
+                    added.push_back(uuid);
+                }
+            }
+            for (auto& uuid : added) {
+                m_hooks.erase(uuid);
             }
         }
 
diff --git a/loader/include/Geode/utils/ObjcHook.hpp b/loader/include/Geode/utils/ObjcHook.hpp
index 7e156777..ec52ae4f 100644
--- a/loader/include/Geode/utils/ObjcHook.hpp
+++ b/loader/include/Geode/utils/ObjcHook.hpp
@@ -35,7 +35,7 @@ namespace geode {
          * @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()) {
+        static Result<std::shared_ptr<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(
@@ -59,7 +59,7 @@ namespace geode {
          * @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()) {
+        static Result<std::shared_ptr<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);
diff --git a/loader/src/loader/Hook.cpp b/loader/src/loader/Hook.cpp
index 376b231f..ae0d6239 100644
--- a/loader/src/loader/Hook.cpp
+++ b/loader/src/loader/Hook.cpp
@@ -6,7 +6,7 @@ using namespace geode::prelude;
 Hook::Hook(std::shared_ptr<Impl>&& impl) : m_impl(std::move(impl)) { m_impl->m_self = this; }
 Hook::~Hook() = default;
 
-Hook* Hook::create(
+std::shared_ptr<Hook> Hook::create(
     void* address,
     void* detour,
     std::string const& displayName,
diff --git a/loader/src/loader/HookImpl.cpp b/loader/src/loader/HookImpl.cpp
index 2fab7464..558a1756 100644
--- a/loader/src/loader/HookImpl.cpp
+++ b/loader/src/loader/HookImpl.cpp
@@ -29,7 +29,7 @@ Hook::Impl::~Impl() {
     }
 }
 
-Hook* Hook::Impl::create(
+std::shared_ptr<Hook> Hook::Impl::create(
     void* address,
     void* detour,
     std::string const& displayName,
@@ -39,7 +39,9 @@ Hook* Hook::Impl::create(
     auto impl = std::make_shared<Impl>(
         address, detour, displayName, handlerMetadata, hookMetadata
     );
-    return new Hook(std::move(impl));
+    return std::shared_ptr<Hook>(new Hook(std::move(impl)), [](Hook* hook) {
+        delete hook;
+    });
 }
 
 Result<> Hook::Impl::enable() {
diff --git a/loader/src/loader/HookImpl.hpp b/loader/src/loader/HookImpl.hpp
index e9258ac0..3dbf8cdd 100644
--- a/loader/src/loader/HookImpl.hpp
+++ b/loader/src/loader/HookImpl.hpp
@@ -22,7 +22,7 @@ public:
     );
     ~Impl();
 
-    static Hook* create(
+    static std::shared_ptr<Hook> create(
         void* address,
         void* detour,
         std::string const& displayName,
@@ -31,7 +31,7 @@ public:
     );
 
     template<class DetourType>
-    static Hook* create(
+    static std::shared_ptr<Hook> create(
         void* address,
         DetourType detour,
         std::string const& displayName,
diff --git a/loader/src/loader/Mod.cpp b/loader/src/loader/Mod.cpp
index 1617d537..0e93d85b 100644
--- a/loader/src/loader/Mod.cpp
+++ b/loader/src/loader/Mod.cpp
@@ -121,8 +121,8 @@ void Mod::registerCustomSetting(std::string_view const key, std::unique_ptr<Sett
     return m_impl->registerCustomSetting(key, std::move(value));
 }
 
-Result<> Mod::claimHook(Hook* hook) {
-    return m_impl->claimHook(hook);
+Result<Hook*> Mod::claimHook(std::shared_ptr<Hook>&& hook) {
+    return m_impl->claimHook(std::move(hook));
 }
 
 Result<> Mod::disownHook(Hook* hook) {
@@ -133,8 +133,8 @@ std::vector<Hook*> Mod::getHooks() const {
     return m_impl->getHooks();
 }
 
-Result<> Mod::claimPatch(Patch* patch) {
-    return m_impl->claimPatch(patch);
+Result<Patch*> Mod::claimPatch(std::shared_ptr<Patch>&& patch) {
+    return m_impl->claimPatch(std::move(patch));
 }
 
 Result<> Mod::disownPatch(Patch* patch) {
diff --git a/loader/src/loader/ModImpl.cpp b/loader/src/loader/ModImpl.cpp
index 6b87660d..363e2438 100644
--- a/loader/src/loader/ModImpl.cpp
+++ b/loader/src/loader/ModImpl.cpp
@@ -132,11 +132,19 @@ bool Mod::Impl::needsEarlyLoad() const {
 }
 
 std::vector<Hook*> Mod::Impl::getHooks() const {
-    return m_hooks;
+    std::vector<Hook*> ret;
+    for (auto& hook : m_hooks) {
+        ret.push_back(hook.get());
+    }
+    return ret;
 }
 
 std::vector<Patch*> Mod::Impl::getPatches() const {
-    return m_patches;
+    std::vector<Patch*> ret;
+    for (auto& patch : m_patches) {
+        ret.push_back(patch.get());
+    }
+    return ret;
 }
 
 // Settings and saved values
@@ -441,27 +449,30 @@ bool Mod::Impl::depends(std::string_view const id) const {
 
 // Hooks
 
-Result<> Mod::Impl::claimHook(Hook* hook) {
+Result<Hook*> Mod::Impl::claimHook(std::shared_ptr<Hook>&& hook) {
     auto res1 = hook->m_impl->setOwner(m_self);
     if (!res1) {
         return Err("Cannot claim hook: {}", res1.unwrapErr());
     }
-    m_hooks.push_back(hook);
 
+    auto ptr = hook.get();
+    m_hooks.push_back(std::move(hook));
     if (!this->isEnabled() || !hook->getAutoEnable())
-        return Ok();
+        return Ok(ptr);
 
     if (!LoaderImpl::get()->isReadyToHook()) {
-        LoaderImpl::get()->addUninitializedHook(hook, m_self);
-        return Ok();
+        LoaderImpl::get()->addUninitializedHook(ptr, m_self);
+        return Ok(ptr);
     }
 
-    auto res2 = hook->enable();
+    auto res2 = ptr->enable();
     if (!res2) {
         return Err("Cannot enable hook: {}", res2.unwrapErr());
     }
 
-    return Ok();
+    
+
+    return Ok(ptr);
 }
 
 Result<> Mod::Impl::disownHook(Hook* hook) {
@@ -473,7 +484,9 @@ Result<> Mod::Impl::disownHook(Hook* hook) {
     if (!res1) {
         return Err("Cannot disown hook: {}", res1.unwrapErr());
     }
-    m_hooks.erase(std::find(m_hooks.begin(), m_hooks.end(), hook));
+    m_hooks.erase(std::find_if(m_hooks.begin(), m_hooks.end(), [&](auto& a) {
+        return a.get() == hook;
+    }));
 
     if (!this->isEnabled() || !hook->getAutoEnable())
         return Ok();
@@ -488,22 +501,23 @@ Result<> Mod::Impl::disownHook(Hook* hook) {
 
 // Patches
 
-Result<> Mod::Impl::claimPatch(Patch* patch) {
+Result<Patch*> Mod::Impl::claimPatch(std::shared_ptr<Patch>&& patch) {
     auto res1 = patch->m_impl->setOwner(m_self);
     if (!res1) {
         return Err("Cannot claim patch: {}", res1.unwrapErr());
     }
-    m_patches.push_back(patch);
 
+    auto ptr = patch.get();
+    m_patches.push_back(std::move(patch));
     if (!this->isEnabled() || !patch->getAutoEnable())
-        return Ok();
+        return Ok(ptr);
 
-    auto res2 = patch->enable();
+    auto res2 = ptr->enable();
     if (!res2) {
         return Err("Cannot enable patch: {}", res2.unwrapErr());
     }
 
-    return Ok();
+    return Ok(ptr);
 }
 
 Result<> Mod::Impl::disownPatch(Patch* patch) {
@@ -515,7 +529,9 @@ Result<> Mod::Impl::disownPatch(Patch* patch) {
     if (!res1) {
         return Err("Cannot disown patch: {}", res1.unwrapErr());
     }
-    m_patches.erase(std::find(m_patches.begin(), m_patches.end(), patch));
+    m_patches.erase(std::find_if(m_patches.begin(), m_patches.end(), [&](auto& a) {
+        return a.get() == patch;
+    }));
 
     if (!this->isEnabled() || !patch->getAutoEnable())
         return Ok();
diff --git a/loader/src/loader/ModImpl.hpp b/loader/src/loader/ModImpl.hpp
index 4378aea5..335b054f 100644
--- a/loader/src/loader/ModImpl.hpp
+++ b/loader/src/loader/ModImpl.hpp
@@ -18,11 +18,11 @@ namespace geode {
         /**
          * Hooks owned by this mod
          */
-        std::vector<Hook*> m_hooks;
+        std::vector<std::shared_ptr<Hook>> m_hooks;
         /**
          * Patches owned by this mod
          */
-        std::vector<Patch*> m_patches;
+        std::vector<std::shared_ptr<Patch>> m_patches;
         /**
          * Whether the mod is enabled or not
          */
@@ -113,11 +113,11 @@ namespace geode {
         SettingValue* getSetting(std::string_view const key) const;
         void registerCustomSetting(std::string_view const key, std::unique_ptr<SettingValue> value);
 
-        Result<> claimHook(Hook* hook);
+        Result<Hook*> claimHook(std::shared_ptr<Hook>&& hook);
         Result<> disownHook(Hook* hook);
         [[nodiscard]] std::vector<Hook*> getHooks() const;
 
-        Result<> claimPatch(Patch* patch);
+        Result<Patch*> claimPatch(std::shared_ptr<Patch>&& patch);
         Result<> disownPatch(Patch* patch);
         [[nodiscard]] std::vector<Patch*> getPatches() const;
 
diff --git a/loader/src/loader/Patch.cpp b/loader/src/loader/Patch.cpp
index 180d7368..15471c95 100644
--- a/loader/src/loader/Patch.cpp
+++ b/loader/src/loader/Patch.cpp
@@ -6,7 +6,7 @@ using namespace geode::prelude;
 Patch::Patch(std::shared_ptr<Impl>&& impl) : m_impl(std::move(impl)) { m_impl->m_self = this; }
 Patch::~Patch() = default;
 
-Patch* Patch::create(void* address, const ByteVector& patch) {
+std::shared_ptr<Patch> Patch::create(void* address, const ByteVector& patch) {
     return Impl::create(address, patch);
 }
 
diff --git a/loader/src/loader/PatchImpl.cpp b/loader/src/loader/PatchImpl.cpp
index db571b98..d38defda 100644
--- a/loader/src/loader/PatchImpl.cpp
+++ b/loader/src/loader/PatchImpl.cpp
@@ -31,11 +31,13 @@ static ByteVector readMemory(void* address, size_t amount) {
     return ret;
 }
 
-Patch* Patch::Impl::create(void* address, const geode::ByteVector& patch) {
+std::shared_ptr<Patch> Patch::Impl::create(void* address, const geode::ByteVector& patch) {
     auto impl = std::make_shared<Impl>(
         address, readMemory(address, patch.size()), patch
     );
-    return new Patch(std::move(impl));
+    return std::shared_ptr<Patch>(new Patch(std::move(impl)), [](Patch* patch) {
+        delete patch;
+    });
 }
 
 Result<> Patch::Impl::enable() {
diff --git a/loader/src/loader/PatchImpl.hpp b/loader/src/loader/PatchImpl.hpp
index 522284f6..67ce4207 100644
--- a/loader/src/loader/PatchImpl.hpp
+++ b/loader/src/loader/PatchImpl.hpp
@@ -13,7 +13,7 @@ public:
     Impl(void* address, ByteVector original, ByteVector patch);
     ~Impl();
 
-    static Patch* create(void* address, const ByteVector& patch);
+    static std::shared_ptr<Patch> create(void* address, const ByteVector& patch);
 
     Patch* m_self = nullptr;
     void* m_address;