Injecting functions into binaries with two-level namespaces #211
Replies: 12 comments 18 replies
-
It certainly is, but compiling it as ObjC will probably link in the ObjC runtime, which might have some side-effects(?). It's probably also slower but that might not be apparent for such a small file.
That's true of course. If you're just injecting a library that adds a function there shouldn't be much side-effects though, and on Mac it will also depend on exactly how those processes are spawned. AFAIK the general recommendation is not to use Either way, both approaches have their advantages and scopes of application. Using |
Beta Was this translation helpful? Give feedback.
-
Well, anyway, I did some very quick testing of a inject library I wrote for Linux *). It provides an overload for I built the wrapper library, ran optool on it to re-export libSystem.B.dylib and then tested simply what library actually provides a function that can be loaded from the resulting library (using dlsym)
My hypothesis was that maybe we could fool two-level-namespace apps to use an inserted library to set the ID of that library to the one it attempts to extend:
As you can see, changing the library's ID has the opposite effect of what I hoped: it simply becomes a copy of the library it re-exports. The added function(s) have disappeared (note the address of For this particular test it is irrelevant if you run optool on the library or not, BTW. *) There Chromium and some other applications do things like using |
Beta Was this translation helpful? Give feedback.
-
The unity example is compiled like this:
How do I compile it as a C file instead of an Objective-C file?
So let's take the Dictionary app. I have an mitm proxy set up to work around Mavericks's outdated https support. Unfortunately, Dictionary.app ignores OS X's system proxy settings, so I can't connect to Wikipedia. Krackers wrote a ProxyFix library to fix this:
To use this, I modified Dictionary.app's info.plist:
This works great! But if I try to print something, and in the print dialog select "Open PDF in Preview", Preview.app will crash!
|
Beta Was this translation helpful? Give feedback.
-
For your test, can't you use `dyld_interpose`?
I don't see how? I wasn't familiar with the feature but it looks to be a formalised/modern version of the overloading I do (by getting the function address with `dlsym(2)` and then calling that in a new function of the same name). I also see you still need DYLD_INSERT_LIBRARIES, undoubtedly with the same caveats as always re: two-level namespace applications.
My goal here was just to get a quick indication of whether the idea I had *could* work. From what I saw it simply can't because the symbols of interest are no longer visible in a library if you change its ID. I have not found a reason to use this particular wrapper library on Darwin. The re-export trick with optool would probably be useful if one only needed to provide the backported functions in the MacPorts LegacySupport library to pre-built binaries.
|
Beta Was this translation helpful? Give feedback.
-
On Thursday March 07 2024 15:11:15 Jonathan wrote:
The unity example is compiled like this:
`clang -compatibility_version 9999 -o /Path/To/UnityMavericksWorkarounds.dylib -dynamiclib /Path/To/UnityMavericksWorkarounds.m`
How do I compile it as a C file instead of an Objective-C file?
AFAIK Clang looks at the file extension to determine what dialect to use, absent more specific instructions. A pure C file has a `.c` extension... ;)
So let's take the Dictionary app. I have an mitm proxy set up to work around Mavericks's outdated https support.
Unrelated, but what problems does that solve exactly - the endless errors related to calendars and address books for instance (which AFAIK are more a problem of outdated certificates)?
<key>LSEnvironment</key>
<dict>
<key>DYLD_INSERT_LIBRARIES</key>
***@***.***_path/../Frameworks/ProxyFix.dylib</string>
</dict>
[...]
Dyld Error Message:
could not load inserted library ***@***.***_path/../Frameworks/ProxyFix.dylib' because image not found
You have 2 solutions here:
1) copy the ProxyFix.dylib library into the Preview.app bundle too (where it wouldn't normally be used)
2) give ProxyFix.dylib an absolute path ID and install it at that location. A variant would be to use just "ProxyFix.dylib" as the ID and install the library in one of the standard locations where dyld searches by default (this variant *may* require building it as a framework, I can't remember).
|
Beta Was this translation helpful? Give feedback.
-
Mavericks does not support any modern cipher suites. So HTTPS doesn't work in apps that use Apple's native libraries.
I had a look at "mitn proxy", found a site that was jubilantly enthusiastic about what their product can do but didn't understand a word of it. Or rather, I understood the words but not how it could be relevant for everyday solutions that don't involve reverse-engineering code or (presumably) jail-breaking iOS devices or hacking them in other ways ;)
I consider both of these solutions worse than leaving the problem unsolved. 🙂 Everything should live in the app bundle, and the problem is moderately difficult to run into.
The "open PDF in Preview" feature is one of the printing functions I use most commonly, so I wouldn't say the particular example is "moderately difficult to run into" ;)
And in that particular example you can still set the ID to the absolute path to the library inside the Dictionary.app bundle. The thing with Apple's app bundles is that they're claimed to be position independent but in reality tend to be full with assumptions that they do in fact live in their default location. IIRC Dictionary.app is one of them so you would not be crippling it any more than it already is.
Anyway, if you're hacking a system like this you better (IMHO) make sure that the code you inject is harmless beyond its intended purpose. I haven't looked at all at what that Proxy library does exactly but I would assume that it's written in such a way that it doesn't change anything for applications that do obey the system proxy settings.
In fact, personally I'd want this kind of patch to be applied in such a way that any application that might need it benefits from it automatically, provided the above holds.
|
Beta Was this translation helpful? Give feedback.
-
On Friday March 08 2024 13:29:52 krackers wrote:
IIRC macports already does this, they offer a variant which reexports system symbols precisely for easy drop in compatability
Not a variant (in the MacPorts sense of the term) but a copy of the library that re-exports libSystem, which gets used exactly as I imagined. I had forgotten I'd noticed that version of the library but can't recall that I ever looked at what it was used for... Thanks for reminding me :)
|
Beta Was this translation helpful? Give feedback.
-
it's effectively reverse proxy running locally on your machine. Since osx does not support modern cipher suite (or tls 1.3 for that matter), it can stand as a go-between, and will make the connection on your behalf, then send you the info over downgraded tls.
I guessed it might be that. I guess it can't hurt to set this up on my own Mac, is there a recipe somewhere I can follow (and doesn't it increase the CPU overhead for traffic that doesn't go through Apple's https APIs)?
|
Beta Was this translation helpful? Give feedback.
-
So ideally you'd use the opposite of that ProxyLib patch to get only specific applications to use a proxy otherwise NOT configured at the system level? That'd avoid the overhead issue.
Or ... use a dedicated little server to run the proxy on?
I make extensive [...] Calendar.app
I notice a lot of errors that appear to come from that, and the address book, but both still seem to work...
Mail.app
That one was nice in 10.6 but I stopped using it when it started to insist on downloading full messages even from the IMAP server I run on the localhost (for archiving my email)...
I would probably try writing a very minimal proxy in Go
Assuming you managed to install a new enough Go version?
BTW, I just read somewhere that 10.11 dropped support for the DYLD_ env. variables, or that certain key system binaries like /bin/sh started "eliding" (unsetting?) them. Is that correct, even when you disable the SIP circus?
|
Beta Was this translation helpful? Give feedback.
-
>So ideally you'd use the opposite of that ProxyLib patch to get only specific applications to use a proxy...
Yeah would technically also work, although all proper Cocoa applications should transparently work with proxies
The idea for this was that you'd "patch" all Cocoa applications that you needed to do modern https with so they'd use a "hidden" proxy. A bit like what Windscribe do with their VNC browser plugin
Maybe you are referring to hardened runtime.
No, the source is a readme from one of the devs working on GCC/Darwin; I think it was concerned specifically with DYLD_LIBRARY_PATH which is evidently a loss not to have in complex build systems. But it did mention "the DYLD_ variables"...
|
Beta Was this translation helpful? Give feedback.
-
On Sat, 9 Mar 2024 at 17:03, Jonathan ***@***.***> wrote:
I direct less technical users to use "Legacy Mac Proxy" on
https://jonathanalland.com/old-osx-projects.html, but you may prefer to
set up it up yourself.
Checking the Readme on that dmg I see you suggest pointing Firefox to the
proxy. That surprises me; the v78 based version I run isn't that recent but
I don't think I ever came across websites it cannot connect to. Certain
sites don't work (well) anymore but that's for other reasons AFAICT. Got an
example?
… Message ID:
***@***.***
com>
|
Beta Was this translation helpful? Give feedback.
-
You have that backwards, I suggest setting Firefox to _ignore_ the proxy!
OOPPS :)
|
Beta Was this translation helpful? Give feedback.
-
Continuing discussion from #210
I don't think so, the example with Unity is pure C. (Although it feels almost strange to call it that since it's a single one-line function.)
How do you change the ID of a library? My understanding is that with two-level namespaces, dyld is looking for the full path to the library.
I generally prefer to use
install_name_tool
anyway because it works even when the app isn't launched from the Terminal. (I know you can add environment variables by editing info.plist, but then those variables are also injected into any processes that app launches which can cause problems.)(@krackers you might find this discussion interesting.)
Beta Was this translation helpful? Give feedback.
All reactions