Reverse engineering objective-c interfaces from static library (like class-dump-z) - objective-c

I have a static library written in objective-c. I have it in the form of a libFoo.a file.
I'd like to extract the classes and methods that are contained within the library, similar to the output of class-dump-z.
I've tried using otool -tV as suggested here.
However, the output is very verbose and includes lots of things other than just the interface declarations.
Per comment from H2CO3, I tried RuntimeBrowser, which seems like an excellent tool. However, opening the .a files from File -> Open didn't seem to do anything. Could be because I was using the Mac version and trying to inspect an iOS library.
I've also tried running class-dump-z against the static library but it doesn't appear to work:
/**
* This header is generated by class-dump-z 0.2a.
* class-dump-z is Copyright (C) 2009 by KennyTM~, licensed under GPLv3.
*
* Source: (null)
*/
Tried regular class-dump but got this error message:
Error: Fat file doesn't contain a valid Mach-O file for the specified
architecture (i386). It probably means that class-dump was run on a
static library, which is not supported.
I downloaded the evaluation version of IDA for Mac (6.4.1303322) and so far it's been the best yet. Very useful--just pop open the static library and you can see a list of the classes and it understands Objective-C 2.0 syntax and you can see the methods.
That being said, I'd still love to see a way to get the output in the same format as class-dump-z.
Anyone know of a way to extract the classes and methods that are contained in an objective-c static library? I can see them in the stack when I stop in the debugger and when I use [NSThread callStackSymbols] so I know the debugging symbols are present.

Related

Can nw addon be built with _HAS_ITERATOR_DEBUGGING=1 for debug mode? (Windows)

Original questin: Is there any way to get what macros nw-gyp add to the build project by default?
I'm developing a nw addon and I've tried to link a custom static lib to .node DLL. However I found nw-gyp will add _HAS_ITERATOR_DEBUGGING=0 by default (It always appends to the addon project to override custom defines), which will affect the actual structure size for STL types (e.g. std::string).
So is there a way to get such macros node gyp added by default, or is there an easy way to make compiler's (maybe the whole toolchain, link tool etc.) configuration for both static lib and nw build project the same?
Now I've add _HAS_ITERATOR_DEBUGGING=0 to my lib and make it MT(D), and It seems to work fine, but I'm not sure if this is the right way. (Some other compiler settings may not cause compilation error but can crash in runtime)
Edit: Share some analysis to make my origin question clearer.
All current question is on Windows platform.
The _HAS_ITERATOR_DEBUGGING=0 is added even when I build nw addon in debug mode (with --debug), and this may be affected by the nw headers downloaded by nw-gyp. For example, headers download from http://node-webkit.s3.amazonaws.com/v0.49.2/nw-headers-v0.49.2.tar.gz , you will find 'defines': [ 'DEBUG', '_DEBUG', 'V8_ENABLE_CHECKS', '_HAS_ITERATOR_DEBUGGING=0' ] in common.gypi at line 288 in Debug_Base config section, and this is most likely inherit from https://github.com/nwjs/chromium.src (I guess here https://github.com/nwjs/chromium.src/blob/nw60/build/config/BUILD.gn#L130). So can it be concluded that Chrome add these defines for debug mode on purpose?
What is the problem _HAS_ITERATOR_DEBUGGING=0 in debug for me? Well, it affects the size for many STL classes (std::string, std::vector and etc.). So all debug lib that need to be linked to nw addon should be compiled with '_HAS_ITERATOR_DEBUGGING=0', otherwise compilation error will occur for static libs and runtime pointer problem crash (struct offset mismatch) for dynamic libs (of course it is not a good practice to use STL in dynamic lib headers, but if you can assume the toolchain same it will still work fine). But this is really hard for me when it comes to third-party binaries, I've got no sources for most of them, so I can't give a debug static lib with _HAS_ITERATOR_DEBUGGING=0 on. This is really frustrating when I need to debug the addon with lldb or VS, since all variables are optimized and you cannot debug their values.
Can I force _HAS_ITERATOR_DEBUGGING=1 for debug mode? As mentioned in origin question, it cannot be done normally like answer from #mmomtchev. A hack way to do is to add "/D _HAS_ITERATOR_DEBUGGING=1" to configurations->Debug->msvs_settings->VCLinkerTool->AdditionalOptions in gyp file for addon, this will append /D _HAS_ITERATOR_DEBUGGING=1 to the end of the compile command which override the former defination. But I'm not sure if this is a good workaround! I've checked v8 header files and have found some classes with std::string and std::vector members. I think force _HAS_ITERATOR_DEBUGGING will cause some problem if you use these classes, but for other classes it is safe (I've tested many cases, normal classes like v8::value v8::function work well). And it is not safe when cooperating with other addons. Let's assume one debug addon A and another release addon B need to communicate with each other, they agree on one C++ struct for data exchange. A common way is to let A to wrap a C++ struct instance to a JS object for user. and let user pass the JS object to B by calling methods provided by B (the JS object is one of the arguments), and then B unwrap the JS object from arguments and get the pointer of the C++ struct instance. All looks fine, but what if the C++ struct has std::string member? The sizes of same C++ struct for A and B are not the same. so B will crash when trying to access the member with type of std::string or std::vector. This is not an issue if _HAS_ITERATOR_DEBUGGING=0 is set for debug mode since _HAS_ITERATOR_DEBUGGING is always disabled for release, and I guess that's why nw addon can work with mixed production mode(debug an release) addons in common cases.
So my final question is: If it is not a good way to force _HAS_ITERATOR_DEBUGGING=1 for debug and I don't have source code for many external compiled lib binaries, does it mean I've no way to build a nw addon in debug mode? Athother possible way is to wrapper those libs with C style API and compile them to dynamic libs, but this is really huge work for me and is unacceptable.
Normally, _HAS_ITERATOR_DEBUGGING=0 is defined by default on all Release builds.
If you need to add macros, you need to add this section to the root of your gyp:
'defines': [ '_HAS_ITERATOR_DEBUGGING=0' ]

Call Objective C code from .NET / Mono(Mac)

I'm porting a .NET-based test automation framework to Mac OS X.
I have significant .NET experience, however, I'm totally a rookie in the Mac world.
I need to call Objective C code from .NET / Mono. I started with the "MonoMac - Binding Objective-C Types" tutorial.
I created an API definition file. I couldn't compile it, because the type "BaseTypeAttribute" couldn't be found. Later I found that this is not a problem, because the btouch tool will compile it (basetypeattribute-not-found-in-a-binding-project).
Since I'm developing for OS X (not iOS), I was not using btouch, I was going to use the bmac tool. Findig that wasn't trivial, but I managed to compile&found it based on this article. Good.
I was not able to compile my binding file, because the bmac said "Type or namespace 'Tasks' does not exists in namespace 'System.Threading'".
Nevertheless, I specified an output folder for the generated .cs files, fixed the compile error (the Tasks wasn't really needed, the error was caused by an unnecessary using that was generated).
So I'm about at the point where I could have been if I followed the manual "Binding New Objective-C Types / Binding_Details" document.
The problem is that I still cannot use my Objective C library.
I can compile and run the C# code with MonoDevelop/Xamarin, but it fails with the message:
System.Exception: Could not create an native instance of the type 'My.Type': the native class hasn't been loaded.
It is possible to ignore this condition by setting MonoMac.ObjCRuntime.Class.ThrowOnInitFailure to false.
at MonoMac.Foundation.NSObject.InitializeObject (Boolean alloced)
at MonoMac.Foundation.NSObject..ctor (MonoMac.Foundation.NSObjectFlag x)
at My.Type..ctor ()
I found an article (coreplot-monomac-bindings-crashing) that says the library must be manually loaded before using it, but I had no luck with it. "Dlfcn.dlopen" always return IntPtr.Zero.
I'm tried to create my lib as "Cocoa Framework", "Cocoa Library" and "Bundle" in XCode. Which one should I use?
Are there any low-level debugging possibilites in Mono(Mac)?
Did anybody managed to do this? (calling objc from .net)
thanks in advance,
-g

How do I link multiple libraries in a Firebreath plugin?

Does anyone know where I can find a Firebreath sample (either Mac OS X or Windows) that illustrates how to create a plugin that includes 1 or more other libraries (.DLLs or .SOs) that each rely on other sub-projects built as static libraries (LIBs)?
For example, let's say that the Firebreath plugin is called PluginA, and that PluginA calls methods from DLL_B and DLL_C. DLL_B and DLL_C are C++ projects. DLL_B calls methods from another project called LIB_D, and DLL_C calls methods from a project called DLL_E.
Therefore, the final package should contain the following files:
PluginA.dll
DLL_B.dll (which also incorporates LIB_D)
DLL_C.dll
DLL_E.dll
I am currently forced to dump all source files in the pluginA solution, but this is just a bottleneck (for example I cannot call libraries written in other languages, such as Objective-C on Mac OS X).
I tried following the samples on Firebreath, but couldn't get them to work, and I found no samples from other users that claimed they were able to get it to work. I tried using CMAKE, and also running the solutions directly from X-Code, but the end result was the same (received linking errors, after deployment DLL_C couldn't find DLL_E etc.)
Any help would be appreciated - thank you,
Mihnea
You're way overthinking this.
On windows:
DLLs don't depend on a static library because if they did it would have been compiled in when they were built.
DLLs that depend on another DLL generally just need that other DLL to be present in the same location or otherwise in the DLL search path.
Those two things taken into consideration, all you need to do is locate the .lib file that either is the static library or goes with the .dll and add a target_link_library call for each one. There is a page on firebreath.org that explains how to do this.
On linux it's about the same but using the normal rules for finding .so files.

How to strip Objective-C symbols from OS X binary?

OK, I know there have been other posts about how you can't actually strip Objective-C symbols from an OS X binary because they're necessary for Obj-C to work at all, but my case is a bit different.
I have a single binary which is a bundle. It is intended to be used as either a VST plugin, or an AudioUnit plugin. The idea is that the binary contains all the entry points for both formats, and you just compile it once, and then name one copy with ".vst" for the VST version, and ".component" for the AU version. (This is using the JUCE framework BTW.)
The problem is that for the AU side, you must export an Obj-C class for creating the Cocoa UI view. On the VST side, this class will never be used. But if you have a host like Ableton Live which allows you to simultaneously load both AU and VST versions of the same plugin, now we run into the typical Obj-C namespace collision issue.
On the VST side, that particular Obj-C class will never get used. So what I'd like to do is to strip those Obj-C classes from the resulting binary using "strip". This still maintains the advantage of just compiling everything once for both formats.
Anyway, I've tried using "strip -R stripfile.txt <path to binary>", where stripfile.txt contains the symbols I want to strip, but it always fails saying that the symbols can't be found in the binary. I've tried mangling the names in the strip file, but that doesn't help (or I'm doing it wrong).
Here are the relevant symbols that I want to strip, as output by "nm -m":
000000000003bb00 (__TEXT,__text) non-external -[JuceDemoProjectAU description]
000000000003bb60 (__TEXT,__text) non-external -[JuceDemoProjectAU interfaceVersion]
000000000003ba00 (__TEXT,__text) non-external -[JuceDemoProjectAU uiViewForAudioUnit:withSize:]
0000000000b02398 (__DATA,__objc_data) external _OBJC_CLASS_$_JuceDemoProjectAU
0000000000b023c0 (__DATA,__objc_data) external _OBJC_METACLASS_$_JuceDemoProjectAU
Any ideas?
BTW, I have subsequently been able to dynamically register the class in question (using a unique name), which also solves the problem. However, if I could get strip working, I could potentially deploy a solution for already existing binaries in the field.
You can not just simply strip a class from a binary. What you can do however is to trick the Objective-C runtime into believing your plugin does not contain any Objective-C code. Just change __objc_imageinfo into __objc_imageinfX for example in your VST plugin binary. You can do it easily with perl:
perl -pi -e 's/__objc_imageinfo/__objc_imageinfX/g' <path to binary>
After patching the VST plugin, all the Objective-C initialization will be bypassed and you won’t see this error message: Class JuceDemoProjectAU is implemented in both …/VSTPlugin and …/AUPlugin. One of the two will be used. Which one is undefined.
Beware, you should really not use this trick! The appropriate solution to your problem is either to compile two different version of your plugin or to register classes dynamically as others suggested.
There was a thread about something similar to this on the coreaudio-list last year: Collision between Cocoa classes for AU and VST plugins.
The solution offered was to register the classes dynamically which is what you say you already have working. If there was a way to strip the symbols like you wanted, I'm sure these guys would have known about it.

Calling MATLAB Engine from Cocoa Application

I'm writing a Cocoa application and I'm trying to link it with the MATLAB Engine to call MATLAB functions. So far I've added the .app/extern/include/ directory (the one that contains the engine.h header) to the header search paths (and subsequently #imported engine.h) and added the .app/extern/lib/maci64 directory to the library search paths (though that doesn't really do anything). I've been looking through the MATLAB documentation and it looks like MATLAB has its own compiler 'mex' for MATLAB engine applications… but clearly that doesn't work for a Cocoa app (and anyway, on my system, the 'mex' command starts PDFTex and has nothing to do with MATLAB). Also, the engine libraries in that directory are in an odd format (.map) which seems to be a debugging symbol file and not a normal Mac library (dylib, a, framework, etc.). Thoughts?