#include #include "ceioctl.h" #include "storeinfo.h" #include "debug.h" #include "TffsDiskReader.h" #include "stringutils.h" #ifdef WITHDEBUG #define tffsdebug debug #else #define tffsdebug while(0) #endif /* * trueffs.dll is found on these devices: * atom hp thuraya * htc:artemis blueangel elf harrier herald himalaya prophet startrek tornado typhoon wallaby wizard universal alpine apache charmer * * */ char BDK_SIGNATURE[5]= "BIPO"; DWORD *g_pWriteEnableFlag; // if partition=="" -> open device as file. bool OpenTFFSDisk(const WCHAR *szDeviceName, const WCHAR *szPartitionName, HANDLE& hStore, HANDLE& hPartition) { if (szPartitionName && wcslen(szPartitionName)) { hStore = OpenStore(szDeviceName); if (hStore == INVALID_HANDLE_VALUE || hStore == NULL) { error("OpenTFFSDisk: OpenStore('%ls')", szDeviceName); return false; } hPartition = PSLOpenPartition(hStore, szPartitionName); if (hPartition == INVALID_HANDLE_VALUE || hPartition == NULL) { error("PSLOpenPartition('%ls')", szPartitionName); CloseHandle(hStore); hStore= NULL; return false; } } else { hStore= NULL; hPartition= CreateFile( szDeviceName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); if (hPartition == INVALID_HANDLE_VALUE || hPartition == NULL) { error("OpenTFFSDisk: OpenStore('%ls')", szDeviceName); return false; } } return true; } bool CloseTFFSDisk(HANDLE hStore, HANDLE hPartition) { CloseHandle(hPartition); CloseHandle(hStore); return true; } bool TFFS_BDK_GetInfo(HANDLE hDisk, DWORD dwBinaryPartitionNr, DWORD &dwLength, DWORD &dwCount) { flBDKOperationInput in; memset(&in, 0, sizeof(in)); in.partitionNumber = (BYTE)dwBinaryPartitionNr; in.type = BDK_GET_INFO; memcpy(in.bdkStruct.oldSign, BDK_SIGNATURE, 4); in.bdkStruct.signOffset = 8; in.bdkStruct.startingBlock = 0; flOutputStatusRecord out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_BDK_OPERATION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_GET_INFO)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_GET_INFO) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } // used length: in.bdkStruct.length dwLength= in.bdkStruct.startingBlock; dwCount= in.bdkStruct.flags; return true; } bool TFFS_OTP_GetSize(HANDLE hDisk, DWORD& dwSize, DWORD &dwMaxSize) { flOtpInput in; memset(&in, 0, sizeof(in)); flOutputStatusRecord out; memset(&out, 0, sizeof(out)); in.type= OTP_SIZE; DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_OTP, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_SIZE)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_SIZE) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } // in.lockedFlag dwSize= in.usedSize; dwMaxSize= in.length; return true; } bool TFFS_GetCustomerId(HANDLE hDisk, DWORD &id) { flCustomerIdOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_CUSTOMER_ID, NULL, 0, &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_CUSTOMER_ID)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_CUSTOMER_ID) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } memcpy(&id, out.id, 4); return true; } bool TFFS_GetUniqueId(HANDLE hDisk, GUID& id) { flUniqueIdOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_UNIQUE_ID, NULL, 0, &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_UNIQUE_ID)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_UNIQUE_ID) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } memcpy(&id, out.id, 16); return true; } bool TFFS_GetNrOfPartitions(HANDLE hDisk, DWORD& dwPartitionCount) { flCountPartitionsOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_NUMBER_OF_PARTITIONS, NULL, 0, &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_NUMBER_OF_PARTITIONS)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_NUMBER_OF_PARTITIONS) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } dwPartitionCount= out.noOfPartitions; return true; } const char *doctypenames[]= { "NOT_DOC", "DOC", "MDOC", "DOC2000TSOP", "MDOCP_16", "MDOCP", "DOC_H1", "MDOC512_G3", "MDOC256_P3", "MDOC256_G3", "MDOC128_P3", "AMD_NOR", "SEIJA", "MDOC_G4", "MDOC_P4", }; #define NDOCTYPENAMES (sizeof(doctypenames)/sizeof(*doctypenames)) //////////////////////////////////////////////////////////////////////// // info functions bool TFFS_GetInfo(HANDLE hDisk) { flDiskInfoOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_GET_INFO, NULL, 0, &out, sizeof(out), &nReturned, NULL)) { debug("get_info - out: %hs\n", hexdump((BYTE*)&out, sizeof(out)).c_str()); error("DeviceIoControl(FL_IOCTL_GET_INFO)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_GET_INFO) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } debug("getinfo: logical=%08lx boot=%08lx base=%08lx ft=%04x phys=%08lx unitsize=%08lx\n", out.info.logicalSectors, out.info.bootAreaSize, out.info.baseAddress, out.info.flashType, out.info.physicalSize, out.info.physicalUnitSize); debug("getinfo: doctype=%02x(%s) lifetime=%02x driver='%s' osak='%s' cyl=%d hd=%d sc=%d\n", out.info.DOCType, (out.info.DOCType>=0 && out.info.DOCType<= NDOCTYPENAMES)? doctypenames[out.info.DOCType]: "", out.info.lifeTime, out.info.driverVer, out.info.OSAKVer, out.info.cylinders, out.info.heads, out.info.sectors); return true; } //////////////////////////////////////////////////////////////////////////////////// // read functions bool TFFS_BDK_InitRead(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG llOffset, DWORD dwSize, DWORD dwSectorSize) { flBDKOperationInput in; memset(&in, 0, sizeof(in)); in.partitionNumber = (BYTE)dwBinaryPartitionNr; in.type = BDK_INIT_READ; memcpy(in.bdkStruct.oldSign, BDK_SIGNATURE, 4); in.bdkStruct.signOffset = 8; in.bdkStruct.startingBlock = (DWORD)(llOffset/dwSectorSize); in.bdkStruct.length = dwSize; in.bdkStruct.flags = 2; // ??? flOutputStatusRecord out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_BDK_OPERATION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(%d, FL_IOCTL_BDK_OPERATION, BDK_INIT_READ, start=%d, size=0x%x)", dwBinaryPartitionNr, (DWORD)(llOffset/dwSectorSize), dwSize); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_INIT_READ) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } return true; } bool TFFS_BDK_ReadNextSector(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG llOffset, DWORD dwLength, BYTE *buffer, DWORD &dwRead) { flBDKOperationInput in; memset(&in, 0, sizeof(in)); // limit to 512 bytes per call for stable operation if (dwLength>512) dwLength= 512; BYTE *localbuf= (BYTE*)alloca(dwLength); memset(localbuf, 0, dwLength); in.partitionNumber = (BYTE)dwBinaryPartitionNr; in.type = BDK_READ; memcpy(in.bdkStruct.oldSign, BDK_SIGNATURE, 4); in.bdkStruct.signOffset = 8; in.bdkStruct.startingBlock = 0; // is ignored ?? (DWORD)(llOffset/dwSectorSize); in.bdkStruct.length = dwLength; in.bdkStruct.bdkBuffer = localbuf; // !!! this must be allocated on the stack. in.bdkStruct.flags = 2; // ??? flOutputStatusRecord out; memset(&out, 0, sizeof(out)); //debug("disk_bdk_readnext: reading %I64x %08lx ss=%08lx\n", llOffset, dwLength, dwSectorSize); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_BDK_OPERATION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_READ)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_READ) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } memcpy(buffer, localbuf, dwLength); dwRead= dwLength; //debug("disk_bdk_readnext: read %08lx\n", dwRead); return true; } bool TFFS_OTP_Read(HANDLE hDisk, ULONGLONG llOffset, DWORD dwLength, BYTE *buffer, DWORD &dwRead) { flOtpInput in; memset(&in, 0, sizeof(in)); flOutputStatusRecord out; memset(&out, 0, sizeof(out)); BYTE *localbuf= (BYTE*)alloca(dwLength); memset(localbuf, 0, dwLength); in.type = OTP_READ; in.usedSize= 0; in.length = dwLength; in.buffer= localbuf; tffsdebug("tffs_otp_read: reading %I64x %08lx\n", llOffset, dwLength); debug("otpcmd: %s\n", hexdump((BYTE*)&in, sizeof(in)).c_str()); DWORD nReturned=0; // NOTE: ignoring the errors returned by this api // it always seems to return 'crc-error' if (!DeviceIoControl(hDisk, FL_IOCTL_OTP, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_READ) - nr=0x%x, st=%08lx : %s", nReturned, out.status, localbuf); //return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_READ) - status=%08lx", out.status); //SetLastError(ERROR_INTERNAL_ERROR); //return false; } strncpy((char*)buffer, (char*)localbuf, in.length); dwRead= strlen((char*)buffer); tffsdebug("tffs_otp_read: read %08lx\n", dwRead); return true; } //.......... bool TFFS_ReadSectors(HANDLE hDisk, ULONGLONG llOffset, DWORD dwLength, BYTE *buffer, DWORD &dwBytesRead, DWORD dwSectorSize) { flReadWriteInput in; memset(&in, 0, sizeof(in)); BYTE *localbuf= (BYTE*)alloca(dwLength); if (localbuf==NULL) { debug("ERROR allocating stack buffer\n", localbuf); return false; } memset(localbuf, 0, dwLength); if (dwLength > dwLength) dwLength= dwLength; in.firstSector= (DWORD)(llOffset/dwSectorSize); in.numberOfSectors= dwLength/dwSectorSize; in.buf= localbuf; flReadWriteOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_READ_SECTORS, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_READ_SECTORS)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_READ_SECTORS) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } dwBytesRead= out.numberOfSectors*dwSectorSize; if (dwBytesRead > dwLength) dwBytesRead= dwLength; memcpy(buffer, localbuf, dwBytesRead); return true; } //////////////////////////////////////////////////////////////////////////////////// // write functions bool TFFS_BDK_InitWrite(HANDLE hDisk, DWORD dwBinaryPartitionNr, ULONGLONG llOffset, DWORD dwSize, DWORD dwSectorSize) { flBDKOperationInput in; memset(&in, 0, sizeof(in)); in.partitionNumber = (BYTE)dwBinaryPartitionNr; in.type = BDK_INIT_WRITE; memcpy(in.bdkStruct.oldSign, BDK_SIGNATURE, 4); in.bdkStruct.signOffset = 8; in.bdkStruct.startingBlock = (DWORD)(llOffset/dwSectorSize); in.bdkStruct.length = dwSize; in.bdkStruct.flags = 0x0a; // ERASE_BEFORE_WRITE flOutputStatusRecord out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_BDK_OPERATION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_INIT_WRITE, start=%08x len=%08x)", (DWORD)(llOffset/dwSectorSize), dwSize); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_INIT_WRITE, start=%08x len=%08x) - status=%08lx", (DWORD)(llOffset/dwSectorSize), dwSize, out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } return true; } bool TFFS_BDK_WriteNextSector(HANDLE hDisk, DWORD dwBinaryPartitionNr, DWORD dwStartSector, ULONGLONG llOffset, DWORD dwLength, const BYTE *buffer, DWORD &dwWritten) { flBDKOperationInput in; memset(&in, 0, sizeof(in)); // limit to 512 bytes per call for stable operation if (dwLength>512) dwLength= 512; BYTE *localbuf= (BYTE*)alloca(dwLength); memcpy(localbuf, buffer, dwLength); in.partitionNumber = (BYTE)dwBinaryPartitionNr; in.type = BDK_WRITE; memcpy(in.bdkStruct.oldSign, BDK_SIGNATURE, 4); in.bdkStruct.signOffset = 8; in.bdkStruct.startingBlock = dwStartSector; in.bdkStruct.length = dwLength; in.bdkStruct.bdkBuffer = localbuf; // !!! this must be allocated on the stack. in.bdkStruct.flags = 0x0a; // ??? flOutputStatusRecord out; memset(&out, 0, sizeof(out)); //debug("disk_bdk_writenext: writing %I64x %08lx\n", llOffset, dwLength); // special for herald //*(DWORD*)0xB0027354= 1; // special for artemis //*(DWORD*)0xB0027350= 1; if (g_pWriteEnableFlag) *g_pWriteEnableFlag= 1; DWORD nReturned=0; if (!DeviceIoControl(hDisk, FL_IOCTL_BDK_OPERATION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_WRITE, l=0x%x nret=0x%x, start=0x%x ofs=0x%I64x)", dwLength, nReturned, dwStartSector, llOffset); if (nReturned==4) { debug("BDK_WRITE return value: %08lx\n", *(DWORD*)&out); } return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_BDK_OPERATION, BDK_WRITE) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } dwWritten= in.bdkStruct.length; //debug("disk_bdk_writenext: wrote %08lx\n", dwWritten); return true; } bool TFFS_OTP_Write(HANDLE hDisk, ULONGLONG llOffset, DWORD dwLength, const BYTE *buffer, DWORD &dwWritten) { flOtpInput in; memset(&in, 0, sizeof(in)); flOutputStatusRecord out; memset(&out, 0, sizeof(out)); BYTE *localbuf= (BYTE*)alloca(dwLength); memcpy(localbuf, buffer, dwLength); in.type = OTP_WRITE_LOCK; in.usedSize= 0; in.length = dwLength; in.buffer= localbuf; tffsdebug("tffs_otp_write: writing %I64x %08lx\n", llOffset, dwLength); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_OTP, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_WRITE)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_OTP, OTP_WRITE) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } dwWritten= in.length; tffsdebug("tffs_otp_write: wrote %08lx\n", dwWritten); return true; } //.......... bool TFFS_WriteSectors(HANDLE hDisk, ULONGLONG llOffset, DWORD dwLength, const BYTE *buffer, DWORD &dwBytesWritten, DWORD dwSectorSize) { flReadWriteInput in; memset(&in, 0, sizeof(in)); BYTE *localbuf= (BYTE*)alloca(dwLength); memcpy(localbuf, buffer, dwLength); if (dwLength > dwLength) dwLength= dwLength; in.firstSector= (DWORD)(llOffset/dwSectorSize); in.numberOfSectors= dwLength/dwSectorSize; in.buf= localbuf; flReadWriteOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned; if (!DeviceIoControl(hDisk, FL_IOCTL_WRITE_SECTORS, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("DeviceIoControl(FL_IOCTL_WRITE_SECTORS)"); return false; } if (out.status != flOK) { error("DeviceIoControl(FL_IOCTL_WRITE_SECTORS) - status=%08lx", out.status); SetLastError(ERROR_INTERNAL_ERROR); return false; } dwBytesWritten= out.numberOfSectors*dwSectorSize; if (dwBytesWritten > dwLength) dwBytesWritten= dwLength; return true; } // protection functions bool TFFS_ChangeType(HANDLE hDisk, bool bInsert, BYTE *password) { //flChangeTypeionInput in; memset(&in, 0, sizeof(in)); BYTE in[10]; in[0]= PROTECTABLE | (bInsert ? 0 : WRITE_PROTECTED); memcpy(in+1, password, 8); in[9]= PROTECTION_CHANGE_TYPE; flProtectionOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned=0; if (!DeviceIoControl(hDisk, FL_IOCTL_BDTL_HW_PROTECTION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("FL_IOCTL_BDTL_HW_PROTECTION-%s-key", bInsert?"insert":"remove"); return false; } return true; } bool TFFS_BDK_ChangeType(HANDLE hDisk, DWORD dwBinaryPartitionNr, bool bInsert, BYTE *password) { //flBDKChangeTypeionInput in; memset(&in, 0, sizeof(in)); BYTE in[11]; in[0]= dwBinaryPartitionNr; in[1]= PROTECTABLE | (bInsert ? 0 : WRITE_PROTECTED); memcpy(in+2, password, 8); in[10]= PROTECTION_CHANGE_TYPE; flProtectionOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned=0; if (!DeviceIoControl(hDisk, FL_IOCTL_BINARY_HW_PROTECTION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("FL_IOCTL_BINARY_HW_PROTECTION-%s-key", bInsert?"insert":"remove"); return false; } return true; } bool TFFS_Protect(HANDLE hDisk, bool bInsert, BYTE *password) { //flProtectionInput in; memset(&in, 0, sizeof(in)); BYTE in[10]; in[0]= 0; memcpy(in+1, password, 8); in[9]= bInsert?PROTECTION_INSERT_KEY:PROTECTION_REMOVE_KEY; flProtectionOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned=0; if (!DeviceIoControl(hDisk, FL_IOCTL_BDTL_HW_PROTECTION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("FL_IOCTL_BDTL_HW_PROTECTION-%s-key", bInsert?"insert":"remove"); return false; } return true; } bool TFFS_BDK_Protect(HANDLE hDisk, DWORD dwBinaryPartitionNr, bool bInsert, BYTE *password) { //flBDKProtectionInput in; memset(&in, 0, sizeof(in)); BYTE in[11]; in[0]= dwBinaryPartitionNr; in[1]= 0; memcpy(in+2, password, 8); in[10]= bInsert?PROTECTION_INSERT_KEY:PROTECTION_REMOVE_KEY; flProtectionOutput out; memset(&out, 0, sizeof(out)); DWORD nReturned=0; if (!DeviceIoControl(hDisk, FL_IOCTL_BINARY_HW_PROTECTION, &in, sizeof(in), &out, sizeof(out), &nReturned, NULL)) { error("FL_IOCTL_BINARY_HW_PROTECTION-%s-key", bInsert?"insert":"remove"); return false; } return true; }