Created
October 12, 2023 16:12
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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