DBMS_LOB.SUBSTR, para un BLOB, devolverá un RAW. La mayoría de los entornos lo representarán en hexadecimal. Puede usar la función DUMP para verlo en otros formatos.
select dump(dbms_lob.substr(product_image,10,1),10),
dump(dbms_lob.substr(product_image,10,1),16),
dump(dbms_lob.substr(product_image,10,1),17)
from APEX_DEMO.DEMO_PRODUCT_INFO
where product_id = 9;
Esto devuelve los primeros 10 bytes del BLOB en decimal (por ejemplo, 0-255), hexadecimal y carácter. Este último puede arrojar basura no imprimible a la pantalla y, si los conjuntos de caracteres del cliente y de la base de datos no coinciden, someterse a alguna 'traducción'.
Puede usar UTL_RAW.CAST_TO_VARCHAR2, que puede darle lo que desea.
select utl_raw.cast_to_varchar2(dbms_lob.substr(product_image,10,1)) chr
from APEX_DEMO.DEMO_PRODUCT_INFO
where product_id = 9