Example #1
0
        public static bool SecurityAccess(KW2000Dialog kwp2000, byte accessMode)
        {
            const byte identificationOption = 0x94;
            var        responseMsg          = kwp2000.SendReceive(Service.readEcuIdentification, new byte[] { identificationOption });

            if (responseMsg.Body[0] != identificationOption)
            {
                throw new InvalidOperationException($"Received unexpected identificationOption: {responseMsg.Body[0]:X2}");
            }
            Logger.WriteLine(Utils.DumpAscii(responseMsg.Body.Skip(1)));

            const int maxTries = 16;

            for (var i = 0; i < maxTries; i++)
            {
                responseMsg = kwp2000.SendReceive(Service.securityAccess, new byte[] { accessMode });
                if (responseMsg.Body[0] != accessMode)
                {
                    throw new InvalidOperationException($"Received unexpected accessMode: {responseMsg.Body[0]:X2}");
                }
                var seedBytes = responseMsg.Body.Skip(1).ToArray();
                var seed      = (uint)(
                    (seedBytes[0] << 24) |
                    (seedBytes[1] << 16) |
                    (seedBytes[2] << 8) |
                    seedBytes[3]);
                var key = CalcRB8Key(seed);

                try
                {
                    responseMsg = kwp2000.SendReceive(Service.securityAccess,
                                                      new[] {
                        (byte)(accessMode + 1),
                        (byte)((key >> 24) & 0xFF),
                        (byte)((key >> 16) & 0xFF),
                        (byte)((key >> 8) & 0xFF),
                        (byte)(key & 0xFF)
                    });

                    Logger.WriteLine("Success!!!");
                    return(true);
                }
                catch (NegativeResponseException)
                {
                    if (i < (maxTries - 1))
                    {
                        Logger.WriteLine("Trying again.");
                    }
                }
            }

            return(false);
        }
Example #2
0
        public void DumpEeprom(string filename)
        {
            Logger.WriteLine("Sending wakeup message");
            var kwpVersion = _kwpCommon.FastInit((byte)_controllerAddress);

            var kwp2000 = new KW2000Dialog(_kwpCommon, (byte)_controllerAddress);

            Kwp2000Message resp;

            // Need to decrease these timing parameters to get the ECU to wake up.
            kwp2000.P3 = 0;
            kwp2000.P4 = 0;
            kwp2000.SendMessage(DiagnosticService.startCommunication, Array.Empty <byte>());
            kwp2000.P3 = 6;
            try
            {
                resp = kwp2000.SendReceive(DiagnosticService.testerPresent, Array.Empty <byte>());
            }
            catch (InvalidOperationException)
            {
                // Ignore "Unexpected DestAddress: 00"
            }

            kwp2000.P3 = 55;

            resp = kwp2000.SendReceive(DiagnosticService.startDiagnosticSession, new byte[] { 0x85 });

            const byte accMod = 0x41;

            resp = kwp2000.SendReceive(DiagnosticService.securityAccess, new byte[] { accMod });

            // ECU normally doesn't require seed/key authentication the first time it wakes up in
            // KWP2000 mode so sending an empty key is sufficient.
            var buf = new List <byte> {
                accMod + 1
            };

            if (!Enumerable.SequenceEqual(resp.Body, new byte[] { accMod, 0x00, 0x00 }))
            {
                // Normally we'll only get here if we wake up the ECU and it's already in KWP2000 mode,
                // which can happen if a previous download attempt did not complete. In that case we
                // need to calculate and send back a real key.
                var seedBuf = resp.Body.Skip(1).Take(4).ToArray();
                var keyBuf  = LVL41Auth(0x508DA647, 0x3800000, seedBuf);

                buf.AddRange(keyBuf);
            }
            resp = kwp2000.SendReceive(DiagnosticService.securityAccess, buf.ToArray());

            var loader = Edc15VM.GetLoader();
            var len    = loader.Length;

            // Ask the ECU to accept our loader and store it in RAM
            resp = kwp2000.SendReceive(DiagnosticService.requestDownload, new byte[]
            {
                0x40, 0xE0, 0x00,                                       // Load address 0x40E000
                0x00,                                                   // Not compressed, not encrypted
                (byte)(len >> 16), (byte)(len >> 8), (byte)(len & 0xFF) // Length
            },
                                       excludeAddresses: true);

            // Break the loader into blocks and send each one
            var maxBlockLen = resp.Body[0];
            var s           = new MemoryStream(loader);

            while (true)
            {
                Thread.Sleep(5);

                var blockBytes = new byte[maxBlockLen];
                var readCount  = s.Read(blockBytes, 0, maxBlockLen - 1);
                if (readCount == 0)
                {
                    break;
                }

                resp = kwp2000.SendReceive(
                    DiagnosticService.transferData, blockBytes.Take(readCount).ToArray(),
                    excludeAddresses: true);
            }

            // Ask the ECU to execute our loader
            kwp2000.SendMessage(
                DiagnosticService.startRoutineByLocalIdentifier, new byte[] { 0x02 },
                excludeAddresses: true);
            resp = kwp2000.ReceiveMessage();

            // Custom loader command to send all 512 bytes of the EEPROM
            kwp2000.SendMessage(
                (DiagnosticService)0xA6, Array.Empty <byte>(),
                excludeAddresses: true);
            resp = kwp2000.ReceiveMessage();
            if (!resp.IsPositiveResponse(DiagnosticService.transferData))
            {
                throw new InvalidOperationException($"Dump EEPROM failed.");
            }

            var  eeprom = new List <byte>();
            byte b;

            for (int i = 0; i < 512; i++)
            {
                b = _kwpCommon.Interface.ReadByte();
                eeprom.Add(b);
            }

            var dumpFileName = filename ?? $"EDC15_EEPROM.bin";

            File.WriteAllBytes(dumpFileName, eeprom.ToArray());
            Logger.WriteLine($"Saved EEPROM to {dumpFileName}");

            resp = kwp2000.ReceiveMessage();

            // Custom loader command to reboot the ECU to return it to normal operation.
            kwp2000.SendMessage(
                (DiagnosticService)0xA2, Array.Empty <byte>(),
                excludeAddresses: true);
            resp = kwp2000.ReceiveMessage();

            b = _kwpCommon.Interface.ReadByte();
            if (b == 0x55)
            {
                Logger.WriteLine($"Reboot successful!");
            }
        }