Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Print NSString Objective-C | Frida 12.0.8 #607

Open
jcalabres opened this issue Aug 26, 2018 · 6 comments
Open

Print NSString Objective-C | Frida 12.0.8 #607

jcalabres opened this issue Aug 26, 2018 · 6 comments

Comments

@jcalabres
Copy link

@jcalabres jcalabres commented Aug 26, 2018

Hi, I was trying to hook the method - isEqualToString from NSString class.
This method receives a NSString pointer. The problem comes when I want to print this string, I've noticed differents types inhereted from NSString: __NSCFString and NSCFConstantString.
Only __NSCFString objects, prints well, but NSCFConstantString don't prints well, they are empty strings, example:

// Get a reference to the NSString class.
var NSString = ObjC.classes.NSString;

// Intercept the method
Interceptor.attach(NSString["- isEqualToString:"].implementation, {
    onEnter: function(args) {
       var str=new ObjC(ptr(args[2]));
        if(str.$className=="__NSCFConstantString"){
            copy=str["- mutableCopy"]();
            console.log("x_x: "+copy.UTF8String().toString());
        }else{
            console.log("NSString: "+str.UTF8String().toString());
        }
        return true;
  }
});

As you can see in code, I get to change the type of constant string to the other with - mutableCopy (). However I can't get to print the string.
Anyone knows how to print a NSString correctly? How to manage toll-free Bridging in Frida, since we can't cast Objective-C objects (?)
Thanks to all.

@jcalabres jcalabres changed the title Print NSString Objective-C Print NSString Objective-C | Frida 12.0.8 Aug 27, 2018
@csftech
Copy link

@csftech csftech commented Aug 27, 2018

Try this frida/frida-core#7.

@jcalabres
Copy link
Author

@jcalabres jcalabres commented Aug 27, 2018

Hi, I tried it before and doesn't work.
Thank you!

@Kc57
Copy link

@Kc57 Kc57 commented Dec 14, 2018

I am also running into this issue and have not found a way to address it. I have tried the code listed above as well as in the linked issue with no luck. Any additional pointers that may help?

@retroplasma
Copy link

@retroplasma retroplasma commented Mar 7, 2019

Try this: new ObjC.Object(ptr(...)).toString()

@Kc57
Copy link

@Kc57 Kc57 commented Mar 13, 2019

@retroplasma Thanks for the reply! This seems to work for when hooking the return value for stringWithUTF8String but not when hooking the argument for isEqualToString.

Checking on the types for each, it looks like stringWithUTF8String returns a __NSCFString but isEqualToString takes a __NSCFConstantString as an argument. This seems to be the same behavior that @jcalabres describes in the original issue.

I have included a sample hook for each that demonstrates the issue as well as the output:

Interceptor.attach(ObjC.classes.NSString['+ stringWithUTF8String:'].implementation, {
    onEnter: function (args) {
      console.log('[+] Hooked +[NSString stringWithUTF8String:] ');
        //console.log('\t[+] Backtrace:\n\t' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n\t'));
    },
    onLeave: function (retval) {
      var str = new ObjC.Object(ptr(retval)).toString()
      console.log('[+] Returning [NSString stringWithUTF8String:] -> ', str);
      console.log("[+] Type of retval -> " + new ObjC.Object(retval).$className);
      return retval;
    }
});

Interceptor.attach(ObjC.classes.NSString['- isEqualToString:'].implementation, {
    onEnter: function (args) {
      var str = new ObjC.Object(ptr(args[2])).toString()
      console.log("[+] Type of args[2] -> " + new ObjC.Object(args[2]).$className);
      console.log('[+] Hooked -[NSString isEqualToString:] ->' , str);
      //console.log('\t[+] Backtrace:\n\t' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n\t'));
    }
});

image

@rustymagnet3000
Copy link

@rustymagnet3000 rustymagnet3000 commented Apr 23, 2019

@jcalabres question _"Anyone knows how to print a NSString correctly?"

Short answer

frida --codeshare mrmacete/objc-method-observer -f objc_playground
observeSomething('*[* stringWithUTF8String*]');
observeSomething('*[* isEqualToString*]');

Out-of-the-box you can watch all of the values. Does that help?

Long answer
Depending on how you initialized the string, you could step into different code paths. For example, isEqualToString on macOS:

(lldb) lookup isEqualToString
****************************************************
3 hits in: CoreFoundation
****************************************************
isEqualToString
-[__NSCFString isEqualToString:]
-[NSTaggedPointerString isEqualToString:]

****************************************************
5 hits in: Foundation
****************************************************
-[NSString isEqualToString:]
-[NSPathStore2 isEqualToString:]
-[NSConstantString isEqualToString:]
-[NSSimpleCString isEqualToString:]
-[__NSLocalizedString isEqualToString:]

On macOS I watched the SuperClass and InstanceType for str2 and str3 differ due to the number of characters in the init statement.

Objc code:

        NSString *str1 = @"foobar";
        NSString *str2 = [NSString stringWithFormat:@"barbar%d", 55];
        NSString *str3 = [NSString stringWithUTF8String:"foobarfoobar"];

Debugger view:

(lldb) po [str1 class]
__NSCFConstantString
(lldb) po [str1 superclass]
__NSCFString

(lldb) po [str2 class]
NSTaggedPointerString
(lldb) po [str2 superclass]
NSString

(lldb) po [str3 class]
__NSCFString
(lldb) po [str3 superclass]
NSMutableString

Let's say I slightly modify @Kc57's code. I get ...

Interceptor.attach(ObjC.classes.NSString['+ stringWithUTF8String:'].implementation, {
    onEnter: function (args) {
      console.log('[+] Hooked +[NSString stringWithUTF8String:] ');
    },
    onLeave: function (retval) {
      var str = new ObjC.Object(ptr(retval)).toString()
      console.log('[+] Returning [NSString stringWithUTF8String:] -> ', str);
      return retval;
    }
});

Interceptor.attach(ObjC.classes.__NSCFString['- isEqualToString:'].implementation, {
    onEnter: function (args) {
      var str = new ObjC.Object(ptr(args[2])).toString()
      console.log('[+] Hooked __NSCFString[- isEqualToString:] ->' , str);
    }
});

Interceptor.attach(ObjC.classes.NSTaggedPointerString['- isEqualToString:'].implementation, {
    onEnter: function (args) {
      var str = new ObjC.Object(ptr(args[2])).toString()
      console.log('[+] Hooked NSTaggedPointerString[- isEqualToString:] ->' , str);
    }
});

// RESULTS ✅  
[+] Returning [NSString stringWithUTF8String:] ->  foobarfoobar
[+] Hooked __NSCFString[- isEqualToString:] -> foobar
[+] Hooked NSTaggedPointerString[- isEqualToString:] -> barbar55
[+] Hooked __NSCFString[- isEqualToString:] -> foobarfoobar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants