Understanding iOS string formatting in assembly code - ios

I am new to assembly code and am learning a lot through examining disassembled iOS code through Hopper. One thing I cannot figure out is how to determine the variables that are being used in a formatted string. Here is a code snippet.
r0 = [var_60 myCustomString];
r0 = [r0 retain];
r22 = [[NSString stringWithFormat:#"%#%#%#"] retain];
[r0 release];
As you can see a variable is set in r0 just prior to r22. Then stringWithFormat:#"%#%#%#" is called with three variables (i.e. %#).
How would I go about finding what the other two variables are. I know one is myCustomString but do I just go back through the code and determine what other variables have not been released? If so, what order would the formatted string work in. For example, would myCustomString be the first format variable (%#) or the last one since it was most recently defined.
Thank you for your help!
EDIT
Here is the decompiled view of this variable:

Related

NativeScript: Get string from interop.reference

To start, here is my code:
var buffer = malloc(interop.sizeof(interop.types.UTF8CString));
var fillBuffer = mac.getBytes(buffer);
var bytes = new interop.Reference(interop.types.UTF8CString, buffer);
var hexMac = bytes[0];
The variable 'Mac' is an NSData objected retrieved from CoreBluetooth. It is the scan response from a BLE device, which contains the peripheral's MAC address (00:0b:57:a2:fb:a0).
This problem is linked to THIS question I had posted earlier.
The solution provided is great; however, I cannot seem to implement this in nativescript :
(instancetype)stringWithFormat:(NSString *)format, ...;
Intellisense tells me the method doesnt exist on type NSString.
Due to that issue, I decided to go another route (as you can tell). I am filling a buffer with the bytes of the MAC address. In the code above, bytes[0] equates to 0xb57a2fba0.
I am now trying to convert that (which is an interop.Reference) into a string that I can store on the back-end (preferably in the xx:xx:xx:xx:xx format).
I have been at this all weekend, and cannot seem to find a solution. I even broke down objc!foundation.d.ts to figure out if stringWithFormat was supported, to no avail.
The nativescript community slack was unable to provide a resolution as well.
Please help if you can!
I don't know anything about NativeScript at all, but given the other code you wrote, I assume you're calling +alloc first, and so mean to use -initWithFormat: (an instance method that initializes) rather than +stringWithFormat: (a class method which handles allocation and initialization).

How to avoid hardcoding keys for encryption (Objective C)?

In my Objective C code, I have a consumer key and secret hardcoded in my code to be used in SHA-1 encryption. What I would like to know is whether I could avoid hardcoding to improve security. I have found the following so far,
Finding 1
https://www.owasp.org/index.php/Technical_Risks_of_Reverse_Engineering_and_Unauthorized_Code_Modification#Cryptographic_Key_Replacement
Steps explained are as follows,
Damage static keys that are declared in source code. Such keys should be damaged while on disk to prevent an adversary from analyzing and intercepting the original key;
Next, the application should repair the key just before the code requiring the key uses it;
Immediately before use of the key, the application should perform a checksum of the key’s value to verify that the non-damaged key matches the value that the code declares at build time; and
Finally, the application should immediately re-damage the key in memory after the application has finished using it for that particular call.
Finding 2
https://github.com/UrbanApps/UAObfuscatedString
Can somebody help me please?
Sample code:
+ (NSString *) getOauthHeaderForRequestString:(NSString *)requestString {
NSString *oauthConsumerKey = #"<consumer key which I want avoid hardcoding>";
NSString *oauthConsumerSecret = #"<consumer secret which I want to avoid hardcoding>";
NSString *oauthSignatureMethod = #"HMAC-SHA1";
NSString *oauthVersion = #"1.0";
NSString *oauthNonce = [self generateNonce];
NSString *oauthtimestamp = [NSString stringWithFormat:#"%d", (int)[[NSDate date] timeIntervalSince1970]];
NSArray * params = [NSArray arrayWithObjects:
[NSString stringWithFormat:#"%#%%3D%#", #"oauth_consumer_key", oauthConsumerKey],
[NSString stringWithFormat:#"%#%%3D%#", #"oauth_nonce", oauthNonce],
[NSString stringWithFormat:#"%#%%3D%#", #"oauth_signature_method", oauthSignatureMethod],
[NSString stringWithFormat:#"%#%%3D%#", #"oauth_timestamp", oauthtimestamp],
[NSString stringWithFormat:#"%#%%3D%#", #"oauth_version", oauthVersion],
[NSString stringWithFormat:#"%#%%3D%#", #"request", [requestString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]],
nil];
params = [params sortedArrayUsingSelector:#selector(compare:)];
NSString *parameters = [params componentsJoinedByString:#"%26"];
NSString *postURL = #"<my post url>";
NSArray * baseComponents = [NSArray arrayWithObjects:
#"POST",
[self encodeString:postURL],
parameters,
nil];
NSString * baseString = [baseComponents componentsJoinedByString:#"&"];
NSArray *signingKeyComponents = [NSArray arrayWithObjects:oauthConsumerSecret, #"", nil];
NSString *signingKey = [signingKeyComponents componentsJoinedByString:#"&"];
NSData *signingKeyData = [signingKey dataUsingEncoding:NSUTF8StringEncoding];
NSData *baseData = [baseString dataUsingEncoding:NSUTF8StringEncoding];
uint8_t digest[20] = {0};
CCHmac(kCCHmacAlgSHA1, signingKeyData.bytes, signingKeyData.length, baseData.bytes, baseData.length, digest);
NSData *signatureData = [NSData dataWithBytes:digest length:20];
NSString *oauthSignature = [self base64forData:signatureData];
// final request build
NSString *oauthHeader = #"OAuth ";
oauthHeader = [oauthHeader stringByAppendingFormat:#"oauth_consumer_key=\"%#\"",oauthConsumerKey];
oauthHeader = [oauthHeader stringByAppendingFormat:#",oauth_nonce=\"%#\"",oauthNonce];
oauthHeader = [oauthHeader stringByAppendingFormat:#",oauth_signature=\"%#\"",[self encodeString:oauthSignature]];
oauthHeader = [oauthHeader stringByAppendingFormat:#",oauth_signature_method=\"%#\"",oauthSignatureMethod];
oauthHeader = [oauthHeader stringByAppendingFormat:#",oauth_timestamp=\"%#\"",oauthtimestamp];
oauthHeader = [oauthHeader stringByAppendingFormat:#",oauth_version=\"1.0\""];
return oauthHeader;
}
I've written about the challenges of solving this problem before, but I wanted to demonstrate a little bit using your UAObfuscatedString idea, since I think this is the kind of solution most people are looking for, but is worse than nothing. It's important to note: I'm not particularly good at this. I'm not a seasoned reverse engineer and commercial systems are way beyond my skillset. I'm just a guy with Hopper and literally five minutes of reverse engineering work (I ran a timer; 5:35s, including upgrading Hopper because I hadn't run it in a few months).
So, I wrote an iOS program with UAObfuscatedString. I used Swift because Swift is generally a little harder to reverse engineer than ObjC. ObjC is a reverse engineer's dream.
let identifier = "c".o.m.dot.u.r.b.a.n.a.p.p.s.dot.e.x.a.m.p.l.e
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
print(identifier)
return true
}
I then archived it, so it's optimized code, etc. etc. just like you'd send to the App Store. I then loaded it up in to Hopper and looked at the app delegate's init. That's where constants are initialized, based on the assumption that most people stick this stuff in their app delegate. Obviously if I see a class named KeyStorage or SecretStuffHelper, I'd look there first....
void * -[_TtC13ObfuscateTest11AppDelegate init](void * self, void * _cmd) {
*(r31 + 0xffffffffffffffe0) = r20;
*(0xfffffffffffffff0 + r31) = r19;
*(r31 + 0xfffffffffffffff0) = r29;
*(r31 + 0x0) = r30;
r0 = sub_100005e14();
return r0;
}
Hmm, it calls this anonymous function sub_100005e14(). Let's see what that does.
...
0000000100005e38 adr x0, #0x100006859 ; "c"
...
0000000100005e48 bl imp___stubs___T0SS18UAObfuscatedStringE1oSSfg
...
0000000100005e50 bl imp___stubs___T0SS18UAObfuscatedStringE1mSSfg
...
0000000100005e74 bl imp___stubs___T0SS18UAObfuscatedStringE3dotSSfg
...
0000000100005e98 bl imp___stubs___T0SS18UAObfuscatedStringE1uSSfg
...
0000000100005ebc bl imp___stubs___T0SS18UAObfuscatedStringE1rSSfg
...
0000000100005ee0 bl imp___stubs___T0SS18UAObfuscatedStringE1bSSfg
...
0000000100005f04 bl imp___stubs___T0SS18UAObfuscatedStringE1aSSfg
...
0000000100005f28 bl imp___stubs___T0SS18UAObfuscatedStringE1nSSfg
...
0000000100005f4c bl imp___stubs___T0SS18UAObfuscatedStringE1aSSfg
...
0000000100005f70 bl imp___stubs___T0SS18UAObfuscatedStringE1pSSfg
...
0000000100005f94 bl imp___stubs___T0SS18UAObfuscatedStringE1pSSfg
...
0000000100005fb8 bl imp___stubs___T0SS18UAObfuscatedStringE1sSSfg
...
0000000100005fdc bl imp___stubs___T0SS18UAObfuscatedStringE3dotSSfg
...
0000000100006000 bl imp___stubs___T0SS18UAObfuscatedStringE1eSSfg
...
0000000100006024 bl imp___stubs___T0SS18UAObfuscatedStringE1xSSfg
...
0000000100006048 bl imp___stubs___T0SS18UAObfuscatedStringE1aSSfg
...
000000010000606c bl imp___stubs___T0SS18UAObfuscatedStringE1mSSfg
...
0000000100006090 bl imp___stubs___T0SS18UAObfuscatedStringE1pSSfg
...
00000001000060b4 bl imp___stubs___T0SS18UAObfuscatedStringE1lSSfg
...
00000001000060d8 bl imp___stubs___T0SS18UAObfuscatedStringE1eSSfg
I'm not sure why the Swift demangler isn't working here, but anyway, we can easily see the pattern:
_T0SS18UAObfuscatedStringE1oSSfg => o
_T0SS18UAObfuscatedStringE1mSSfg => m
_T0SS18UAObfuscatedStringE3dotSSfg => dot => .
_T0SS18UAObfuscatedStringE1uSSfg => u
...
Realizing there are these USObfuscatedString methods, I search for that and find everywhere in the app that uses obfuscated strings. If I was willing to up my game a little and spend a day or so playing with it, I could probably write a tool to automatically extract every UAObfuscatedString just using otool and the binary.
And this is the deep lesson. You've just labeled all the strings you want to hide. Once I realize that UAObfuscatedString is a thing, you just made it easier for me to find your sensitive information. It is literally worse than nothing. Your only hope here is that the attacker doesn't know this exists. That's the problem with obfuscation, and what separates obfuscation from security.
I want also to emphasize that I spent 5 minutes and 35 seconds attacking this program. Yes, I knew basically what kind of thing I was looking for, but I also have no skills at this. If UAObfuscatedString were to become popular, I assure you that the auto-detect/de-obfuscate tool would become part of every script-kiddie's toolbox ("script-kiddie" is what security folks call attackers who do not know what they're doing, and just use automated tools that others have written).
The lesson here is that if you want to obfuscate, you're better off making up some random approach yourself. It won't be effective, but it probably won't be actively harmful to your goal in the way that most FOSS solutions are. "Free and open source" can be very good for security, but are the worst possible thing for obscurity.
If hiding information is really important to your business plan and you can't change your business plan, then you should expect to spend a lot of money on this problem and hire a team of people dedicated to constantly evolving your obfuscation system to keep ahead of attackers who will adapt to whatever you build.
So I recommend use yours second finding
https://github.com/UrbanApps/UAObfuscatedString
and add the regenerated strings to the keychain at the first application launch
so all methods could use values from keychain later in you code.
also I recommend build a singleton that will provide access to such values too keep all in one for time you want to change or update this solution
In general I wrote may api keys just inline in code, sometime declare them split it into two parts for safety. I am using a brain factor;)
let's say you API key xxx-xxxx-xxxx
I code the string xxx-xxxx-xFFF which as you see has same length as right key, somewhere in other method I cut las FFF and append right xxx postfix.
If you have a paranoia you could do it in different classes that defined in same file for convenience but stays alphabetically different places like AStoredKeys TheRightPostfixes that somehow hides your approach from disassemblers.
Honestly there is not much you can do. Literals are probably the best choice, but consider that you really don't know who will have a device and what they are doing with it. It's safe to assume that any talented engineer will be able to get to the keys and code on the device. Even if you protect your keys, there are apps, like screen scrapers and other things than can really get information. Obfuscation is not a good long term practice and good engineers can figure their way around this... it just slows them down. You do have control over your server, so focus on keeping that solid.
In general instead of thinking of securing your keys, think more about limiting information and access.
In regards to data, minimize private data to be received. For example, credit card numbers are never displayed and only the last 4 digits are stored. Or in the case of a banking app, only account balances are displayed, and they also offer two factor authentication (with an image for example). If a device is compromised, while it would suck to have a person's balance known, it's not the end of the world.
This also tends to be good corporate practice as it keeps you safe from any allegations. A person can't allege that information was compromised if you don't have it in the first place.
With access, limit what an app is capable of doing. Firewall it in a sense. Or provide other authentication steps, like SMS verification, two factor authentication. You can also let the server do the secure tasks for you. In the case of banking again, instead of allowing unlimited transfers, limit the number of transfers or the amount. Limit the accounts to which it can be transferred.
You could keep the password separately, in a file on an encrypted disc, or encrypted USB stick. Your code would just retrieve the appropriate file from secure storage. All an attacker would see in your code is the name of the password file.
If that is not practical, then you could XOR encrypt the password in your code. Your application will contain text strings like: "Please enter your password." That doesn't look like a key, but you could use that string as the XOR key to encrypt/decrypt the password. This is more vulnerable as an attacker would see the XOR key you are using in your code and be able to decrypt for herself.
Whatever method you use, do remember to overwrite the variable that holds the actual password before it goes out of scope.

My NSDictionary somehow has multiple values for one key

I have been attempting to debug a issue with my code, and just came upon an odd phenomenon. Found this in the debug area when a breakpoint was triggered:
Am I correct in observing that there are multiple values for this key: #"6898173"??
What are possible causes of this? I do not set those key-value pairs using the string literal, but by getting a substring of a string retrieved and decoded from a GKSession transmission.
I still have this up in the debug area in xcode, incase theres anything else there that might help.
EDIT:
By request, here is the code that would have created one of the two strings (another was created at an earlier time):
[carForPeerID setObject:[[MultiScreenRacerCarView alloc] initWithImage:[UIImage imageNamed:#"simple-travel-car-top_view"] trackNumber:[[[NSString stringWithUTF8String:data.bytes] substringWithRange:range] intValue]] forKey:[[NSString stringWithUTF8String:[data bytes]] substringFromIndex:9]];
The string in data might look something like this:
car00.0146898173
EDIT:
Code that sends the data:
[self.currentSession sendData:[[NSString stringWithFormat:#"car%i%#%#", [(MultiScreenRacerCarView *)[carForPeerID objectForKey:peerID] trackNumber], speed, [(MultiScreenRacerCarView *)[carForPeerID objectForKey:peerID] owner]] dataUsingEncoding:NSUTF8StringEncoding] toPeers:#[(NSString *)[peersInOrder objectAtIndex:(self.myOrderNumber + 1)]] withDataMode:GKSendDataReliable error:nil];
Sorry its hard to read. Its only one line.
What you're seeing is a debugger "feechure". When you have a mutable dictionary and modify it, the debugger may not show you the correct view of the object.
To reliably display the contents of an NSMutableArray or NSMutableDictionary, switch to the console and type po carForPeerID.

why not EXC_BAD_ACCESS?

I've written the following code:
NSString *string = [[NSString alloc] initWithFormat:#"test"];
[string release];
NSLog(#"string lenght = %d", [string length]);
//Why I don't get EXC_BAD_ACCESS at this point?
I should, it should be released. The retainCount should be 0 after last release, so why is it not?
P.S.
I am using latest XCode.
Update:
NSString *string = [[NSString alloc] initWithFormat:#"test"];
NSLog(#"retainCount before = %d", [string retainCount]);// => 1
[string release];
NSLog(#"retainCount after = %d", [string retainCount]);// => 1 Why!?
In this case, the frameworks are likely returning the literal #"test" from NSString *string = [[NSString alloc] initWithFormat:#"test"];. That is, it determines the literal may be reused, and reuses it in this context. After all, the input matches the output.
However, you should not rely on these internal optimizations in your programs -- just stick with the reference counting rules and well-defined behavior.
Update
David's comment caused me to look into this. On the system I tested, NSString *string = [[NSString alloc] initWithFormat:#"test"]; returns a new object. Your program messages an object which should have been released, and is not eligible for the immortal string status.
Your program still falls into undefined territory, and happens to appear to give the correct results in some cases only as an artifact of implementation details -- or just purely coincidence. As David pointed out, adding 'stuff' between the release and the log can cause string to really be destroyed and potentially reused. If you really want to know why this all works, you could read the objc runtime sources or crawl through the runtime's assembly as it executes. Some of it may have an explanation (runtime implementation details), and some of it is purely coincidence.
Doing things to a released object is an undefined behavior. Meaning - sometimes you get away with it, sometimes it crashes, sometimes it crashes a minute later in a completely different spot, sometimes a variable ten files away gets mysteriously modified.
To catch those issues, use the NSZombie technique. Look it up. That, and some coding discipline.
This time, you got away because the freed up memory hasn't been overwritten by anything yet. The memory that string points at still contains the bytes of a string object with the right length. Some time later, something else will be there, or the memory address won't be valid anymore. And there's no telling when this happens.
Sending messages to nil objects is, however, legitimate. That's a defined behavior in Objective C, in fact - nothing happens, 0 or nil is returned.
Update:
Ok. I'm tired and didn't read your question carefully enough.
The reason you are not crashing is pure luck. At first I though that you were using initWithString: in which case all the answers (including my original one (below)) about string literals would be valid.
What I mean by "pure luck"
The reason this works is just that the object is released but your pointer still points to where it used to be and the memory is not overwritten before you read it again. So when you access the variable you read from the untouched memory which means that you get a valid object back. Doing the above is VERY dangerous and will eventually cause a crash in the future!
If you start creating more object in between the release and the log then there is a chance that one of them will use the same memory as your string had and then you would crash when trying to read the old memory.
It is even so fragile that calling log twice in a row will cause a crash.
Original answer:
String literals never get released!
Take a look at my answer for this question for a description of why this is.
This answer also has a good explanation.
One possible explanation: You're superfluously dynamically allocating a string instead of just using the constant. Probably Cocoa already knows that's just a waste of memory (if you're not creating a mutable string), so it maybe releases the allocated object and returns the constant string instead. And on a constant string, release and retain have no effect.
To prove this, it's worth comparing the returned pointer to the constant string itself:
int main()
{
NSString *s = #"Hello World!";
NSString *t = [[NSString alloc] initWithFormat:s];
if (s == t)
NSLog(#"Strings are the same");
else
NSLog(#"Not the same; another instance was allocated");
return 0;
}

Using output parameters with ARC

So I have read this question, which seems to be exactly the kind of problem I am having, but the answer in that post does not solve my problem. I am attempting to write a data serialization subclass of NSMutableData. The problematic function header looks like this:
-(void)readString:(__autoreleasing NSString **)str
I do some data manipulation in the function to get the particular bytes the correspond to the next string in the data stream, and then I call this line:
*str = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
No errors in this code. But when I try to call the function like so:
+(id) deserialize:(SerializableData *)data
{
Program *newProgram = [[Program alloc] init];
[data readString:&(newProgram->programName)];
On the line where I actually call the function, I get the following error:
Passing address of non-local object to __autoreleasing parameter for write-back
I have tried placing the __autoreleasing in front of the NSString declaration, in front of the first *, and between the two *'s, but all configurations generate the error.
Did I just miss something when reading the other question, or has something in the ARC compiler changed since the time of that post?
EDIT:
It seems that the problem is coming from the way I am trying to access the string. I can work around it by doing something like this:
NSString* temp;
[data readString&(temp)];
newProgram.programName = temp;
but I would rather have direct access to the ivar
You can't. You might gain insight from LLVM's document Automatic Reference Counting, specifically section 4.3.4. "Passing to an out parameter by writeback". However, there really isn't that much extra detail other than you can't do that (specifically, this isn't listed in the "legal forms"), which you've already figured out. Though maybe you'll find the rationale interesting.

Resources