Radio Inspire

How To Learn Sign Language

APDU Communication between Device and Host – Hardware Wallet Research #6


After we reverse engineered some parts of
the ledger firmware, AND found source code of an older ledger firmware version, our next
goal will be to find, where the ledger handles the APDU messages coming from USB. And that is actually pretty easy. So. We know from the debug output that the ledger
uses APDU messages to communicate. application protocol data unit ( APDU ) is
the communication unit between a smart card reader and a smart card. It’s just one simple standard that you can
use to implement messages for communication. Anyway. When we reverse engineered the button_press
handler, we found a function that we called bootloader_continue. Because this is where it continued to, after
we released the button. And we also compared the assembly, with the
old source code from Ledger’s github. And we saw that what we called bootloader_continue
appears to be the function bootloader_apdu_interp. And the name already says a lot. In there we see a io_usb_hid_init, followed
by a while(true) loop. In case you didn’t know, having a for-loop
without any conditions, it is an endless loop, like while(true). And in this loop we see io_exchange (input/output
exchange) and a lot of references to APDU. CHANNEL_APDU, no apdu received, G_io_apdu_buffer. And we can also see switch/case statements,
that appear to uses one byte of the APDU buffer, specifically the second byte – APDU Offset
for the Instruction. And for example this case statement – Instruction
Get_version shows, that the byte 0x01 is the instruction GET_VERSION. From the other offset values we can also see
that the first byte of the APDU commands is reffered to as CLA. And we can see that before the switch/case
statement it checks that first byte. It compares it to a constant CLA, which has
to be 0xE0! And now remembe the APDU commands we saw in
the chrome app’s debug output. Each APDU command started with 0xe0. Which means each second byte here refers to
the Instruction, or the meaning, of this particular apdu message. Cool, right? Now let’s have a quick look at this function
in IDA. Zooming out we can directly spot the big loop. Around everything. And right at the start of the function we
see a compare to 0xe0. So this part here is this this! And when we follow the call graph we can also
find that IDA identified this as switch-case statements. This one has 5 cases. If you leave the graph view it’s easier
to see how this is implemented. First there is a compare to R0, to check if
it’s less or same. And then branch, or jump, to the switch jump
here. Which means there are 5 switch cases. 0,1,2,3 and 4. And this switch jump is implemented as a small
function. Here we can find a major difference between
ARM and other architectures like Intel x86. ARM has a so called Link Register. A link register is a special-purpose register
which holds the address to return to when a function call completes. On ARM the return address is not automatically
pushed onto the stack like with a call on x86. Instead it just writes the return address
into the link register LR. If a function has multiple hierarchies down,
it has to remember the LR on the stack though, otherwise the next branch will overwrite the
register again. Thus many functions will Push it to the stack,
along a lot of other registers, very similar to x86. And also pop the pushed LR value back into
the program counter PC to return. But you don’t need it if you don’t branch
further. And this small function doesn’t call anything
else, so it can just branch back to LR when it’s done. However if you pay attention, it actually
modifies LR before it jumps there. LR would point into the data you see here. This is not assembly. But IDA already recognized this as a jump
table for the switch statement. So first it moves LR, which points at the
start of the jump table into R1. Then it performs a shift right, and a shift
left. It does that to clear the last bit that is
set, because we have thump code. If that’s new to you, please checkout earlier
videos in the series. So R1 now really points to here at the start. And then we load a byte at the offset R0. And the offset r0 is the switch value. So it will load one of these bytes depending
on if R0 was 0, 1,2,3 or 4. Then it will shift that byte to the left by
one. Which sounds weird but it’s actually super
smart. Like we know, ARM code is always aligned. And the last bit 0 or 1 decides if the instruction
is a thumb instruction or not. We have here only thumb code, so the LR register,
which points to the next code to return to, will have the last bit set. And with the next instruction we see that
it adds the offset, it got in R1, onto the link register. The link register already has the last bit
set, which means this jump offset will never have a bit 1 at the end. It will always be 0. This means you can safe one bit for your jump
table. For example if you want to jump to offset
0xc. That would be 1100. The last bit will always be 0. So you can just store 110. And then shift left by one. That doesn;t make much sense for a small value
like that. But what if you want to jump to 0x14C. That doesn’t fit into a byte? Or does it? Shifting it right by one, will make it 0xA6. And then it fits into a byte. And when we want to use it, we load that single
byte. Shift it by left by one, and we get the last
zero back. This means this 0xA6 here actually represents
a jump to the offset 0x14C. So 0x14c PLUS 0x806 is 0x952. So this case would juuuuump here! Because my cursor is still placed on the jump
table function, IDA highlights the switch-case jump targets with a black arrow. So we can verify, yep, this is correct. It jumps here. IDA also added an automatic comment that this
is one of the cases for the jumptable from 0x802. Cool! So this is how you can reverse engineer and
work through that code. Now let’s move away from IDA and the code
for a moment and look at the communication from the HOST side. So your computer. If you do your research into ledger and the
provided software well, you will stumble over a repository from ledger that contains “Python
tools for Ledger Blue and Nano S”. For example you could find this code when
you look through ledger’s support article describing how to check the hardware integrity. And there they install a python module called
ledgerblue and use the checkGenuine function, to verify the software on the chip. And the source code for it is linked here. When you look into the main function of this
module you can see how it talks to the ledger hardware. There is a communication module that exposes
the functio getDongle, that returns a dongle instance. This is then passed to getDeployedSecretV2. There we immediatly can see that it builds
an APDU message from raw bytes. 0xe0, is the CLA. And the 0x4 is the instruction. Looking into the firmware source code we can
check what instruction nr 0x4 would be, and so that’s Instruction VALIDATE_TARGET_ID. And it’s simple what it does. It takes a received ID and compares it to
the constant device’s ID. It’s just a function that you can use to
check that your device you are talking to is in fact the device you meant to talk to. Here in the python code you can see how the
ID you can specify is added to the APDU message. Anyway. Once you have that APDU data, you can then
call donge.exchange() to send that message to the device! From other instances of this exchange function
we can also see that it can return data. Cool! So let’s test this. Let’s get a python virtual environment… Then let’s pip install ledgerblue. Aaaaand now we can use it. To test I open just a python interpreter. from ledgerblue.comm import getDongle. By the way, python pro-tip. There is a builtin function help() which shows
you information about python functions and classes. For some stuff the help can be super detailed. It’s like a linux man page. So we can call help(getDongle) and we get
some info. In this case it’s not amazing, but we will
see that the first parameter turns Debug on and off. So let’s get a dongle with getDongle and
set debug to true. Next we can call dongle.exchange with a bytearray. The bytearray starts with 0xe0, and then the
instruction, in this case 0x01, which stands for Get_version. Now before we hit enter we have to make sure
that the ledger is connected in bootloader mode. So pressing the button and connecting it. Then let’s issue the command! And it worked! We see an outgoing APDU message which was
our get_version. And we see an incoming message. Now what these values exactly mean, I don’t
know. I guess somehow they contain the current version
of the device firmware. And we can probably look through more of the
code to see how ledger parses these value in their own software, but it’s not that
important for us right now. Before we finish this video. One last small thing. Of course we can also debug this now easily
with gdb. We know that here it checks the first byte
of the received APDU command to check if it’s 0xe0. So we could use our GDB setup to set a breakpoint
there. But I wanted to show you something else. IDA also can attach to a remote GDB server. So we can select the debugger to be Remote
GDB debugger, and then go into the debugger settings and set it to the gdb server port
exposed by the st-link utility. We just have to make sure the utility is running,
and then we can select “attach to process” in IDA. “attach to the process started on
target”, and IDA switches to the debugger view. And we are at reset now. And debugging like this is maybe a bit nicer,
because we can also have the graph view. So let’s quickly navigate to the place where
it compares the APDU message and set a breakpoint there. In this case a regular software breakpoint
didn’t seem to work for me. So I went into the breakpoint list and edited
the breakpoint. Making it a hardware breakpoint. This is a feature of the Chip itself. The st-utility even has an output telling
us that it found 4 hw breakpoint registers. So hardware breakpoints allow us to tell the
arm chip to break on certain conditions. In this case we say: “when you access this
address with the intention to execute the instruction there, please stop!”. Let’s try it out. We do the same thing again, we press the button
of the ledger and hit continue, so the ledger starts. Okay, we are in bootloader mode and IDA shows
the process is running. Now let’s issue our APDU command again,
and IDA immediately gets focus because we hit the breakpoint. So the byte of the APDU command is copied
from this address, which we know is a RAM address. So we can use the hex view to navigate to
this address and look into the RAM of the device. AND YES! Here is our APDU command. So this is cool. And maybe looks better having this graph view
and so forth. But like I already mentioned with the breakpoint
behaviour, this is also super janky. For example if I try to perform a single step,
it just breaks. Maybe there is somewhere a setting to configure
single stepping to also use hardware breakpoints or something, but I don’t know. Also I’m kinda used to normal GDB at this
point. Anyway… now we have everything in place
to look into the firmware update next video.

53 Replies to “APDU Communication between Device and Host – Hardware Wallet Research #6”

  • hm, premieres in 2 days? That seems like too much. Just makes me wish I could watch the video now, and I'll forget about it again by the time it's up. I'd personally do the premiere 6 hours ahead at most.

  • Dude wtf. I clicked the link and was disappointed that there is no video. What's the point? The subscribers will see it anyway.

  • Honestly, Youtube Premieres suck. They draw people's attention BEFORE the video release, and then when it is released YouTube's algorithm doesn't show it to people as frequently as it did when you just uploaded a new video, so it gains less views. Just look at the Strange Parts channel and compare the views on regular videos and one single vid released via premieres

  • So, I saw a couple of content creators trying this feature, non of them did stick to it. Just putting this out here…

  • I honestly hope this is a live stream or else this is just freaking stupid. I watch everything you release to the point that I stop whatever I'm doing to do so. And to have new content pop up in my feed that I need to wait 2 days to watch is like a massive slap on the balls. Announcing livestreams ahead of time is fine. So people know when to tune in, but video on demand should not be announced this way. Its not like its a 2 hour documentary to get hyped about. Sorry to rage like this, but this feature frustrates the hell out of me.

  • Fuck this shit. I don't want to see a picture of a video for two days. If I tell YouTube I'm not interested to make this bullshit go away will it think I won't want to watch the video as well? Why the hell do I want PICTURES on the front page of my VIDEO app? Pull your heads out of your collective asses Google. Seriously.

  • These premiere feature should be reserved for livestreams and not for regular videos.
    I already unsubscribed channels making use of it and i will continue to do so.

  • I love your videos very much, I saw this in my subscription feed and got excited for nothing. I would prefer making a community post letting us know the date of your next video. The premiere feature is just a tease and then it doesn't even show up on your feed the day of.

  • I think the main thing here is that we didn't know beforehand that you were going to start scheduling videos. So we see the notification and got excited, then realized we couldn't watch it; However; if this is a consistent release schedule, yeah absolutely. Hype it up. Maybe pin a comment with a hint on what it is? We're all just salty because we're so used to having the content release same day.

  • APDU is fun an simple. Curious to see what you have to say about it. I’ve worked with it lots via OMNIKEY 542x readers

  • In my recommend feed it didn't show that it was a premier, so it was confusing at first lol, after reading the comments I agree, even tho I can get a reminder I would prefer just a post since I don't have social media. Anyways, I love your content and if it wasn't for you I would still be a script kiddo, thank you for sharing your knowledge. 🙂

  • Reingefallen… Ist dein gutes recht, das Premiere-Feature mal auszuprobieren, dagegen habe ich wirklich nichts. Aber das Thumbnail ist ein bisschen unglücklich gewählt. Wäre cool, wenn du in Zukunft unten rechts etwas weißraum oder so lassen könntest. Den Premiere-Tag sieht man aktuell sehr schlecht; Vielleicht hat das dazu beigetragen, dass sich hier einige Zuschauer ein bisschen ärgern, weil sie ein Video erwartet haben.

    Allgemein muss ich aber auch sagen, dass ich das Feature persönlich auch nicht mag.

  • Dont use premiere, just release the video when its done. Its disheartening to see a video in your subscriptions that you cant watch.

  • As others have mentioned the premiere feature is just spam in the subscription feed. All good channels give up on it after trying it a few times, so I can only hope the LiveOverflow channel will do the same… because LiveOverflow is a very good channel.

  • I’m calling my long lost relatives to book a flight and get their ass to my living room tomorrow. Just so we can all watch the world premiere of whatever this #6 APDU video consists of.

  • Is it possible to disable premiere feature somewhere in YouTube settings? I want to see only videos I can actually watch

  • IMO, the Premiere function has advantages and disadvantages. I'm not a lover nor a hater of it. The only real advantage I can see is the live chat, but there are some disadvantages such as the fact you can't speed up the video. The waiting "disadvantage" is not really a disadvantage, because it's scheduled anyways, and as he mentioned in another video, he keeps a few future videos unlisted in order to have a "video cushion", like a financial cushion, just in case he can't make a video on time.

  • I think what even when we can't see the video, it's cool because we are more motivated to see her !!

    Sorry if my english is not very good, I'm french..

    PS : It's very cool what you do a video on Reverse Engineering..

  • Additional stupidity of the premiere thing: you arrive a few minutes late and youtube starts the video from that many minutes in, which doesn't work at all for your type of content. Well, you get the idea … Gonna enjoy the video from the start now, thanks 😀

  • Ignoring the hate for Premiere, I really enjoyed it! It was really distracting and fun to chat with everybody. For me at least it was really exciting and I might try it again.

  • The last messages don’t show up in the chat replay. Maybe it’d be a good idea to add padding at the end if you do another Premiere?

  • 12:25 – Yo dawg. I’ve heard you like watching browsers so I’ve put browser window inside of a browser window inside your browser.

  • Maybe it is time for some related comment there.
    It is kinda unexpected why software debugging do not work there and you need hardware breakpoints. On the other side FW may lack debugging support as software breakpoints need OS/supervisor support. If you have some spare time you can read how debuggers work, it is fun topic.

  • Also don't like premiere but please guys, don't dislike the video. Just leave a comment or like another stating your opinion

  • Keep doing 70+ hour premieres and I'll keep disliking the respective videos. Reminders are not a good feature. Takes extra work and scheduling to not miss it.
    I can take maybe 5 minutes of waiting so we watch together, but not multiple days. By the time you finally release I'll have forgotten and it's buried by other videos.
    Also I want 2x speed, which cannot be used while it's fake "live".

  • WTH you used the premier feature???! Unsubbed…

    only joking. I don't understand why everyone is freaking out . Even in the sub box / home page it is clearly labeled as a premier so its your own fault if you clicked on it thinking it was an actual completed video….

  • Love the video, LiveOverflow! I saw you use the python interpreter for one of the tasks and I was wondering if you've heard about ipython/Jupyter? Those tools are a lot more interactive and helpful when dealing with Python code.

    Cheers!

    Svitch 😀

  • It's kinda disheartening to see an upcoming premiere in my sub feed, like "Hey here's a video that you can watch live at the same time as everyone else, but you won't make it because you'll probably forget or be busy.".

  • What? 512 likes vs 90 dislikes? And everything because of this "premiere" feature that people apparently don't like? But what about the video? Seriously, WAT

  • I have no idea what any of this means. Lol it seems super interesting tho. Does anyone have suggestions how or where to start learning?

  • Everyone hating on LiveOverflow for premieres, have you ever heard of a certain thing called "hype?"

Leave a Reply

Your email address will not be published. Required fields are marked *