Jump to content

Sandisk Wireless Connect 16G Flash Drive


Recommended Posts

I Picked up the Sandisk Wireless Connect 16G at w.mart for $20 figured it would be fun to hack

Processor: Marvell: 88wm302 (per FCC filing pictures)


I tried pulling apart the firmware, comparing between the three firmware files I was able to find (2034) (2038) (2050)

I was able to narrow the checksum down to a 96 byte area of the file but I just can't seem to crack the encoding maybe (3-way cipher??)

I do know the version number is checksummed with the value in decimal converted to hex



0802 = 2050

07EE = 2038

07F2 = 2034



I finally gave up and took the device apart, there is a SD card inside the device.

Taking the card out and putting it into a card reader I was able to see the device had (2) 16mb uninitialized partitions

the second of them had the device firmware in it.

While the card is within the Connect device this second partition is not accessible.

File size is stored at the beginning of every file but I have yet to find the drive table so it must be a custom filesystem.


I have edited the file 'sort.js' to allow index redirection to my own file

I'll be adding this once i get it finished and simplified the process a bit.



settings.xml is accessible from root 'sandisk.com/settings.xml'

the device uses a http.post method to rewrite the xml file,

I expanded this to try and re-write the scripts but got reply of 'Bad Request'

/myconnect/files/ and /myconnect/wfd/ are the same directory

javascript is in /static/js/

the media javascript is in /static/mejs

css is in /static/css/ 

Index.html seems to be auto generated from a templatesort.js fills the page

Link to comment
Share on other sites


So first we will talk about how to restore the device

Lets face it, that is the most important part to any good device hack;

Plus It'll be similar to how you can put the modified firmware on the device



First, lets make an image of the device

Windows users:

You will need some drive image software that will do RAW read and write,

I Found HDDGURU: HDDRawCopy1.10 can do the job


When you make your image backup don't compress it if you plan to change the firmware as you will have to edit this image

HxD hex editor supports editing drive images and is a pretty good great free hex editor (RC2.0) https://mh-nexus.de/downloads/HxDSetup.zip

once you are done editing you can put your patched firmware back with HDDRawCopy

I have made a compressed Restore image Here:

The image is compressed with HDDRawCopy can handle it natively since it made it, Linux users probably won't be able to use it (see below)


Linux Users:

you should know dd

Active@ Disk Editor can edit the image or directly edit the drive http://www.disk-editor.org/ beware it is quite finicky but usable

I have made a gz compressed Restore image Here:




You will need to open your drive to remove the SD card;

We don't have access to the second hidden partition while it is in the wireless flash drive

Insert a card into the back just behind the sandisk logo then work your way around each side to open the snaps

finally slide the top forward to remove it from the usb plug



Link to comment
Share on other sites

2 hours ago, kdodge said:

is the Sandisk Wireless Connect, act as an access point, and have a web interface for configuration?

Yes, it is a wifi access point for up to 3 devices, with configuration

I saw where someone said it could be put on another network but I have yet to make that work

Link to comment
Share on other sites

I have one of those and fancied the idea to couple that with a pineapple.  Something went bad on it and can't find the storage partition, I need to reformat it.

Link to comment
Share on other sites

14 minutes ago, Spoonish said:

I have one of those and fancied the idea to couple that with a pineapple.  Something went bad on it and can't find the storage partition, I need to reformat it.

You will need that recovery image if it is a problem with the device code otherwise in windows just reformat with FAT 32 and that will fix the storage partition

Link to comment
Share on other sites

Ok so some progress, I figured out the file structure in the firmware and made a little AutoIt script to extract the files

I have yet to find where the file names and extensions are stored but I deduced all but the binary one, the .unk file in all the firmwares is a binary file and is the same in (2050) and (2038) but different between (2050) and (2034)

Also there is a curious Text file with hex bytes in it I'd really like to know what it is for..

Do be aware if you are pointing this thing at a full disk image (16- 32 GB) you are going to be waiting for a long while..

See updated file extraction script below

Edited by Bilgus
remove old code
Link to comment
Share on other sites

Here is an updated script with more robust header searching and the ability to set an offset on files larger than 16 mb and the ability to resume on error



#include <FileConstants.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIFiles.au3>
#include <AutoItConstants.au3>
#include <String.au3>
#include <Array.au3> ; Required for _ArrayDisplay() only.
#include <File.au3> ;FileWriteLog

Local $sFileOpenDialog = FileOpenDialog("Choose Firmware File", _
		@ScriptDir, "All (*)|Disk Images (*.img)|Firmware (*.df3)", 3)

Local $sLogPath = $sFileOpenDialog & ".log"
Local $sWritePath = $sFileOpenDialog & "_Files\"
Local $sMessage = ""
Local Const $sSplashTitle = "Extract Connect Files"
Global $iStartPos = 0

While ($iStartPos > -1)
	$iStartPos = ExtractConnectFiles($sFileOpenDialog, $sLogPath, $sWritePath, $iStartPos)

Func _StringEqualSplit($sString, $iNumChars)
	If (Not IsString($sString)) Or $sString = "" Then Return SetError(1, 0, 0)
	If (Not IsInt($iNumChars)) Or $iNumChars < 1 Then Return SetError(2, 0, 0)
	Return StringRegExp($sString, "(?s).{1," & $iNumChars & "}", 3)
EndFunc   ;==>_StringEqualSplit

Func _Exit($hLogFile, $hBinaryFileOpen)
	$iStartPos = -1
EndFunc   ;==>_Exit

Func FindStorageHeader($sFilePath, $iFileSz, $iStartPos) ;FF FF FF FF 00 00 [00 00 SZ BY] .. [00 00 00 01]
	Local $i, $hBinaryFileOpen = FileOpen($sFilePath, 0 + 16)
	Local $sHexSearch = "0xFFFFFFFF0000"
	Local $iSearchSz = Int((StringLen($sHexSearch) - 2) / 2)
	Local $iFileSzKb = Int($iFileSz / 1024)
	Local $iRetPos = -1
	Local $iFileHeaderLen = 0
	If $hBinaryFileOpen = -1 Then
		MsgBox($MB_SYSTEMMODAL, "", "An error occurred when reading the file.")
		Return -1
	If ($iFileSzKb > 17000) Then ; Probably a diskimage let user decide where to search
		$iStartPos = InputBox("Large File, Search from a different offset?", "Enter the offset you would like to search from [0 -" _
				 & $iFileSz - $iSearchSz - 1 & "]", $iStartPos, Default, -1, -1, Default, Default, 30)
	For $i = $iStartPos To $iFileSz - $iSearchSz - 1
		$iFileProgress = Int(($i + 1) / 1024)
		If ($iFileProgress = ($i + 1) / 1024) Then
			If (0 = ControlSetText($sSplashTitle, "", "Static1", $sMessage & _
					"Searching for Storage Header... (" & $iFileProgress & " / " & $iFileSzKb & ") ")) Then ExitLoop

		FileSetPos($hBinaryFileOpen, $i, 0)
		$Data = FileRead($hBinaryFileOpen, $iSearchSz) ; ;FF FF FF FF 00 00
		If ($Data = $sHexSearch) Then
			$iFileHeaderLen = Dec(ExtractHexBytes($hBinaryFileOpen, $i + 4, 4), 1) ; [00 00 SZ BY] extract len in hex convert to 32 bit decimal
			$iRetPos = $i
			If (1 = Dec(ExtractHexBytes($hBinaryFileOpen, $i + 8, 4), 1)) Then ExitLoop ;.. [00 00 00 01]
	Return $iRetPos
EndFunc   ;==>FindStorageHeader

Func ExtractHexBytes($hBinaryFileOpen, $iStart, $iBytes)
	Local $iOldPos = FileGetPos($hBinaryFileOpen)
	If @error Or $hBinaryFileOpen = -1 Then
		MsgBox($MB_SYSTEMMODAL, "", "An error occurred when reading the file.")
		Return ""

	FileSetPos($hBinaryFileOpen, $iStart, 0) ;Offset from beginning
	Global $Data = FileRead($hBinaryFileOpen, $iBytes)
	FileSetPos($hBinaryFileOpen, $iOldPos, 0) ;Restore original position
	Return StringTrimLeft(String($Data), 2) ;Remove 0x from beginning
EndFunc   ;==>ExtractHexBytes

Func FileTypeExtension($iFileType)
	Local Const $aFileExt[12][2] = [[0, ".UNK"], [1, ".UNK"], _
			[14, ".swf"], [15, ".zip"], [25, ".gif"], [27, ".png"], _
			[28, ".xml"], [33, ".css"], [35, ".html"], [36, ".JS"], [37, ".txt"]]

	Local $i = 0
	Local $sExt = $aFileExt[0][1]
	For $i = 0 To UBound($aFileExt) - 1
		If ($aFileExt[$i][0] = $iFileType) Then
			Local $sExt = $aFileExt[$i][1]
	Return $sExt
EndFunc   ;==>FileTypeExtension

Func ExtractConnectFiles($sFilePath, $sLogPath, $sWritePath, $iStartPos)
	Local $hLogFile = FileOpen($sLogPath, 1)
	Local $iFileSz = FileGetSize($sFilePath)
	Local $i = 0, $j = 0
	Local $sLogMsg = "Extract Connect Files Started" & @CRLF & "Sz: " & $iFileSz & " bytes, Path: " & $sFilePath & @CRLF

	$sMessage = $sLogMsg
	SplashTextOn($sSplashTitle, $sMessage & _
			"Searching for Storage Header...", -1, 200, -1, 18, _
	_FileWriteLog($hLogFile, $sLogMsg)
	$iStartPos = FindStorageHeader($sFilePath, $iFileSz, $iStartPos)
	If ($iStartPos > -1) Then
		$sLogMsg = "Storage Header Found @ " & String(Hex($iStartPos))
		$sMessage = $sMessage & $sLogMsg & @CRLF
		_FileWriteLog($hLogFile, $sLogMsg)
		$sLogMsg = "!Error! Storage Header Not Found!"
		_FileWriteLog($hLogFile, $sLogMsg)
		ControlSetText($sSplashTitle, "", "Static1", $sMessage & @CRLF & $sLogMsg & @CRLF & "Exiting...")
		_Exit($hLogFile, -1)
	ControlSetText($sSplashTitle, "", "Static1", $sMessage)
	Local $hBinaryFileOpen = FileOpen($sFilePath, 0 + 16)
	If $hBinaryFileOpen = -1 Then
		MsgBox($MB_SYSTEMMODAL, "", "An error occurred when reading the file.")
		_Exit($hLogFile, -1)
	Local $iFileHeaderLen = Dec(ExtractHexBytes($hBinaryFileOpen, $iStartPos + 4, 4), 1) ;extract len in hex convert to 32 bit decimal
	If ($iFileHeaderLen > 600 Or $iFileHeaderLen < 200) Then
		Local $iCancelTryContinue = MsgBox(16 + 6, "Error", _
				"Header Length is out of range continue to force or try again to find a new header", 30)

		If ($iCancelTryContinue = 2) Then
			_Exit($hLogFile, -1)
		ElseIf ($iCancelTryContinue = 10 Or $iCancelTryContinue = -1) Then ;tryagain or timeout
			Return $iStartPos + 1
	Local $sFileHeader = ExtractHexBytes($hBinaryFileOpen, $iStartPos + 8, $iFileHeaderLen)
	$sLogMsg = "FileHeader Sz: " & $iFileHeaderLen & " bytes" & @CRLF & "Data:[" & $sFileHeader & "]"
	$sMessage = $sMessage & "File Header Found! Sz: " & $iFileHeaderLen & " bytes" & @CRLF
	ControlSetText($sSplashTitle, "", "Static1", $sMessage)
	_FileWriteLog($hLogFile, $sLogMsg)
	Local $iElemsPer = 3 ; Each file has [Index, offset, Type]
	Local $aS = _StringEqualSplit($sFileHeader, 8)
	If IsArray($aS) Then
		Local $iFileCount = Int(UBound($aS) / $iElemsPer)
		Local $aFileData[$iFileCount][4] ;We will store the file data as [FileIndex, FileType, FileOffset, SzBytes]
		$j = 0 ;
		;_ArrayDisplay($aS, "Raw File Header", Default, 32 + 64, Default, "", Default, 0xDDFFDD)
		For $i = 0 To UBound($aS) - 1 Step $iElemsPer
			$aFileData[$j][0] = Dec($aS[$i + 0])
			$aFileData[$j][1] = FileTypeExtension(Dec($aS[$i + 2]))
			$aFileData[$j][2] = $iStartPos + Dec($aS[$i + 1])
			Local $iFileHeaderOffset = Dec(ExtractHexBytes($hBinaryFileOpen, $aFileData[$j][2], 4), 1)
			If ($iFileHeaderOffset = $aFileData[$j][0]) Then ;check header at offset see if it matches
				$aFileData[$j][3] = Dec(ExtractHexBytes($hBinaryFileOpen, $aFileData[$j][2] + 4, 4), 1) ;extract len in hex convert to 32 bit decimal

				$aFileData[$j][3] = "BAD HEADER"
				Local $iCancelTryContinue = MsgBox(16 + 6, "Error", _
						"File Has a bad Header continue or try again to find a new storage header", 30)

				If ($iCancelTryContinue = 2) Then
					_Exit($hLogFile, $hBinaryFileOpen)
				ElseIf ($iCancelTryContinue = 10 Or $iCancelTryContinue = -1) Then ;tryagain or timeout
					Return $iStartPos + 1

			$sLogMsg = "File Index: " & $aFileData[$j][0] & " File Type: " & _
					$aFileData[$j][1] & " File Offset: 0x" & Hex($aFileData[$j][2], 8) & _
					" File Size Bytes:" & $aFileData[$j][3]

			_FileWriteLog($hLogFile, $sLogMsg)
			$j = $j + 1
			If ($j > $iFileCount) Then
				MsgBox($MB_SYSTEMMODAL, "", "An error occurred when reading FileData")
		_ArrayDisplay($aFileData, $sSplashTitle & " Found", Default, 16 + 32 + 64, Default, _
				"Index |Type |Offset |Bytes ", 500, 0xDDFFDD)

		$sMessage = $sMessage & "Extracting Files: " & $sWritePath & @CRLF
		If (7 = MsgBox(4 + 32 + 256, "Extract Files?", "Press Yes to Extract files to" & @CRLF & $sWritePath)) Then
			_Exit($hLogFile, $hBinaryFileOpen)
		SplashTextOn($sSplashTitle, $sMessage, -1, 200, -1, 18, BitOR($DLG_TEXTLEFT, $DLG_NOTONTOP, $DLG_MOVEABLE), "", 10)

		For $i = 0 To $iFileCount - 1
			If ($aFileData[$i][3] <> "BAD HEADER") Then
				ControlSetText($sSplashTitle, "", "Static1", $sMessage & " (" & $i + 1 & "/" & $iFileCount & ") " & _
						$aFileData[$i][0] & $aFileData[$i][1])

				FileSetPos($hBinaryFileOpen, ($aFileData[$i][2]) + 8, 0)
				Local $hBinaryFileWrite = FileOpen($sWritePath & $aFileData[$i][0] & $aFileData[$i][1], 2 + 8 + 16)
				If @error Or $hBinaryFileOpen = -1 Then
					MsgBox($MB_SYSTEMMODAL, "", "An error occurred trying to write the file." & @CRLF & _
							$sWritePath & $aFileData[$i][0] & $aFileData[$i][1])

				FileWrite($hBinaryFileWrite, FileRead($hBinaryFileOpen, $aFileData[$i][3]))



	_Exit($hLogFile, $hBinaryFileOpen)
EndFunc   ;==>ExtractConnectFiles


Edited by Bilgus
Forum wouldn't let me upload images till after saving once??
Link to comment
Share on other sites

  • 2 months later...

I've pretty much stopped work on this, I was able to edit the firmware on the device to allow a redirect to my own index.html on page load

Unfortunately it seems the device has the web address hardcoded to www.sandisk.com/myconnect

and I'm pretty sure its in the actual rom because I couldn't find it in the firmware.

I was more hoping to be able to redirect any address to my own pages but if you are just looking for that (limited) functionality I've included instructions


I'd recommend looking into the zsin devices if you need the form factor https://wiki.hackerspace.pl/projects:zsun-wifi-card-reader


or just get one of those small openwrt micro routers which is the route I took


You will have to use a hex editor on the image you pull from the device, use the file extractor abovet to get a little context into the file you need to edit

find the first instance of this:

var resizeTimer;.function doResize() {clearTimeout(resizeTimer); if(lastWidth != $(window).width()) 


then search backwards from that point for:
// Finally, protect remaining links with a click function that will mute the audio player if it is playing.

// and pause if we leave the page.

Free up enough space for our redirect by deleting the comments....

Shift the whole file up and finally
place this just before 'AirStash.initializePage();

window.onresize = function() {

resizeTimer = setTimeout(doResize, 300);


Note the text below is to the end of the file so don't duplicate 'AirStash.initializePage();

window.onresize = 

function() {
    resizeTimer = setTimeout(doResize, 300);



function elm_hide(h){
var e = document.getElementsByTagName("*");for(var i = 0; i < e.length; i++){e

[i].style.visibility = h;}
function ld_pg(u, cb){
if(window.location.search == ''){elm_hide("hidden");}
var r = new 

var s = window.location.search;
r.open('GET',u, true);

== 4 && (r.status == 200) && (s == '' || s == '?dbg')){$('html').html(r.responseText);if(s == '?dbg'){console.log

('Redirect old:' + window.location.href + ' new:' + u);console.log("<html>" + $("html").html() + "</html>");}

r.onreadystatechange=null;return;} else if (r.status != 200) {//Continue loading page as normal
ld_pg('/wfd/.web/index.html', function(){AirStash.initializePage

();window.onresize = function() {clearTimeout(resizeTimer);resizeTimer = setTimeout(doResize, 300);}}
















Link to comment
Share on other sites

  • 4 weeks later...
  • 4 weeks later...
On 11/1/2017 at 10:35 PM, Forgiven said:

I'm pretty sure that post is about the wireless media drive, a ~3x3" brick.

I wasn't able to get a telenet session or even any open ports besides 80 on the wireless flash drive ( a 1x3" boxy thumb drive)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...