2022-04-18 01:06:03 -07:00
using System ;
using System.IO ;
using System.IO.Compression ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
using System.Windows.Forms ;
static class Class_RWD
{
private static string part_number_prefix = "" ;
private static List < byte [ ] > firmware_candidates = new List < byte [ ] > ( ) ;
public static byte [ ] _keys = new byte [ ] { } ;
2022-04-18 12:39:55 -07:00
public static byte [ ] _firmware_encrypted = new byte [ ] { } ;
2022-04-18 01:06:03 -07:00
public static UInt32 start = 0 U ;
public static UInt32 size = 0 U ;
2022-04-19 02:07:30 -07:00
private static string [ ] SuppportedVersions = new string [ ] { } ;
private static string [ ] SuppportedFWKeys = new string [ ] { } ;
private static string CanAddress = "" ;
private static byte [ ] DecodersBytes = new byte [ ] { } ; //Used to decode rwd to bin
private static byte [ ] EncodersBytes = new byte [ ] { } ; //Used to encode bin to rwd
private static byte [ ] RWD_encrypted_StartFile = new byte [ ] { } ; //Used to encode bin to rwd
2022-04-20 22:32:03 -07:00
public static byte BootloaderSum = 0 ;
2022-04-18 01:06:03 -07:00
private static GForm_Main GForm_Main_0 ;
public static void Load ( ref GForm_Main GForm_Main_1 )
{
GForm_Main_0 = GForm_Main_1 ;
}
2022-04-19 02:07:30 -07:00
public static void CompressFile ( string ThisFile , string CompressedName )
{
FileStream originalFileStream = File . Open ( ThisFile , FileMode . Open ) ;
FileStream compressedFileStream = File . Create ( CompressedName ) ;
GZipStream compressor = new GZipStream ( compressedFileStream , CompressionMode . Compress ) ;
originalFileStream . CopyTo ( compressor ) ;
}
2022-04-18 01:06:03 -07:00
public static byte [ ] Decompress ( string ThisFile )
{
Stream compressedStream = new MemoryStream ( File . ReadAllBytes ( ThisFile ) ) ;
2022-04-19 02:07:30 -07:00
GZipStream zipStream = new GZipStream ( compressedStream , CompressionMode . Decompress ) ;
2022-04-18 01:06:03 -07:00
MemoryStream resultStream = new MemoryStream ( ) ;
zipStream . CopyTo ( resultStream ) ;
return resultStream . ToArray ( ) ;
}
2022-04-19 02:07:30 -07:00
public static UInt16 ToUInt16BE ( byte [ ] TwoBytes )
{
UInt16 k0 = BitConverter . ToUInt16 ( TwoBytes , 0 ) ;
UInt16 k1 = BitConverter . ToUInt16 ( BitConverter . GetBytes ( k0 ) . Reverse ( ) . ToArray ( ) , 0 ) ;
return k1 ;
}
2022-04-24 02:49:42 -07:00
public static UInt32 ToUInt32BE ( byte [ ] FourBytes )
{
int k0 = BitConverter . ToInt32 ( FourBytes , 0 ) ;
int k1 = BitConverter . ToInt32 ( BitConverter . GetBytes ( k0 ) . Reverse ( ) . ToArray ( ) , 0 ) ;
return ( UInt32 ) k1 ;
}
/ * public static UInt16 checksum_by_sum ( byte [ ] fw , uint start , uint end )
2022-04-19 02:07:30 -07:00
{
int s = 0 ;
uint valuescount = ( end - start ) / 2 ;
for ( int i = 0 ; i < valuescount ; i + + )
{
byte [ ] ThisTwoBytes = new byte [ 2 ] { fw [ start + ( i * 2 ) ] , fw [ start + ( i * 2 ) + 1 ] } ;
s + = ToUInt16BE ( ThisTwoBytes ) ;
if ( s > 0xFFFF ) s - = 0xFFFF ;
}
return ( UInt16 ) s ;
}
private static UInt16 checksum_by_negative_sum ( byte [ ] fw , uint start , uint end )
{
int s = 0 ;
uint valuescount = ( end - start ) / 2 ;
for ( int i = 0 ; i < valuescount ; i + + )
{
byte [ ] ThisTwoBytes = new byte [ 2 ] { fw [ start + ( i * 2 ) ] , fw [ start + ( i * 2 ) + 1 ] } ;
s - = ToUInt16BE ( ThisTwoBytes ) ;
if ( s < 0 ) s + = 0xFFFF ;
}
return ( UInt16 ) s ;
2022-04-24 02:49:42 -07:00
} * /
private static UInt32 Get_rwd_checksum ( byte [ ] data , uint start , uint end )
{
uint s = 0 ;
uint valuescount = ( end - start ) ;
for ( int i = 0 ; i < valuescount ; i + + )
{
byte ThisValuee = data [ start + i ] ;
s + = ThisValuee ;
if ( s > 0xFFFFFFFF ) s - = 0xFFFFFFFF ;
}
s = ToUInt32BE ( BitConverter . GetBytes ( s ) ) ;
return ( UInt32 ) s ;
2022-04-19 02:07:30 -07:00
}
2022-04-18 01:06:03 -07:00
2022-04-19 02:07:30 -07:00
//######################################################################################################
//######################################################################################################
public static void LoadBIN ( string f_name , string f_nameFW )
{
byte [ ] data = File . ReadAllBytes ( f_name ) ;
GForm_Main_0 . method_1 ( "Encrypting file: " + f_name ) ;
//Load .rwd file for obtaining 'encryption' method and then encrypt the .bin using the same method.
LoadRWD ( f_nameFW , true , false ) ;
2022-04-24 02:49:42 -07:00
//Copy Start file bytes from the selected rwd file, then add the dat aand checksum bytes
byte [ ] dataEncrypted = new byte [ RWD_encrypted_StartFile . Length + data . Length + 4 ] ;
2022-04-19 02:07:30 -07:00
for ( int i = 0 ; i < RWD_encrypted_StartFile . Length ; i + + ) dataEncrypted [ i ] = RWD_encrypted_StartFile [ i ] ;
//Encrypt .bin data bytes to .rwd format
for ( int i = 0 ; i < data . Length ; i + + )
{
byte ThisByte = data [ i ] ;
dataEncrypted [ RWD_encrypted_StartFile . Length + i ] = EncodersBytes [ ThisByte ] ;
}
//Fix Checksums
2022-04-24 02:49:42 -07:00
UInt32 ChecksumValue = Get_rwd_checksum ( dataEncrypted , 0 , ( uint ) dataEncrypted . Length ) ;
byte [ ] ChecksumBytes = BitConverter . GetBytes ( ChecksumValue ) ;
if ( ChecksumBytes . Length = = 4 )
{
for ( int i = 0 ; i < ChecksumBytes . Length ; i + + )
{
dataEncrypted [ ( ( dataEncrypted . Length - 1 ) - 4 ) + i ] = ChecksumBytes [ i ] ;
}
GForm_Main_0 . method_1 ( "Checksum bytes fixed!" ) ;
}
else
{
GForm_Main_0 . method_1 ( "Checksum is not 4bytes long!" ) ;
}
2022-04-19 02:07:30 -07:00
//Save Encrypted rwd firmware
string ThisPath = Path . GetDirectoryName ( f_name ) + @"\" + Path . GetFileNameWithoutExtension ( f_name ) + ".rwd" ;
File . Create ( ThisPath ) . Dispose ( ) ;
File . WriteAllBytes ( ThisPath , dataEncrypted ) ;
GForm_Main_0 . method_1 ( "Saved encrypted firmware file: " + ThisPath ) ;
//Save ZIPPED Encrypted firmware
CompressFile ( ThisPath , ThisPath + ".gz" ) ;
}
//######################################################################################################
//######################################################################################################
public static void LoadRWD ( string f_name , bool FullDecrypt , bool Saving )
2022-04-18 01:06:03 -07:00
{
byte [ ] data = new byte [ ] { } ;
if ( Path . GetExtension ( f_name ) . ToLower ( ) . Contains ( "gz" ) ) data = Decompress ( f_name ) ;
else data = File . ReadAllBytes ( f_name ) ;
GForm_Main_0 . method_1 ( "Decrypting file: " + f_name ) ;
string indicatorBytes = data [ 0 ] . ToString ( "x2" ) + data [ 1 ] . ToString ( "x2" ) + data [ 2 ] . ToString ( "x2" ) ;
if ( indicatorBytes ! = "5a0d0a" )
2022-05-14 16:57:57 -07:00
//if (indicatorBytes != "5a0d0a" && indicatorBytes != "310d0a")
2022-04-18 01:06:03 -07:00
{
GForm_Main_0 . method_1 ( "Not Compatible file!" ) ;
return ;
}
2022-05-14 16:57:57 -07:00
byte Mode = 0x5a ;
if ( indicatorBytes = = "310d0a" ) Mode = 0x31 ;
2022-04-18 01:06:03 -07:00
byte [ ] headers0 = { } ;
byte [ ] headers1 = { } ;
byte [ ] headers2 = { } ;
byte [ ] headers3 = { } ;
byte [ ] headers4 = { } ;
byte [ ] headers5 = { } ;
2022-05-14 16:57:57 -07:00
int idx = 3 ;
2022-04-18 01:06:03 -07:00
for ( int i = 0 ; i < 6 ; i + + )
{
byte [ ] header = { } ;
2022-05-14 16:57:57 -07:00
if ( Mode = = 0x5a )
2022-04-18 01:06:03 -07:00
{
2022-05-14 16:57:57 -07:00
byte count = data [ idx ] ;
2022-04-18 01:06:03 -07:00
idx + = 1 ;
2022-05-14 16:57:57 -07:00
for ( int j = 0 ; j < count ; j + + )
{
// first byte is length of value
int length = data [ idx ] ;
idx + = 1 ;
byte [ ] v = Slice ( data , idx , idx + length ) ;
idx + = length ;
header = Push ( header , v ) ;
}
}
if ( Mode = = 0x31 )
{
byte [ ] h_prefix = new byte [ 2 ] ;
idx + = 4 ;
h_prefix [ 0 ] = data [ idx ] ;
h_prefix [ 1 ] = data [ idx + 1 ] ;
//h_prefix[2] = data[idx + 2];
idx + = 2 ;
if ( h_prefix [ 0 ] ! = 0x0d & & h_prefix [ 1 ] ! = 0x0a )
{
GForm_Main_0 . method_1 ( "header delimiter not found!" ) ;
return ;
}
2022-04-18 01:06:03 -07:00
2022-05-14 16:57:57 -07:00
//while (data[idx] != h_prefix[0] && data[idx + 1] != h_prefix[1] && data[idx + 2] != h_prefix[2])
while ( data [ idx ] ! = h_prefix [ 0 ] & & data [ idx + 1 ] ! = h_prefix [ 1 ] )
{
int end_idx = - 1 ;
for ( int j = idx ; j < data . Length - 1 ; j + + )
{
if ( data [ j ] = = 0x0d & & data [ j + 1 ] = = 0x0a )
{
end_idx = j ;
j = data . Length ;
}
}
if ( end_idx = = - 1 )
{
GForm_Main_0 . method_1 ( "field delimiter not found!" ) ;
return ;
}
byte [ ] v_data = Slice ( data , idx , end_idx ) ;
idx + = v_data . Length ;
//skip past field delimiter
//byte[] v_suffix = Slice(data, idx, idx + 2);
idx + = 2 ;
header = Push ( header , v_data ) ;
}
//skip past delimiter
byte [ ] h_suffix = Slice ( data , idx , idx + 2 ) ;
idx + = 3 ;
if ( h_prefix ! = h_suffix )
//if (h_prefix[0] != h_suffix[0] && h_prefix[1] != h_suffix[1])
{
Console . WriteLine ( h_prefix [ 0 ] . ToString ( "X2" ) + h_prefix [ 1 ] . ToString ( "X2" ) ) ;
Console . WriteLine ( h_suffix [ 0 ] . ToString ( "X2" ) + h_suffix [ 1 ] . ToString ( "X2" ) ) ;
GForm_Main_0 . method_1 ( "header prefix and suffix do not match" ) ;
return ;
}
2022-04-18 01:06:03 -07:00
}
if ( i = = 0 ) headers0 = header ;
if ( i = = 1 ) headers1 = header ;
if ( i = = 2 ) headers2 = header ; //ECU Type (Auto/Manual)
if ( i = = 3 ) headers3 = header ; //Versions
if ( i = = 4 ) headers4 = header ; //Security Keys
if ( i = = 5 ) headers5 = header ; //Firmware Keys
}
start = ReadUInt32BE ( data , idx ) ;
idx + = 4 ;
size = ReadUInt32BE ( data , idx ) ;
idx + = 4 ;
2022-04-19 02:07:30 -07:00
//Get Start file bytes array
RWD_encrypted_StartFile = new byte [ idx ] ;
for ( int i = 0 ; i < idx ; i + + ) RWD_encrypted_StartFile [ i ] = data [ i ] ;
2022-04-18 01:06:03 -07:00
byte [ ] firmware = Slice ( data , idx , data . Length - 4 ) ;
idx + = firmware . Length ;
UInt32 checksum = ReadUInt32BE ( data , idx ) ;
idx + = 4 ;
if ( idx ! = data . Length ) GForm_Main_0 . method_1 ( "not at end of file after unpacking" ) ;
if ( ( headers3 . Length / 16 ) ! = ( headers4 . Length / 6 ) ) GForm_Main_0 . method_1 ( "different number of versions and security access tokens" ) ;
_firmware_encrypted = firmware ;
_keys = headers5 ;
2022-04-19 02:07:30 -07:00
//Get supported versions and supported firmwares keys
int VersionsCount = ( headers3 . Length / 16 ) ;
SuppportedVersions = new string [ VersionsCount ] ;
SuppportedFWKeys = new string [ VersionsCount ] ;
string SoftwareKey = _keys [ 0 ] . ToString ( "X2" ) + _keys [ 1 ] . ToString ( "X2" ) + _keys [ 2 ] . ToString ( "X2" ) ;
for ( int i = 0 ; i < VersionsCount ; i + + )
{
//Get Supported versions
byte [ ] buf = new byte [ 16 ] ;
int EmptyCount = 0 ;
for ( int i2 = 0 ; i2 < 16 ; i2 + + )
{
buf [ i2 ] = headers3 [ ( i * 16 ) + i2 ] ;
if ( buf [ i2 ] = = 0 )
{
buf [ i2 ] = 0x2E ;
EmptyCount + + ;
}
}
2022-04-20 22:32:03 -07:00
2022-04-19 02:07:30 -07:00
//Remove Empty chars
byte [ ] bufRedo = new byte [ 16 - EmptyCount ] ;
for ( int i2 = 0 ; i2 < bufRedo . Length ; i2 + + ) bufRedo [ i2 ] = buf [ i2 ] ;
SuppportedVersions [ i ] = System . Text . Encoding . ASCII . GetString ( bufRedo ) ;
//Get supported Firmwares keys according to the supported versions
byte [ ] bufkey = new byte [ 6 ] ;
for ( int i2 = 0 ; i2 < 6 ; i2 + + )
{
bufkey [ i2 ] = headers4 [ ( i * 6 ) + i2 ] ;
}
SuppportedFWKeys [ i ] = bufkey [ 0 ] . ToString ( "X2" ) + bufkey [ 1 ] . ToString ( "X2" ) + bufkey [ 2 ] . ToString ( "X2" ) + bufkey [ 3 ] . ToString ( "X2" ) + bufkey [ 4 ] . ToString ( "X2" ) + bufkey [ 5 ] . ToString ( "X2" ) ;
}
//Get CanAddress Infos
2022-04-20 22:32:03 -07:00
CanAddress = "18DA" + headers2 [ 0 ] . ToString ( "X2" ) + "F1" ;
string AdditionnalCanInfos = "" ;
if ( headers2 [ 0 ] = = 0x0e ) AdditionnalCanInfos = " (CVT Transmission (maybe?))" ;
if ( headers2 [ 0 ] = = 0x10 ) AdditionnalCanInfos = " (Manual Transmission)" ;
if ( headers2 [ 0 ] = = 0x11 ) AdditionnalCanInfos = " (Automatics Transmission)" ;
if ( headers2 [ 0 ] = = 0x30 ) AdditionnalCanInfos = " (Electric Power Sterring)" ;
2022-04-19 02:07:30 -07:00
//Print/Log Informations
GForm_Main_0 . method_1 ( "Firmware Start: 0x" + start . ToString ( "X" ) ) ;
GForm_Main_0 . method_1 ( "Firmware Size: 0x" + size . ToString ( "X" ) ) ;
2022-04-20 22:32:03 -07:00
GForm_Main_0 . method_1 ( "CanAddress: 0x" + CanAddress + AdditionnalCanInfos ) ;
2022-04-19 02:07:30 -07:00
GForm_Main_0 . method_1 ( "Software Keys: 0x" + SoftwareKey ) ;
GForm_Main_0 . method_1 ( "Supported Versions (and keys): " ) ;
for ( int i = 0 ; i < SuppportedVersions . Length ; i + + ) GForm_Main_0 . method_1 ( SuppportedVersions [ i ] + " (0x" + SuppportedFWKeys [ i ] + ")" ) ;
//Perform FULL decryption (convert .rwd to .bin)
if ( FullDecrypt ) DecryptRWD ( f_name , Saving ) ;
2022-04-18 01:06:03 -07:00
}
2022-04-19 02:07:30 -07:00
private static void DecryptRWD ( string f_name , bool Saving )
2022-04-18 01:06:03 -07:00
{
part_number_prefix = get_part_number_prefix ( f_name ) ;
firmware_candidates = decrypt ( part_number_prefix ) ;
if ( firmware_candidates . Count = = 0 )
{
//try with a shorter part number
GForm_Main_0 . method_1 ( "failed on long part number, trying truncated part number ..." ) ;
part_number_prefix = get_part_number_prefix ( f_name , true ) ;
firmware_candidates = decrypt ( part_number_prefix ) ;
}
if ( firmware_candidates . Count = = 0 )
{
GForm_Main_0 . method_1 ( "decryption failed!" ) ;
GForm_Main_0 . method_1 ( "(could not find a cipher that results in the part number being in the data)" ) ;
return ;
}
2022-04-19 02:07:30 -07:00
//Remove duplicated Candidates
if ( firmware_candidates . Count > 1 )
{
List < byte [ ] > firmware_candidatesBUFFER = firmware_candidates ;
firmware_candidates = new List < byte [ ] > ( ) ;
byte [ ] LastCandidate = firmware_candidatesBUFFER [ firmware_candidatesBUFFER . Count - 1 ] ;
for ( int i = 0 ; i < firmware_candidatesBUFFER . Count - 1 ; i + + )
{
byte [ ] CurrentCandidate = firmware_candidatesBUFFER [ i ] ;
if ( CurrentCandidate ! = LastCandidate )
{
firmware_candidates . Add ( CurrentCandidate ) ;
}
}
firmware_candidates . Add ( LastCandidate ) ;
}
2022-04-18 01:06:03 -07:00
if ( firmware_candidates . Count > 1 ) GForm_Main_0 . method_1 ( "multiple sets of keys resulted in data containing the part number" ) ;
//###################################################################
//###################################################################
2022-04-20 22:32:03 -07:00
foreach ( byte [ ] fc in firmware_candidates )
{
//Checksum location for SH7058 1mb rom file are located at 0x8400, it's a 1byte sum calculated from negative sum of the full binary
//Since we are missing the bootloader section of the full binary we have to remove the section 0x0000 to 0x8000(Start_Address)
//we can calculate what was the 'sum' of the bootloader by subtracting the 'sum' of the decrypted firmware!
2022-05-14 16:57:57 -07:00
if ( fc . Length - 1 = = 0xF7FFF | | fc . Length - 1 = = 0x1EFFFF | | fc . Length - 1 = = 0x26FFFF )
2022-04-20 22:32:03 -07:00
{
2022-05-14 16:57:57 -07:00
int CheckLocation = 0 ;
if ( fc . Length - 1 = = 0xF7FFF ) CheckLocation = 0x400 ;
if ( fc . Length - 1 = = 0x1EFFFF ) CheckLocation = 0x12 ; //0x10012
if ( fc . Length - 1 = = 0x26FFFF ) CheckLocation = 0x1F03E6 ; //0x2003E6
byte num = GetBootloaderSum ( fc , CheckLocation ) ;
byte num2 = GetNegativeChecksumFWBin ( fc , CheckLocation ) ;
2022-04-20 22:32:03 -07:00
byte ThisSum = num ;
ThisSum - = num2 ;
2022-05-14 16:57:57 -07:00
byte chk = fc [ CheckLocation ] ;
2022-04-20 22:32:03 -07:00
if ( chk = = ThisSum )
{
GForm_Main_0 . method_1 ( "checksums good!" ) ;
BootloaderSum = num ;
GForm_Main_0 . method_1 ( "Bootloader Sum are 0x" + BootloaderSum . ToString ( "X" ) ) ;
}
}
}
//###############################################
2022-04-18 01:06:03 -07:00
/ * List < byte [ ] > firmware_good = new List < byte [ ] > ( ) ;
idx = 0 ;
foreach ( byte [ ] fc in firmware_candidates )
{
//# concat all address blocks to allow checksum validation using memory addresses
byte [ ] firmwareBLK = new byte [ ] { } ;
foreach ( int block in xrange ( fc . Length ) ) {
start = firmware_blocks [ block ] [ "start" ] ;
//# fill gaps with \x00;
if ( firmwareBLK . Length < start ) {
firmwareBLK + = ' \ x00 ' * ( start - firmwareBLK . Length ) ;
}
firmwareBLK + = fc [ block ] ;
}
//# validate known checksums
if ( f_base in checksums . keys ( ) )
{
GForm_Main_0 . method_1 ( string . Format ( "firmware[{0}] checksums:" , idx ) ) ;
bool match = true ;
foreach ( start , end in checksums [ f_base ] )
{
byte sum = ord ( get_checksum ( firmwareBLK [ start : end ] ) ) ;
byte chk = ord ( firmwareBLK [ end ] ) ;
string Value2 = "" ;
if ( chk = = sum ) Value2 = "=" ;
else Value2 = "!=" ;
GForm_Main_0 . method_1 ( string . Format ( "{0} {1} {2}" , chk . ToString ( "X2" ) , Value2 , sum . ToString ( "X2" ) ) ) ;
if ( sum ! = chk ) match = false ;
}
if ( match )
{
GForm_Main_0 . method_1 ( "checksums good!" ) ;
firmware_good . append ( firmwareBLK ) ;
}
else
{
GForm_Main_0 . method_1 ( "checksums bad!" ) ;
}
}
else
{
//# no checksums so assume good
firmware_good . append ( firmwareBLK ) ;
}
idx + = 1 ;
} * /
//###################################################################
//###################################################################
//Saving Decrypted Firmwares
2022-04-19 02:07:30 -07:00
if ( Saving )
2022-04-18 01:06:03 -07:00
{
2022-04-19 02:07:30 -07:00
bool AsSavedFile = false ;
int FileCount = 1 ;
foreach ( byte [ ] f_data in firmware_candidates )
{
string FileNumber = "" ;
if ( firmware_candidates . Count > 1 ) FileNumber = "_" + FileCount ;
string ThisPath = Path . GetDirectoryName ( f_name ) + @"\" + Path . GetFileNameWithoutExtension ( f_name ) . Replace ( ".rwd" , "" ) . Replace ( ".RWD" , "" ) + ".0x" + start . ToString ( "X" ) + FileNumber + ".bin" ;
File . Create ( ThisPath ) . Dispose ( ) ;
File . WriteAllBytes ( ThisPath , f_data ) ; //-> f_data[start_addr:]
GForm_Main_0 . method_1 ( "Saved decrypted firmware file: " + ThisPath ) ;
AsSavedFile = true ;
FileCount + + ;
}
if ( AsSavedFile ) GForm_Main_0 . method_1 ( "Note: The decrypted firmware file (.bin), is not a complete .bin file! It cannot be used to perform a 'Flash Rom' to the ECU, the bootloader section from 0x0000 to 0x" + start . ToString ( "X" ) + " of the rom is Missing." ) ;
2022-04-18 01:06:03 -07:00
}
}
2022-05-14 16:57:57 -07:00
public static byte GetBootloaderSum ( byte [ ] FWFileBytes , int CheckLocation )
2022-04-20 22:32:03 -07:00
{
//###############################
//Get Checksum (sum)
byte [ ] BufferBytes = FWFileBytes ;
2022-05-14 16:57:57 -07:00
byte num = BufferBytes [ CheckLocation ] ;
byte num2 = GetNegativeChecksumFWBin ( BufferBytes , CheckLocation ) ;
2022-04-20 22:32:03 -07:00
byte BTSum = num ;
BTSum + = num2 ;
return BTSum ;
}
2022-05-14 16:57:57 -07:00
public static byte GetNegativeChecksumFWBin ( byte [ ] byte_1 , int CheckLocation )
2022-04-20 22:32:03 -07:00
{
byte b = 0 ;
for ( int i = 0 ; i < byte_1 . Length ; i + + )
{
2022-05-14 16:57:57 -07:00
if ( i ! = CheckLocation ) b - = byte_1 [ i ] ;
2022-04-20 22:32:03 -07:00
}
return b ;
}
2022-04-18 01:06:03 -07:00
public static byte [ ] Push ( byte [ ] bArray , byte [ ] newBytes )
{
byte [ ] newArray = new byte [ bArray . Length + newBytes . Length ] ;
bArray . CopyTo ( newArray , newBytes . Length ) ;
for ( int i = 0 ; i < newBytes . Length ; i + + )
{
newArray [ i ] = newBytes [ i ] ;
}
return newArray ;
}
public static byte [ ] Slice ( byte [ ] bArray , int StartInd , int EndInd )
{
int Lenght = ( EndInd - StartInd ) ;
byte [ ] newArray = new byte [ Lenght ] ;
for ( int i = 0 ; i < Lenght ; i + + )
{
newArray [ i ] = bArray [ StartInd + i ] ;
}
return newArray ;
}
public static UInt32 ReadUInt32BE ( byte [ ] buffer , int StartInd )
{
var value = BitConverter . ToUInt32 ( buffer , StartInd ) ;
var rs = BitConverter . ToUInt32 ( BitConverter . GetBytes ( value ) . Reverse ( ) . ToArray ( ) , 0 ) ;
return rs ;
}
private static string get_part_number_prefix ( string fn , bool Short = false )
{
string f_name = Path . GetFileNameWithoutExtension ( fn ) ;
f_name = f_name . Replace ( "-" , "" ) . Replace ( "_" , "" ) ;
string prefix = f_name . Substring ( 0 , 5 ) + "-" + f_name . Substring ( 5 , 3 ) ;
if ( ! Short ) prefix + = '-' + f_name . Substring ( 8 , 4 ) ;
return prefix ;
}
public static byte [ ] StringToByteArray ( string hex )
{
return Enumerable . Range ( 0 , hex . Length )
. Where ( x = > x % 2 = = 0 )
. Select ( x = > Convert . ToByte ( hex . Substring ( x , 2 ) , 16 ) )
. ToArray ( ) ;
}
2022-04-27 04:52:09 -07:00
public static int HexStringToInt ( string hex )
{
byte [ ] ThisBytes = StringToByteArray ( hex ) ;
if ( ThisBytes . Length = = 2 ) return BitConverter . ToInt16 ( ThisBytes , 0 ) ;
if ( ThisBytes . Length = = 4 ) return BitConverter . ToInt32 ( ThisBytes , 0 ) ;
//if (ThisBytes.Length == 8) return BitConverter.ToInt64(ThisBytes, 0);
return 0 ;
}
2022-04-18 01:06:03 -07:00
static byte [ ] _get_decoder ( string key1 , string key2 , string key3 , string op1 , string op2 , string op3 ) {
byte [ ] decoder = new byte [ 256 ] ;
List < byte > values = new List < byte > { } ;
for ( int e = 0 ; e < 256 ; e + + ) {
byte KB1 = StringToByteArray ( key1 ) [ 0 ] ;
byte KB2 = StringToByteArray ( key2 ) [ 0 ] ;
byte KB3 = StringToByteArray ( key3 ) [ 0 ] ;
uint d = GetCalc ( op3 , GetCalc ( op2 , GetCalc ( op1 , ( uint ) e , KB1 ) , KB2 ) , KB3 ) & 0xFF ;
decoder [ e ] = ( byte ) d ;
values . Add ( ( byte ) d ) ;
}
if ( values . Count = = 256 ) return decoder ;
return null ;
}
private static uint GetCalc ( string ThisOperator , uint V1 , uint V2 )
{
if ( ThisOperator = = "^" ) return CalcXOR ( V1 , V2 ) ;
if ( ThisOperator = = "&" ) return CalcAND ( V1 , V2 ) ;
if ( ThisOperator = = "|" ) return CalcOR ( V1 , V2 ) ;
if ( ThisOperator = = "+" ) return CalcADD ( V1 , V2 ) ;
if ( ThisOperator = = "-" ) return CalcSUB ( V1 , V2 ) ;
if ( ThisOperator = = "*" ) return CalcMUL ( V1 , V2 ) ;
if ( ThisOperator = = "/" ) return CalcDIV ( V1 , V2 ) ;
if ( ThisOperator = = "%" ) return CalcMOD ( V1 , V2 ) ;
return 0 ;
}
private static uint CalcXOR ( uint V1 , uint V2 )
{
return V1 ^ V2 ;
}
private static uint CalcAND ( uint V1 , uint V2 )
{
return V1 & V2 ;
}
private static uint CalcOR ( uint V1 , uint V2 )
{
return V1 | V2 ;
}
private static uint CalcADD ( uint V1 , uint V2 )
{
return V1 + V2 ;
}
private static uint CalcSUB ( uint V1 , uint V2 )
{
return V1 - V2 ;
}
private static uint CalcMUL ( uint V1 , uint V2 )
{
return V1 * V2 ;
}
private static uint CalcDIV ( uint V1 , uint V2 )
{
return V1 / V2 ;
}
private static uint CalcMOD ( uint V1 , uint V2 )
{
return V1 % V2 ;
}
private static string [ ] swapTwoNumber ( string [ ] list , int k , int i )
{
string [ ] BufferedContent = new string [ list . Length ] ;
for ( int i2 = 0 ; i2 < list . Length ; i2 + + ) BufferedContent [ i2 ] = list [ i2 ] ;
string temp = BufferedContent [ k ] ;
BufferedContent [ k ] = BufferedContent [ i ] ;
BufferedContent [ i ] = temp ;
return BufferedContent ;
}
private static string [ ] CheckIntegrity ( string [ ] Bufferedlist , string [ ] BufferedDone )
{
string OutputLine = "" ;
for ( int i = 0 ; i < Bufferedlist . Length ; i + + ) OutputLine + = Bufferedlist [ i ] + "|" ;
bool Founded = false ;
for ( int i = 0 ; i < BufferedDone . Length ; i + + )
{
if ( BufferedDone [ i ] = = OutputLine ) Founded = true ;
}
if ( ! Founded )
{
string [ ] NewBuffer = new string [ BufferedDone . Length + 1 ] ;
for ( int i = 0 ; i < BufferedDone . Length ; i + + ) NewBuffer [ i ] = BufferedDone [ i ] ;
NewBuffer [ BufferedDone . Length ] = OutputLine ;
BufferedDone = NewBuffer ;
}
return BufferedDone ;
}
public static string [ ] prnPermut ( string [ ] list )
{
string [ ] DoThisList = list ;
string [ ] BufferedContent = new string [ ] { } ;
string [ ] Bufferedlist = { DoThisList [ 0 ] , DoThisList [ 1 ] , DoThisList [ 2 ] } ; //A-B-C
BufferedContent = CheckIntegrity ( Bufferedlist , BufferedContent ) ;
for ( int i = 0 ; i < DoThisList . Length ; i + + )
{
//A-B-C
//B-A-C
//A-C-B
//C-B-A
Bufferedlist = swapTwoNumber ( DoThisList , 0 , i ) ; //SWAP A & XX
BufferedContent = CheckIntegrity ( Bufferedlist , BufferedContent ) ;
Bufferedlist = swapTwoNumber ( DoThisList , 1 , i ) ; //SWAP B & XX
BufferedContent = CheckIntegrity ( Bufferedlist , BufferedContent ) ;
}
//A-B-c -> B-C-A
Bufferedlist = swapTwoNumber ( DoThisList , 0 , 2 ) ; //SWAP A & C
Bufferedlist = swapTwoNumber ( Bufferedlist , 0 , 1 ) ; //SWAP A & B
BufferedContent = CheckIntegrity ( Bufferedlist , BufferedContent ) ;
//A-B-c -> C-A-B
Bufferedlist = swapTwoNumber ( DoThisList , 0 , 1 ) ; //SWAP A & B
Bufferedlist = swapTwoNumber ( Bufferedlist , 0 , 2 ) ; //SWAP A & C
BufferedContent = CheckIntegrity ( Bufferedlist , BufferedContent ) ;
return BufferedContent ;
}
public static string [ ] prnPermutALL ( string [ ] list )
{
string [ ] DoThisList = list ;
string [ ] BufferedContent = new string [ ] { } ;
int StartInd = 0 ;
string [ ] Bufferedlist = new string [ ] { } ;
//BufferedContent = CheckIntegrity(Bufferedlist, BufferedContent);
for ( int i4 = StartInd ; i4 < DoThisList . Length ; i4 + + )
{
for ( int i3 = StartInd ; i3 < DoThisList . Length ; i3 + + )
{
for ( int i2 = StartInd ; i2 < DoThisList . Length ; i2 + + )
{
string [ ] OperatorsList = new string [ 3 ] { DoThisList [ i2 ] , DoThisList [ i3 ] , DoThisList [ i4 ] } ;
BufferedContent = CheckIntegrity ( OperatorsList , BufferedContent ) ;
for ( int i = StartInd ; i < 3 ; i + + )
{
Bufferedlist = swapTwoNumber ( OperatorsList , StartInd , i ) ; //SWAP A & XX
BufferedContent = CheckIntegrity ( Bufferedlist , BufferedContent ) ;
Bufferedlist = swapTwoNumber ( OperatorsList , StartInd + 1 , i ) ; //SWAP B & XX
BufferedContent = CheckIntegrity ( Bufferedlist , BufferedContent ) ;
}
}
}
}
return BufferedContent ;
}
2022-04-19 02:07:30 -07:00
private static void MakeEncoderArray ( )
{
EncodersBytes = new byte [ 256 ] ;
if ( DecodersBytes . Length ! = EncodersBytes . Length )
{
GForm_Main_0 . method_1 ( "Something went wrong getting Encoders bytes!" ) ;
}
else
{
for ( int i = 0 ; i < EncodersBytes . Length ; i + + )
{
EncodersBytes [ DecodersBytes [ i ] ] = ( byte ) i ;
}
}
}
2022-04-18 01:06:03 -07:00
private static List < byte [ ] > decrypt ( string search_value )
{
//# sometimes there is an extra character after each character
//# 37805-RBB-J530 -> 3377880550--RRBCBA--JA503000
//string search_value_padded = search_value.Join(".", search_value);
string search_value_padded = "" ;
foreach ( char ThisChar in search_value )
{
search_value_padded + = ThisChar + "." ;
}
2022-04-19 02:07:30 -07:00
string search_exact = search_value . ToUpper ( ) ;
string search_padded = search_value_padded . ToUpper ( ) ;
2022-04-20 22:32:03 -07:00
GForm_Main_0 . method_1 ( "Searching:" ) ;
2022-04-24 16:05:27 -07:00
GForm_Main_0 . method_1 ( "'" + search_exact + "' and '" + search_padded + "'" ) ;
2022-04-18 01:06:03 -07:00
string [ ] operators = new string [ 8 ] {
"fn:^" , //XOR
"fn:&" , //AND
"fn:|" , //OR
"fn:+" , //ADD
"fn:-" , //SUB
"fn:*" , //MUL
"fn:/" , //DIV
"fn:%" , //MOD
} ;
2022-04-20 22:32:03 -07:00
if ( _keys . Length ! = 3 )
{
GForm_Main_0 . method_1 ( "excatly three keys currently required, cannot perform decryption!" ) ;
return new List < byte [ ] > { } ;
}
2022-04-18 01:06:03 -07:00
2022-04-20 22:32:03 -07:00
//#####################################################################################################
//This code is for trying all Keys and cypher methods to find the correct decrypting cypher
/ * List < string > keys = new List < string > { } ;
2022-04-18 01:06:03 -07:00
for ( int i = 0 ; i < _keys . Length ; i + + ) {
string k = _keys [ i ] . ToString ( "x2" ) ;
keys . Add ( String . Format ( "val:" + k + ",sym:" + "k{0}" , i ) ) ;
}
2022-04-20 22:32:03 -07:00
string [ ] key_perms = prnPermut ( keys . ToArray ( ) ) ;
string [ ] op_perms = prnPermutALL ( operators ) ; * /
//#####################################################################################################
//BUT the cypher seem to always be: (((i ^ k2) + k1) - k0) & 0xFF so use this code instead for 1000x faster decryption
string KeyPermStr = "" ;
for ( int i = _keys . Length - 1 ; i > = 0 ; i - - )
2022-04-19 02:07:30 -07:00
{
2022-04-20 22:32:03 -07:00
string k = _keys [ i ] . ToString ( "x2" ) ;
KeyPermStr + = String . Format ( "val:" + k + ",sym:" + "k{0}" , i ) + "|" ;
2022-04-19 02:07:30 -07:00
}
2022-04-20 22:32:03 -07:00
string OPPermStr = "fn:^,o1|fn:+,o2|fn:-,o3|" ;
string [ ] key_perms = new string [ ] { KeyPermStr } ;
string [ ] op_perms = new string [ ] { OPPermStr } ;
//#####################################################################################################
2022-04-18 01:06:03 -07:00
List < string > display_ciphers = new List < string > { } ;
2022-04-20 22:32:03 -07:00
List < byte [ ] > firmware_candidates_0 = new List < byte [ ] > { } ;
2022-04-18 01:06:03 -07:00
List < byte [ ] > attempted_decoders = new List < byte [ ] > { } ;
int CurrentDone = 0 ;
foreach ( string Line in key_perms )
{
string k1 = "" ;
string k2 = "" ;
string k3 = "" ;
string o1 = "" ;
string o2 = "" ;
string o3 = "" ;
string k1_CMD = "" ;
string k2_CMD = "" ;
string k3_CMD = "" ;
string [ ] SplittedParams = Line . Split ( '|' ) ;
int DoneCount = 0 ;
//Get keys values
foreach ( string Commands in SplittedParams )
{
string [ ] SplittedParamsValue = Commands . Split ( ',' ) ;
if ( SplittedParamsValue [ 0 ] . Contains ( "val" ) )
{
string thisvalue = SplittedParamsValue [ 0 ] . Split ( ':' ) [ 1 ] ;
string thiscommand = SplittedParamsValue [ 1 ] . Split ( ':' ) [ 1 ] ;
if ( DoneCount = = 0 )
{
k1 = thisvalue ;
k1_CMD = thiscommand ;
}
if ( DoneCount = = 1 )
{
k2 = thisvalue ;
k2_CMD = thiscommand ;
}
if ( DoneCount = = 2 )
{
k3 = thisvalue ;
k3_CMD = thiscommand ;
}
DoneCount + + ;
}
}
2022-04-19 02:07:30 -07:00
2022-04-18 01:06:03 -07:00
//Get operators values
foreach ( string LineOP in op_perms )
{
string [ ] SplittedParamsOP = LineOP . Split ( '|' ) ;
DoneCount = 0 ;
foreach ( string Commands in SplittedParamsOP )
{
string [ ] SplittedParamsValue = Commands . Split ( ',' ) ;
if ( SplittedParamsValue [ 0 ] . Contains ( "fn" ) )
{
string thisvalue = SplittedParamsValue [ 0 ] . Split ( ':' ) [ 1 ] ;
if ( DoneCount = = 0 ) o1 = thisvalue ;
if ( DoneCount = = 1 ) o2 = thisvalue ;
if ( DoneCount = = 2 ) o3 = thisvalue ;
DoneCount + + ;
}
}
2022-04-19 02:07:30 -07:00
//Perform decoding of bytes and search for ECU name string
2022-04-18 01:06:03 -07:00
int Percent = ( CurrentDone * 100 ) / ( key_perms . Length * op_perms . Length ) ;
GForm_Main_0 . method_4 ( Percent ) ;
CurrentDone + + ;
2022-04-19 02:07:30 -07:00
DecodersBytes = _get_decoder ( k1 , k2 , k3 , o1 , o2 , o3 ) ;
//MakeEncoderArray();
if ( DecodersBytes ! = null & & ! attempted_decoders . Contains ( DecodersBytes ) )
2022-04-18 01:06:03 -07:00
{
2022-04-19 02:07:30 -07:00
attempted_decoders . Add ( DecodersBytes ) ;
2022-04-18 01:06:03 -07:00
byte [ ] candidate = new byte [ _firmware_encrypted . Length ] ;
char [ ] decryptedCharArr = new char [ _firmware_encrypted . Length ] ;
for ( int i2 = 0 ; i2 < _firmware_encrypted . Length ; i2 + + )
{
2022-04-19 02:07:30 -07:00
byte ThisByte = DecodersBytes [ _firmware_encrypted [ i2 ] ] ;
2022-04-18 01:06:03 -07:00
candidate [ i2 ] = ThisByte ;
decryptedCharArr [ i2 ] = ( char ) ThisByte ;
}
string decrypted = new string ( decryptedCharArr ) ;
if ( ( decrypted . Contains ( search_exact ) | | decrypted . Contains ( search_padded ) ) & & ! firmware_candidates_0 . Contains ( candidate ) )
{
2022-04-19 02:07:30 -07:00
MakeEncoderArray ( ) ;
2022-04-18 01:06:03 -07:00
GForm_Main_0 . method_Log ( "X" ) ;
firmware_candidates_0 . Add ( candidate ) ;
display_ciphers . Add ( string . Format ( "(((i {0} {1}) {2} {3}) {4} {5}) & 0xFF" ,
o1 , k1_CMD ,
o2 , k2_CMD ,
o3 , k3_CMD ) ) ;
}
else
{
GForm_Main_0 . method_Log ( "." ) ;
}
Application . DoEvents ( ) ;
}
}
}
2022-04-19 02:07:30 -07:00
GForm_Main_0 . ResetProgressBar ( ) ;
2022-04-18 01:06:03 -07:00
foreach ( string cipher in display_ciphers ) {
GForm_Main_0 . method_1 ( String . Format ( "cipher: {0}" , cipher ) ) ;
}
return firmware_candidates_0 ;
}
}