Skip to content

Instantly share code, notes, and snippets.

@shinyquagsire23
Created October 12, 2023 16:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shinyquagsire23/4898423b83f5438d7585f75d245187dd to your computer and use it in GitHub Desktop.
Save shinyquagsire23/4898423b83f5438d7585f75d245187dd to your computer and use it in GitHub Desktop.
Directly talking SCSI with a USB mass storage devices on Linux, to (attempt to) recover raw NAND data from a drive which lost configuration
import usb.core
import usb.util
import struct
import time
import os
# echo 1-1:1.0 > /sys/bus/usb/drivers/usb-storage/unbind
os.system("/bin/bash -c \"echo 1-1:1.0 > /sys/bus/usb/drivers/usb-storage/unbind\"")
# find our device
dev = usb.core.find(idVendor=0x048D, idProduct=0x1181)
if dev is None:
dev = usb.core.find(idVendor=0x048D, idProduct=0x1177)
#dev = usb.core.find(idVendor=0x13FE, idProduct=0x4300)
# was it found?
if dev is None:
raise ValueError('Device not found')
# set the active configuration. With no arguments, the first
# configuration will be the active one
dev.set_configuration()
# get an endpoint instance
cfg = dev.get_active_configuration()
intf = cfg[(0,0)]
ep_out = usb.util.find_descriptor(
intf,
# match the first OUT endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
ep_in = usb.util.find_descriptor(
intf,
# match the first OUT endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)
ep_in.clear_halt()
ep_out.clear_halt()
dev.ctrl_transfer(0xA1, bRequest = 0xFE, data_or_wLength=1)
tag = 1
def send_scsi_cmd(cdb, data_expect):
global tag
ums_hdr = struct.pack("<LLLBBB", 0x43425355, tag, data_expect, 0x0 if data_expect == 0 else 0x80, 0x0, len(cdb))
if (len(cdb) < 0x10):
cdb += (struct.pack("<B", 0) * (0x10 - len(cdb)))
try:
ep_out.write(ums_hdr + cdb)
except:
a=""
tag += 1
#time.sleep(1)
output = []
try:
if (data_expect != 0):
output = ep_in.read(data_expect)
except:
a = ""
resp = ep_in.read(0xD)
#print (output)
#print (resp)
return bytes(output)
def send_scsi_cmd_4(cdb, data_expect):
global tag
ums_hdr = struct.pack("<LLLBBB", 0x43425355, tag, data_expect, 0x0 if data_expect == 0 else 0x80, 0x0, 0xC)
try:
ep_out.write(ums_hdr + cdb)
except:
a=""
tag += 1
#time.sleep(1)
output = None
try:
if (data_expect != 0):
output = ep_in.read(data_expect)
except:
a = ""
resp = ep_in.read(0xD)
#print (output)
#print (resp)
return bytes(output)
def send_scsi_cmd_wr(cdb, extra, data_expect):
global tag
ums_hdr = struct.pack("<LLLBBB", 0x43425355, tag, data_expect, 0, 0x0, len(cdb))
if (len(cdb) < 0x10):
cdb += (struct.pack("<B", 0) * (0x10 - len(cdb)))
try:
ep_out.write(ums_hdr + cdb)
except:
a=""
try:
ep_out.write(extra)
except:
a=""
tag += 1
#time.sleep(1)
output = None
resp = ep_in.read(0xD)
#print (output)
#print (resp)
return bytes(resp)
def send_scsi_cmd_2(cdb, data_expect, somelen):
global tag
ums_hdr = struct.pack("<LLLBBB", 0x43425355, tag, data_expect, 0x80, 0, somelen)
try:
ep_out.write(ums_hdr + cdb)
except:
ep_out.clear_halt()
a=""
tag += 1
time.sleep(1)
try:
if (data_expect != 0):
print (ep_in.read(data_expect))
except:
a = ""
ep_in.clear_halt()
print (ep_in.read(0xD))
def send_scsi_cmd_3(cdb, data_expect, somelen):
global tag
ums_hdr = struct.pack("<LLLBBB", 0x43425355, tag, data_expect, 0, 0, somelen)
try:
ep_out.write(ums_hdr + cdb)
except:
ep_out.clear_halt()
a=""
tag += 1
time.sleep(1)
output = None
try:
if (data_expect != 0):
output = ep_in.read(data_expect)
except:
a = ""
ep_in.clear_halt()
print (ep_in.read(0xD))
return output
#ums_hdr = struct.pack("<LLLBBB", 0x43425355, tag, 0x12, 0x80, 0x0, 0x6)
#cdb = struct.pack(">BLBLLH", 0x3, 0x12, 0x0, 0,0,0)
#ums_hdr = struct.pack("<LLLBBB", 0x43425355, tag, 0, 0, 0x0, 0x6)
#cdb = struct.pack(">BLBLLH", 0, 0, 0x0, 0,0,0)
#ums_hdr = struct.pack("<LLLBBB", 0x43425355, tag, 0x2000, 0x80, 0x0, 0x6)
#cdb = struct.pack(">BLBLLH", 0x12, 0x24, 0x0, 0,0,0)
idk_info = struct.pack(">BBBBBBLLH", 0x12, 0x01, 0x80, 0,0xFF,0, 0,0,0)
get_ready = struct.pack(">BBLBBLBBBB", 0xFD, 0x2, 0x0, 0x82, 0x0, 0x0, 0x0, 0,0,0)
set_ready = struct.pack(">BBLBBL", 0xFD, 0x2, 0x0, 0x83, 0x0, 0x1)
set_ready_off = struct.pack(">BBLBBL", 0xFD, 0x2, 0x0, 0x83, 0x0, 0x0)
read_data = struct.pack(">BBLBBLBBBB", 0xFD, 0x2, 0x0, 0x04, 0x1, 0x0, 0x0, 0,0,0)
read_id = struct.pack(">BBLBBBBBBBBBB", 0xFD, 0x80, 0x0, 0x01, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0)
read_capacity = struct.pack(">BLBLLH", 0x25, 0x0, 0x0, 0,0,0)
read_block = struct.pack(">BBLBHBLH", 0x28, 0x0, 0x0, 0,1,0, 0,0)
read_id_unk = struct.pack(">BBBBBBBBBBBBBBBB", 0xFD, 0x06, 0,0,0,0, 0x08, 0x0, 0x0, 0x0, 0x0, 0x9, 0x0, 0,0,0x0)
read_id_unk2 = struct.pack(">BBBBBBBBBBBBBBBB", 0xFD, 0x03, 0,0,0,0, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0,0,0x0)
read_id_unk3 = struct.pack(">BBBBBBBBBBBB", 0xFD, 0x06, 0,0,0,0, 0x02, 0x0, 0x8, 0x0, 0x0, 0x0)
root_access_on = struct.pack(">BBBBBBBBBBBBBBBB", 0xFD, 0x0D, 0,0,0,0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0,0,0x0)
idk_nand = struct.pack(">BBBBBBBBBBBBBBBB", 0xFD, 0x0D, 0,0,0x6,0, 0x08, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0,0,0x0)
read_id_ext = struct.pack(">BBBBBBBBBBBBBBBB", 0xFD, 0x06, 0,0,0,0, 0x00, 0x0, 0x8, 0x0, 0x0, 0x1, 0x0, 0,0,0x0)
#unk = struct.pack(">BBBBBBBBBBBBBBBB", 0xFD,0x03,0x00,0x00, 0xC0,0x00,0x01,0x00, 0x8,0x0,0x0,0x0, 0x0,0x0,0x0,0x0)
'''
f = open("dump_idk2_00.bin", "wb")
for i in range(0, 0x10000 // 0x100):
addr = i*0x100
which = 0 # 0 is config, 1 is none, 2 is... registers? 3 is none, 4 is ROM
read_data_2 = struct.pack(">BBLBBLBBBB", 0xFD, 0x2, addr, which, 0x1, 0x0, 0x0, 0,0,0)
b = send_scsi_cmd(read_data_2, 0x100)
#print (b)
f.write(bytes(b))
f.close()
'''
# write test
'''
f = open("dump_idk_01.bin", "wb")
for i in range(0, 0x100 // 0x100):
addr = 0xF00#i*0x100
which = 1 # 0 is config, 1 is none, 2 is... registers? 3 is none, 4 is ROM
read_data_2 = struct.pack(">BBLBBL", 0xFD, 0x2, addr, which, 0x1)
extra = struct.pack(">L", 0xFFFFFFFF) + (struct.pack(">B", 0)*(0x100-0x4))
b = send_scsi_cmd_wr(read_data_2, extra, 0x100)
print (b)
f.write(bytes(b))
f.close()
f = open("dump_newtst_00.bin", "wb")
for i in range(0, 0x100 // 0x100):
addr = 0xF00
which = 0 # 0 is config, 1 is none, 2 is... registers? 3 is none, 4 is ROM
read_data_2 = struct.pack(">BBLBBLBBBB", 0xFD, 0x2, addr, which, 0x1, 0x0, 0x0, 0,0,0)
b = send_scsi_cmd(read_data_2, 0x100)
print (b)
f.write(bytes(b))
f.close()
'''
# addr 0x4D00, which 0xFC is some firmware
send_scsi_cmd_2(get_ready, 1, 0xC)
send_scsi_cmd(set_ready, 0)
send_scsi_cmd(read_capacity, 8)
'''
# write to every sector with its index
for i in range(0x5B00, 0x1DAFFFF):
addr = i
write_block = struct.pack(">BBLBHB", 0x2A, 0x0, addr, 0,1,0)
read_block = struct.pack(">BBLBHB", 0x28, 0x0, addr, 0,1,0)
to_write = struct.pack(">LL", i, 0xDEADF00F) * (0x200//8)
for j in range(0,10):
write_good = False
try:
send_scsi_cmd_wr(write_block, to_write, len(to_write))
write_good = True
except:
a=""
if write_good:
break
#print(send_scsi_cmd(read_block, 0x200))
if i % 0x100 == 0:
print (hex(i))
'''
#send_scsi_cmd_wr(read_id_unk3, open("flash_init.bin", "rb").read(), 0x1000)
#print(send_scsi_cmd_4(root_access_on, 0x400))
f = open("usb2_nand_raw_test3.bin", "wb")
for i in range(0, 0x1DAFFFF):
addr_0 = i & 0xFF
addr_1 = (i >> 8) & 0xFF
addr_2 = (i >> 16) & 0xFF
addr_3 = (i >> 24) & 0xFF
addr = 0x0000+i
which = 0xFC # 0 is config, 1 is none, 2 is... registers? 3 is none, 4 is ROM
read_data_2 = struct.pack(">BBLBBBHBBBBB", 0xFD, 0x8, addr, which, 0, 1, 0, 0,0,0,0,0)
b = send_scsi_cmd_4(read_data_2, 0x200)
f.write(bytes(b))
if i % 0x100 == 0:
print (hex(i), "...")
f.close()
#b = send_scsi_cmd_4(idk_nand, 0x200)
#print (b)
#while (1):
#send_scsi_cmd(set_ready, 0)
#send_scsi_cmd_2(get_ready, 1, 0xC)
#send_scsi_cmd(read_id, 0)
#send_scsi_cmd(read_capacity, 8)
#send_scsi_cmd(read_block, 64)
#send_scsi_cmd(read_data, 0x100)
#send_scsi_cmd_2(unk, 4096, 0xC)
#send_scsi_cmd_2(unk, 4096, 0xC)
#send_scsi_cmd_3(read_id_unk, 0, 0xC)
#send_scsi_cmd_3(read_id_unk2, 0, 0xC)
#send_scsi_cmd_2(idk_info, 255, 0x6)
#send_scsi_cmd_2(read_id_ext, 64, 0xC)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment