Skip to content

Commit

Permalink
Added experimental code to see if Audi A2 clusters are unlocked the s…
Browse files Browse the repository at this point in the history
…ame was as Audi C5 clusters. Simplified VDO Seek/Key calculation code. Added support for 1J0919860B clusters.
gmenounos committed Jun 6, 2024
1 parent e684251 commit 4968d84
Showing 6 changed files with 57 additions and 50 deletions.
22 changes: 11 additions & 11 deletions Cluster/AudiC5Cluster.cs
Original file line number Diff line number Diff line change
@@ -45,7 +45,7 @@ public void UnlockForEepromReadWrite()
{
throw new InvalidOperationException("Unable to login to cluster");
}

var @interface = _kw1281Dialog.KwpCommon.Interface;
@interface.SetBaudRate(19200);
@interface.SetParity(Parity.Even);
@@ -59,7 +59,7 @@ public string DumpEeprom(uint? address, uint? length, string? dumpFileName)
ArgumentNullException.ThrowIfNull(address);
ArgumentNullException.ThrowIfNull(length);
ArgumentNullException.ThrowIfNull(dumpFileName);

WriteBlock([Constants.Hello]);

var blockBytes = ReadBlock();
@@ -81,7 +81,7 @@ public string DumpEeprom(uint? address, uint? length, string? dumpFileName)
foreach (var password in passwords)
{
Log.WriteLine("Sending login request");

blockBytes = [Constants.Login, 0x9D];
blockBytes.AddRange(Encoding.ASCII.GetBytes(password));
WriteBlock(blockBytes);
@@ -99,7 +99,7 @@ public string DumpEeprom(uint? address, uint? length, string? dumpFileName)
Log.WriteLine($"Warning: Expected block of type ${Constants.Ack:X2}");
}
}

if (!succeeded)
{
throw new InvalidOperationException("Unable to login to cluster");
@@ -111,17 +111,17 @@ public string DumpEeprom(uint? address, uint? length, string? dumpFileName)

Log.WriteLine($"Dumping EEPROM to {dumpFileName}");
DumpEeprom(address.Value, length.Value, maxReadLength: 0x10, dumpFileName);

_kw1281Dialog.SetDisconnected();

return dumpFileName;
}

private void DumpEeprom(
uint startAddr, uint length, byte maxReadLength, string fileName)
{
using var fs = File.Create(fileName, bufferSize: maxReadLength, FileOptions.WriteThrough);

var succeeded = true;
for (var addr = startAddr; addr < startAddr + length; addr += maxReadLength)
{
@@ -134,11 +134,11 @@ private void DumpEeprom(
blockBytes.AddRange(
Enumerable.Repeat((byte)0, readLength - blockBytes.Count));
}

fs.Write(blockBytes.ToArray(), offset: 0, blockBytes.Count);
fs.Flush();
}

if (!succeeded)
{
Log.WriteLine();
@@ -209,7 +209,7 @@ private List<byte> ReadBlock()
{
var blockBytes = new List<byte>();
byte checksum = 0x00;

try
{
var header = ReadByte();
@@ -259,7 +259,7 @@ private static class Constants
}

private readonly IKW1281Dialog _kw1281Dialog;

public AudiC5Cluster(IKW1281Dialog kw1281Dialog)
{
_kw1281Dialog = kw1281Dialog;
13 changes: 8 additions & 5 deletions Cluster/VdoCluster.cs
Original file line number Diff line number Diff line change
@@ -286,9 +286,9 @@ public bool RequiresSeedKey()
var responseBlocks = response.Where(b => !b.IsAckNak).ToList();
if (responseBlocks is [CustomBlock])
{
int accessLevel = responseBlocks[0].Body.First();
int accessLevel = responseBlocks[0].Body.First();
Log.WriteLine($"Access level is {accessLevel}.");

return accessLevel;
}
else
@@ -371,18 +371,21 @@ private static byte[][] GetClusterUnlockCodes(string softwareVersion)
case "VAT500MH 01.20": // 1J5920925C V09
return [[0x01, 0x04, 0x3D, 0x35]];

case "$01 $00 $14 $01": // 1J0919860B A4-KOMBIINSTR. VDO V15
return [[0x01, 0x08, 0x05, 0x02]];

case "V798MLA 01.00": // 7D0920800F V01, 1J0919951C V55
return [[0x02, 0x03, 0x05, 0x09]];

case "$00 $00 $13 $01": // 8D0919880M B5-KOMBIINSTR. VDO D02
return [[0x09, 0x06, 0x05, 0x02]];

case "VSQX01LM 01.00": // 6Q0920800 KOMBI+WEGFAHRSP VDO V11
return [[0x31, 0x39, 0x34, 0x46]];

case "VCLM09MH $00 $09": // 3BD920848E KOMBI+WEGFAHRSP VDO V03
return [[0x32, 0x31, 0x36, 0x31]];

case "VQMJ07HH 08.40": // 6Y0920843L KOMBIINSTRUMENT VDO V04
case "VQMJ07LM 09.00": // 6Q0920804Q KOMBIINSTRUMENT VDO V06
return [[0x34, 0x3F, 0x43, 0x39]];
@@ -425,7 +428,7 @@ private static byte[][] GetClusterUnlockCodes(string softwareVersion)

case "VSQX01LM 01.10": // 6Q0920900 KOMBI+WEGFAHRSP VDO V18
return [[0x43, 0x43, 0x3D, 0x37]];

case "KPQMLA` $01": // 6Y1920860G KOMBIINSTRUMENT VDO V12
return [[0x47, 0x3B, 0x31, 0x3F]];

48 changes: 24 additions & 24 deletions Cluster/VdoKeyFinder.cs
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@ public static byte[] FindKey(
}

Log.WriteLine($"Access level {accessLevel} secret: {Utils.DumpBytes(secret)}");

var key = CalculateKey(
[seed[1], seed[3], seed[5], seed[7]],
secret);
@@ -62,7 +62,7 @@ public static byte[] FindKey(
[0x4b, 0xd0, 0x7f, 0xad],
[0x55, 0x16, 0xa8, 0x94] // AccessLevel 7
];

/// <summary>
/// Table of secrets, one for each access level.
/// </summary>
@@ -100,12 +100,12 @@ private static byte[] CalculateKey(
IReadOnlyList<byte> seed,
IReadOnlyList<byte> secret)
{
var work = new byte[] { 0x07, seed[0], seed[1], seed[2], seed[3], 0x00, 0x00 };
var work = new byte[] { seed[0], seed[1], seed[2], seed[3], 0x00, 0x00 };
var secretBuf = secret.ToArray();

Scramble(work);

var y = work[1] & 0x07;
var y = work[0] & 0x07;
var temp = y + 1;

var a = LeftRotate(0x01, y);
@@ -122,36 +122,36 @@ private static byte[] CalculateKey(

for (var x = 0; x < 2; x++)
{
work[4] = work[0];
work[0] ^= work[2];

work[5] = work[1];
work[1] ^= work[3];

work[6] = work[2];
work[2] ^= work[4];

work[4] = work[6];
work[3] = work[5];
work[2] = work[4];

LeftRotateSecondAndThirdBytes(work, (byte)(work[3] & 0x07));
LeftRotateFirstTwoBytes(work, work[2] & 0x07);

y = x << 1;

var carry = true;
(work[1], carry) = Utils.SubtractWithCarry(work[1], secretBuf[y], carry);
(work[2], _) = Utils.SubtractWithCarry(work[2], secretBuf[y + 1], carry);
(work[0], carry) = Utils.SubtractWithCarry(work[0], secretBuf[y], carry);
(work[1], _) = Utils.SubtractWithCarry(work[1], secretBuf[y + 1], carry);
}

Scramble(work);

return [work[1], work[2], work[3], work[4]];
return [work[0], work[1], work[2], work[3]];
}

private static void Scramble(byte[] key)
private static void Scramble(byte[] work)
{
key[5] = key[1];
key[1] = key[2];
key[2] = key[4];
key[4] = key[3];
key[3] = key[5];
work[4] = work[0];
work[0] = work[1];
work[1] = work[3];
work[3] = work[2];
work[2] = work[4];
}

private static byte SetOrClearBits(
@@ -184,14 +184,14 @@ private static void RightRotateFirst4Bytes(
}
}

private static void LeftRotateSecondAndThirdBytes(
byte[] key, int count)
private static void LeftRotateFirstTwoBytes(
byte[] work, int count)
{
while (count != 0)
while (count > 0)
{
var carry = (key[2] & 0x80) != 0;
(key[1], carry) = Utils.LeftRotate(key[1], carry);
(key[2], _) = Utils.LeftRotate(key[2], carry);
var carry = (work[1] & 0x80) != 0;
(work[0], carry) = Utils.LeftRotate(work[0], carry);
(work[1], _) = Utils.LeftRotate(work[1], carry);
count--;
}
}
1 change: 1 addition & 0 deletions ControllerAddress.cs
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ enum ControllerAddress
CentralElectric = 0x09,
Cluster = 0x17,
CanGateway = 0x19,
Immobilizer = 0x25,
CentralLocking = 0x35,
Navigation = 0x37,
CCM = 0x46,
17 changes: 10 additions & 7 deletions Tester.cs
Original file line number Diff line number Diff line change
@@ -504,21 +504,24 @@ public void GetClusterId()

public void GetSkc()
{
if (_controllerAddress == (int)ControllerAddress.Cluster)
if (_controllerAddress is (int)ControllerAddress.Cluster or (int)ControllerAddress.Immobilizer)
{
var ecuInfo = Kwp1281Wakeup();
if (ecuInfo.Text.Contains("4B0920") ||
ecuInfo.Text.Contains("4Z7920"))
ecuInfo.Text.Contains("4Z7920") ||
ecuInfo.Text.Contains("8Z0920"))
{
Log.WriteLine($"Cluster is Audi C5");
var family = ecuInfo.Text.StartsWith('4') ? "C5" : "A2";

Log.WriteLine($"Cluster is Audi {family}");

var cluster = new AudiC5Cluster(_kwp1281);

cluster.UnlockForEepromReadWrite();
var dumpFileName = cluster.DumpEeprom(0, 0x800, "AudiC5.bin");
var dumpFileName = cluster.DumpEeprom(0, 0x800, $"Audi{family}.bin");

var buf = File.ReadAllBytes(dumpFileName);

var skc = Utils.GetShort(buf, 0x7E2);
var skc2 = Utils.GetShort(buf, 0x7E4);
var skc3 = Utils.GetShort(buf, 0x7E6);
6 changes: 3 additions & 3 deletions kw1281test.csproj
Original file line number Diff line number Diff line change
@@ -5,9 +5,9 @@
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>BitFab.KW1281Test</RootNamespace>
<LangVersion>latest</LangVersion>
<AssemblyVersion>0.97.0.0</AssemblyVersion>
<FileVersion>0.97.0.0</FileVersion>
<Version>0.97.0-beta</Version>
<AssemblyVersion>0.98.0.0</AssemblyVersion>
<FileVersion>0.98.0.0</FileVersion>
<Version>0.98.0-beta</Version>
<Copyright>Copyright © 2024 Greg Menounos</Copyright>
<DebugType>embedded</DebugType>
<DebugSymbols>true</DebugSymbols>

0 comments on commit 4968d84

Please sign in to comment.