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.