user2576008
user2576008

Reputation: 499

How to access Objective C obfuscated class from swift

I have a project where I used both, Objective C and Swift. From security reasons, for some classes and methods written in Objective C I used obfuscation.

This is my code:

#ifndef AccessManager_h

#define AccessManager ySbIXoscpewLLSwVacDpZvPvQeNDtG
#define loginWithUsername TEWhYyXaCdGrCViPbZZHWXoBiUPvPn

#endif

@interface AccessManager : AFHTTPSessionManager

-(void)loginWithUsername:(NSString*)username password:(NSString*)password success:(WSSuccessBlock)success failure:(WSFailureBlock)failure;

@end

And this is my swift code that tried to access the obfuscated class

AccessManager.instance().login(withUsername: "my_user", password: "password", success: { (response) in
        //TODO
    }) { (error) in
        //TODO
    }

And this is the error that I get when I build the project

Undefined symbols for architecture armv7:
"_OBJC_CLASS_$_AccessManager", referenced from:
      objc-class-ref in MySwiftClass.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)

How can access an Objective C class that is obfuscated from Swift?

Upvotes: 1

Views: 997

Answers (3)

Neha Tripathi
Neha Tripathi

Reputation: 61

If you want to use preprocessor like -

#define ABC DEF

where DEF is a Class name. You need to import this file in your bridging header and then define it as below:

typedef DEF* ABC;

You can refer to this answer

Swift is not able to understand the type of the defined preprocessor which is why you are not able to use it.

Upvotes: 1

Nicolas Miari
Nicolas Miari

Reputation: 16256

Below is very basic example, but gives an idea of what you can do:

Provide an interface to your class and method's runtime representations, by means of global C-functions that are callable from Swift code.

Unlike Objective-C methods, which use dynamic dispatch and whose names thus survive into the binary as plain strings (selectors), C function calls are compiled into jump instructions to the appropriate memory address; the function name is not present in the binary for hackers to decompile/inspect.


AccessManager.h:

#import <Foundation/Foundation.h>

#ifndef AccessManager_h
#define AccessManager ySbIXoscpewLLSwVacDpZvPvQeNDtG
#define loginWithUsername TEWhYyXaCdGrCViPbZZHWXoBiUPvPn
#endif

/// Provides the class object at runtime
Class accessManagerClass();

/// Provides the method name at runtime
SEL loginMethodName();

@interface AccessManager : NSObject

- (instancetype) init;
- (void) loginWithUsername:(NSString*) userName;

@end

AccessManager.m:

#import "AccessManager.h"

Class accessManagerClass() {
    return [AccessManager self];
}

SEL loginMethodName() {
    return @selector(loginWithUsername:);
}

@implementation AccessManager

- (void) loginWithUsername:(NSString*) userName {
    // Dummy implementation, for demonstration purposes:
    NSLog(@"%s", __func__);
    NSLog(userName);
}

@end

Bridging Header:

#import "AccessManager.h"

ViewController.swift (most of the class omitted):

override func viewDidLoad() {
    super.viewDidLoad()

    if let managerClass: AnyClass = accessManagerClass(), let methodName = loginMethodName() {

        // Instantiate the manager from the class:
        let manager = (managerClass as! NSObject.Type).init()

        // (I'm still a bit fuzzy about metatypes on Swift,
        //  perhaps the line above can be improved)

        // Call the obfuscated method: 
        manager.perform(methodName, with: "AAAA")
    }
}

When run, it prints:

% -[ySbIXoscpewLLSwVacDpZvPvQeNDtG TEWhYyXaCdGrCViPbZZHWXoBiUPvPn:]
% AAAA

...which proves that:

  1. Class and method name are obfuscated at runtime.
  2. The method is actually called

I put a sample project with all the code above on GitHub.

Upvotes: 0

Puneet Sharma
Puneet Sharma

Reputation: 9484

By using Macros you have changed the name of the class and the method name. This is an easy way to perform obfuscation.

But, that would also break the Swift-Objective-C interoperability if you try to use original class name and its methods.

You can of-course still use your obj-c class by the redefined names in a Swift class(changed the block params to simple BOOLs for simplicity):

let accessManager = ySbIXoscpewLLSwVacDpZvPvQeNDtG()
accessManager.teWhYyXaCdGrCViPbZZHWXoBiUPvPn("", password: "", success: true, failure: true)

Upvotes: 0

Related Questions