Pages: [1]
Author Topic: ME7.9.10 immo function  (Read 6592 times)
woj
Hero Member
*****

Karma: +41/-3
Offline Offline

Posts: 500


« on: August 19, 2018, 02:28:07 PM »

I am in progress of dissecting this one, still not there yet, but already know some things that might be enough to get some feedback from you to speed up things. The line from EEPROM (has an identical copy in the next row) relevant for immo is:

01 01 CA BF F1 53 51 88 00 B3 E8 DC A4 F9 [CS: 40 F8]

The first two bytes are some status / configuration bytes (and here it is probably where one manipulates it to virginise / disable it). The next six are the immo code data (they stay fixed), and the remaining six get updated every key on (most of them). In the first six bytes the decimal recovery code is encoded as follows:

CA BF F1 -> 1BFCA -> 12631 (when the nibble is >=10 subtract 9).

That's all I know for now, if it looks familiar to anyone don't be shy.
Logged
woj
Hero Member
*****

Karma: +41/-3
Offline Offline

Posts: 500


« Reply #1 on: August 20, 2018, 01:50:54 PM »

Some more insights from looking at the code. When the first two bytes read from EEPROM are not 01 01 then the whole EEPROM row is overwritten with a "canonical" (?) one from flash:

01 01 0B 16 21 2C 37 42 01 08 07 06 05 04 [CS]

bytes #2-#7 in decimal happen to be 11 22 33 44 55 66. The last 5 are also clearly some default initialisation. The remaining 01 at #8 is a flag that so far I know is 00 on initialised ECUs, on uninitialised 01 together with a check on flash byte named DFPMEEPWFSINDEPENDEND in the definition when 00 they skip whole bunch of EEPROM cleaning up (mostly DTC area from what I understand). This byte could be the virgin state of the immo, but (1) I am not sure yet, (2) I have no means of checking it in practice. Yet another thing is, IIRC, I have once seen some ebay immo off program resetting the whole row to FF-s.
Logged
woj
Hero Member
*****

Karma: +41/-3
Offline Offline

Posts: 500


« Reply #2 on: August 21, 2018, 12:26:53 PM »

Run some tests, the first two bytes in this row changed from 01 01 to something else do not cause the immo data to be overwritten with the canonical one. What does happen though, if I clean the whole EEPROM to FF-s, then the whole EEPROM gets written with the canonical image from the flash.

But more importantly, I played a bit more with all these bytes in the EEPROM row and was observing what happens with the IMMO unlock requests sent out to the code box. Long story short, if byte #8 is equal to 00, then a proper unlock code is sent of this form:

0010A001   [7]  05 73 8D DC 3E 0A D4

32 times, because I do not have a code box on the bench. Then a protocol termination of 0010A001 [7] 15 00 00 00 00 00 00.

When I change the byte #8 to 01, irrespective of other changes, the immo request message becomes:

0010A001   [7]  85 00 00 00 00 00 00

which means I have hit the nerve. I can only presume this is the virgin byte, but to test it further I'd need a code box on my bench. 32 attempts here are terminated with 81 00 00 00 00 00 00.

It would also be interesting to know how this code request is calculated. The program code that does this traverses some data back and forth, does some xoring and adding, a bit tedious to sort out (though my wild guess is that the last two bytes are a seed of some sort). One thing I know for sure, it is different each time, and different even after I reset the EEPROM contents to the same value it seems. The constantly changing second part of this EEPROM row somehow reflects this I guess.
Logged
woj
Hero Member
*****

Karma: +41/-3
Offline Offline

Posts: 500


« Reply #3 on: August 22, 2018, 06:53:33 AM »

Not sure who do I write this for, but never mind Wink I figured out how the challenge response protocol works. The challenge recalculation for the next round is still a mystery (but it seems irrelevant anyhow, what counts is the challenge that one gets), but on the surface this is what happens. The ECU sends:

05 [4 bytes of challenge] [2 bytes of ECU CS]

Code box replies:

AB [2 bytes of code box CS] 00 00 00 00

The calculation of both CS values is done following the C code I reconstructed (the immo key is fake, but I verified this with the data from my car):


#include <stdlib.h>
#include <stdio.h>

// Sample ECU request: 05 [93 9E B4 C3] [0B 4A]
// Code box reply:     AB [0A 6E] 00 00 00 00

int main() {

        // Calculation keys from Flash
        unsigned char keys[] = {
                // key 1
                0xD7, 0x74, 0x24, 0x91, 0x83, 0x65, 0xBC, 0x4D, 0xE3, 0x55, 0x38, 0xFB, 0x76, 0x2C, 0x8D, 0x70,
                0xF5, 0x23, 0x85, 0xE5, 0x8C, 0x1C, 0xFC, 0x6E, 0xA7, 0x22, 0xB9, 0x33, 0x39, 0x7C, 0x48, 0x0A,
                // key 2
                0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
                // key 3
                0x66, 0x66, 0x66, 0x66, 0x99, 0x99, 0x99, 0x99, 0x66, 0x66, 0x66, 0x66, 0x99, 0x99, 0x99, 0x99,
                0x99, 0x99, 0x99, 0x99, 0x66, 0x66, 0x66, 0x66, 0x99, 0x99, 0x99, 0x99, 0x66, 0x66, 0x66, 0x66
        };

        // Immo data bytes from the ECU EEPROM, row 04/05, bytes 2..7
        unsigned char immo[] = { 0x6D, 0x28, 0x36, 0xA9, 0xCA, 0xE4 };

        // Sample challenge from the request
        unsigned char chal[] = { 0x93, 0x9E, 0xB4, 0xC3 };

        unsigned char temp[] = {
                chal[3] ^ immo[0] ^ 0x04, chal[2] ^ immo[1] ^ 0x00,
                chal[1] ^ immo[2] ^ 0x08, chal[0] ^ immo[3] ^ 0x0E
        };

        int ee_key = ((immo[4] | (immo[5] << Cool) ^ 0x0011) << 2;

        unsigned int cs_ecu = 0, cs_expected = 0;

        int count = 0x54;
        while(count > 0) {
                int index_data = ((temp[3] & 0x84) | (temp[2] & 0x28) | (temp[1] & 0x50) | (temp[0] & 0x03)) & 0xFF;
                int index1 = 0x20+(index_data & 0x07);
                int index2 = (index_data >> 3) & 0x1F;

                unsigned int t = 2 * ((temp[0] & 0xFF) | ((temp[1] << Cool & 0xFF00) | ((temp[2] << 16) & 0xFF0000) | ((temp[3] << 24) & 0xFF000000));
                temp[0] = t & 0xFF; temp[1] = (t >> Cool & 0xFF; temp[2] = (t >> 16) & 0xFF; temp[3] = (t >> 24) & 0xFF;

                if(keys[0x28+index2] & keys[index1]) temp[0] |= 0x01;

                if(count <= 0x0E) {
                        cs_expected <<= 1;
                        if(keys[index2] & keys[index1]) cs_expected |= 0x01;
                }else if(count <= 0x22) {
                        if(ee_key & 0x8000) temp[0] ^= 0x01;
                        ee_key <<= 1;
                }else if (count <= 0x2E) {
                        cs_ecu <<= 1;
                        if(keys[index2] & keys[index1]) cs_ecu |= 0x01;
                }
                count--;
        }
        cs_ecu &= 0x0FFF;
        cs_expected &= 0x3FFF;
        printf("CS ECU:\t\t\t%04X\nExpected response CS:\t%04X\n", cs_ecu, cs_expected);
        return 0;
}

The ECU CS proves the possession of the right immo code to the code box, the expected CS proves to the ECU the possession of the right code by the code box.

If anyone cares. I am yet to test if I can actually unlock the immo on my bench ECU this way. The next step is to reverse engineer the virgin reset code.
Logged
IamwhoIam
Hero Member
*****

Karma: +44/-100
Offline Offline

Posts: 1031


« Reply #4 on: August 22, 2018, 11:17:08 AM »

Nice work!!!
Logged

I have no logs because I have a boost gauge (makes things easier)
woj
Hero Member
*****

Karma: +41/-3
Offline Offline

Posts: 500


« Reply #5 on: August 22, 2018, 12:30:11 PM »

It gets better Smiley I did unlock the bench ECU with a crafted message according to my C program. Better still, I changed the virgin bit to 1 and managed to reset the code to my own with this protocol:

Received: 8010A001 [07] 85000000000000
Sending:  8010A000 [07] AADEADBEEFCCDD
Received: 8010A001 [07] 86000000000000
Sending:  8010A000 [07] AADEADBEEFCCDD
Received: 8010A001 [07] 87000000000000
Received: 8010A001 [07] 84000000000000

This entered the immo code DDCCEFBEADDE (simply reversed order) into EEPROM and reset the virgin flag. And then after key cycle I could unlock it again.

But I think there is something wrong still with this protocol. 84 is clearly the protocol termination (nothing on this ID is sent later), but I find the repetition of the code sending weird. Though I have to check the ECU code, I vaguely remember some comparison there to match two instances, maybe something like password confirm routine. What do you think?
Logged
woj
Hero Member
*****

Karma: +41/-3
Offline Offline

Posts: 500


« Reply #6 on: August 23, 2018, 01:10:43 PM »

So this immo reset protocol is actually correct, the ECU expects the request code 0xAA to be sent twice, first it stores it in temporary place, on the second one compares the two and resets the code to the new one.

There is also a request code 0x99, all I can see is that it flips a protocol state bit of some sort back and forth and otherwise does nothing, depending on the bit the reply is then 0x86 or 0x87. This bit enables / disables some things in further protocol (and I had problems sending some messages after getting 0x87 here), but I do not see what it is yet. Then there is also a message with code 0x10 to which the ECU replies with code 0x81, but it is not yet clear what it's for and when it can/should be used.

But, I am not sure I care anymore, I know how to unlock the immo knowing the key, and I know how to reset it when in virgin state. That pretty much covers me for whatever whenever I want to do with it.
Logged
IamwhoIam
Hero Member
*****

Karma: +44/-100
Offline Offline

Posts: 1031


« Reply #7 on: August 25, 2018, 01:07:31 PM »

Immo off setting might be interesting?
Logged

I have no logs because I have a boost gauge (makes things easier)
woj
Hero Member
*****

Karma: +41/-3
Offline Offline

Posts: 500


« Reply #8 on: August 25, 2018, 01:29:16 PM »

It does not look like this ECU has immo off option through EEPROM. There is only one flag in the immo data in EEPROM and that is the virgin flag (setting it on does not allow to start the engine, perhaps not a surprise for you Bosch savvy guys, on old MM systems it was different). The immo can be globally disabled though by flipping one condition in the Flash, a development left over of the kind:

if(0) {
  // unlock immo
}else{
  // do immo stuff
}

Logged
370rx
Jr. Member
**

Karma: +0/-0
Offline Offline

Posts: 39


« Reply #9 on: October 05, 2018, 12:43:01 AM »

+
« Last Edit: February 26, 2020, 02:02:30 AM by 370rx » Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Page created in 0.028 seconds with 16 queries. (Pretty URLs adds 0s, 0q)