3

I am trying to create a dynamic library for iOS and load it at runtime. After taking a look at this question and this answer, I have been doing it using iOSOpenDev and deploying everything on my iPhone. The xCode project for the dylib is called KDylibTwo and the files I modiefied are:

KDylibTwo.h

#import <Foundation/Foundation.h>

@interface KDylibTwo : NSObject
-(void)run;
@end

KDylibTwo.m

#import "KDylibTwo.h"

@implementation KDylibTwo

-(id)init
{
    if ((self = [super init]))
    {
    }

    return self;
}

-(void)run{
    NSLog(@"KDylibTwo loadded.");
}

@end

In order to test if my library works, after building it for profiling (the way iOSOpenDev deploys it on iPhone), I can find it stored on my device at /usr/lib/libKDylibTwo.dylib and built a tweak (again using iOSOpenDev), hooking the SpringBoard as follows:

#include <dlfcn.h>

%hook SBApplicationIcon

-(void)launch{
    NSLog(@"\n\n\n\n\n\n\nSBHook For libKDylibTwo.dylib");

    void* dylibLink = dlopen("/usr/lib/libKDylibTwo.dylib", RTLD_NOW);

    if(dylibLink == NULL) {
        NSLog(@"Loading failed.");
    } else {
        NSLog(@"Dylib loaded.");

        void (*function)(void);
        *(void **)(&function) = dlsym(dylibLink, "run");
        if (function) {
            NSLog(@"Function found.");
            (*function)();
        } else {
            NSLog(@"Function NOT found");
        }
    }

    NSLog(@"End of code");
    %log;
    %orig;
}

%end

After installing the tweak on the device and tapping on an icon (that would fire the hooked code), the Console output looks like:

Aug 28 13:03:35 Pudge SpringBoard[18254] <Warning>: SBHook For libKDylibTwo.dylib
Aug 28 13:03:35 Pudge SpringBoard[18254] <Warning>: Dylib loaded.
Aug 28 13:03:35 Pudge SpringBoard[18254] <Warning>: Function NOT found
Aug 28 13:03:35 Pudge SpringBoard[18254] <Warning>: End of code
Aug 28 13:03:35 Pudge SpringBoard[18254] <Warning>: -[<SBApplicationIcon: 0x1d5008c0> launch]

My question is what am I doing wrong and the the library's function is not called or executed! I think I should clarify that I am only talking about jailbroken devices and not App Store development, so please don't go ahead posting that it cannot be done!

Thank you in advance,
Panagiotis.

Community
  • 1
  • 1
Panagiotis
  • 309
  • 2
  • 13
  • I'm not home and can't test right now. But, Victor is right that the technique i showed is for calling C functions, not Obj-C – Nate Aug 28 '13 at 20:27

2 Answers2

6

As Victor Ronin pointed out, "dlsym" is for C symbols. To obtain objective-C class from dylib that you linked at runtime you can use objc runtime functions. In your case:

void* dylibLink = dlopen("/usr/lib/libKDylibTwo.dylib", RTLD_NOW);
id KDylibTwo = [[objc_getClass("KDylibTwo") alloc] init];
[KDylibTwo run];

First line is linking your library at runtime. This is required in order to use code inside of it.

Second line creates instance of class KDylibTwo. objc_getClass function returns class object that you can later use to create instances of this class like you would with any objective-C class - using alloc and init methods. Once you obtained class object with objc_getClass you can work with him like nothing happend. At this point you can forget that you dynamically linked you library at runtime.

Third line is calling run method. As you can see, it's normal objective-C syntax. Nothing is changed because you linked your library at runtime. You can call any method you want.

creker
  • 8,920
  • 1
  • 28
  • 45
  • Thank you so much! Works perfectly and no need to sign for the SMS!! But how can I make a call to a specific function I would like to run from my library and send or get data? Probably something to do with the `dylibLink` variable which seems to be unused. – Panagiotis Aug 28 '13 at 21:19
  • Can you elaborate what exactly do you want to achieve? – creker Aug 28 '13 at 21:28
  • 1
    As for signing, the entitlement is required for my code to work. If you tested it by loading dylib in springboard then you already have this entitlement. SpringBoard already contains it. If you gonna link this dylib to your app it needs this entitlement or it will not work. – creker Aug 28 '13 at 21:41
  • You are right I guess. Didn't think of that! Has to do with a research project trying to develop some kind of framework using SMS on iPhone. What I need is to be able to handle incoming messages, modify them and then show them to the user and vice versa. When the user wants to send a message, I will be editing and then send it - like adding headers and stuff on the SMS. I will surely need to load a library for the incoming SMS part, which I haven't studied yet, and thought I could make a workaround with the library for my app. I am really new to the jailbreak stuff! – Panagiotis Aug 28 '13 at 21:51
  • But you have been more than helpful and I am grateful for that :) – Panagiotis Aug 28 '13 at 21:52
  • @creker: That's great answer. I didn't realize that dlopen will actually add objective c info to some internal objective c lookup table. – Victor Ronin Aug 28 '13 at 22:29
  • @creker, which **entitlement** are you referring to here? – Nate Aug 29 '13 at 04:19
  • @Nate There is no entitlement here, just a follow up on some comments made at this post http://stackoverflow.com/questions/18383462/automatically-send-sms-on-ios-6-jailbreak. Can you help on how to make calls inside the library's functions...? – Panagiotis Aug 29 '13 at 08:49
  • @Panagiotis, ok, thanks. What question do you have (about making calls inside the library's functions)? – Nate Aug 29 '13 at 09:08
  • @Nate The code provided by creker works perfectly and calls my init and run functions in my library. If I had a function named `myMethod` in my dylib, how could I make it run from the application? – Panagiotis Aug 29 '13 at 09:22
  • @Panagiotis, that's what the example [in this answer shows](http://stackoverflow.com/questions/4733847/can-you-build-dynamic-libraries-for-ios-and-load-them-at-runtime/10509453#10509453). The `init()` function would be an example of calling a dylib C function, using `dlsym()`. – Nate Aug 29 '13 at 09:27
  • @Nate No I was wondering about Objective-C methods. Using the code provided here and not only C functions. – Panagiotis Aug 29 '13 at 09:31
  • @Panagiotis, Are you saying that you don't fully understand creker's answer? The second line of code there does have a couple things going on, inside it. (Going to sleep for tonight, but can check back tomorrow...) – Nate Aug 29 '13 at 09:42
  • @Nate I think I have understand it. If I use both these lines, my functions `init()` and `run()` are both been called. If I use one of them, nothing happens. But If I create a function `myMethod()` in the same dylib, how can that one be called with the above code? – Panagiotis Aug 29 '13 at 09:47
  • @Panagiotis, I updated my answer. That should answer your question. – creker Aug 29 '13 at 13:10
  • @creker, This is almost what I am talking about. If a method inside that library is called `myMethod`, how could I make it run? Maybe using a selector or something? For example I could test that the method exists with this line of code `(([KDylibTwo respondsToSelector:@selector(myMethod)]) ? NSLog(@"Responded") : NSLog(@"Didn't respond"));`. But how can I make it run? – Panagiotis Aug 29 '13 at 16:32
  • @Panagiotis, that's a strange question given that you are obviously familiar with objective-C. `[KDylibTwo myMethod]` will run your method. – creker Aug 29 '13 at 16:59
  • @creker That's exactly what I firstly tried, but considering that I do not import my library anywhere, the error `LoadDylib.xm:19:5: No known instance method for selector 'myMethod'` is justified I suppose... – Panagiotis Aug 29 '13 at 17:25
  • 1
    @Panagiotis, in the past it was giving a warning. In Objective-C it's not an error to call method that is not known at compile time. In fact, it's one of the advantages of this language and it's OOP design. It's compiler thing that I don't really understand. To solve this you can use `performSelector` or `NSInvocation` depending on whether you need to pass multiple arguments. But why do you need to do it like this? Why not declare `myMethod` so that compiler can see it like you did with 'run' method? – creker Aug 29 '13 at 17:51
  • @creker, Will give it a try! I didn't declare it, it just worked (probably because `run` is implemented by default). – Panagiotis Aug 29 '13 at 17:53
2

I have never used dlsym to get a pointer to objective c method (I believe it's not possible to call objective c method through dlsym, but I may be wrong).

However, most important bit of information that second parameter of dlsym should be the symbol name.

Symbol name "run" will work only for C function. Something like:

EXPORT void run()
{
 NSLog(@"Run");
}

Object C method has more complex symbol names and as I said, I am not sure whether they could be passed to dlsym at all.

Victor Ronin
  • 21,310
  • 16
  • 85
  • 171
  • I think you are right. But just tried it (using Theos for the dylib to avoid Objective-C headers and stuff) adding only the function as you stated it and unfortunately I am getting the same result. – Panagiotis Aug 28 '13 at 13:54
  • I believe, it should be marked also by EXPORT. I recommend to read this article on dynamic libraries for OS X (taking into account that iOS has the same/very similar kernel) - https://developer.apple.com/library/mac/documentation/developertools/conceptual/dynamiclibraries/100-Articles/CreatingDynamicLibraries.html#//apple_ref/doc/uid/TP40002073-SW1 – Victor Ronin Aug 28 '13 at 15:32
  • EXPORT has to be defined firstly, but yet again, doesn't help! `#define EXPORT __attribute__((visibility("default")))` – Panagiotis Aug 28 '13 at 16:06
  • Hmmm... That's strange. I don't know then. Try your code on OS X first, where it's more common things to do (and easier to debug). – Victor Ronin Aug 28 '13 at 17:16