有没有办法在iOS应用程序中列出所有混合方法?

有没有办法在iOS应用程序中列出所有混合方法?

问题描述:

我基本上正在寻找一种方法来检测何时/第三方图书馆的混战。我最近遇到了一个广告库使用AFNetworking的古怪分叉的情况。 AFNetworking对NSURLSessionTask进行了调整,在某些情况下,这两个混合体并没有很好地发挥作用。我真的希望能够检测和理智检查这种事情,理想情况下甚至在应用程序中保留每个混合方法的版本化转储,这样我们就可以看到谁修补了什么以及风险是什么。谷歌和堆栈溢出搜索只发布了一堆关于如何调整的教程。任何人遇到这个问题或有解决方案?看起来我可以使用objc / runtime.h编写代码,但我无法想象我是第一个需要这个的人。

I'm essentially looking for a way to detect when/what third party libraries swizzle. I recently ran into a situation where an ad library used an oddball fork of AFNetworking. AFNetworking swizzles NSURLSessionTask, and the two swizzles didn't play nicely under certain circumstances. I'd really like to be able to detect and sanity check this kind of thing, and ideally even keep a versioned dump of every swizzled method in the app so we have some visibility into who's monkey patching what and what the risks are. Google and stack overflow search have turned up nothing but a bunch of tutorial on how to swizzle. Anybody run into this issue or have a solution? It looks like I might be able to code something up using objc/runtime.h but I can't imagine I'm the first person to need this.

这是我能够得到的最接近的,经过几个小时的修补。它涉及使用 mach_override 的分支,关于加载顺序的几个DYLD怪癖,以及疯狂黑客的胃。

Here's the closest I was able to get, with a few hours of tinkering. It involves using a fork of mach_override, a couple of DYLD quirks regarding load order, and a stomach for crazy hacks.

它只能在模拟器上运行,但这应该足以满足您的用例(我当然希望您没有依赖于设备的依赖项) 。

It will only work on the simulator, but that should suffice for the use case you seem to have (I certainly hope you don't have device-only dependencies).

代码的内容如下所示:

#include <objc/runtime.h>
#include <mach_override/mach_override.h>

// It is extremely important that we have DYLD run this constructor as soon as the binary loads. If we were to hook
// this at any other point (for example, another category on NSObject, in the main application), what could potentially
// happen is other `+load` implementations get invoked before we have a chance to hook `method_exchangeImplementation`,
// and we don't get to see those swizzles.
// It is also extremely important that this exists inside its own dylib, which will be loaded by DYLD before _main() is
// initialized. You must also make sure that this gets loaded BEFORE any other userland dylibs, which can be enforced by
// looking at the order of the 'link binary with libraries' phase.
__attribute__((constructor))
static void _hook_objc_runtime() {
  kern_return_t err;
  MACH_OVERRIDE(void, method_exchangeImplementations, (Method m1, Method m2), &err) {
    printf("Exchanging implementations for method %s and %s.\n", sel_getName(method_getName(m1)), sel_getName(method_getName(m2)));

    method_exchangeImplementations_reenter(m1, m2);
  }
  END_MACH_OVERRIDE(method_exchangeImplementations);

  MACH_OVERRIDE(void, method_setImplementation, (Method method, IMP imp), &err) {
    printf("Setting new implementation for method %s.\n", sel_getName(method_getName(method)));

    method_setImplementation_reenter(method, imp);
  }
  END_MACH_OVERRIDE(method_setImplementation);
}

这非常简单,产生如下输出:

Which is surprisingly simple, and produces output like this:


交换方法描述和custom_description的实现。

Exchanging implementations for method description and custom_description.

有没有好办法(没有使用断点并查看堆栈跟踪)来确定哪个类正在调整,但对于大多数情况,只要看看选择器应该给你一个关于从那里去的地方的提示。

There is no good way (without using a breakpoint and looking through the stack trace) to figure out which class is being swizzled, but for most things, just taking a peek at the selectors should give you a hint about where to go from there.

它似乎适用于我在 + load 期间创建的几个类别,以及我的阅读 mach_override 和DYLD的内部结构,只要您正确设置了库加载顺序,就可以在任何其他用户区代码之前初始化它,如果你把它放入在它自己的动态库中。

It appears to work with a couple of categories that I've created that swizzle during +load, and from my reading of mach_override and DYLD's internals, as long as you have your library load order properly setup, you can expect this to be initialized before any other user-land code, if you put it in it's own dynamic library.

现在,我无法保证这一点的安全性,但作为一个调试工具保留它似乎很有用,所以我发布了d我的例子是github:

Now, I can't vouch for safety of this, but it seems useful to keep around as a debugging tool, so I've published my example to github:

https:// github。 com / richardjrossiii / mach_override_example

这是麻省理工学院的许可,所以请随意使用。

It's MIT licensed, so feel free to use as you see fit.