BMW M5 Forum and M6 Forums banner

41 - 60 of 84 Posts

·
Registered
Joined
·
225 Posts
Bypassing RSA could be as simple as changing the pointers to point to the program segments and copy the signature from the program. Looks like the signed program segments are 0x10000 to 0x3FED9 and 0x40000 to 0x6FFEFF. Data segments are 0x78010 to 0x780C9 and 0x781EA to 0x7FFDF. This method would be broken if the module writes a some "verification passed" bytes in the signature checked region after the program check passes.

I do not see the public keys stored in the program section, which suggests the keys and signature verification code are stored in the boot sector (which apparently cannot be updated on this module unlike others). So modifying the verification routines themselves doesn't seem feasible. One strategy I've seen used on newer BMW automatic transmission computers is to modify a value in RAM which happens to store the regions you're "allowed" to write to, and then just directly writing the "verification passed" bytes.

Beyond RSA, the checksum itself seems to be a CRC-16, though I cannot figure out the exact algorithm just yet (I bet you could find a CRC table in the full flash if you look). Stored at 0x78090. Default checked region is 0x781EA to 0x7DF6E
 

·
Registered
Joined
·
1,345 Posts
Discussion Starter #42
Interesting little tidbit... I updated location 0x782e0( I wanted to test what I thought this word did) and it seems to boot fine.



Admittedly I have not put it in the car yet, it's raining and the garage is occupied now, but it does seem to pass my initial checks of bench verifying. Which basically consists of checking few gpio lines and seeing it sending out out messages over the PT CAN bus. Also when I hooked it to the logic analyzer it didn't access any of the those locations sequentially, which I would assume it would do if was CRC checking. So I'm wondering if does actually bothers with the CRC. As far as the RSA I think that's what data sections 0x 780ce to 0x7814e .



I guess we'll know for sure when I get it in the car but it didn't do what I thought it would so far.
 

·
Registered
Joined
·
1,345 Posts
Discussion Starter #45
Anyone tried a 44 pin test clip on the AM29F400 to see if you can read/write without soldering?
I like to do things the hard way... I'm working on a serial flash bootloader this week. it's still gonna requiring soldering on 4 maybe 5 leads though unless we can come with a bed of nails. The advantage is gonna be not needing to drill the rivets nor soldering the flash.

If you get the test clip to work let me know :)

Also I'm thinking those tables you posted earlier are the automatic mode shift points in vehicle speed .Just a theory though at this point.
 

·
Registered
Joined
·
95 Posts
Let me know what happens when you wang the flashed TCU in the car bud.


Test clip on the SMG2 TCU will be no good as it's on the underside under the CPU. Is it the same on the SMG3 TCU?
 

·
Registered
Joined
·
1,345 Posts
Discussion Starter #47
Let me know what happens when you wang the flashed TCU in the car bud.


Test clip on the SMG2 TCU will be no good as it's on the underside under the CPU. Is it the same on the SMG3 TCU?
Correct the SMGII and SMGIII are basically the same, same flash cpu and static ram. The lay out is basically the same but the supporting components are different, the III has a ton more pull ups and caps it looks like the SMGII used drivers or line buffers(quick glance not super looked into)

So yeah either one would require the rivets to be drilled to get to the flash, hence the the boot loader flashing idea.

I'm putting new struts on the kids car tonight so I hopefully , I'll get it out of the garage and can get back to what's important.
 

·
Registered
Joined
·
225 Posts
Okay, looking through the binary Ferris sent me, bypassing RSA should be simple. I've confirmed that the "verification passed" bytes are not written in the signed region after the check passes. So it should be as simple as changing the pointers in the parameter section to match the program section. If you want to write program modifications then we might have to get creative, but you shouldn't really need to mess with the program too much.


If I'm right, to bypass RSA, all you have to do is replace 0x780B0 -> 0x7814D with the following
Code:
020000000100D9FE030000000400FFFE0600DAFE020000FF020020000000F765336EA85DAE3FB1EA716BAAFE64BBDADC1E39166F067EB5724818401923BD8FAC07A855444295DC33E5BE0417360263F512835CE2B1A4CEA98A19ED3D4E415309D95D60F04586685937B5B0DF507E0EC782BC5D91691A76051F491AC2676B1FB71D10B1D711F9F94CA985C091F6C7249939EC746385FC86255B2AECD3E048
Easy test would be to replace that section in an 0da and see if it still flashes successfully.

Oh and for reference, the public key is:
Code:
n = 0xAB76AA1E9E5B37269D53883564E991BB9CD9DEDDC8BEE75CEB847A3F77965480DBEF70365D7448E396380618E7B3E3657AB58079C1CB0B1169690EE865581236D81947C8EADE9EA65EB3D510AA3818034BDE4323B29AF2139E0260C96ABBFB4B569894AAA270A36151FDA214ABAD1BE4737C72704D048E2D767866C8B1550549
e =3
 

·
Registered
Joined
·
1,345 Posts
Discussion Starter #49
Okay, looking through the binary Ferris sent me, bypassing RSA should be simple. I've confirmed that the "verification passed" bytes are not written in the signed region after the check passes. So it should be as simple as changing the pointers in the parameter section to match the program section. If you want to write program modifications then we might have to get creative, but you shouldn't really need to mess with the program too much.


If I'm right, to bypass RSA, all you have to do is replace 0x780B0 -> 0x7814D with the following
Code:
020000000100D9FE030000000400FFFE0600DAFE020000FF020020000000F765336EA85DAE3FB1EA716BAAFE64BBDADC1E39166F067EB5724818401923BD8FAC07A855444295DC33E5BE0417360263F512835CE2B1A4CEA98A19ED3D4E415309D95D60F04586685937B5B0DF507E0EC782BC5D91691A76051F491AC2676B1FB71D10B1D711F9F94CA985C091F6C7249939EC746385FC86255B2AECD3E048
Easy test would be to replace that section in an 0da and see if it still flashes successfully.

Oh and for reference, the public key is:
Code:
n = 0xAB76AA1E9E5B37269D53883564E991BB9CD9DEDDC8BEE75CEB847A3F77965480DBEF70365D7448E396380618E7B3E3657AB58079C1CB0B1169690EE865581236D81947C8EADE9EA65EB3D510AA3818034BDE4323B29AF2139E0260C96ABBFB4B569894AAA270A36151FDA214ABAD1BE4737C72704D048E2D767866C8B1550549
e =3
SWEET!!! I'll give it a shot later this week if no one else does.

That would be awesome if it works since it would be the most non invasive way for the community to flash their own changes. Did you guys on the MSS54 project write a bin to 0da utility? If not it might be worth investing some time to do that, even a better use of time then going down the bootloader route I was planning on doing this week.
 

·
Registered
Joined
·
225 Posts
Worked out the checksum. Python code below (edit paths, filenames etc as necessary)

Code:
def crc_16_fast(crc,msg):
    
    table = (
    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
    0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
    0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
    0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
    )
    
    for byte in msg:
        crc = table[(crc^byte)&0xff] ^ (crc >>8)
    return crc & 0xFFFF

in_file = open('../Downloads/SMG3Read.bin',"rb")
in_file.seek(0x781ea)
data = in_file.read(0x5D85)


result = crc_16_fast(0x5858, data)
print (hex(result))
 

·
Registered
Joined
·
1,345 Posts
Discussion Starter #52 (Edited)
A quick inconclusive update...

So I updated what I thought would control the first start mode when switching to D. Sorry the location is a page back and I'm on my laptop without my notes. This would be first the update ever written so I wasn't expecting much, I started the car and put into D and it dropped into S1 not D1. Then when I was about to move the car it went into a failsafe transmission fault and locked everything out.. I pulled the codes and it complained about a short to ground on one of the PMW channels. I'll have to look over all the lead/haywires I soldered, maybe remove them and check for any shorts.

Assuming there is a short this proves the following.
1)There is no CRC on the data area I updated that the TCU actually cares about once written.
2)the location I updated actually controls the first start mode, though I'll have to try to figure it out a bit more. I was expecting D5 not S1.
3)There are lot more failsafes built in than I thought.

I think I'm gonna invest some time in trying the RSA work around and maybe writing the serial downloader in case that doesn't work.
 

·
Registered
Joined
·
1,345 Posts
Discussion Starter #53
Well sadly it turns out that inpa is filthy liar the error is probably related to the CRC not matching. Pulled all the wires checked all the solder joints and had the same error crop up. Then I reflashed it back to the base tune with WINKFP and the error is gone. I'm gonna use Mirza's crc generator and try again.

I still find it strange it doesn't check the CRC until you go to drive off.
 

·
Registered
Joined
·
225 Posts
Updated version of the script that's a bit more user friendly

Code:
import sys
import struct

def probablybetterwaystodothisbutthisiseasy(x):
    upper = x << 8
    lower = x >> 8

    return (upper + lower) & 0xFFFF

def crc_16_fast(crc,msg):
    
    table = (
    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
    0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
    0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
    0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
    )
    
    for byte in msg:
        if sys.version_info[0] < 3:
            crc = table[(crc^ord(byte))&0xff] ^ (crc >>8)
        else:
            crc = table[(crc^byte)&0xff] ^ (crc >>8)
    return crc & 0xFFFF

if len(sys.argv) == 1:
    if sys.version_info[0] < 3:
        filename = raw_input("Enter path/filename: ")
    else:
        filename = input("Enter path/filename: ")
    print ("Note: You can also give filename as a command line argument")
else:
    filename = sys.argv[1]
    
in_file = open(filename,"rb")
in_file.seek(0x78090)
storedCS = in_file.read(0x2)
in_file.seek(0x781ea)
data = in_file.read(0x5d85)



print ("Stored Checksum: " + hex((struct.unpack('>H',storedCS))[0]))
print ("Calculated Checksum: " + (hex(probablybetterwaystodothisbutthisiseasy(crc_16_fast(0x5858, data)))))
Probably should just have it patch the file itself, but for now it's fine.
 

·
Registered
Joined
·
1,345 Posts
Discussion Starter #55
@terraphantm thanks for updating that and helping it's an important step. @MartynT and were talking and found that it only works if the blank data areas are 0xff, as would be set when blanking the eeprom. So if one uses the 0da -> bin converter posted earlier it doesn't work out. I'll post the update this morning.
 

·
Registered
Joined
·
1,345 Posts
Discussion Starter #56 (Edited)
A Bit of a GOOD NEWS update... MASSIVE shout out to @terraphantm and @MartynT . It seems they took on a similar project on the M3 Forum and hopefully they'll be a more sharing and people interested now.

So here we are.... With a corrected CRC we're able to modify the data area and have the TCU not fault. We tried using the 0Da both with the RSA correction and with out and sadly it security faults. So as of today only the rom burner works, I'm working on the UART boot loader, I can't keep removing the rom for every change as every time I remove I risk damage to the board, as well as trying to work around the RSA keys.

Mode memory confirmed working, so you leave it in S5 come back and restart it it's on S5 same as D5 or whatever. I think we found the locations for setting the initial but I'm not pulling the rom for that today.

I'm going to edit the first post with discovery locations.
 

·
Registered
Joined
·
1,345 Posts
Discussion Starter #57
Mode Memoy

Well sadly I can't edit the first post so I'm going to have just drop info in subsequent posts...

Byte 0x782d1 is mode memory 1 enabled 0 disabled.

I think the last bytes in that row are the settings when there is no memory.
 

Attachments

·
Registered
Joined
·
225 Posts
A Bit of a GOOD NEWS update... MASSIVE shout out to @terraphantm and @MartynT . It seems they took on a similar project on the M3 Forum and hopefully they'll be a more sharing and people interested now.

So here we are.... With a corrected CRC we're able to modify the data area and have the TCU not fault. We tried using the 0Da both with the RSA correction and with out and sadly it security faults. So as of today only the rom burner works, I'm working on the UART boot loader, I can't keep removing the rom for every change as every time I remove I risk damage to the board, as well as trying to work around the RSA keys.

Mode memory confirmed working, so you leave it in S5 come back and restart it it's on S5 same as D5 or whatever. I think we found the locations for setting the initial but I'm not pulling the rom for that today.

I'm going to edit the first post with discovery locations.
Agh, I thought for sure that'd work. Might have to figure out how to actually set this up in IDA and explore the signature verification code.

Regarding the bootloader - you might be able to just use minimon instead of writing your own software. Under software downloads here: https://www.infineon.com/cms/en/product/microcontroller/legacy-products-c500-c166-xc166-audo1-family/c166-family/c167cs/
 

·
Registered
Joined
·
1,345 Posts
Discussion Starter #59 (Edited)
Agh, I thought for sure that'd work. Might have to figure out how to actually set this up in IDA and explore the signature verification code.

Regarding the bootloader - you might be able to just use minimon instead of writing your own software. Under software downloads here: https://www.infineon.com/cms/en/product/microcontroller/legacy-products-c500-c166-xc166-audo1-family/c166-family/c167cs/
I have the eeprom from the failed attempt, I want to see it's state and what it updates when it happens. I'll have to pull it later.

I have minimon the problem is, I THINK, is going to be there is an watch dog on the PMIC it's not really a pmic but it acts like one, if you don't pulse it ,it asserts the reset line in the processor. So I'd have to write my own to ouput the pulses..


also I need some resistors for the connection board and just threw out a box of them last year. so I'm waiting on some new ones.

...or we make 0da work so I don't have to :)
 

·
Registered
Joined
·
225 Posts
I have the eeprom from the failed attempt, I want to see it's state and what it updates when it happens. I'll have to pull it later.

I have minimon the problem is, I THINK, is going to be there is an watch dog on the PMIC it's not really a pmic but it acts like one, if you don't pulse it ,it asserts the reset line in the processor. So I'd have to write my own to ouput the pulses..


also I need some resistors for the connection board and just threw out a box of them last year. so I'm waiting on some new ones.

...or we make 0da work so I don't have to :)
Well I double checked - using the segments defined in those RSA headers, both signatures decrypt properly with the same key, and the result matches the md5 of the segments. So if the signature check routine pulls the segments from that header, it should work. If those headers are cosmetic and the segments are actually hard coded, that's a problem. Or if there's some code that restricts the address range of the segments when doing a parameter sig check vs program, that could also be an issue. That has not been the case with every other BMW module I've worked with / broken RSA in, but it does seem like something is weird here.

Or maybe there's another checksum I'm missing. I did notice there's a second CRC table in the program for the CCITT polynomial rather than the IBM one.
 
41 - 60 of 84 Posts
Top