# Full version
# This attempts to extract the password from WD ROYL drives by dumping
# module 02. It provides possible passwords based on a likely pattern
# that proceeds the passwords. You then have the option to try the password
# to unlock the drive or disable security, or to try to find more possible
# passwords. If no more possible passwords are found it will exit.



# set the 4 search bytes
# these are the 4 bytes that likely preceed the user password
seti $searchbyte0 = 0x00
seti $searchbyte1 = 0x01
seti $searchbyte2 = 0x07
seti $searchbyte3 = 0x00

# set alternative 4 search bytes
# these are the 4 bytes that may preceed the user password
seti $searchbyte4 = 0x00
seti $searchbyte5 = 0x01
seti $searchbyte6 = 0x07
seti $searchbyte7 = 0x00



# this subroutine is put here so following commands recognize variables
subroutine get_security_status
  buffersize 512
  protocol pio-data-in
  direction from
  ata28cmd 0 0 0 0 0 0xa0 0xec
  if $ata_return_error != 0
    gosub error
  endif
  seti $tempnum = buffer 257
  seti $security_level = $tempnum & 1
  seti $tempnum = buffer 256
  seti $enhanced_security_erase_supported = $tempnum & 32
  seti $security_count_expired = $tempnum & 16
  seti $security_frozen = $tempnum & 8
  seti $security_locked = $tempnum & 4
  seti $security_enabled = $tempnum & 2
  seti $security_supported = $tempnum & 1
  if $security_supported > 0
    echo "security_supported= yes"
  else
    echo "security_supported= no"
  endif
  if $enhanced_security_erase_supported > 0
    echo "enhanced_security_erase_supported= yes"
  else
    echo "enhanced_security_erase_supported= no"
  endif
  if $security_frozen > 0
    echo "security_frozen= yes"
  else
    echo "security_frozen= no"
  endif
  if $security_count_expired > 0
    echo "security_count_expired= yes"
  else
    echo "security_count_expired= no"
  endif
  if $security_enabled > 0
    echo "security_enabled= yes"
  else
    echo "security_enabled= no"
  endif
  if $security_locked > 0
    echo "security_locked= yes"
  else
    echo "security_locked= no"
  endif
endsubroutine



gosub get_security_status
if $security_enabled = 0
  echo "Security is not enabled on this drive, nothing to do."
  previousscript
endif

echo "Trying to dump module 2 (ROYL drives)"
gosub dump_mod_2
if $dumperror = 1
  gosub show_ata_return
  echo "Failed getting module 2"
  previousscript
endif

#gosub read_file

seti $finished = 0
seti $position = 0
gosub find_password
if $finished = 1
  previousscript
endif

while 1 = 1
  echo "What would you like to do?"
  echo "1) Try to unlock with user password"
  echo "2) Try to unlock with master password"
  echo "3) Try to remove security with user password"
  echo "4) Try to remove security with with master password"
  echo "5) Continue trying to find the next possible password"
  echo "6) Quit"
  echo "Enter your choice:
  userinput $choicestring
  seti $choice = $choicestring 0
  if $choice = 1
    if $security_locked = 0
      echo "Drive is already unlocked!"
    else
      seti $type = 0
      gosub unlock
      gosub get_security_status
      if $security_locked = 0
        echo "Drive unlocked!"
      endif
    endif
  elseif $choice = 2
    if $security_locked = 0
      echo "Drive is already unlocked!"
    else
      seti $type = 1
      gosub unlock
      gosub get_security_status
      if $security_locked = 0
        echo "Drive unlocked!"
      endif
    endif
  elseif $choice = 3
    seti $type = 0
    gosub remove_password
    gosub get_security_status
    if $security_enabled = 0
      echo "Security has been disabled! Nothing more to do."
      previousscript
    endif
  elseif $choice = 4
    seti $type = 1
    gosub remove_password
    gosub get_security_status
    if $security_enabled = 0
      echo "Security has been disabled! Nothing more to do."
      previousscript
    endif
  elseif $choice = 5
    seti $position = $position + 1
    gosub find_password
    if $finished = 1
      previousscript
    endif
  elseif $choice = 6
    previousscript
  else
    echo "bad choice= " $choice
  endif
done


end


subroutine error
  echo "***Drive reported command error***"
  #gosub show_cmd_status
  gosub show_sense_data
  gosub show_ata_return
  previousscript
endsubroutine


subroutine read_file
  readscratchpad 22.bin 0 0 512
  seti $mod_length_bytes = 512
endsubroutine


subroutine dump_mod_2
  seti $dumperror = 0
  seti $max_sectors = 8
  seti $max_size = 8 * 512
  scratchpadsize $max_size
  protocol non-data
  direction none
  buffersize 0
  ata28cmd 0x45 0x0b 0x00 0x44 0x57 0xa0 0x80
  if $ata_return_error != 0
    gosub show_ata_return
    seti $dumperror = 1
    returnsub
  endif
  buffersize 512
  clearbuffer
  setbuffer 0
    08 00 01 00 02
  endbuffer
  protocol pio-data-out
  direction to
  ata28cmd 0xd6 0x01 0xbe 0x4f 0xc2 0xa0 0xb0
  if $ata_return_error != 0
    gosub show_ata_return
    seti $dumperror = 1
    returnsub
  endif
  protocol pio-data-in
  direction from
  ata28cmd 0xd5 0x01 0xbf 0x4f 0xc2 0xa0 0xb0
  if $ata_return_error != 0
    gosub show_ata_return
    seti $dumperror = 1
    returnsub
  endif
  copybuffertoscratchpad 0 0 512

  seti $mod_length_sectors = scratchpad 0xa
  seti $tempnum = scratchpad 0xb
  seti $tempnum = $tempnum > 8
  seti $mod_length_sectors = $mod_length_sectors + $tempnum
  seti $mod_length_bytes = $mod_length_sectors * 512

  seti $count = 1
  while $count < $mod_length_sectors
    ata28cmd 0xd5 0x01 0xbf 0x4f 0xc2 0xa0 0xb0
    if $ata_return_error != 0
      gosub show_ata_return
      seti $dumperror = 1
      returnsub
    endif
    seti $tempnum = $count * 512
    copybuffertoscratchpad 0 $tempnum 512
    seti $count = $count + 1
    if $count > $max_sectors
      break
    endif
  done

  #printscratchpad 0 $mod_length_bytes
endsubroutine


subroutine find_password
  seti $max_start = $mod_length_bytes - 68
  while $position < $max_start
    seti $position1 = $position + 1
    seti $position2 = $position + 2
    seti $position3 = $position + 3
    seti $byte0 = scratchpad $position
    seti $byte1 = scratchpad $position1
    seti $byte2 = scratchpad $position2
    seti $byte3 = scratchpad $position3
    if $byte0 = $searchbyte0
      if $byte1 = $searchbyte1
        if $byte2 = $searchbyte2
          if $byte3 = $searchbyte3
            seti $userpassword = $position3 + 1
            seti $masterpassword = $position3 + 33
            echo "possible user password:"
            printscratchpad $userpassword 32
            echo "possible master password:"
            printscratchpad $masterpassword 32
            returnsub
          endif
        endif
      endif
    endif
    if $byte0 = $searchbyte4
      if $byte1 = $searchbyte5
        if $byte2 = $searchbyte6
          if $byte3 = $searchbyte7
            seti $userpassword = $position3 + 1
            seti $masterpassword = $position3 + 33
            echo "possible user password:"
            printscratchpad $userpassword 32
            echo "possible master password:"
            printscratchpad $masterpassword 32
            returnsub
          endif
        endif
      endif
    endif
    seti $position = $position + 1
  done
  seti $finished = 1
  echo "No more passwords to be found"
endsubroutine



subroutine remove_password
  # set the buffer size
  buffersize 512
  # clear the buffer to 0's
  clearbuffer

  # put the type in the buffer
  seti $byte0 = $type & 0x01
  setbuffer 0
    $byte0
  endbuffer

  if $byte0 = 0
    copyscratchpadtobuffer $userpassword 2 32
  else
    copyscratchpadtobuffer $masterpassword 2 32
  endif

  # set the LBAs and count to 0
  seti $count = 0
  seti $LBAlow = 0
  seti $LBAmid = 0
  seti $LBAhigh = 0

  # set some things for the ata command
  protocol pio-data-out
  tlengthfield sectorcount
  transferunit block
  direction to
  # set features to 0
  seti $features = 0
  # set device bits 7(compatibility) 5(compatibility)
  seti $device = 0xa0
  # set the command for security disable password pio data-out
  seti $command = 0xf6

  # perform the command
  ata28cmd $features $count $LBAlow $LBAmid $LBAhigh $device $command
  if $ata_return_error != 0
    gosub error
  endif
endsubroutine


subroutine unlock
  buffersize 512
  clearbuffer
  # put the type in the buffer
  seti $byte0 = $type & 0x01
  setbuffer 0
    $byte0
  endbuffer

  if $byte0 = 0
    copyscratchpadtobuffer $userpassword 2 32
  else
    copyscratchpadtobuffer $masterpassword 2 32
  endif

  # set the LBAs and count to 0
  seti $count = 0
  seti $LBAlow = 0
  seti $LBAmid = 0
  seti $LBAhigh = 0

  # set some things for the ata command
  protocol pio-data-out
  tlengthfield sectorcount
  transferunit block
  direction to
  # set features to 0
  seti $features = 0
  # set device bits 7(compatibility) 5(compatibility)
  seti $device = 0xa0
  # set the command for security unlock pio data-out
  seti $command = 0xf2

  # perform the command
  ata28cmd $features $count $LBAlow $LBAmid $LBAhigh $device $command
  if $ata_return_error != 0
    gosub error
  endif
endsubroutine




subroutine show_sense_data
  hex
  echo "sense_key=0x" $io_sense_key " asc=0x" $io_asc " ascq=0x" $io_ascq
  decimal
endsubroutine


subroutine show_cmd_status
  echo "status=" $io_status " masked_status=" $io_masked_status " msg_status=" $io_msg_status " sb_len_wr=" $io_sb_len_wr " host_status=" $io_host_status " driver_status=" $io_driver_status " resid=" $io_resid " duration=" $io_duration " info=" $io_info
endsubroutine


subroutine show_ata_return
  hex
  echo "error=0x" $ata_return_error " count=0x" $ata_return_count " lba=0x" $ata_return_lba " device=0x" $ata_return_device " status=0x" $ata_return_status
  decimal
endsubroutine
