CAR HACKING VILLAGE - CAN Signal Extraction from OpenXC with Radare2
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Gardiner, Ben
OpenXC builds its firmware - for both the open and proprietary builds - using JSON data structures which define the CAN signals. These definitions are akin to the CAN database files (.dbc) files. Reverse engineering of the open openXC builds (as an educational excersise) reveals that it is a straightforward matter to identify and extract the CAN signal definitions from the binary. Attendees will learn: What are dbc files? How strings lead reverse engineers to interesting code via backwards cross-references? What tools do attackers use to reverse engineer raw binary firmwares? How do they use them? What are some simple, useful deterrents? How do descriptive data structures - JSON in particular - aid attackers in their reverse engineering efforts? What mitigations are possible for this risk? The exposition of machine code in the talk will be via the free radare2 RE tool.
 So I'm going to be talking to you about uh, Radare 2. It has a lot of pronunciations. Uh, people tell me that I'm probably saying it wrong. I'm just going to keep saying Radare 2. I'm sorry, that's what I'm going to do. It's going to be about 25 minutes. I'm talking about OpenXE, which is uh, Ford's platform for moving canned messages over Bluetooth, uh, to like mobile apps and it's kind of neat. Because OpenXE is open source, we can actually look at the firmware and kind of skip a lot of the discovery parts and just focus on reverse engineering with Radare. So it's really, it's going to be a whole bunch of command line stuff. The talk is kind of in the Gen2 quadrant. There's going to be just a lot of commands and you know, I'll have the slides up. You can refer to the commands later. I'll try to describe what I'm doing too, but it's, it's not going to be in Boon 2 style. It's going to be kind of like just fly, you know, go. So we'll see. Well first up OpenXE, you know, uh, this is a cool platform that kind of takes canned messages and translates them into message pack format, which is like JSON and it lets you build these mobile apps for iOS recently for Android. It's actively developed. Um, it's, it's pretty fun. I recommend you go check it out. They give you hardware platforms and the software development. Uh, so you can do some cool stuff with it. Radare. So uh, Radare 2 is like this reverse engineering suite of tools. There's a whole bunch of command line utilities you can use like RA Band and RA Hash. I'm going to be talking almost exclusively about R2, which is like the reverse engineering part of it. So I'll show you a little bit of Radare. Uh, I really wanted to do everything like command line style. Um, but this is actually my backup deck because the command line stuff just didn't work. But I'm going to do this style of like, here's a fake command prompt and I'm going to kind of scroll down. So a Radare session, you might open up a file. It's like an L file from binary samples and then you want to analyze it. So AA, every command in Radare starts with like hierarchical letters. So A is for analysis commands and AA is just like do the basic analysis. Okay. It says great. I looked at all the flags and I found some stuff. Thanks. Uh, S is for seek. So I'm going to like seek to the function called main. There I did it. And then more analysis commands, AX is for listing cross references. So here I'm just listing all the cross references that happen to be referring to main. And you can see that the analysis actually completed because of the whole bunch of cross references. This is great. And this is usually the experience you get with Radare, especially on like L files and PE files and stuff. It's really great at finding all that metadata, uh, in the symbol table and then helping you kind of walk your way through the binary. Now when you're dealing with a raw firmware file, just like a bin file, you don't actually get all those nice symbol exports, right? So you can open up in Radare. You can ask it to do the analysis. It'll say, great, I analyze zero things for you because I don't know where main is, right? There's nothing there. There's no metadata. So you have to actually kind of teach Radare about where the file goes, do some searching for functions. Uh, and first Easter egg, Radare has a, has Clippy. Clippy is installed. So you can actually get Clippy to tell you things if you, uh, you want a little bit of help. Uh, he likes to help. Radare also does really great, uh, control flow graph visualizations in the terminal. So this is actually like text mode using UTF-8 lines. Uh, and all the disassembly for every disassembly, uh, flavor that it supports, it'll do this kind of control flow layout, which is gorgeous. Uh, it's VV to get there. I'm not going to be showing you disassembly because this talk is really about extracting data. So we're going to be looking at how to pretty print, uh, canned signal information inside OpenXC. So not disassembly, uh, more like data stuff. But if you want to just have great control flow graphs for free, check out Radare. It's great. Okay. It's going to be a lot of commands. I put together this summary of all the commands that I'm going to use. Uh, I will also show this slide at the end. So, you know, you'll have lots of time to take pictures for it. It'll probably be in a PDF somewhere as well. You can see that the commands are all really hierarchical, right? All the analysis commands start with A. All the printing commands starts with P. Uh, information for the binary starts with I. And then there's two different things. And the most important one is really the question mark. You can use question mark as a post fix. And if you put it at the end of any letter, basically, it'll tell you what that letter is as a command. And the help in, the help information in the command line for Radare 2 is really great. So if you know that to put question mark at the end, you can actually walk your way through Radare pretty well. The other thing is question mark first is more like an echo command. So you can, question mark E will echo like actual echo command line, the normal stuff. Question mark V shows you like hexadecimal values. Question mark capital E shows you Clippy. We saw that already. So to recap, just to make sure we know we're talking about, OpenXC takes these JSON files as part of its build and turns them into these CAN signal structures. Okay? And what we're going to do is go through the Radare commands necessary to actually go backwards and get the information out of the CAN signal structures that are in the firmware. They're going to kind of reverse that arrow. This is reverse engineering, right? Okay. This isn't the first time OpenXC has been reversed. I've given some talks about doing this with Ida Pro. Ida Pro is very expensive and this is now free. I run the same time I did the sans talk. Someone who had to handle BSMT put out a blog post detailing how to do the steps with some Ida Pro Python scripts. So BSMT's blog has like a fully automated way to do this using Ida Pro, which is kind of cool. Also, you know, I'm not the person who invented firmware reverse engineering. I'm totally standing on the shoulders of giants and there are many. I really appreciate the help of Craig Hefner and his blog post. I recommend all of his work. And then finally, I didn't invent Radare. That's done by Trufey or Pancake, Pancake Knop Code. He actually has a talk here, this YouTube link, where he takes the MD380, the Titerra radios and he reverses the ARM firmware in the Titerra radio. It's a firmware blob. It's using a lot of the same techniques. So I'm really building on all this previous work here. Okay. We don't have a whole lot of time. So I'm really just going to do the yellow stuff. Right? I'm going to assume, okay, we already know that we've got the firmware in our hand. You know, that's always a hard step with the device you just got, maybe getting the firmware. We already know the architecture. We already know the load address. We're just going to assume that stuff. And we're going to go do this yellow stuff, load it into R2. We're going to assume that we figured out where the loader loop is, you know, where the C runtime stuff does the copying. And we'll just do a copy for ourselves. And then we'll do the pretty printing of the structures. Okay. So first up, we want to load this thing. So we already know because we're smart and we did some reverse engineering already that the thing can get loaded at hex 10,000. All right. If you wanted to do this in a one off R2 command, you can do that with the dash M as I'm showing here at M for the mapped address, hex 10,000. The architecture, which is A dash A is arm. The size like the bit width is 16 for thumb. And this is a bit of a weird round hole or a square peg and a round hole because thumb isn't necessarily 60 bit addressing. And that'll actually bite us when we're doing data printing. But you have to say B16 to get it to disassemble and thumb. And then you just give it the file. And this is the file that I got from the open source build of a vifirmware from open XE. Okay. Now we don't necessarily want to just do the command line version of this because we're going to keep adding stuff in. It's kind of like when you build a project night of pro, you have like an IDB, right? Rather than work with an IDB, we're going to have this like config file for right there. And we're going to keep building in little commands. So instead of that one line command, we're going to start with like this R2 script file. And I'm going to set the architecture. It's asm arc, asm CPU, asm bits. So this E command is setting config values. And under the hood, when you do those command line switches for dash A and dash B, that's really what's happening is just setting these config values. Okay. So then I'm going to say, okay, the bin address is hex 10,000. I'm going to call something flash, the F flash. So F is the flag command. In RAID air, you can name any address by just calling it a flag. So F flash is hex 10,000. And then O is for open files. So ON, I'm mapping a new file, the VI firmware file, at the address flash, which I just called 10,000. Okay. And then I'm setting this thing VA. With RAID air, it knows the difference between file addresses and virtual memory addresses. And now that I've mapped the file, we need to tell RAID air to switch into that virtual address space because I've just mapped it, right? So now I'm going to start referring to things by hex 10,000 instead of zero. Zero would be the file offset. Hex 10,000 is the virtual offset. Right? So I'm going to switch to VA. And then lastly, the capital S, I'm adding a section. So I'm creating a section for the flash, giving next key little bits, and dollar S is the size of the file. And that's the kind of RAID air magic that you just kind of get used to. And you write this once in the config file, and then you just kind of move on, right? Okay. So what else we got to do? We know that there's a loader loop in this firmware. Loader loops are for C runtime, you know, it takes like your segment that's packed up into the binary file and puts it into the writable data segment, for example. That's what we're going to do here. We're going to emulate that. We know that it does a copy from 32EBC up to this million C8 hex address. And we know the length. So we're going to define data as this million C8. And then we're going to go and make another section. And this time you'll notice that the offset is different, right? Because the sections when you make them, they refer to the file offset. So I'm doing it, I'm making the section start from 22, not 32. But it'll be mapped at 32 because that's the map address, right? And then the last command, now everything's set up, we actually know enough to use RAID airs like search for preludes, you know, like push, you know, every time you start a function, it's always the same little push and set up of the stack. And RAID air knows how to search for that. So you can go AAP, it'll search through all the code sections that you define, and it'll define functions that it recognizes as preludes. And that's a really great command for raw binaries. So at this point, we've mapped the code. And we have search for preludes. And PowerPoint crashed? I don't know. Let's try again. We might have to drink. Let's see. Okay. Can you see that? Oh, good. And it crashed again. This is great. I should have made backup, backup strats. That's what I really needed. Okay. Right. So we have everything kind of mapped. I'm going to try to present, no, I'm not going to present this like, it's just going to crash again. We have everything mapped, okay? But you can see here when I'm showing you, when you just kind of dump the memory, you're not seeing, for instance, that there's a string defined here. Like if it found the string, it would say str.signal1, it had identified the string, Radar would have. And when you do the disassembly, like right here, instead of seeing disassembly of op codes, you actually see that it was data. Right? Like, if you use IDEPRO before, there's a difference between saying it's code or saying it's a quad d-word. Right? What we want to see here to actually look at the data structures is turn this stuff into data. So it's not enough that we've mapped it. We have to actually somehow massage the information to get it together. So in this slide, which I'm sure won't crash PowerPoint, good. I'm showing you that you can ask Radar what it knows about strings. So here I'm saying, hey, Radar, IZ, what strings do you know? And it says nothing, nothing at all. But you can ask Radar to search through the entire file and just do like a string match, just like, you know, GNU strings does. And it says, I know all these strings. But if you look at the addresses, they're all in 22. Right? They're not in the data segment that we created. They're in the wrong base offset. So the problem we have now is we have to actually take all those strings and map them where we want them to go. Probably with a patch to Radar, you could fix this because IZ should do all data segments. But when you make a data segment, it doesn't recognize it. It only sees it when it comes from an L file. So this happens a lot when you're using Radar. And the solution is always just script it. Right? So I like Python. You could script it with Ruby. I know that there's like, you know, choices like VIEmax, Ruby, Python. But R2Pype lets you script Radar. Very simple Python script. I'm looking at the output of IIZ. And then I'm just adding that hex 10,000 to the base so that I can redefine all the strings. Right? So then when I'm done that, they're all redefined. All right. We need to groom the data, too. Right? Because we know that when we looked at that data section in memory, we saw disassembly. We didn't see quad words. Craig Heffner wrote a really nice script for Ida Pro called codatify. When you're looking at firmware files, it's really useful to use this because it just kind of like grooms the entire data segment, makes everything a quad word, sets everything to an offset type. And then what you get is like nice aligned data that automatically has cross references. So when you just start looking at X refs and start looking at data segments, it just starts popping out at you. With Radar, you don't get that automatically. But we can script it. Right? And what we're doing here is just walking the entire area of that data segment we created, defining everything as a quad word, and then creating a data reference of the value of that quad word. So you might be left with a bunch of false positives, but it's better to have a bunch of false positives than have none of the cross references at all. Okay. So here's a look at what our project file is now. You can see we have the data segment. All the stuff we did before is in gray, and I'm highlighting in white how you actually execute those Python scripts. So Radar has this weird, has the shebang idiom. Right? So you go hash, bang, or exclamation point, Python to run my Python script, and then I give it the two arguments. I'm just, all I'm doing, my project file now includes those two scripts that we defined. Now, I know we looked at a lot of strings and text and stuff, so I just wanted to give you a funny picture. Take a break. But there will be more commands. Okay. More commands. So we're loading stage three. Everything is all set. We know from our previous research that can signals, the whole array starts at this particular address. Just let's assume that you can figure it out by looking at the cross refs. If we go to that point and we say, hey, Radar, what cross refs are there? It says, okay, good. Now we have cross refs. See, code data file went, set everything as it would quad word and made data cross refs, and there's the proof. We actually have our data cross references. And if we disassemble at that location, we don't see disassembly. We now see nice quad word statements, which is kind of like what you see in Ida Pro after you set everything to the data type, right? This helps us inspect the data better. Lastly, there's this really nice command called PXR. It does telescoping. So if anyone uses like Ponebug or any of those GDB add-ons, telescoping is where you take the value on your stack and you just keep treating it like a pointer until you can't treat it like a pointer anymore. So you get this view of memory as a telescopes, right? And PXR does that for you automatically. So you can see PXR is telling us, yep, this particular address is pointing to something in data and that's pointing to something in data. Not good. That's all set. And we can see that we actually are referring to a string signal one, and it's actually starting to map to that structure really well, right? What we would really love to be able to do is say, okay, if this signal is called tire pressure, what can message is that in? Right? That's kind of like what we would like to know, right? If you had some vehicle and you wanted to figure out where's the tire pressure signal, that's what you'd like to know. And this kind of telescoping isn't telling us enough. We want to go backwards to get all that mapping information. Okay. What we really want is types, right? Radar actually knows how to parse header files and how to pretty print types. So we could eventually tell it, hey, you know, we know this is a pointer to can message. And we know that this is a pointer to a string. Can you just pretty print that for me so I can see the ID in the string right next to each other? The answer is, yes, you can. The first problem you run into is if you rent load a raw binary file, you don't get any basic types, right? So here I'm asking Radar, hey, I opened that raw binary file. What types do you know about? I'm saying T, enter. It says nothing. I don't know any types. Okay. So what if I ask you to give me the types and radar commands? Because the star post fix turns any output from instead just printing like the information in human form to printing it in Radar command so you can just reuse it. It says, no, sorry, I don't know any Radar commands for types either. The workaround is you just open any L file that's close to what you want to do and then use that T star command to tell that instance of Radar to dump all its type information to a file, which I'm doing with like a redirect here at the bottom, right? And then when I go to the other instance of Radar, I can load that up, see the dot. I can load the types 32 file. So I got all the basic info and I'm like, great, I got the basic types. I'll just go and load the header file from open XC, it'll be fine, right? No, it's not fine. Seg fault. But we can fix that. You take the header file, you massage the header file a little bit. I won't bore you with that. You just kind of like, you know, fix the types. And all of a sudden we have all the info. Okay, so here's our new project file. We made some more flags, see the F commands, we're saying these are addresses that have important names. I'm doing dot types 32 to load in that basic type information. And then I'm just loading a can util.h file, which I've massaged into something that doesn't make Radar seg fault, which is useful. Now I have to set the bit width back to 32. When you're doing disassembly, it needs to be 16 to recognize thumb. But when you're doing the data inspection, you want the pointers to all be 32 wide. And if you leave it as 16, it treats pointers as half words, right? And then you just don't even see the data. So we set it back to 32 to continue. All right. Where are we at? We can go to that can signal starter, right? I can ask Radar, what type information do you know about this can signal type? And it prints back this PF thing. So what it's telling me is this is a PF, a print format command for dumping that can signal structure, right? Now it's quite a long string. You know, you have this kind of PZBBFFF and then a whole bunch of names, okay? If we just do that straight up, things don't really line up properly and we don't get stuff like instead of seeing the address of that can message, we really would just like to see the arbitration ID in that message, right? That's the mapping we want to go for. And then you notice that factor doesn't even make sense. You can't have a factor of zero because if you take a number and you multiply that by zero, you're not going to get that number back. It's a useless can signal. So something has gone wrong. There's a lot of format commands, like a lot of them. Each one of them does something subtly different. If you're going to start doing this kind of thing, I recommend starting with that header file because then at least you don't have to just like grok the entire format. You can tweak one format at a time. And what I did was PF question, question to get this list, okay? So we have that signal start. I'm going to first fix the can message type, which is the thing that the signal structure refers to because what I want to see is the arbitration ID. And that's really the only thing I care about in this message structure. See, it's got an arbitrary, a bus, an ID, a format, frequency and stuff. I don't care about the rest. I just want that ID. So I know that the print format statement as PDE and all that stuff, I'm going to ignore things. And you can ignore stuff with colons and dots. So I'm going to change it to, you know, colon X dot colon colon that whole statement you see there with the PF. And all of a sudden, all I see is the ID. Great. That's all I want, right? So I'm going to make a format identifier, like a custom for an identifier. I'm going to call it just the can message arbitration ID, please. And it will remember that. And I can use that command. So now what I said is print me the current thing as a pointer to the structure. And I got back exactly what I wanted. I got just the arbitration ID. So I'm sitting here at the top of the array, sitting on a pointer to the structure that has the arbitration ID. And I asked it to print me just the ID. We're good. So now we can build up the rest. Another break. I know I'm doing a lot of text. Here you go. Funny picture. Okay. All right. So back to the can signal structure. That's a really, really big print format statement. And it misaligned. So you look at the one that I'm highlighting in blue, there was an alignment problem in the can signal structure. And I had to add those two dots between the N1 and the F. And I've told it now, okay, I got two pointers, two bytes, two things you should ignore, and then a whole bunch of floats. And the good news is when you do that, it's exactly the info you want. So we have our bit position. We have our bit size. We have a factor that makes sense. We don't have like a pointer to the message with the arbitration ID yet. We need to get that to work. The problem is you can print either a pointer to a string in a format specifier or a pointer to a structure in a format specifier, but you cannot print both a pointer to a structure and a pointer to a string in a format specifier. It just doesn't work for some reason. So more workarounds. We'll just print twice, right? But this gives us a chance to talk about macros, right? So Radar has this idea of macros. See the little round brackets. So I define this thing called just print something. And it's, you know, doing one print command, comma, another print command. And then I can just call that macro by putting in a round brackets later. We're off to the races. Okay. So we load this thing up. I can now say invoke that macro. See the round brackets on print signal. And then I'm using the iterate operator. So I'm telling Radar to run that command on every address between the steps. It's just like Python's range operator. This address to that address with this step. And that means I can actually print each thing in a row in that whole array and we get what we're looking for, right? So you got the message structure pointer, which is just showing you the arbitration ID right next to the bit position and the bit size and the factors and the max values. And that's all the really key information that you needed, right? If you compare like what's in the JSON from the build to what you can now pretty print with Radar, all the info you want is right there, right? So we're good. Now, because I like pain and we're not over time, let's do a live demo. What do you think? Live demo? All right. Let's do this. So actually, I'm in the right folder. This is good. All right. We're going to invoke Radar. I have created the final stage, final boss, okay? We have our macro defined. I've also introduced a new command here with CF. CF lets you do like what you do in IDA where you set an address to be formatted a particular way. So you can tell it here's that print format statement and just make it persistent on this address. So I can go through all of memory and make it formatted so that when I do the disassembly, I can actually see the arrays. Here we go. Final boss stage like that. Good. We'll seek to can signals start. No, we won't. Why not? Come on, live demo. I did the wrong stage, guys. Here we go. Here we go. Final boss. Yep. All right. So we formatted memory. Sorry. For those of you who can't see my keyboard, I'm typing V and then I hit the letter P to go to the disassembly view. And when we're looking at disassembly, you know, we see the D words and when we're properly aligned in every place, we see the nice structures. And this is all the way through that array of can signals. So we did it. Are there any questions? I know that was really fast and a lot of commands. This is the reference for commands. Let me put it up again so you guys can take some pictures. I'll definitely get these slides out as well. Hey, thanks for your attention, guys. I'm going to have another drink.
 So I'm going to be talking to you about uh, Radare 2. It has a lot of pronunciations. Uh,  people tell me that I'm probably saying it wrong. I'm just going to keep saying Radare 2. I'm sorry,  that's what I'm going to do. It's going to be about 25 minutes. I'm talking about OpenXE, which is  uh, Ford's platform for moving canned messages over Bluetooth, uh, to like mobile apps and it's  kind of neat. Because OpenXE is open source, we can actually look at the firmware and kind of skip  a lot of the discovery parts and just focus on reverse engineering with Radare. So it's really,  it's going to be a whole bunch of command line stuff. The talk is kind of in the Gen2 quadrant.  There's going to be just a lot of commands and you know, I'll have the slides up. You can refer  to the commands later. I'll try to describe what I'm doing too, but it's, it's not going to be in  Boon 2 style. It's going to be kind of like just fly, you know, go. So we'll see. Well first up  OpenXE, you know, uh, this is a cool platform that kind of takes canned messages and translates them  into message pack format, which is like JSON and it lets you build these mobile apps for iOS  recently for Android. It's actively developed. Um, it's, it's pretty fun. I recommend you go  check it out. They give you hardware platforms and the software development. Uh, so you can do some  cool stuff with it. Radare. So uh, Radare 2 is like this reverse engineering suite of tools. There's  a whole bunch of command line utilities you can use like RA Band and RA Hash. I'm going to be  talking almost exclusively about R2, which is like the reverse engineering part of it. So I'll  show you a little bit of Radare. Uh, I really wanted to do everything like command line style. Um,  but this is actually my backup deck because the command line stuff just didn't work. But I'm going  to do this style of like, here's a fake command prompt and I'm going to kind of scroll down. So a  Radare session, you might open up a file. It's like an L file from binary samples and then you  want to analyze it. So AA, every command in Radare starts with like hierarchical letters. So A is  for analysis commands and AA is just like do the basic analysis. Okay. It says great. I looked at  all the flags and I found some stuff. Thanks. Uh, S is for seek. So I'm going to like seek to the  function called main. There I did it. And then more analysis commands, AX is for listing cross  references. So here I'm just listing all the cross references that happen to be referring to main.  And you can see that the analysis actually completed because of the whole bunch of cross  references. This is great. And this is usually the experience you get with Radare, especially on  like L files and PE files and stuff. It's really great at finding all that metadata, uh, in the  symbol table and then helping you kind of walk your way through the binary. Now when you're  dealing with a raw firmware file, just like a bin file, you don't actually get all those nice  symbol exports, right? So you can open up in Radare. You can ask it to do the analysis. It'll  say, great, I analyze zero things for you because I don't know where main is, right? There's nothing  there. There's no metadata. So you have to actually kind of teach Radare about where the file goes,  do some searching for functions. Uh, and first Easter egg, Radare has a, has Clippy. Clippy is  installed. So you can actually get Clippy to tell you things if you, uh, you want a little bit of  help. Uh, he likes to help. Radare also does really great, uh, control flow graph visualizations in  the terminal. So this is actually like text mode using UTF-8 lines. Uh, and all the disassembly for  every disassembly, uh, flavor that it supports, it'll do this kind of control flow layout, which is  gorgeous. Uh, it's VV to get there. I'm not going to be showing you disassembly because this talk is  really about extracting data. So we're going to be looking at how to pretty print, uh, canned signal  information inside OpenXC. So not disassembly, uh, more like data stuff. But if you want to just have  great control flow graphs for free, check out Radare. It's great. Okay. It's going to be a lot of  commands. I put together this summary of all the commands that I'm going to use. Uh, I will also  show this slide at the end. So, you know, you'll have lots of time to take pictures for it. It'll  probably be in a PDF somewhere as well. You can see that the commands are all really hierarchical,  right? All the analysis commands start with A. All the printing commands starts with P. Uh,  information for the binary starts with I. And then there's two different things. And the most  important one is really the question mark. You can use question mark as a post fix. And if you put  it at the end of any letter, basically, it'll tell you what that letter is as a command. And the  help in, the help information in the command line for Radare 2 is really great. So if you know that  to put question mark at the end, you can actually walk your way through Radare pretty well. The  other thing is question mark first is more like an echo command. So you can, question mark E will  echo like actual echo command line, the normal stuff. Question mark V shows you like hexadecimal  values. Question mark capital E shows you Clippy. We saw that already. So to recap, just to make sure  we know we're talking about, OpenXC takes these JSON files as part of its build and turns them  into these CAN signal structures. Okay? And what we're going to do is go through the Radare  commands necessary to actually go backwards and get the information out of the CAN signal structures  that are in the firmware. They're going to kind of reverse that arrow. This is reverse engineering,  right? Okay. This isn't the first time OpenXC has been reversed. I've given some talks about  doing this with Ida Pro. Ida Pro is very expensive and this is now free. I run the same time I did  the sans talk. Someone who had to handle BSMT put out a blog post detailing how to do the steps  with some Ida Pro Python scripts. So BSMT's blog has like a fully automated way to do this using  Ida Pro, which is kind of cool. Also, you know, I'm not the person who invented firmware reverse  engineering. I'm totally standing on the shoulders of giants and there are many. I really appreciate  the help of Craig Hefner and his blog post. I recommend all of his work. And then finally,  I didn't invent Radare. That's done by Trufey or Pancake, Pancake Knop Code. He actually has a  talk here, this YouTube link, where he takes the MD380, the Titerra radios and he reverses the  ARM firmware in the Titerra radio. It's a firmware blob. It's using a lot of the same techniques.  So I'm really building on all this previous work here. Okay. We don't have a whole lot of time.  So I'm really just going to do the yellow stuff. Right? I'm going to assume, okay, we already know  that we've got the firmware in our hand. You know, that's always a hard step with the device you  just got, maybe getting the firmware. We already know the architecture. We already know the load  address. We're just going to assume that stuff. And we're going to go do this yellow stuff,  load it into R2. We're going to assume that we figured out where the loader loop is, you know,  where the C runtime stuff does the copying. And we'll just do a copy for ourselves. And then  we'll do the pretty printing of the structures. Okay. So first up, we want to load this thing.  So we already know because we're smart and we did some reverse engineering already that the  thing can get loaded at hex 10,000. All right. If you wanted to do this in a one off R2 command,  you can do that with the dash M as I'm showing here at M for the mapped address, hex 10,000.  The architecture, which is A dash A is arm. The size like the bit width is 16 for thumb. And this  is a bit of a weird round hole or a square peg and a round hole because thumb isn't necessarily 60  bit addressing. And that'll actually bite us when we're doing data printing. But you have to say  B16 to get it to disassemble and thumb. And then you just give it the file. And this is the file  that I got from the open source build of a vifirmware from open XE. Okay. Now we don't  necessarily want to just do the command line version of this because we're going to keep adding  stuff in. It's kind of like when you build a project night of pro, you have like an IDB, right?  Rather than work with an IDB, we're going to have this like config file for right there. And we're  going to keep building in little commands. So instead of that one line command, we're going to  start with like this R2 script file. And I'm going to set the architecture. It's asm arc, asm CPU,  asm bits. So this E command is setting config values. And under the hood, when you do those  command line switches for dash A and dash B, that's really what's happening is just setting  these config values. Okay. So then I'm going to say, okay, the bin address is hex 10,000. I'm  going to call something flash, the F flash. So F is the flag command. In RAID air, you can name any  address by just calling it a flag. So F flash is hex 10,000. And then O is for open files. So  ON, I'm mapping a new file, the VI firmware file, at the address flash, which I just called 10,000.  Okay. And then I'm setting this thing VA. With RAID air, it knows the difference between file  addresses and virtual memory addresses. And now that I've mapped the file, we need to tell RAID  air to switch into that virtual address space because I've just mapped it, right? So now I'm  going to start referring to things by hex 10,000 instead of zero. Zero would be the file offset.  Hex 10,000 is the virtual offset. Right? So I'm going to switch to VA. And then lastly, the capital  S, I'm adding a section. So I'm creating a section for the flash, giving next key little bits,  and dollar S is the size of the file. And that's the kind of RAID air magic that you just kind of  get used to. And you write this once in the config file, and then you just kind of move on, right?  Okay. So what else we got to do? We know that there's a loader loop in this firmware. Loader  loops are for C runtime, you know, it takes like your segment that's packed up into the binary  file and puts it into the writable data segment, for example. That's what we're going to do here.  We're going to emulate that. We know that it does a copy from 32EBC up to this million C8 hex  address. And we know the length. So we're going to define data as this million C8. And then we're  going to go and make another section. And this time you'll notice that the offset is different,  right? Because the sections when you make them, they refer to the file offset. So I'm doing it,  I'm making the section start from 22, not 32. But it'll be mapped at 32 because that's the map  address, right? And then the last command, now everything's set up, we actually know enough  to use RAID airs like search for preludes, you know, like push, you know, every time you start a  function, it's always the same little push and set up of the stack. And RAID air knows how to  search for that. So you can go AAP, it'll search through all the code sections that you define,  and it'll define functions that it recognizes as preludes. And that's a really great command for  raw binaries. So at this point, we've mapped the code. And we have search for preludes.  And PowerPoint crashed? I don't know. Let's try again. We might have to drink.  Let's see. Okay. Can you see that? Oh, good.  And it crashed again. This is great.  I should have made backup, backup strats. That's what I really needed. Okay. Right. So we have  everything kind of mapped. I'm going to try to present, no, I'm not going to present this  like, it's just going to crash again. We have everything mapped, okay? But you can see here  when I'm showing you, when you just kind of dump the memory, you're not seeing, for instance,  that there's a string defined here. Like if it found the string, it would say str.signal1,  it had identified the string, Radar would have. And when you do the disassembly, like right  here, instead of seeing disassembly of op codes, you actually see that it was data. Right? Like,  if you use IDEPRO before, there's a difference between saying it's code or saying it's a quad  d-word. Right? What we want to see here to actually look at the data structures is turn  this stuff into data. So it's not enough that we've mapped it. We have to actually somehow  massage the information to get it together. So in this slide, which I'm sure won't crash  PowerPoint, good. I'm showing you that you can ask Radar what it knows about strings. So here  I'm saying, hey, Radar, IZ, what strings do you know? And it says nothing, nothing at all.  But you can ask Radar to search through the entire file and just do like a string match,  just like, you know, GNU strings does. And it says, I know all these strings. But if you look  at the addresses, they're all in 22. Right? They're not in the data segment that we created.  They're in the wrong base offset. So the problem we have now is we have to actually take all those  strings and map them where we want them to go. Probably with a patch to Radar, you could fix  this because IZ should do all data segments. But when you make a data segment, it doesn't  recognize it. It only sees it when it comes from an L file. So this happens a lot when you're using  Radar. And the solution is always just script it. Right? So I like Python. You could script it with  Ruby. I know that there's like, you know, choices like VIEmax, Ruby, Python. But R2Pype lets you  script Radar. Very simple Python script. I'm looking at the output of IIZ. And then I'm just  adding that hex 10,000 to the base so that I can redefine all the strings. Right? So then when  I'm done that, they're all redefined. All right. We need to groom the data, too. Right? Because  we know that when we looked at that data section in memory, we saw disassembly. We didn't see  quad words. Craig Heffner wrote a really nice script for Ida Pro called codatify. When you're  looking at firmware files, it's really useful to use this because it just kind of like grooms the  entire data segment, makes everything a quad word, sets everything to an offset type. And then what  you get is like nice aligned data that automatically has cross references. So when you just start  looking at X refs and start looking at data segments, it just starts popping out at you.  With Radar, you don't get that automatically. But we can script it. Right? And what we're doing here  is just walking the entire area of that data segment we created, defining everything as a  quad word, and then creating a data reference of the value of that quad word. So you might be left  with a bunch of false positives, but it's better to have a bunch of false positives than have none  of the cross references at all. Okay. So here's a look at what our project file is now. You can  see we have the data segment. All the stuff we did before is in gray, and I'm highlighting in white  how you actually execute those Python scripts. So Radar has this weird, has the shebang idiom.  Right? So you go hash, bang, or exclamation point, Python to run my Python script, and then I give  it the two arguments. I'm just, all I'm doing, my project file now includes those two scripts that  we defined. Now, I know we looked at a lot of strings and text and stuff, so I just wanted to  give you a funny picture. Take a break. But there will be more commands. Okay. More commands.  So we're loading stage three. Everything is all set. We know from our previous research that can  signals, the whole array starts at this particular address. Just let's assume that you can figure  it out by looking at the cross refs. If we go to that point and we say, hey, Radar, what cross refs  are there? It says, okay, good. Now we have cross refs. See, code data file went, set everything as  it would quad word and made data cross refs, and there's the proof. We actually have our data cross  references. And if we disassemble at that location, we don't see disassembly. We now see nice quad  word statements, which is kind of like what you see in Ida Pro after you set everything to the  data type, right? This helps us inspect the data better. Lastly, there's this really nice command  called PXR. It does telescoping. So if anyone uses like Ponebug or any of those GDB add-ons,  telescoping is where you take the value on your stack and you just keep treating it like a pointer  until you can't treat it like a pointer anymore. So you get this view of memory as a telescopes,  right? And PXR does that for you automatically. So you can see PXR is telling us, yep, this  particular address is pointing to something in data and that's pointing to something in data.  Not good. That's all set. And we can see that we actually are referring to a string signal one,  and it's actually starting to map to that structure really well, right? What we would really love  to be able to do is say, okay, if this signal is called tire pressure, what can message is that  in? Right? That's kind of like what we would like to know, right? If you had some vehicle and you  wanted to figure out where's the tire pressure signal, that's what you'd like to know. And this  kind of telescoping isn't telling us enough. We want to go backwards to get all that mapping  information. Okay. What we really want is types, right? Radar actually knows how to parse header  files and how to pretty print types. So we could eventually tell it, hey, you know, we know this  is a pointer to can message. And we know that this is a pointer to a string. Can you just pretty  print that for me so I can see the ID in the string right next to each other? The answer is, yes,  you can. The first problem you run into is if you rent load a raw binary file, you don't get any  basic types, right? So here I'm asking Radar, hey, I opened that raw binary file. What types do you  know about? I'm saying T, enter. It says nothing. I don't know any types. Okay. So what if I ask you  to give me the types and radar commands? Because the star post fix turns any output from instead  just printing like the information in human form to printing it in Radar command so you can just  reuse it. It says, no, sorry, I don't know any Radar commands for types either. The workaround  is you just open any L file that's close to what you want to do and then use that T star command  to tell that instance of Radar to dump all its type information to a file, which I'm doing with  like a redirect here at the bottom, right? And then when I go to the other instance of Radar,  I can load that up, see the dot. I can load the types 32 file. So I got all the basic info and  I'm like, great, I got the basic types. I'll just go and load the header file from open XC, it'll be  fine, right? No, it's not fine. Seg fault. But we can fix that. You take the header file, you massage  the header file a little bit. I won't bore you with that. You just kind of like, you know, fix the  types. And all of a sudden we have all the info. Okay, so here's our new project file. We made some  more flags, see the F commands, we're saying these are addresses that have important names. I'm doing  dot types 32 to load in that basic type information. And then I'm just loading a can util.h file,  which I've massaged into something that doesn't make Radar seg fault, which is useful. Now I have  to set the bit width back to 32. When you're doing disassembly, it needs to be 16 to recognize  thumb. But when you're doing the data inspection, you want the pointers to all be 32 wide. And if  you leave it as 16, it treats pointers as half words, right? And then you just don't even see the  data. So we set it back to 32 to continue. All right. Where are we at? We can go to that can  signal starter, right? I can ask Radar, what type information do you know about this can signal  type? And it prints back this PF thing. So what it's telling me is this is a PF, a print format  command for dumping that can signal structure, right? Now it's quite a long string. You know,  you have this kind of PZBBFFF and then a whole bunch of names, okay? If we just do that straight  up, things don't really line up properly and we don't get stuff like instead of seeing the address  of that can message, we really would just like to see the arbitration ID in that message, right?  That's the mapping we want to go for. And then you notice that factor doesn't even make sense.  You can't have a factor of zero because if you take a number and you multiply that by zero,  you're not going to get that number back. It's a useless can signal. So something has gone wrong.  There's a lot of format commands, like a lot of them. Each one of them does something subtly  different. If you're going to start doing this kind of thing, I recommend starting with that  header file because then at least you don't have to just like grok the entire format. You can tweak  one format at a time. And what I did was PF question, question to get this list, okay? So  we have that signal start. I'm going to first fix the can message type, which is the thing that  the signal structure refers to because what I want to see is the arbitration ID. And that's  really the only thing I care about in this message structure. See, it's got an arbitrary, a bus, an  ID, a format, frequency and stuff. I don't care about the rest. I just want that ID. So I know  that the print format statement as PDE and all that stuff, I'm going to ignore things. And you  can ignore stuff with colons and dots. So I'm going to change it to, you know, colon X dot colon  colon that whole statement you see there with the PF. And all of a sudden, all I see is the ID.  Great. That's all I want, right? So I'm going to make a format identifier, like a custom for an  identifier. I'm going to call it just the can message arbitration ID, please. And it will  remember that. And I can use that command. So now what I said is print me the current thing as a  pointer to the structure. And I got back exactly what I wanted. I got just the arbitration ID. So  I'm sitting here at the top of the array, sitting on a pointer to the structure that has the arbitration  ID. And I asked it to print me just the ID. We're good. So now we can build up the rest. Another  break. I know I'm doing a lot of text. Here you go. Funny picture. Okay. All right. So back to the  can signal structure. That's a really, really big print format statement. And it misaligned. So  you look at the one that I'm highlighting in blue, there was an alignment problem in the can  signal structure. And I had to add those two dots between the N1 and the F. And I've told it now,  okay, I got two pointers, two bytes, two things you should ignore, and then a whole bunch of floats.  And the good news is when you do that, it's exactly the info you want. So we have our bit  position. We have our bit size. We have a factor that makes sense. We don't have like a pointer  to the message with the arbitration ID yet. We need to get that to work. The problem is you can  print either a pointer to a string in a format specifier or a pointer to a structure in a format  specifier, but you cannot print both a pointer to a structure and a pointer to a string in a  format specifier. It just doesn't work for some reason. So more workarounds. We'll just print  twice, right? But this gives us a chance to talk about macros, right? So Radar has this idea of  macros. See the little round brackets. So I define this thing called just print something. And it's,  you know, doing one print command, comma, another print command. And then I can just call that macro  by putting in a round brackets later. We're off to the races. Okay. So we load this thing up. I can  now say invoke that macro. See the round brackets on print signal. And then I'm using the iterate  operator. So I'm telling Radar to run that command on every address between the steps. It's just like  Python's range operator. This address to that address with this step. And that means I can  actually print each thing in a row in that whole array and we get what we're looking for, right? So  you got the message structure pointer, which is just showing you the arbitration ID right next to  the bit position and the bit size and the factors and the max values. And that's all the really  key information that you needed, right? If you compare like what's in the JSON from the build  to what you can now pretty print with Radar, all the info you want is right there, right? So we're  good. Now, because I like pain and we're not over time, let's do a live demo. What do you think?  Live demo? All right. Let's do this. So actually, I'm in the right folder. This is good. All right.  We're going to invoke Radar. I have created the final stage, final boss, okay? We have our macro  defined. I've also introduced a new command here with CF. CF lets you do like what you do in IDA  where you set an address to be formatted a particular way. So you can tell it here's that  print format statement and just make it persistent on this address. So I can go through all of memory  and make it formatted so that when I do the disassembly, I can actually see the arrays. Here  we go. Final boss stage like that. Good. We'll seek to can signals start. No, we won't. Why not?  Come on, live demo. I did the wrong stage, guys. Here we go. Here we go. Final boss.  Yep. All right. So we formatted memory. Sorry. For those of you who can't see my keyboard,  I'm typing V and then I hit the letter P to go to the disassembly view. And when we're looking  at disassembly, you know, we see the D words and when we're properly aligned in every place,  we see the nice structures. And this is all the way through that array of can signals. So we did it.  Are there any questions? I know that was really fast and a lot of commands.  This is the reference for commands. Let me put it up again so you guys can take some pictures.  I'll definitely get these slides out as well. Hey, thanks for your attention, guys. I'm going to  have another drink.
DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_0_3275.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_3276_4739.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_4740_5147.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_5148_7259.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_7260_7991.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_7992_8711.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_8712_9263.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_9264_9839.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_9840_11807.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_11808_13535.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_13536_13931.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_13932_15095.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_15096_18851.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_18852_19523.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_19524_19763.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_19764_21287.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_21288_22583.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_22584_23231.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_23232_23411.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_23412_23699.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_23700_24443.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_24444_28403.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_28404_31439.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_31440_33443.png DEF_CON_26_CAR_HACKING_VILLAGE_-_Ben_Gardiner_-_CAN_Signal_Extraction_from_OpenXC_with_Radare2_Uoevu_33444_35509.png