#include #include "pkfuncs.h" #include "debug.h" #include "stringutils.h" #include "args.h" #include // SLOCK 1 // SUNLOCK 1 // MFGDATA 1 // HTCLOGO 1 // GSMDATA 1 // GSMCODE 0x18 // SPLASH 2 // HTCSRV 1 // // volumespec: // nPgsPerBlk; 0040 // nSctsPerPg; 04 // nBadPos; 02 // nEccPos; 08 // nTrTime; 0000c350 // nTwTime; 00055730 // nTeTime; 001e8480 // nTfTime; 00000032 // nTotalBlks; 000003e9 // nMEFlag; 00000001 // val_field30; 00000002 // aUID[16]; ec 00 ec ee e9 6a 32 32 33 33 32 31 07 07 09 06 // // partnr attr start size ( in blocks ) // pi0.2: 00000002 00000002 00000005 00000020 gsm etc // pi0.3: 00000003 00000002 00000025 00000160 os // pi0.6: 00000006 00000022 00000001 00000004 spl // pi0.8: 00000008 00000001 00000185 00000264 userfs // // 1 block = 256 sectors // 1 sector = 512 bytes // // unistore docu: // part2 = stage 3 bootloader // part3 = os image // part8 = fat filesystem // // partition attr: // 1 BML_PI_ATTR_RW // 2 BML_PI_ATTR_RO // 20 BML_PI_ATTR_FROZEN // // c:\local\wince500\PUBLIC\COMMON\OAK\INC\diskio.h /* -- from the samsung sgh i900 ondisk.dll BML_Init 0x1013FC4, {0, 0x01, 0,0, 0,0,0,0, 0,0}, 0x28, 0, 0 BML_Open 0x1013FC4, {arg0, 0x02, 0,0, 0,0,0,0, 0,0}, 0x28, 0, 0 BML_Close 0x1013FC4, {arg0, 0x03, 0,0, 0,0,0,0, 0,0}, 0x28, 0,0 // 4 BML_Read 0x1013FC4, {arg0, 0x05, 0, arg1, arg2, arg3, 0, arg4, arg5, 0}, 0x28, 0,0 BML_Write 0x1013FC4, {arg0, 0x06, 0, arg1, arg2, arg3, 0, arg4, arg5, 0}, 0x28, 0,0 BML_EraseBlk 0x1013FC4, {arg0, 0x07, arg1, 0, 0,0,0,0, arg2, 0}, 0x28, 0, 0 BML_GetVolId 0x1013FC4, {arg0, 0x08, 0,0, 0,0,0,0, 0,0}, 0x28, arg1, 0x10 // 9 BML_ReadRes 0x1013FC4, {arg0, 0x0A, 0, arg1, arg2, arg3, 0, arg4, arg5, 0}, 0x28, 0,0 BML_WriteRes 0x1013FC4, {arg0, 0x0B, 0, arg1, arg2, arg3, 0, arg4, arg5, 0}, 0x28, 0,0 BML_MEraseBlk 0x1013FC4, {arg0, 0x0C, 0, 0, 0,0,0,0, arg2,arg1}, 0x28,0,0 // D // E BML_LoadPIEntry 0x1013FC4, {arg0, 0x0F, ?,0, 0,0,0,0, 0,0},0x28, arg2={arg1}, 0x10 BML_GetVolInfo 0x1013FC4, {arg0, 0x10, 0,0, 0,0,0,0, 0,0}, 0x28, arg1, 0x34 BML_Format 0x1013FC4, {arg0, 0x11, ?? // 12 BML_CopyBack 0x1013FC4, {arg0, 0x13, 0, 0, 0, 0, 0, 0, arg2, 0}, 0x28, arg1, 0x10 BML_FlushOp 0x1013FC4, {arg0, 0x14, 0, 0, 0,0,0,0, arg1, 0}, 0x28, 0, 0 // 15 // 16 ? BML_LoadPIExt 0x1013FC4, {arg0, 0x17, arg1,0, 0,0,0,0, 0,0},0x28, arg2,0xC // 18 ? BML_Copy 0x1013FC4, {arg0, 0x19, 0,0, 0,0,0,0, arg2,0},0x28, arg1,0x38 BML_SGLRead 0x1013FC4, {arg0, 0x1A, 0,arg1, arg2,0,arg3,arg4, arg5,0}, 0x28, 0,0 BML_SGLWrite 0x1013FC4, {arg0, 0x1B, 0,arg1, arg2,0,arg3,arg4, arg5,0}, 0x28, 0,0 // 1C ? // 1D ? // 1E ? // 1F ? BML_GetDevInfo 0x1013FC4, {arg0, 0x20, 0, ...}, 0x28, arg1, 0x30 di0: 0040 nPgsPerBlk; 04 nSctsPerPg; 02 nBadPos; 00000008 nEccPos; 0000c350 nTrTime; 00055730 nTwTime; 001e8480 nTeTime; 00000032 nTfTime; 000007d2 nTotalBlks; 00000001 nMEFlag; 00000002 val_field30; ec 00 a2 0d ad 78 32 31 32 32 30 30 06 06 08 08 aUID pi.: id unknown start size pi0.3: 00000003 00000022 00000012 000003ea DSK1: pi0.5: 00000005 00000022 00000005 00000003 pi0.6: 00000006 00000022 00000001 00000004 pi0.7: 00000007 00000001 000007d1 00000001 pi0.8: 00000008 00000001 000003fc 0000030d DSK2: pi0.9: 00000009 00000022 00000008 0000000a pi0.A: 0000000a 00000001 00000709 000000c8 */ extern "C" BOOL KernelIoControl(DWORD dwIoControlCode, LPVOID lpInBuf, DWORD nInBufSize, LPVOID lpOutBuf, DWORD nOutBufSize, LPDWORD lpBytesReturned); struct VolumeSpec { // size=0x34 WORD nPgsPerBlk; // 00 BYTE nSctsPerPg; // 02 BYTE nBadPos; // 03 BYTE nEccPos; // 04 BYTE field_5; // 05 BYTE field_6; // 06 BYTE field_7; // 07 DWORD nTrTime; // 08 DWORD nTwTime; // 0C DWORD nTeTime; // 10 DWORD nTfTime; // 14 DWORD nTotalBlks; // 18 DWORD nMEFlag; // 1C DWORD val_field30; // 20 BYTE aUID[16]; // 24 }; struct PartSpec { // size= 0x10 DWORD id; DWORD unknown; DWORD start; DWORD size; }; struct DevInfo { DWORD d[12]; }; #define ONDISK_INIT 0x01 // no params #define ONDISK_OPENVOL 0x02 // no params #define ONDISK_CLOSEVOL 0x03 // no params // 4 #define ONDISK_WRITE 0x05 // 5 params #define ONDISK_READ 0x06 // 5 params #define ONDISK_ERASEBLK 0x07 // 2 params #define ONDISK_GETVOLID 0x08 // returns 0x10 bytes // 9 #define ONDISK_READRES 0x0a // 5 params #define ONDISK_WRITERES 0x0b // 5 params #define ONDISK_MERASEBLK 0x0C // 2 params // d // e #define ONDISK_LOADPIENTRY 0x0f // no params, returns 0x10 bytes #define ONDISK_GETVOLINFO 0x10 // no params, returns 0x34 bytes #define ONDISK_FORMAT 0x11 // ? // 12 #define ONDISK_COPYBACK 0x13 // 1 param, returns 0x10 #define ONDISK_FLUSHOP 0x14 // 1 param // 15 #define ONDISK_LOADPIEXT 0x17 // 1 param, returns 0x0C // 0x18 #define ONDISK_COPY 0x19 // 1 param, returns 0x38 #define ONDISK_SGLREAD 0x1A // 5 params #define ONDISK_SGLWRITE 0x1B // 5 params #define ONDISK_GETDEVINFO 0x20 // no params, returns 0x30 bytes #define CMDDWSIZE 10 int g_cmdsize= 0x24; int g_ondiskioctl= 0x1013fc0; bool getdiskinfo(DWORD vol, struct VolumeSpec *di) { DWORD cmd[CMDDWSIZE]; DWORD nReturned=0; cmd[0]=vol; cmd[1]=ONDISK_GETVOLINFO; cmd[2]=0; cmd[3]=0; cmd[4]=0; cmd[5]=0; cmd[6]=0; cmd[7]=0; cmd[8]=0; cmd[9]=0; if (!KernelIoControl(g_ondiskioctl, cmd, g_cmdsize, (BYTE*)di, sizeof(struct VolumeSpec), &nReturned)) { error("kioctl(FLASH, diskinfo)"); return false; } return true; } bool getdevinfo(DWORD vol, struct DevInfo *di) { DWORD cmd[CMDDWSIZE]; DWORD nReturned=0; cmd[0]=vol; cmd[1]=ONDISK_GETVOLINFO; cmd[2]=0; cmd[3]=0; cmd[4]=0; cmd[5]=0; cmd[6]=0; cmd[7]=0; cmd[8]=0; cmd[9]=0; if (!KernelIoControl(g_ondiskioctl, cmd, g_cmdsize, (BYTE*)di, sizeof(struct DevInfo), &nReturned)) { error("kioctl(FLASH, diskinfo)"); return false; } return true; } bool getpartinfo(DWORD vol, DWORD part, struct PartSpec*pi) { DWORD cmd[CMDDWSIZE]; DWORD nReturned=0; pi->id=part; cmd[0]=vol; cmd[1]=ONDISK_LOADPIENTRY; cmd[2]=0; cmd[3]=0; cmd[4]=0; cmd[5]=0; cmd[6]=0; cmd[7]=0; cmd[8]=0; cmd[9]=0; if (!KernelIoControl(g_ondiskioctl, cmd, g_cmdsize, (BYTE*)pi, sizeof(struct PartSpec), &nReturned)) { error("kioctl(FLASH, diskinfo)"); return false; } return true; } bool init_flash() // ioctl 1 { DWORD cmd[CMDDWSIZE]; DWORD nReturned=0; cmd[0]=0; cmd[1]=ONDISK_INIT; cmd[2]=0; cmd[3]=0; cmd[4]=0; cmd[5]=0; cmd[6]=0; cmd[7]=0; cmd[8]=0; cmd[9]=0; if (!KernelIoControl(g_ondiskioctl, cmd, g_cmdsize, NULL, 0, &nReturned)) { error("kioctl(FLASH, init1)"); return false; } return true; } bool open_flash(DWORD vol) // ioctl 2 { DWORD cmd[CMDDWSIZE]; DWORD nReturned=0; cmd[0]=vol; cmd[1]=ONDISK_OPENVOL; cmd[2]=0; cmd[3]=0; cmd[4]=0; cmd[5]=0; cmd[6]=0; cmd[7]=0; cmd[8]=0; cmd[9]=0; if (!KernelIoControl(g_ondiskioctl, cmd, g_cmdsize, NULL, 0, &nReturned)) { error("kioctl(FLASH, open)"); return false; } return true; } bool read_sector(DWORD vol, DWORD secnr, DWORD nsec, BYTE *buf) { DWORD cmd[CMDDWSIZE]; DWORD nReturned=0; cmd[0]=vol; cmd[1]=ONDISK_READRES; cmd[2]=0; cmd[3]=secnr; cmd[4]=nsec; cmd[5]=(DWORD)buf; cmd[6]=0; cmd[7]=0; // ptr to spare array of nand memory cmd[8]=2; // LLD_FLAG_ECC_ON cmd[9]=0; //OutputDebugString(L"<1>"); //debug("cmd: %s\n", hexdump((BYTE*)cmd, 9, 4).c_str()); if (!KernelIoControl(g_ondiskioctl, cmd, g_cmdsize, NULL, 0, &nReturned)) { error("kioctl(FLASH, read)"); return false; } //debug("nret=%08lx cmd=%s\n", nReturned, hexdump((BYTE*)cmd, 9, 4).c_str()); //OutputDebugString(L"<2>"); return true; } bool save(const TCHAR *file, DWORD vol, DWORD start, DWORD nsect) { HANDLE h= CreateFile(file, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (h==INVALID_HANDLE_VALUE || h==NULL) { error("creating %ls", file); return false; } //OutputDebugString(L"<0a>"); ByteVector buf; buf.resize(0x20000); debug("saving %d: %d:%d to %ls\n", vol, start, nsect, file); //OutputDebugString(L"<0b>"); for (DWORD secnr= start ; secnr < start+nsect; secnr+=buf.size()/0x200) { memset(vectorptr(buf), 0xaa, buf.size()); //OutputDebugString(L"<0c>"); if (!read_sector(vol, secnr, buf.size()/0x200, vectorptr(buf))) { //memset(buf, 0x55, sizeof(buf)); } DWORD wrote=0; if (!WriteFile(h, vectorptr(buf), buf.size(), &wrote, NULL)) { error("write %08lx", secnr); CloseHandle(h); return false; } } CloseHandle(h); return true; } void usage() { debug("Usage: bkondisk [rootdir]\n"); debug(" will save all partitions on all volumes in files on \n"); debug("Usage: bkondisk [-vVOLUME] [-pPARTITION] [rootdir]\n"); debug(" will save a specific partition on \n"); debug("Usage: bkondisk [-vVOLUME] [-bSTARTBLOCK] [-nNBLOCKS] [filename]\n"); debug(" will save the specified blocks to \n"); debug("Usage: bkondisk -i\n"); debug(" will only list disk info in the logfile\n"); } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { DebugSetLogfile("bkondisk.log"); BOOL bMode = SetKMode(TRUE); DWORD dwPerm = SetProcPermissions(0xFFFFFFFF); StringList args; if (!SplitString(ToString(lpCmdLine), args, false)) { error("Error in commandline"); return false; } DWORD volume=0; DWORD partition=-1; std::string root; DWORD start_block=-1; DWORD block_count=-1; bool info_only= false; for (StringList::iterator i= args.begin() ; i!=args.end() ; ++i) { std::string& arg= *i; if (arg[0]=='-') switch(arg[1]) { case '0': g_cmdsize= 0x24; g_ondiskioctl= 0x1013fc0; break; case '1': g_cmdsize= 0x28; g_ondiskioctl= 0x1013fc4; break; case 'v': HANDLESTLULOPTION(volume, DWORD); break; case 'p': HANDLESTLULOPTION(partition, DWORD); break; case 'b': HANDLESTLULOPTION(start_block, DWORD); break; case 'n': HANDLESTLULOPTION(block_count, DWORD); break; case 'i': info_only=true; break; default: usage(); } else { if (root.size()) root += ' '; root += arg; } } if (!init_flash()) { debug("error initializing flash\n"); return false; } // todo: find real storagecard by using ?? api to enum storage cards if (root.empty()) root= "\\Storage Card"; debug("listing partions for each volume in format:\n pi.: id unknown start size\n"); for (DWORD vol=(volume==-1)?0:volume ; (volume==-1)?(vol<2):vol==volume ; vol++) { if (!open_flash(vol)) { debug("error initializing flash vol %d\n", vol); continue; } struct VolumeSpec di; memset(&di, 0, sizeof(di)); if (!getdiskinfo(vol, &di)) { debug("error getting di(%d)\n", vol); } else { debug("di%d: %s\n", vol, hexdump((BYTE*)&di, 13, 4).c_str()); } if (di.nTotalBlks==0) continue; if (start_block!=-1) { if (block_count==-1) block_count=di.nTotalBlks-start_block; save(ToWString(root).c_str(), vol, start_block*di.nSctsPerPg*di.nPgsPerBlk, block_count*di.nSctsPerPg*di.nPgsPerBlk); return 0; } typedef std::map PartitionMap; PartitionMap savedblocks; DWORD minblock=0xFFFFFFFF; DWORD maxblock=0; for (DWORD part=(partition==-1)?0:partition ; (partition==-1)?(part<32):part==partition ; part++) { struct PartSpec pi; memset(&pi, 0, sizeof(pi)); if (!getpartinfo(vol, part, &pi)) { debug("error getting pi(%d.%d)\n", vol, part); } else { if (pi.unknown || pi.start || pi.size) { debug("pi%d.%d: %s\n", vol, part, hexdump((BYTE*)&pi, 4, 4).c_str()); if (!info_only) save(ToWString(stringformat("%s\\bk_%d%d_%04x.img", root.c_str(), vol, part, pi.start)).c_str(), vol, pi.start*di.nSctsPerPg*di.nPgsPerBlk, pi.size*di.nSctsPerPg*di.nPgsPerBlk); if (savedblocks.find(pi.start)!=savedblocks.end()) { debug("!!! partition reuses block\n"); } savedblocks[pi.start]= pi.size; if (pi.startmaxblock) maxblock=pi.start+pi.size; } } } if (partition==-1) { if (minblock) { if (info_only) { debug("no partition for blocks 0x%x l=0x%x\n", 0, minblock); } else { save(ToWString(stringformat("%s\\bk_%d__%04x.img", root.c_str(), vol, 0)).c_str(), vol, 0, minblock*di.nSctsPerPg*di.nPgsPerBlk); } savedblocks[0]= minblock; } if (maxblockblockptr) { if (info_only) { debug("no partition for blocks 0x%x l=0x%x\n", blockptr, (*mi).first-blockptr); } else { save(ToWString(stringformat("%s\\bk_%d__%04x.img", root.c_str(), vol, blockptr)).c_str(), vol, blockptr*di.nSctsPerPg*di.nPgsPerBlk, ((*mi).first-blockptr)*di.nSctsPerPg*di.nPgsPerBlk); } } else if ((*mi).first