forked from rusefi/UnlockECU
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
41 changed files
with
2,606 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# UnlockECU | ||
|
||
 | ||
|
||
Free, open-source ECU seed-key unlocking tool. | ||
|
||
## Getting started | ||
|
||
Download and unarchive the application from the [Releases](https://github.com/jglim/UnlockECU/releases/) page, then run the main application `VisualUnlockECU.exe`. | ||
|
||
Ensure that you have *.NET Desktop Runtime 5.0.0*. , available from [here](https://dotnet.microsoft.com/download/dotnet/5.0). | ||
|
||
## License | ||
|
||
MIT | ||
|
||
Icon from [http://www.famfamfam.com/lab/icons/silk/](http://www.famfamfam.com/lab/icons/silk/) | ||
|
||
Excluding the icon, this application **does not include or require copyrighted or proprietary files**. Security functions and definitions have been reverse-engineered and reimplemented. | ||
|
||
*When interacting with this repository (PR, issues, comments), please avoid including copyrighted/proprietary files, as they will be removed without notice.* | ||
|
||
## Features | ||
|
||
- There is no need for additional files such as security DLLs. The application supports a set of security providers out of the box, and definitions are stored in `db.json`. | ||
- Security functions are completely reverse engineered and re-implemented in C#. | ||
- The project is unencumbered by proprietary binary blobs, and can be shared freely without legal issues. | ||
|
||
## Demo | ||
|
||
 | ||
|
||
## Adding definitions | ||
|
||
Definitions specify a seed-key function for a specific ECU and security level. The input seed's size, output key's length as well as the security provider must be specified. Some security providers require specific parameters to operate. | ||
|
||
Here is an example of a definition: | ||
|
||
``` | ||
{ | ||
"EcuName": "ME97", | ||
"AccessLevel": 5, | ||
"SeedLength": 2, | ||
"KeyLength": 2, | ||
"Provider": "PowertrainBoschContiSecurityAlgo2", | ||
"Origin": "ME97_ME97_13_10_01", | ||
"Parameters": [ | ||
{ | ||
"Key": "Table", | ||
"Value": "37C1A8179AE3745B", | ||
"DataType": "ByteArray" | ||
}, | ||
{ | ||
"Key": "uwMasc", | ||
"Value": "4108", | ||
"DataType": "ByteArray" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
Currently, these security providers are available: | ||
|
||
- DaimlerStandardSecurityAlgo | ||
- DaimlerStandardSecurityAlgoMod | ||
- DaimlerStandardSecurityAlgoRefG | ||
- DRVU_PROF | ||
- EDIFF290 | ||
- EsLibEd25519 | ||
- ESPSecurityAlgoLevel1 | ||
- MarquardtSecurityAlgo | ||
- OCM172 | ||
- PowertrainBoschContiSecurityAlgo1 | ||
- PowertrainBoschContiSecurityAlgo2 | ||
- PowertrainDelphiSecurityAlgo | ||
- PowertrainSecurityAlgo | ||
- PowertrainSecurityAlgo2 | ||
- PowertrainSecurityAlgoNFZ | ||
- RBTM | ||
- RDU222 | ||
- RVC222_MPC222_FCW246_LRR3 | ||
- SWSP177 | ||
|
||
The definitions file `db.json` should be found alongside the application's main binary. | ||
|
||
## Notes | ||
|
||
- If your diagnostics file has unlocking capabilities, usually your diagnostics client can already perform the unlocking without further aid. Check your client's available functions for phrases such as `Entriegeln` , `Zugriffberechtigung` , and `Unlock`. | ||
- Generally, this application operates like most DLL-based seed-key generators. If you already have a DLL-based tool, this application does not offer much more (only includes a few modern targets such as `HU7`). | ||
- Definitions are reverse-engineered from DLLs and SMR-D files. If the definition does not innately exist in those files, they will not be available here (e.g. high-level instrument cluster definitions). | ||
- There are ECUs that share the same seed-key function. For example, `CRD3` and `CRD3S2` appear to share the same function as `CRD3NFZ`. | ||
- The core of this project is a "portable" .NET 5 class library which can be reused on other platforms. | ||
- As the security providers are now written in a high-level language, they can be better studied. For example, `DaimlerStandardSecurityAlgo` performs a XOR with its private key as a final step, which allows the private key to be recovered from a known seed and key. | ||
- `DaimlerStandardSecurityAlgo` is usually used for firmware flashing, and might not unlock other capabilities such as variant-coding. | ||
|
||
## Contributing | ||
|
||
Contributions in adding security providers and definitions are welcome. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 16 | ||
VisualStudioVersion = 16.0.30711.63 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnlockECU", "UnlockECU\UnlockECU.csproj", "{9DBD6CB7-68B3-4801-95B7-D760C49E2A83}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualUnlockECU", "VisualUnlockECU\VisualUnlockECU.csproj", "{FA2EF721-9B46-4EB9-8444-0ABAF6F5185A}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnlockECUTests", "UnlockECUTests\UnlockECUTests.csproj", "{6252DB08-EFD2-4889-B97F-090726D9DC9C}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{9DBD6CB7-68B3-4801-95B7-D760C49E2A83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{9DBD6CB7-68B3-4801-95B7-D760C49E2A83}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{9DBD6CB7-68B3-4801-95B7-D760C49E2A83}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{9DBD6CB7-68B3-4801-95B7-D760C49E2A83}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{FA2EF721-9B46-4EB9-8444-0ABAF6F5185A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{FA2EF721-9B46-4EB9-8444-0ABAF6F5185A}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{FA2EF721-9B46-4EB9-8444-0ABAF6F5185A}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{FA2EF721-9B46-4EB9-8444-0ABAF6F5185A}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{6252DB08-EFD2-4889-B97F-090726D9DC9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{6252DB08-EFD2-4889-B97F-090726D9DC9C}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{6252DB08-EFD2-4889-B97F-090726D9DC9C}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{6252DB08-EFD2-4889-B97F-090726D9DC9C}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {CC1E2894-FC7F-474F-8A14-00529B7EF07F} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace UnlockECU | ||
{ | ||
/// <summary> | ||
/// Utilities for bit and byte operations. | ||
/// (Frequently copied-and-pasted across my projects) | ||
/// </summary> | ||
public class BitUtility | ||
{ | ||
/// <summary> | ||
/// Sets all values in an array of bytes to a specific value | ||
/// </summary> | ||
/// <param name="value">Value to set byte array to</param> | ||
/// <param name="buf">Target byte array buffer</param> | ||
public static void Memset(byte value, byte[] buf) | ||
{ | ||
for (int i = 0; i < buf.Length; i++) | ||
{ | ||
buf[i] = value; | ||
} | ||
} | ||
// Internally used by BytesFromHex | ||
private static byte[] StringToByteArrayFastest(string hex) | ||
{ | ||
// see https://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array | ||
if (hex.Length % 2 == 1) | ||
{ | ||
throw new Exception("The binary key cannot have an odd number of digits"); | ||
} | ||
byte[] arr = new byte[hex.Length >> 1]; | ||
for (int i = 0; i < hex.Length >> 1; ++i) | ||
{ | ||
arr[i] = (byte)((GetHexValue(hex[i << 1]) << 4) + (GetHexValue(hex[(i << 1) + 1]))); | ||
} | ||
return arr; | ||
} | ||
// Internally used by StringToByteArrayFastest | ||
private static int GetHexValue(char hex) | ||
{ | ||
int val = (int)hex; | ||
return val - (val < 58 ? 48 : 55); | ||
} | ||
/// <summary> | ||
/// Converts an array of bytes into its hex-string equivalent | ||
/// </summary> | ||
/// <param name="inBytes">Input byte array</param> | ||
/// <param name="spacedOut">Option to add spaces between individual bytes</param> | ||
/// <returns>Hex-string based on the input byte array</returns> | ||
public static string BytesToHex(byte[] inBytes, bool spacedOut = false) | ||
{ | ||
return BitConverter.ToString(inBytes).Replace("-", spacedOut ? " " : ""); | ||
} | ||
|
||
/// <summary> | ||
/// Converts an array of bytes into a printable hex-string | ||
/// </summary> | ||
/// <param name="hexString">Input hex-string to convert into a byte array</param> | ||
/// <returns>Byte array based on the input hex-string</returns> | ||
public static byte[] BytesFromHex(string hexString) | ||
{ | ||
return StringToByteArrayFastest(hexString.Replace(" ", "")); | ||
} | ||
|
||
/// <summary> | ||
/// Resize a smaller array of bytes to a larger array. The padding bytes will be 0. | ||
/// </summary> | ||
/// <param name="inData">Input byte array</param> | ||
/// <param name="finalSize">New size for the input array</param> | ||
/// <returns>Resized byte array</returns> | ||
public static byte[] PadBytes(byte[] inData, int finalSize) | ||
{ | ||
if (inData.Length > finalSize) | ||
{ | ||
return inData; | ||
} | ||
byte[] result = new byte[finalSize]; | ||
Buffer.BlockCopy(inData, 0, result, 0, inData.Length); | ||
return result; | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace UnlockECU | ||
{ | ||
public class Definition | ||
{ | ||
public string EcuName { get; set; } | ||
public int AccessLevel { get; set; } | ||
public int SeedLength { get; set; } | ||
public int KeyLength { get; set; } | ||
public string Provider { get; set; } | ||
public string Origin { get; set; } | ||
public List<Parameter> Parameters { get; set; } | ||
|
||
[System.Text.Json.Serialization.JsonIgnore] | ||
public string ParamParent; | ||
|
||
public override string ToString() | ||
{ | ||
StringBuilder sb = new StringBuilder($"Name: {EcuName} ({Origin}), Level: {AccessLevel}, Seed Length: {SeedLength}, Key Length: {KeyLength}, Provider: {Provider}"); | ||
return sb.ToString(); | ||
/* | ||
// uncomment and remove the return above to print verbose parameter data | ||
foreach (Parameter row in Parameters) | ||
{ | ||
sb.AppendLine(); | ||
sb.Append($"Parameter[{row.Key}] ({row.DataType}) : {row.Value}"); | ||
} | ||
return sb.ToString(); | ||
*/ | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace UnlockECU | ||
{ | ||
public class Parameter | ||
{ | ||
public string Key { get; set; } | ||
public string Value { get; set; } | ||
public string DataType { get; set; } | ||
[System.Text.Json.Serialization.JsonIgnore] | ||
public int AccessLevel = -1; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using System; | ||
using System.IO; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace UnlockECU | ||
{ | ||
class Program | ||
{ | ||
|
||
static void Main(string[] args) | ||
{ | ||
Console.WriteLine("UnlockECU (Running as console application)"); | ||
|
||
string definitionJson = File.ReadAllText("db.json"); | ||
|
||
List<Definition> definitions = System.Text.Json.JsonSerializer.Deserialize<List<Definition>>(definitionJson); | ||
List<SecurityProvider> providers = SecurityProvider.GetSecurityProviders(); | ||
|
||
ReverseKey(BitUtility.BytesFromHex("BA00D268 972D452D"), BitUtility.BytesFromHex("BE515D46")); // reverse key 0x3F9C71A5 (CRD3S2SEC9A) | ||
|
||
Console.ReadKey(); | ||
} | ||
|
||
static void ReverseKey(byte[] inSeed, byte[] outKeyBytes) | ||
{ | ||
long kA = 1103515245L; | ||
long kC = 12345L; | ||
|
||
long seedA = BytesToInt(inSeed, Endian.Big, 0); | ||
long seedB = BytesToInt(inSeed, Endian.Big, 4); | ||
|
||
long outKey = BytesToInt(outKeyBytes, Endian.Big); | ||
|
||
long intermediate1 = kA * seedA + kC; | ||
long intermediate2 = kA * seedB + kC; | ||
|
||
long xorA = intermediate1 ^ intermediate2; | ||
|
||
long reverseCryptoKey = (xorA ^ outKey) & 0xFFFFFFFF; // reverse key 0x3F9C71A5 (CRD3S2SEC9A) | ||
|
||
Console.WriteLine($"Reversed DSSA key: {reverseCryptoKey:X}"); | ||
} | ||
|
||
public enum Endian | ||
{ | ||
Big, | ||
Little, | ||
} | ||
public static uint BytesToInt(byte[] inBytes, Endian endian, int offset = 0) | ||
{ | ||
uint result = 0; | ||
if (endian == Endian.Big) | ||
{ | ||
result |= (uint)inBytes[offset++] << 24; | ||
result |= (uint)inBytes[offset++] << 16; | ||
result |= (uint)inBytes[offset++] << 8; | ||
result |= (uint)inBytes[offset++] << 0; | ||
} | ||
else | ||
{ | ||
result |= (uint)inBytes[offset++] << 0; | ||
result |= (uint)inBytes[offset++] << 8; | ||
result |= (uint)inBytes[offset++] << 16; | ||
result |= (uint)inBytes[offset++] << 24; | ||
} | ||
return result; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace UnlockECU | ||
{ | ||
/// <summary> | ||
/// Simpler version of DaimlerStandardSecurityAlgo with custom kA, kC, and no blockB | ||
/// </summary> | ||
class DRVU_PROF : SecurityProvider | ||
{ | ||
public override bool GenerateKey(byte[] inSeed, byte[] outKey, int accessLevel, List<Parameter> parameters) | ||
{ | ||
byte[] cryptoKeyBytes = GetParameterBytearray(parameters, "KeyConst"); | ||
uint cryptoKey = BytesToInt(cryptoKeyBytes, Endian.Big); | ||
|
||
long kA = 258028488L; | ||
long kC = 1583629211L; | ||
|
||
if ((inSeed.Length != 4) || (outKey.Length != 4)) | ||
{ | ||
return false; | ||
} | ||
|
||
long seedA = BytesToInt(inSeed, Endian.Big, 0); | ||
|
||
long intermediate1 = kA * seedA + kC; | ||
long seedKey = intermediate1 % cryptoKey; | ||
|
||
IntToBytes((uint)seedKey, outKey, Endian.Big); | ||
return true; | ||
} | ||
|
||
public override string GetProviderName() | ||
{ | ||
return "DRVU_PROF"; | ||
} | ||
} | ||
} |
Oops, something went wrong.