unit RplDecode; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, libeay32, StdCtrls, RC4, PrivateKey; type TRPLRecord = record NPC: string; CCC: string; HWC: string; SIMLOCK: string; SIMLOCK_KEY: string; SUPERDONGLE_KEY: string; CMLA_KEY: string; WMDRM_PD: string; end; function DecodeRpl(filename: string; savefile: boolean = false): TRPLRecord; implementation function GetErrorMessage: string; var ErrMsg: array[0..160] of char; begin ERR_error_string(ERR_get_error, @ErrMsg); result := StrPas(@ErrMsg); end; procedure InitOpenSSL; begin OpenSSL_add_all_algorithms; OpenSSL_add_all_ciphers; OpenSSL_add_all_digests; ERR_load_crypto_strings; end; procedure FreeOpenSSL; begin EVP_cleanup; end; function ReadPrivateKey(AFileName: TFileName): pEVP_PKEY; var keyfile: pBIO; x: pEVP_PKEY; function cb(buffer: PChar; blength: integer; verify: integer; data: pointer): integer; cdecl; begin result := 0; end; begin keyfile := BIO_new(BIO_s_file()); BIO_read_filename(keyfile, PChar(AFilename)); x := nil; result := PEM_read_bio_PrivateKey(keyfile, x, @cb, nil); if result = nil then raise Exception.Create('Unable to read private key. ' + GetErrorMessage); BIO_free(keyfile); end; procedure RSADecrypt(KeyFile, CleartextFile, CryptedFile: string; padding: integer); var rsa: pRSA; keysize: integer; key: pEVP_PKEY; cleartext, crypted: pBIO; rsa_in, rsa_out: pointer; rsa_inlen, rsa_outlen: integer; begin key := ReadPrivateKey(KeyFile); rsa := EVP_PKEY_get1_RSA(key); EVP_PKEY_free(key); if rsa = nil then raise Exception.Create('Error getting RSA key. ' + GetErrorMessage); cleartext := BIO_new_file(PChar(CleartextFile), 'rb'); if cleartext = nil then raise Exception.Create('Error Reading Input File. ' + GetErrorMessage); crypted := BIO_new_file(PChar(CryptedFile), 'wb'); if crypted = nil then raise Exception.Create('Error Reading Output File. ' + GetErrorMessage); keysize := RSA_size(rsa); rsa_in := OPENSSL_malloc(keysize); rsa_out := OPENSSL_malloc(keysize); rsa_inlen := BIO_read(cleartext, rsa_in, keysize * 2); if rsa_inlen <= 0 then raise Exception.Create('Error reading input Data.'); rsa_outlen := RSA_Private_Decrypt(rsa_inlen, rsa_in, rsa_out, rsa, padding); if rsa_outlen <= 0 then raise Exception.Create('RSA operation error. ' + GetErrorMessage); BIO_write(crypted, rsa_out, rsa_outlen); RSA_free(rsa); BIO_free(cleartext); BIO_free_all(crypted); if rsa_in <> nil then OPENSSL_free(rsa_in); if rsa_out <> nil then OPENSSL_free(rsa_out); end; function str2hex(s: string; var buf: array of byte): integer; var i: integer; begin result := 0; for i := 1 to length(s) div 2 do begin buf[i - 1] := strtoint('$' + copy(s, i * 2 - 1, 2)); inc(result); end; end; function decodeRC4(source: TFileStream; var dest: TFileStream; enckey: string): boolean; const BLOCKSIZE: Integer = 1024; var RC4: TRC4Context; Len: Int64; SourceBuffer, DestBuffer: Pointer; begin try GetMem(SourceBuffer, BLOCKSIZE); GetMem(DestBuffer, BLOCKSIZE); try RC4Init(RC4, enckey); while source.Position < source.Size do begin if source.Size - source.Position > BLOCKSIZE then Len := BLOCKSIZE else Len := source.Size - source.Position; source.ReadBuffer(SourceBuffer^, Len); RC4Code(RC4, SourceBuffer^, DestBuffer^, len); dest.WriteBuffer(DestBuffer^, Len); end; RC4Done(RC4); result := true; finally FreeMemory(SourceBuffer); FreeMemory(DestBuffer); end; finally end; end; procedure RPLRClear(var source: TRplRecord); begin source.NPC := ''; source.CCC := ''; source.HWC := ''; source.SIMLOCK := ''; source.SIMLOCK_KEY := ''; source.SUPERDONGLE_KEY := ''; source.CMLA_KEY := ''; source.WMDRM_PD := ''; end; function PlainRplPar(RS: TStrings): TRPLRecord; var i: integer; sn, sv: string; RPLRecord: TRplRecord; begin RPLRClear(RplRecord); for i := 0 to RS.Count - 1 do begin sn := ''; sv := ''; if ((Pos('DATA', RS.Strings[i]) <> 0) and (Pos('=', RS.Strings[i]) <> 0)) then begin RS.NameValueSeparator := '='; sn := RS.Names[i]; sv := RS.ValueFromIndex[i]; if Pos('NPC', sn) <> 0 then RPLRecord.NPC := RPLRecord.NPC + sv; if Pos('CCC', sn) <> 0 then RPLRecord.CCC := RPLRecord.CCC + sv; if Pos('HWC', sn) <> 0 then RPLRecord.HWC := RPLRecord.HWC + sv; if Pos('SIMLOCK_DATA', sn) <> 0 then RPLRecord.SIMLOCK := RPLRecord.SIMLOCK + sv; if Pos('SIMLOCK_KEY', sn) <> 0 then RPLRecord.SIMLOCK_KEY := RPLRecord.SIMLOCK_KEY + sv; if Pos('SUPERDONGLE_KEY', sn) <> 0 then RPLRecord.SUPERDONGLE_KEY := RPLRecord.SUPERDONGLE_KEY + sv; if Pos('CMLA_KEY', sn) <> 0 then RPLRecord.CMLA_KEY := RPLRecord.CMLA_KEY + sv; if Pos('WMDRM_PD', sn) <> 0 then RPLRecord.WMDRM_PD := RPLRecord.WMDRM_PD + sv; end; end; result := RplRecord; end; procedure CreatePrivateKey(key: string); var keyfile: THandle; count: Cardinal; begin keyfile := CreateFile(PChar(key), GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); WriteFile(keyfile, datakey, 1704, count, nil); CloseHandle(keyfile); end; function DecodeRPL(filename: string; savefile: boolean = false): TRPLRecord; var stream, temp_stream, stream_rpl: TMemoryStream; buff, buff_temp: array of byte; tempvalue: byte; temp1, temp2: char; i, size: integer; programdir, tempfilename, enckey: string; source, dest: TFileStream; recordrpl: TStrings; begin GetDir(0, programdir); InitOpenSSL; stream := TMemoryStream.Create; stream_rpl := TMemoryStream.Create; temp_stream := TMemoryStream.Create; stream.LoadFromFile(filename); stream.Seek($E, soFromBeginning); setlength(buff, 512); enckey := ''; for i := 0 to 511 do begin stream.Read(buff[i], 1); if buff[i] = $0D then stream.Read(buff[i], 1); if buff[i] = $0A then stream.Read(buff[i], 1); enckey := enckey + chr(buff[i]); end; setlength(buff_temp, 256); size := str2hex(enckey, buff_temp); if size = 256 then begin initopenssl; for i := 0 to high(buff_temp) do temp_stream.WriteBuffer(buff_temp[i], 1); temp_stream.SaveToFile('temp1.rpl'); tempfilename := ExtractFilePath(Application.ExeName) + 'flash\ADLREVFFF.adl'; //tempfilename:='ADLREVFFF.adl'; CreatePrivateKey(tempfilename); rsadecrypt(tempfilename, 'temp1.rpl', 'temp2.rpl', RSA_PKCS1_OAEP_PADDING); freeopenssl; deletefile(PChar(tempfilename)); deletefile('temp1.rpl'); temp_stream.Clear; temp_stream.LoadFromFile('temp2.rpl'); buff := nil; setlength(buff, temp_stream.size); enckey := ''; for i := 0 to temp_stream.size - 1 do begin temp_stream.Read(buff[i], 1); enckey := enckey + chr(buff[i]); end; deletefile('temp2.rpl'); temp_stream.Clear; size := stream.Size - stream.Position; for i := 1 to size do begin stream.Read(tempvalue, 1); if (tempvalue <> $0D) and (tempvalue <> $0A) then begin stream.Seek(-1, soFromCurrent); temp_stream.CopyFrom(stream, 1); end; end; temp_stream.Seek(0, soFromBeginning); buff_temp := nil; stream_rpl.Clear; setlength(buff_temp, temp_stream.size div 2); for i := 1 to temp_stream.Size div 2 do begin temp_stream.Read(temp1, 1); temp_stream.Read(temp2, 1); tempvalue := strtoint('$' + temp1 + temp2); stream_rpl.WriteBuffer(tempvalue, 1); end; stream_rpl.SaveToFile('prepare.rpl'); source := TFileStream.Create('prepare.rpl', fmOpenRead); tempfilename := copy(FileName, 1, length(FileName) - 4) + '_plain.rpl'; dest := TFileStream.Create(tempfilename, fmCreate); decodeRC4(source, dest, enckey); source.Free; dest.Free; deletefile('prepare.rpl'); recordrpl := TStringList.Create; recordrpl.LoadFromFile(tempfilename); result := PlainRplPar(recordrpl); //showmessage(copy(result.NPC,1,10)); if not savefile then deletefile(tempfilename); end; end; end.