unit UnitUFS;

interface
Uses
  D2XXUnit,HexUtils, FBoots, Windows, Masks, Forms,sysutils, classes, boots, dialogs ;
  
  procedure readUID(); // внешняя функция для использования
  function readUIDstep1 ():Boolean; // Общая функция чтения
  function SendRawID(Asic:integer; Loader:string) : integer; // Сама функция чтения данных
  function Select2ndDie(idr:string):Boolean; // подбираем лоадеры
  
implementation
uses UnitE1, UnitPavel, unit1, FlashBoots, USBmain, unitmisc, Graphics, UnitUFS;

function Select2ndDie(idr:string):Boolean;
var
  s:string;
begin
  result:=true;
  idr:=copy(idr,1,5);
  FbusFloader:='';
  FbusSloader:='';
  case Str2Byte(idr[1]+idr[2]) of
  $BA:
  begin
  FbusFloader:=StartDir+'Flash\UFS\Special\RAP3Gv3_BAF3A9C3DBFA8454937DB77F2B8852B1.bin';
  FbusSloader:=StartDir+'Flash\UFS\Special\BootCustom_BAF3A9C3DBFA8454937DB77F2B8852B1.bin';
  bof:=StartDir+'Flash\UFS\Special\RAP3Gv3_BO.bin';
  end;
  $9D:
  begin
  FbusFloader:=StartDir+'Flash\UFS\Special\RAP3Gv3_9DDBFCFE6E73CED7D8C6268C8EB85723.bin';
  FbusSloader:=StartDir+'Flash\UFS\Special\BootCustom_9DDBFCFE6E73CED7D8C6268C8EB85723.bin';
  bof:=StartDir+'Flash\UFS\Special\RAP3Gv3_BO.bin';
  end;
  $E9:
  begin
  FbusFloader:=StartDir+'Flash\UFS\Special\RAP3Gv2_E9EFF4BFAA5393217CA6B17755FC3E14.bin';
  FbusSloader:=StartDir+'Flash\UFS\Special\BootCustom_E9EFF4BFAA5393217CA6B17755FC3E14.bin';
  bof:=StartDir+'Flash\UFS\Special\RAP3Gv2_BO.bin';
  end;
  $38:
  begin
  FbusFloader:=StartDir+'Flash\UFS\Special\RAP3Gv3_38F312750F686F9FC9B1B3778774A195.bin';
  FbusSloader:=StartDir+'Flash\UFS\Special\BootCustom_38F312750F686F9FC9B1B3778774A195.bin';
  bof:=StartDir+'Flash\UFS\Special\RAP3Gv3_BO.bin';
  end;
  $A5:
  begin
  FbusFloader:=StartDir+'Flash\UFS\Special\RAP3Gv3_A5404AE83A594ECADEE532F0C236BFA6.bin';
  FbusSloader:=StartDir+'Flash\UFS\Special\BootCustom_A5404AE83A594ECADEE532F0C236BFA6.bin';
  bof:=StartDir+'Flash\UFS\Special\RAPIDO_BO.bin';
  end;
  $9A:
  begin
  FbusFloader:=StartDir+'Flash\UFS\Special\RAPIDOv11_9A28E119033B91D14D22838C86D0D53C.bin';
  FbusSloader:=StartDir+'Flash\UFS\Special\BootCustom_9A28E119033B91D14D22838C86D0D53C.bin';
  bof:=StartDir+'Flash\UFS\Special\RAPIDO_BO.bin';
  end;
  $CA:
  begin
  FbusFloader:=StartDir+'Flash\UFS\Special\RAPIDOv11_CAEEBB65D3C48E6DC73B49DC5063A2EE.bin';
  FbusSloader:=StartDir+'Flash\UFS\Special\BootCustom_CAEEBB65D3C48E6DC73B49DC5063A2EE.bin';
  bof:=StartDir+'Flash\UFS\Special\RAPIDO_BO.bin';
  end;
  $F2:
   begin
   FbusFloader:=StartDir+'Flash\UFS\Special\RAPIDOv11_F2D76DFAFD66C7F195F278417DF05888.bin';
   FbusSloader:=StartDir+'Flash\UFS\Special\BootCustom_F2D76DFAFD66C7F195F278417DF05888.bin';
   bof:=StartDir+'Flash\UFS\Special\RAPIDO_BO.bin';
   end;
  $F6:
  begin
  FbusFloader:=StartDir+'Flash\UFS\Special\RAPIDOv11_F682624FFB08F6D955DBE7D9C0485084.bin';
  FbusSloader:=StartDir+'Flash\UFS\Special\BootCustom_F682624FFB08F6D955DBE7D9C0485084.bin';
  bof:=StartDir+'Flash\UFS\Special\RAPIDO_BO.bin';
  end;
  $FC:
  begin
  FbusFloader:=StartDir+'Flash\UFS\Special\RAPIDOv11_FCB5C510AF7F09F313D9BDE85A707CC0.bin';
  FbusSloader:=StartDir+'Flash\UFS\Special\BootCustom_FCB5C510AF7F09F313D9BDE85A707CC0.bin';
  bof:=StartDir+'Flash\UFS\Special\RAPIDO_BO.bin';
  end;

  else result:=False;
 end;
end;

function readUIDstep1 ():Boolean;
begin
  result:=false;
 form1._msg('Setting FlashMode');
  if not SwitchBoxMode('FlashBus') then
 begin
 form1._msg('UFSx : FlashMode init fail! Reconnect box');
 form1._msg('');
 form1.SetReady;
 exit;
 end;
 Form1.statusbar.Panels[0].Text:='UFS : Booting phone...';
 ufs_cmd(3500,@CMTread[0],2,@cmd_buf,200);
 //Form1._msg('BootData : '+BufToHexStr(@cmd_buf[0], $FF));
 Application.ProcessMessages;
 if (FT_IN_BUFFER[1]>20) and (FT_IN_BUFFER[2]<>$72) and (FT_IN_BUFFER[2]<>$20) then FetchBootData
 else
 begin
 form1._msg('No answer from phone... :(');
 form1._msg('1. Check cable/connection, try again');
 form1._msg('2. Maybe HW fault or bad cable');
 form1._msg('');
 form1.SetReady;
 Exit;
 end;
 if not Select2ndDie(ROOTKEY) then begin // выбор лоадера по необходимый руткейхэшь
 Form1._msg('Error finding required loader... :(');
 form1._msg('');
 form1.SetReady;
 Exit;
 end;

 if SendRawId(0,FbusFloader)<>0 then exit;
 result:=True;

end;

function SendRawID(Asic:integer; Loader:string) : integer;
var
  rawloader,
  rawblock  : TMemoryStream;
  b         : Boolean;
  chk       : word;
  tmp       : array of Byte;
  i         : integer;
  flblk     : integer;
  lb        : Byte;
  filename  : string;
  mmc       : System.Text;
  id        : string;
begin
  result:=9;
  algo:='';

     Form1.statusbar.Panels[0].Text:='UFS : CMT 2ND boot...'; // шлем бут
     Form1._msg('CMT : Sending 2nd loader...');
     Application.ProcessMessages;
     RAWloader:=TMemoryStream.Create;
     rawloader.LoadFromFile(loader);
     rawloader.Seek(0,soFromBeginning);
     SetLength(tmp, rawloader.Size);
      if rawloader.size=0 then exit;
     result:=8; // RAwloader prepare error
     if (FLbyte=$F1) or (FLbyte=$F5) or (FLbyte=$F3) then begin
      ufs_cmd(50,@prerawcheck[0],3,@cmd_buf,1);
      Form1._msg('Set Data ['+Byte2Str(ft_in_buffer[0])+']');
      //form1._msg('Set Data ['+Byte2Str(replyverify3)+']');
      end;
   rawloader.ReadBuffer(tmp[0], rawloader.Size);
   RawLen[6]:=rawloader.Size  mod $100;
   RawLen[5]:=rawloader.Size  div $100;
   result:=7; // PrebootCheck error - raw len no accepted
   ufs_cmd(50,@Rawlen[0],7,@cmd_buf,2);
   Form1._msg('Set data ['+byte2str(FT_In_Buffer[0])+']');
   devbyte:=FT_In_Buffer[0];
   if FT_In_Buffer[1]<>$72 then Exit;
    Application.ProcessMessages;
    FT_Out_Buffer[0]:=$69;
    FT_Out_Buffer[1]:=$02;
    FT_Out_Buffer[2]:=$0A;
    FT_Out_Buffer[3]:=$00;
    FT_Out_Buffer[5]:=rawloader.Size  mod $100;
    FT_Out_Buffer[4]:=rawloader.Size  div $100;
    FT_Out_Buffer[6]:=$00;
    FT_Out_Buffer[7]:=$00;
    Application.ProcessMessages;
    for i:=0 to rawloader.size+7 do FT_Out_Buffer[i+8]:=TMP[i];
    ufs_cmd(500,@FT_out_buffer,(rawloader.Size+8),@cmd_buf,7);
    result:=6; // rawloader not accepted by phone
    if ft_in_buffer[0]<>$00 then begin
    form1._msg('ERR: '+buftohexstr(@FT_in_buffer[0],7));
    exit;
    end;
    //if ft_in_buffer[5]<>$F1 then exit;
    if ft_in_buffer[6]<>$72 then begin
    form1._msg('ERR: '+buftohexstr(@FT_in_buffer[0],7));
    exit;
    end;
  Application.ProcessMessages;
  Form1._msg('CMT Loader sent, Boot Ok');
  Form1.statusbar.Panels[0].Text:='UFS : 2ND Boot Ok, wait...'; // выполняем переполнение бута
  rawloader.Free;
     RAWloader:=TMemoryStream.Create;
     rawloader.LoadFromFile(bof);
      rawloader.Seek(0,soFromBeginning);
     SetLength(tmp, rawloader.Size);
     rawloader.ReadBuffer(tmp[0], rawloader.Size);
  Application.ProcessMessages;
    FT_Out_Buffer[0]:=$74;
    FT_Out_Buffer[1]:=$20;
    FT_Out_Buffer[2]:=$00;
    FT_Out_Buffer[3]:=$02;
    FT_Out_Buffer[4]:=$E4;
    for i:=0 to rawloader.size+4 do FT_Out_Buffer[i+5]:=TMP[i];
    ufs_cmd(500,@FT_out_buffer,(rawloader.Size+5),@cmd_buf,2);
    rawloader.Free;
    if ft_in_buffer[1]<>$72 then exit;
    Application.ProcessMessages;
    ufs_cmd(500,@flow,Length(flow),@cmd_buf,2);
    Form1.statusbar.Panels[0].Text:='UFS : Exploit Ok, wait...'; // Переполнение прошло, шлем кастом-лоадер
    Application.ProcessMessages;
    Form1._msg('OWF : '+byte2str(ft_in_buffer[0]));
    if ft_in_buffer[1]<>$72 then exit;
     RAWloader:=TMemoryStream.Create;
     rawloader.LoadFromFile(FbusSloader);
      rawloader.Seek(0,soFromBeginning);
     SetLength(tmp, rawloader.Size);
     rawloader.ReadBuffer(tmp[0], rawloader.Size);
     Application.ProcessMessages;
    FT_Out_Buffer[0]:=$74;
    FT_Out_Buffer[1]:=$20;
    FT_Out_Buffer[2]:=$00;
    FT_Out_Buffer[4]:=rawloader.Size  mod $100;
    FT_Out_Buffer[3]:=rawloader.Size  div $100;
    for i:=0 to rawloader.size+4 do FT_Out_Buffer[i+5]:=TMP[i];
    dwordswap(@FT_out_buffer[5]);
    ufs_cmd(500,@FT_out_buffer,(rawloader.Size+5),@cmd_buf,2);
    rawloader.free;
    if ft_in_buffer[1]<>$72 then exit;
    Application.ProcessMessages;
    ufs_cmd(500,@flow,Length(flow),@cmd_buf,2);
    Application.ProcessMessages;
    Form1._msg('OWF2 : '+byte2str(ft_in_buffer[0])); // Кастом-лоадер запущен, начинаем подготовливать стеки
    if ft_in_buffer[1]<>$72 then exit;
    Application.ProcessMessages;
    ufs_cmd(500,@overready , 9 ,@cmd_buf,11);
    Form1._msg('OWF3 : '+byte2str(ft_in_buffer[9]));
    //if ft_in_buffer[8]<>$72 then exit;
    Application.ProcessMessages;
    ufs_cmd(500,@readdieid , 6 ,@cmd_buf, $40);  // читаем наши данные - 20 байт RAP_PUBLIC_ID+20 байт UNIQUEID 
    Form1.statusbar.Panels[0].Text:='UFS : Fetching data, wait...';
   id:=buftohexstr(@ft_in_buffer[0],$40);
   try
   FileName:=getcurrentdir+'\'+'Special'+'\'+buftohexstr(@RAPInfo.PUBLIC_ID,Length(RAPInfo.PUBLIC_ID))+'_fetch.best'; // сохраняем по значению рапайди
   except
    FileName:=getcurrentdir+'\Err_read_info_fetch.best';
   end;
   if fileexists(filename) then filename:=getcurrentdir+'\'+'Special'+'\'+'rand'+'__fetch.best';
   System.Assign (MMC ,FileName ) ;
   System.Rewrite ( MMC );
   System.WriteLn (MMC,'[fetched]');
   System.Writeln (MMC, 'RAPID='+buftohexstr(@RAPInfo.PUBLIC_ID,Length(RAPInfo.PUBLIC_ID)));
   System.Writeln (MMC, 'HASH='+buftohexstr(@RAPInfo.ROOT_KEY_HASH,Length(RAPInfo.ROOT_KEY_HASH)));
   System.Writeln (MMC, 'ROMID='+buftohexstr(@RAPInfo.ROM_ID,Length(RAPInfo.ROM_ID)));
   System.Writeln (MMC, 'id='+id);
   System.Close(mmc);
   Form1._msg('Saved to : '+filename);
   Form1.statusbar.Panels[0].Text:='';

 result:=0;
end;


procedure readUID();
begin
  if not readUIDstep1 then form1._msg('Error fetching data... :(') else form1._msg('ID read done ;)');
end;