Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,672
6,212
There's a method in MobileDevice.framework (the private framework used to communicate with iOS devices from your Mac over USB) called AMDeviceCopyValue(). It takes two strings as arguments: domain and key. I've been able to find some domains and keys that work online, but I can't find the pair that will tell you how many charge cycles are on the iOS device's battery.

There's another program, iCopyBot, which can do this (http://www.icopybot.com/blog/check-ipad-iphone-battery-charge-cycle-count-without-jailbreaking.htm). I've already downloaded and ran the program, and have seen that it works.

I was thinking that if I had a USB Sniffer program of some sort, I could see all the values that the program sends over USB to the connected iOS device, and from that, see what domain/key pairs they use to get how many charge cycles are on the iOS device's battery.

Does anyone know of such a USB sniffer program that I could use? Or maybe you have another suggestion for how I might get these strings. I already have run the terminal command strings on both the binary of MobileDevice and iCopyBot, and while it did include some domains and keys that I knew of already (and some I didn't already know of) - none of them were helpful in extracting this data.
 
Last edited:
The USB packets could be encrypted, so I wouldn't necessarily think a bus sniffer would show anything useful. Not saying they are, just that they could be. And since we're talking iPhone here, I really wouldn't be surprised if there were encryption, even if it's just some obfuscation.

A hardware or hardware/software USB sniffer isn't cheap: ~$400 and up. So that's probably out of the picture.


The first thing I'd try is contacting the developer and asking. They might tell you.

Next, maybe you could run the debugger on the iCopyBot executable, and set a breakpoint on AMDeviceCopyValue(). Then add commands to be executed when the breakpoint hits, and have those commands log the function's parameters. You might also be able to add conditions to the breakpoint. It's a kind of cheap "call monitor".

I haven't tried setting up anything like this in ages, so it may not be possible under lldb. I did a quick check of the lldb docs, and they do support breakpoint conditions and commands, so it's worth a try. I'd try it on my own test-case target function first, to make sure it worked as expected.

It also occurs to me that getting a trace of function calls and parameters is exactly the kind of thing dtrace was designed for. So maybe there's a way to have dtrace tell you every time AMDeviceCopyValue() is called, and what the args are. You'd have to look into the details: man dtrace, Apple's Instruments app, and probably a bunch of tutorials on the web.
 
The USB packets could be encrypted, so I wouldn't necessarily think a bus sniffer would show anything useful. Not saying they are, just that they could be. And since we're talking iPhone here, I really wouldn't be surprised if there were encryption, even if it's just some obfuscation.

My understanding is it uses SSL3.

A hardware or hardware/software USB sniffer isn't cheap: ~$400 and up. So that's probably out of the picture.

Ouch. I was hoping someone had made something decent that was open source or free... maybe just a demo that works well enough for me.


The first thing I'd try is contacting the developer and asking. They might tell you.

I contacted them 3 days ago and haven't heard back from them. Either they just have lousy support and rarely check email or they're intentionally not helping me (not unreasonable... I'd steal some of their thunder by making a program that does some of the things that so far only they've managed to do. But primarily their application is for backup management, whereas mine is for battery management, so I hoped they would help.)

Next, maybe you could run the debugger on the iCopyBot executable, and set a breakpoint on AMDeviceCopyValue(). Then add commands to be executed when the breakpoint hits, and have those commands log the function's parameters. You might also be able to add conditions to the breakpoint. It's a kind of cheap "call monitor".

I haven't tried setting up anything like this in ages, so it may not be possible under lldb. I did a quick check of the lldb docs, and they do support breakpoint conditions and commands, so it's worth a try. I'd try it on my own test-case target function first, to make sure it worked as expected.

Okay, I have lldb running their program, and I got it to break on AMDeviceCopyValue, but now I can't figure out how to get the arguments out. Apple's documentation on lldb says you use the command "frame variable" once you're at a breakpoint and it'll print out all the arguments that were passed in, but it's printing out nothing for me. In Apple's example, they had their breakpoint set on an Obj-C selector whereas I used a C function, so maybe that made a difference somehow?

It also occurs to me that getting a trace of function calls and parameters is exactly the kind of thing dtrace was designed for. So maybe there's a way to have dtrace tell you every time AMDeviceCopyValue() is called, and what the args are. You'd have to look into the details: man dtrace, Apple's Instruments app, and probably a bunch of tutorials on the web.

I tried using dtrace... it had tons of output, but I searched it all for AMDeviceCopyValue and it turned up nothing. I know that can't be right, as lldb paused on a breakpoint for that function.

So here's my question: Why isn't lldb printing out anything when I type in "frame variable" when I'm paused at a breakpoint? This function takes 3 arguments, so I'd expect to see at least those listed, if nothing else.

If I tell it "print domain" it prints out 0x0000000000000000... having NULL as a domain is valid, but then if I tell it "print key" it tells me there's no such variable...
 
Last edited:
Here's what I've determined so far:
- "frame variables" doesn't work because things like variable names and types weren't included when the code was compiled.
- I can still print out a list of all of the registers and their current hexadecimal values by using "register read"
- I can get the unsigned long value out of any register by using "print <register name>"
- I can use "po <register name>" on any register that contains an Obj-C object and get its description.

Here's what I haven't found out yet:
- How can I print out the C string at an address given in a register?
- How can I print out the value at an arbitrary address in memory?

Edit:
Actually, I was mistaken. These aren't C strings - they're CF strings, which means po works on them just fine, I just didn't recognize the output for what it was.

Although to answer my second question, the answer is "memory read" (I think. I saw it in the documentation but I didn't actually try it because I didn't actually need it.)

Edit 2x:
Crap... either LLDB isn't actually breaking on every call to AMDeviceCopyValue(), or this program uses a different method to get this data. I found that the function is called 15 times, but none of the calls provide the specific number I want.

Edit 3x:
Anyone knows how to do this, pipe up on StackOverflow. I've offered a 200 point bounty to anyone who can help me:

http://stackoverflow.com/questions/...ery-charge-cycles-from-a-connected-ios-device
 
Last edited:
Here's what I haven't found out yet:
- How can I print out the C string at an address given in a register?
- How can I print out the value at an arbitrary address in memory?

Well, why won't you just disassemble it and look for such a calls and/or values?
Hoper disassembler makes it pretty readable ;)
 
Well, why won't you just disassemble it and look for such a calls and/or values?
Hoper disassembler makes it pretty readable ;)

I assume you were referring to Hopper Dissassembler. I looked at its website - it looked like it could be helpful. I'll download it and see what I can do with the demo.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.