Technical RSA Bypass Explained

carabuser

Captain
Vendor
Oct 2, 2019
1,042
1
1,175
0
UK
Ride
Z4 35i & 335i
I’ve been wanting to make a thread about this for a while. Every single person here tuning their DME has this clever little exploit applied to their DME so I wanted to document it in case anyone was curious.

To give some context on the discussion I’ve put together a high-level memory map of the bin file. This is what the 2MB file that you make changes to actually looks like:

2MB ROM LAYOUT.png


A brief overview of the areas:
The first area, labelled as the Boot-SW (Supplier) is what some refer to as the SBOOT. This is a small bit of code early on in the DME that handles the base functions of the chip. This contains the ISN, serial number and a backup copy of the vehicle VIN and is often referred to as the locked section of memory as it cannot be written to via the normal methods.

After that we have another area of Boot-SW, this one is customer specific often referred to as CBOOT and contains the code that BMW wrote to handle all the serial interfaces and reprogramming procedure. This can be reprogrammed along with everything after this point.

After that we have a section of ECU-SW which is the actual code that is responsible for the operation of the vehicle (boost control, fuel control, torque management). There are 2 that make up what is referred to as the software. This makes up the vast majority of the data in the 2MB file. This is what people refer to when they use terms like I8A0S, IJE0S or INA0S, this is the name of the software in the car.

We then have the calibration data. That is what most people know as the “Tune”. To put this into layman’s terms, this is the engine’s settings. This area is what is manipulated when you use TunerPro and the public XDF.

The sections in between, in white, are areas that contain the RSA signatures which are referred to as security keys and the file checksums which we won’t get into.


Now we get to the purpose of the post. The “RSA Bypass”:

All tools that read and write to the MSD80 and MSD81 (COBB, OpenFlash, MHD etc) use exactly the same process to do so. That all seemed to have copied each other down the line. I’m not sure who exactly created the original RSA bypass but I believe that COBB purchased/licensed their method and then the rest just coped it. Whoever came up with the original bypass is a real genius and undoubtedly put a lot of blood, sweat and tears into the process. I’m not sure if the trick originated on the MSD80, or if it was an existing trick that was used elsewhere that was just adapted for the MSD8x, but I’ll explain how it’s done in the context of the MSD8x.

To give context on what the RSA bypass is, we need to quickly run through what RSA protection actually is. I’m no expert on cryptography but I’ll give my understanding of it and hopefully if I mess it up, someone can correct me.

The overall function of the RSA protection is to prevent anyone from making any changes to the code inside the DME. This is to protect their warrantied engines and probably a legal requirement to protect emissions related inspection routines. To do this, RSA uses a pair of keys, the private key, that BMW keeps and is still completely secret and a public key that is written into the DME. BMW will use their private key and feed it the contents of the bin into it and it will generate a “signature”. This is then written into spare space in the bin. Once the contents of the bin are written into the DME along with the signature, the DME will use its public key to validate that signature, if the signature is valid the DME will accept the code and boot up normally. If not, the DME will reject the new code and stay in a failsafe mode until a valid file is written.

On some older DMEs they used smaller 512bit keys, probably due to hardware capabilities at the time. People (clever ones) were able to crack these by brute-force and just use the cracked private key to sign their modified files, I believe that's what they use on the MSV DMEs and old school slushbox TCUs. To prevent people cracking their new MSD80/81, BMW uses a 1024bit key and thus puts it outside of the capabilities of current brute-forcing (until quantum computing maybe).

Since brute force is off the cards, alternative exploits were investigated. The person responsible for the RSA bypass probably started off by decompiling the 2MB bin file and probing it for weaknesses. The weakness that we currently use relies on an oversight in the developer’s implementation of the RSA key verification process.

To explain the weakness, I need to add a little bit more detail to the above process of the BMW RSA signature generation. There are 2 signatures in the bin. One for the software and one for the calibration. We will just look at the software one since that is all that matters in this exploit. When the BMW software developers generate the RSA signature, they only look at certain sections of the bin. This can’t cover the entire bin contents because things like the signature itself will change after the signing is done and crucially, they also don’t check sections of memory that they expect to be blank which was the reason this exploit is possible. Once they generate the signature and write it into the bin, they convert that bin into an .0pa which is what WinKFP uses to flash the DME.

On the DME side, to match the process that the BMW engineers used at their end, the range of data that the DME looks at is defined in a table like this:
1697372848286.png



So, by looking at this table we can see the DME will take all the data currently in the chip between 80020000-8003FFFF, 80040000-80053DFF and 80080000-801FFC3F and then verify it with the public key. So as long as the data in those areas matches what BMW fed into the RSA generation using their private key we will pass the RSA check in the DME and our new software will be accepted by the DME. This is what happens when you update your DME using WinKFP and the 0pa and 0da files that in the DATEN files.

If you look at those ranges you can see that the second range looks suspect (80040000-80053DFF). This memory range is inside what should be the calibration sector. This is because the area of code that we referred to above as the CBOOT is actually the code that runs this signature check, so naturally it can’t be written to until the code has passed the RSA check. To verify the code before accepting it, the reprograming procedure requires that the area of the bin that contains the CBOOT code is parked into the calibration area temporarily until the DME can verify the signature, then it will take that code and overwrite the existing CBOOT code.

This is where things get clever. The exploit involves making a copy of the CBOOT code and modifying it to remove the part that verifies the signature, this essentially means the DME will always pass the RSA signature verification if we can manage to get the code accepted by the DME. But modifying this code will mean that it will no longer pass the signature verification while it’s parked in the temporary memory range.

To get around this problem we write both versions of our CBOOT code into DME, the first modified one in the area 80040000-80053DFF that will be written into the CBOOT upon a successful signature check, then the second copy of original unmodified code that we write into the spare calibration sector memory (0x80053E00-0x8007FFFF) which will not be used at all and be overwritten by the calibration data later on.

At this point we still have a problem with the signature as you can see in the above table, the DME will check the memory range where the modified CBOOT code is parked and will fail the signature check. To get around this issue we edit this table that lives over in the ECU-SW code. We do a similar process with this data, make a new copy of this table and place it in some spare memory that isn’t normally checked (the area after 801FFC3F). We then modify the original table so that instead of looking at the original areas where our modified code now lives, we point it to the blank memory areas where we wrote copies of the original code.

This now means once we write all this into the DME, it will check all that data and because all the data we are telling it to check is exactly the same as the data the signature was created with originally is all there, it will pass the check and write our modified code into the CBOOT area.

This now means that the code that is actively running in the CBOOT area of the DME will accept any new code. At this point the DME is “unlocked”.
 

shushikiary

Sergeant
Jun 4, 2018
310
185
0
Ride
335xi
Makes me wonder exactly what they do for protection on things like the flex fuel MHD tunes. They have some kind of encryption on them, but to do that they would have had to modify/fix the checking on the DME or else you can just throw a can bus analyzer on during a full flash write and "unlock" any tune you want.

I suppose I could just use a laterbach and get the JTAG or HSSP hooked up on the DME and a tri-core license and literally watch what it's doing.... but I have better things to do with my time at the moment.
 

shushikiary

Sergeant
Jun 4, 2018
310
185
0
Ride
335xi
Yea but there are almost always ways around that unless they do something like fuse bits, which most don't. I may or may not have friends who work for derive and do this for a living. (And I'm an embedded EE).
 

carabuser

Captain
Vendor
Oct 2, 2019
1,042
1
1,175
0
UK
Ride
Z4 35i & 335i
Makes me wonder exactly what they do for protection on things like the flex fuel MHD tunes. They have some kind of encryption on them, but to do that they would have had to modify/fix the checking on the DME or else you can just throw a can bus analyzer on during a full flash write and "unlock" any tune you want.

I suppose I could just use a laterbach and get the JTAG or HSSP hooked up on the DME and a tri-core license and literally watch what it's doing.... but I have better things to do with my time at the moment.
While the data exchange between the DME and tester are unencrypted I don't think there's anything stopping you reversing it. As you said, you can analyse the CAN traffic, but once you have the data you still need to understand it. I don't think there's any way of truly locking things down in a DME without doing something like changing the RSA keys for both security access file signing and fixing the exploit that I posted about here so that you actually go back to signing tuned files and locking them to ECU serial numbers. Even that would be vulnerable to someone sniffing the CAN traffic but they would then need their own flashing solution to make use of the data and the current flashing solutions out there don't offer the ability to flash custom code.

If you just intended on capturing the locked OTS maps and flashing it as a custom map in MHD that'll work, but there's nothing special in there. If you can't produce a custom tune to achieve the same result as the OTS maps then you are going to struggle to improve on the OTS map by making any changes yourself.
 

shushikiary

Sergeant
Jun 4, 2018
310
185
0
Ride
335xi
No the point would be to modify the tune to how I want it rather than being annoying and asking for 50 revisions of the tune, or how it can sometimes take more than week for a tuner to get back to you. I've asked to pay for a base tune in the past and everyone says no. I'm happy to tune it my self, I did it before I went large single, but the changes were big enough with a large single turbo I didn't want to start from scratch so I paid for a tune, but now I'm beholden to the tuner to make any changes (that's what I hate). There are issues, like it trying to do silly things with lean spool mode under 3k RPM that drive me nuts, and I'd love to go in and just disable it. Or be able to go in and tweak my WGDC number to get them how I want them, etc.

So for me, it would totally be about modifying the tune. The hardest part about the can bus sniff on full write is pulling the data out of the packets and organizing it properly to get a bin file. Easiest thing to do would be to record a full write back to stock as you have the bin to compare already, use it to figure out the order of what data in what packet goes to what address in the bin, then do a full write of the tune and piece it back together hoping its the same. That's where I'd start if I was going to do it.

Heck, I'd be happy to sign an NDA so I can get my pants sued off if I shared the tune if someone was willing to unlock it so I don't have to pester them over and over again for changes, I'd rather do that then do all the work mentioned above. So far though the minor annoyances combined with other projects have made it not high enough on my priority list to attempt. Currently building an LS 408 stroker for my jeep, and I'll just throw a holley dominator on it and tune it my self.
 
  • Like
Reactions: wheela

78dec3b1

New Member
Oct 28, 2023
1
3
0
So for me, it would totally be about modifying the tune. The hardest part about the can bus sniff on full write is pulling the data out of the packets and organizing it properly to get a bin file. Easiest thing to do would be to record a full write back to stock as you have the bin to compare already, use it to figure out the order of what data in what packet goes to what address in the bin, then do a full write of the tune and piece it back together hoping its the same. That's where I'd start if I was going to do it.
FYI: The Continental specification 4CC3KM0S.pdf documents the flash messages requestDownload and transferData ~page 7752, which are sent using ISO 15765-2.
 

Attachments

  • tool.zip
    55 KB · Views: 139

darchap

New Member
Jan 16, 2021
4
0
0
Hello, is this behaviour MSD's only or could the same exploit be applied to other ECUs? (ie EDC)
 

darchap

New Member
Jan 16, 2021
4
0
0
Could possibly work anywhere that the RSA table isn't covered by the signature itself.
Is there any way I could check this? I would like to try modifying a 0da file and see if I could flash it back with winkfp, but first I would like to know a way to check if RSA could be bypassed or not
 

carabuser

Captain
Vendor
Oct 2, 2019
1,042
1
1,175
0
UK
Ride
Z4 35i & 335i
Is there any way I could check this? I would like to try modifying a 0da file and see if I could flash it back with winkfp, but first I would like to know a way to check if RSA could be bypassed or not
You would need to look at the 0pa sector and find the RSA table then see of it covers itself. You also need empty space that isn't covered by the RSA table that you can redirect to.
 

3xpent

New Member
Mar 15, 2025
4
3
0
Very interesting post, really appreciate it!
"in case anyone was curious." is exactly what I am. While my interest is N52/MSV80, I think it should be pretty similar.

@carabuser I got some technical questions, maybe you can fuel my mind.

(I am asking as a hobbyist coming from the automotive industry, owning a BMW for the first time. I got a software tune and want to understand what happened under the hood. While the tune got flashed, I traced the CAN bus for later analysis. From the ISO-TP communication I have reconstructed the binary data which was transferred. Now I am analyzing the binaries (first time seeing Tricore assembly lol) and was able to match your thorough description with what was flashed - mostly)

As per my general understanding, the two main tricks here are the patched bootloader, which also accepts incorrect signatures as well as the RSA memory range config not being covered by the signature itself / anti tampering protection.

Now coming to what confuses me in my MSV80 analysis, maybe you can help me with that:
Contrary to the description, the cloned RSA memory range config was not placed after the original end of the last range, but instead was placed before the modified table at 0x801ffbc0. From my understanding this is within the originally RSA covered memory range . This already arises questions because it alters the protected area.

But whats even more confusing, is that the absolute memory ranges covered by the modified table (aka the exploit) includes more data than the original ranges. While the original config covers a total of 0x1B3A40 bytes, the modified table covers a total of 0x1B3A80 bytes. So theres a difference of 0x40 bytes.
I am assuming that all the ranges are put together and used as digest for a single RSA signature verification (Are there dedicated signatures for each memory block)? How does that still work with a differing number of bytes?

What I also noticed is that the modified table makes use of some kind of overlap in the RSA memory range config. The third entry covers 0x80080000 - 0x801ffbbf and the fourth entry covers 0x801ffb80 - 0x801ffbef (which starts within the previous range but exceeds it eventually).
The overlap covers exactly 0x40 bytes - which is equal to the difference, when just summing all the ranges. I am sensing some kind of relation here.


Heres an overview of the config extracted from the original software and the modified "tune":
1749404158692.png


Sorry for the somewhat lengthy post. Maybe I can get some help with understanding the approach applied here :)


Update: While writing this down I thought again about it and now partially get it: The overlapping area results in the cloned memory section being considered instead of the modified one - this could"fix it up" somehow.
Still don't get the part how the surplus bytes are handled / the "modified" config. As the Mem Range 5 still contains the modified area

And what exactly is considered for signature calculation.

Offset 0x80000000: (green bytes are differences to the original ECU SW, blacked out areas dont matter for the rsa memory regions)
1749408168770.png
 
Last edited:

doublespaces

Administrator
Oct 18, 2016
9,318
4,353
0
AZ
Ride
2009 E93 335i
This is an under rated post, gonna hijack it a bit for nostalgia. I was fortunate enough to have had the exploit explained to me in 2013. I actually have some documents that describe setting up the MS8X bench with an E60 KGM among other things like custom diagnostic tooling that are just succumbing to bit rot unfortunately.

July 21 2013:

Screenshot of one of the earlier builds
1749413883976.png



August 4th 2013:

And here was one of the first screenshots of me beginning the porting process to Android. I didn't get past the front door because my bench unit was not responding and I never got a chance to test my routines for reading out the BIN, I think I suspected my lab power supply.
1749414295627.png


This was my first experience with C# (BMW Flash) and Java (Eclipse/Android) but it wasn't too bad with C++ fundamentals. Pretty sure if I got my DME to work this would have eventually functioned but I also had a lot going on my life back then.

I don't think I can/should release any of the code/tooling/texts I have since they were still given to me in confidence so I suppose this is just gonna die on when my platter drives do. I haven't stayed up to date, chance are some of that already exists in the public domain.

Not sure if you guys remember, but a lot of this was the fallout of Shiv and some people teaming up to create the "OpenFlash Tablet" which wasn't actually open. There is even a Hitler gets bad news video about it:
 
  • Like
Reactions: 3xpent

doublespaces

Administrator
Oct 18, 2016
9,318
4,353
0
AZ
Ride
2009 E93 335i
All tools that read and write to the MSD80 and MSD81 (COBB, OpenFlash, MHD etc) use exactly the same process to do so. That all seemed to have copied each other down the line. I’m not sure who exactly created the original RSA bypass but I believe that COBB purchased/licensed their method and then the rest just coped it. Whoever came up with the original bypass is a real genius and undoubtedly put a lot of blood, sweat and tears into the process. I’m not sure if the trick originated on the MSD80, or if it was an existing trick that was used elsewhere that was just adapted for the MSD8x, but I’ll explain how it’s done in the context of the MSD8x.

What was explained to me is that there are indeed some behind the scenes people, I have a couple of names hinted to me before but I cannot remember if they were the people who wrote the exploit or brokered it. But getting internal technical/engineering drawings/documents were key to these exploits and obtaining that data was not done so by sending a letter asking nicely.
 
  • Like
Reactions: carabuser

carabuser

Captain
Vendor
Oct 2, 2019
1,042
1
1,175
0
UK
Ride
Z4 35i & 335i
Very interesting post, really appreciate it!
"in case anyone was curious." is exactly what I am. While my interest is N52/MSV80, I think it should be pretty similar.

@carabuser I got some technical questions, maybe you can fuel my mind.

(I am asking as a hobbyist coming from the automotive industry, owning a BMW for the first time. I got a software tune and want to understand what happened under the hood. While the tune got flashed, I traced the CAN bus for later analysis. From the ISO-TP communication I have reconstructed the binary data which was transferred. Now I am analyzing the binaries (first time seeing Tricore assembly lol) and was able to match your thorough description with what was flashed - mostly)

As per my general understanding, the two main tricks here are the patched bootloader, which also accepts incorrect signatures as well as the RSA memory range config not being covered by the signature itself / anti tampering protection.

Now coming to what confuses me in my MSV80 analysis, maybe you can help me with that:
Contrary to the description, the cloned RSA memory range config was not placed after the original end of the last range, but instead was placed before the modified table at 0x801ffbc0. From my understanding this is within the originally RSA covered memory range . This already arises questions because it alters the protected area.

But whats even more confusing, is that the absolute memory ranges covered by the modified table (aka the exploit) includes more data than the original ranges. While the original config covers a total of 0x1B3A40 bytes, the modified table covers a total of 0x1B3A80 bytes. So theres a difference of 0x40 bytes.
I am assuming that all the ranges are put together and used as digest for a single RSA signature verification (Are there dedicated signatures for each memory block)? How does that still work with a differing number of bytes?

What I also noticed is that the modified table makes use of some kind of overlap in the RSA memory range config. The third entry covers 0x80080000 - 0x801ffbbf and the fourth entry covers 0x801ffb80 - 0x801ffbef (which starts within the previous range but exceeds it eventually).
The overlap covers exactly 0x40 bytes - which is equal to the difference, when just summing all the ranges. I am sensing some kind of relation here.


Heres an overview of the config extracted from the original software and the modified "tune":
View attachment 112589

Sorry for the somewhat lengthy post. Maybe I can get some help with understanding the approach applied here :)


Update: While writing this down I thought again about it and now partially get it: The overlapping area results in the cloned memory section being considered instead of the modified one - this could"fix it up" somehow.
Still don't get the part how the surplus bytes are handled / the "modified" config. As the Mem Range 5 still contains the modified area

And what exactly is considered for signature calculation.

Offset 0x80000000: (green bytes are differences to the original ECU SW, blacked out areas dont matter for the rsa memory regions)
View attachment 112597
Those bytes changed at the end of the PRG space are the RSA table. It's a series of 4 byte values that represent start and stop ranges for the RSA check.
There is a stock RSA table, and modified RSA table, the stock one is just there so they can pass the RSA check of the memory, the modified one repoints the check so that it skips the ranges that are modified.

The whole trick relies off duplicating any modified code and making the RSA ranges look at original code in unused areas of the ROM.
 
  • Like
Reactions: 3xpent

3xpent

New Member
Mar 15, 2025
4
3
0
I don't think I can/should release any of the code/tooling/texts I have since they were still given to me in confidence so I suppose this is just gonna die on when my platter drives do. I haven't stayed up to date, chance are some of that already exists in the public domain.
Awesome insights! I totally get it that you can't share any of that. Just a pitty that it seems like I'm a bit late to the party.
Fortunately, some of the stuff can be found online if digging deep enough. At least the source code for the BMW Flash tool you've mentioned is somewhat available and I also found some other files which look rather internal :)



The whole trick relies off duplicating any modified code and making the RSA ranges look at original code in unused areas of the ROM.

Thanks for confirming!
In my specific case I have some doubts though. As the modified portion (rsa memory config) is still part of the rsa covered area - which doesn't make sense in my opinion as it alters the bytes used for RSA verification.
For now, all I know is that it was a successful flash, meaning the ECU accepted the modified software.

The modified RSA memory range 5, still covers the exact location of the modified table: 0x801FFBF0-0x801FFC3F. Some kind of trick must be at play for this to work.

Furthermore, the total covered area is not consistent with the original ECU software. Therefore, the RSA verification needs to fail. This would only be different if the modified software were an official BMW release with a different number of bytes.

I am wondering where the crypto stuff (signature, public exponent, modulus) is stored so that I can verify the memory ranges myself and possibly understand what is going on in the modified scenario vs. the original scenario. I assume signature might be the bytes after the last RSA covered section, basically at the end ot the binary.


Update: When "simulating" (I just wrote a small script working with the defined memory ranges) the assumed behavior ( := all specified memory ranges are pulled into a single bytestream used for RSA verification), I get almost identical outputs. They differ just at the end which is what I already expected above:
1749462607578.png

The red bytes are surplus in the modified binary. This must lead to a signature verification failure.
Except they are ignored, because the length of the output has changed. If only the first 0x1b3a40 bytes (size of the original software) are used for verification, the red part would be ignored. This could be the reason why it was accepted by the ECU anyways.

Also the signature (RSA 1024, 128 bytes of signature) really seems to be placed immediately after the rsa configuration tables - and it is identical for both the original SW and the modified SW. Which means that the bytes used for verification MUST be identical in order to pass the check.
Again, with the surplus bytes this is not fulfilled. But if they are ignored....


I guess I have to read through this as it yields a lot of intel https://www.e90post.com/forums/showthread.php?t=1035058
 
Last edited: