/* (C) 2003-2007 Willem Jan Hengeveld * Web: http://www.xs4all.nl/~itsme/ * http://wiki.xda-developers.com/ * * $Id$ */ #include #include "stdio.h" #include "args.h" #include "debug.h" #include "stringutils.h" #include "vectorutils.h" #include #include #include "crc32.h" int g_nDumpUnitSize=1; int g_nMaxWordsPerLine=-1; DWORD g_nStepSize= 0; std::string g_device; int g_verbose= 0; DWORD g_rd_memblock_per_read=1024; DWORD g_rd_memblock_per_cmd= 4096; size_t findstring(const ByteVector& buf, const std::string& str); HANDLE OpenComport(const std::string& portname); bool SetCommParams(HANDLE hPort, int speed, int bits, int parity, int stopbits); bool WriteCommand(HANDLE hPort, const std::string& command); bool WriteData(HANDLE hPort, int nChars, ...); bool ReadData(HANDLE hPort, ByteVector& buffer, int bufsize); bool SendCommand(HANDLE hPort, int nChars, ...); bool WriteMemoryBlock(HANDLE hPort, const ByteVector& buffer, DWORD dwOffset, bool bFromRadio); bool WriteMemoryFromFile(HANDLE hPort, FILE *f, DWORD dwOffset, DWORD dwLength, bool bFromRadio); bool StepMemoryToStdout(HANDLE hPort, DWORD dwOffset, DWORD dwLength, bool bFromRadio); bool CopyMemoryToFile(HANDLE hPort, FILE *f, DWORD dwOffset, DWORD dwLength, bool bFromRadio); bool DumpMemoryToStdout(HANDLE hPort, DWORD dwOffset, DWORD dwLength, bool bFromRadio); void usage() { printf("(C) 2003-2008 Willem jan Hengeveld itsme@xs4all.nl\n"); printf("Usage: xda2dmp [options] start [ length [outfile]]\n"); printf(" if no outfile is given, data is hexdumped to the console\n"); printf(" if no length is given, 256 bytes are hexdumped to the console\n"); printf("Options:\n"); printf(" -r : read from gsm part\n"); printf(" -f : flash TO memory!!\n"); printf(" -1 -2 -4 : dump as bytes/words/dwords\n"); printf(" -w NUM : specify nr of words per line\n"); printf(" -s NUM : specify stepsize, allowing quick overview of memory areas\n"); printf(" -d DEVNAME : connect through specified device (COM1)\n"); printf(" -u : connect through USB device (\\\\.\\WCEUSBSH***)\n"); printf(" -v[v...] : be verbose[r]\n"); printf(" -br SIZE : read buffer size\n"); printf(" -bc SIZE : max bytes per command\n"); } struct readqueue { BYTE *readbuf; DWORD dwBufSize; DWORD dwOverflows; DWORD dwTail; DWORD dwHead; DWORD dwSize; HANDLE hPort; HANDLE hThread; DWORD nThreadId; } q; DWORD WINAPI readthread(LPVOID) { DWORD eventMask; debug("reading\n"); while (WaitCommEvent(q.hPort, &eventMask, NULL)) { // |----T>---H----| // |----H----T>---| if (eventMask&EV_RXCHAR) { DWORD nRead= 0; do { if (q.dwSize==q.dwBufSize) { q.dwOverflows++; break; } if (q.dwHead==q.dwBufSize) q.dwHead= 0; DWORD dwCurTail= q.dwTail; if (!ReadFile(q.hPort, q.readbuf+q.dwHead, dwCurTail <= q.dwHead ? q.dwBufSize-q.dwHead : dwCurTail - q.dwHead, &nRead, NULL)) { error("ReadFile"); return 1; } debug("received %d bytes\n", nRead); q.dwHead+=nRead; q.dwSize+=nRead; } while (nRead>0); } else debug("rx event %08lx\n", eventMask); } debug("end readthread\n"); return 0; } void initqueue() { q.dwBufSize= 65536; q.readbuf= new BYTE[q.dwBufSize]; q.dwTail= 0; q.dwSize= 0; q.dwHead= 0; q.hThread= CreateThread(NULL, 0, readthread, NULL, 0, &q.nThreadId); if (q.hThread==INVALID_HANDLE_VALUE || q.hThread==NULL) { error("ERROR creating NHthread\n"); q.hThread= NULL; } } void receivedata(BYTE *buf, DWORD dwBufSize, DWORD *pnRead) { DWORD dwRead= 0; while (q.dwSize>0 && dwRead dwBufSize-dwRead) dwWanted= dwBufSize-dwRead; memcpy(buf+dwRead, q.readbuf+q.dwTail, dwWanted); q.dwTail += dwWanted; q.dwSize -= dwWanted; dwRead += dwWanted; debug("receivedata: %08lx\n", dwWanted); } *pnRead= dwRead; } void readanswer(ByteVector &data) { DWORD count; DWORD dataptr= 0; DWORD tLastData= 0; DWORD tStart= GetTickCount(); data.clear(); debug("waiting for answer\n"); while (1) { Sleep(50); data.resize(dataptr+512); receivedata(vectorptr(data), 512, &count); dataptr += count; data.resize(dataptr); if (count) tLastData= GetTickCount(); if ( (tLastData && (GetTickCount() - tLastData > 500)) || (GetTickCount()-tStart > 5000 ) ) { // stop listening if more than .5 sec no data. break; } debug("readdata: %08lx %08lx %d\n", tLastData, GetTickCount(), count); } } void answerdump(const ByteVector& data) { bighexdump(data, hexdumpflags(DUMPUNIT_BYTE, 16, DUMP_STRINGS)); } int main(int argc, char **argv) { DebugStdOut(); bool bFromRadio= false; int argsfound=0; DWORD dwOffset=0; DWORD dwLength=0; std::string filename; bool bUseUsbDevice= false; bool bFlashMemory= false; for (int i=1 ; i3) { usage(); return 1; } if (argsfound==1) dwLength= 0x100; if (g_nMaxWordsPerLine<0) g_nMaxWordsPerLine= 16/g_nDumpUnitSize; if (g_device.empty()) { if (bUseUsbDevice) g_device= "\\\\.\\WCEUSBSH001"; else g_device= "COM1"; } FILE *f= NULL; if (!filename.empty()) { f= fopen(filename.c_str(), bFlashMemory ? "rb" : "wb"); if (f==NULL) { perror(filename.c_str()); return 1; } } q.hPort= OpenComport(g_device); if (q.hPort==INVALID_HANDLE_VALUE || q.hPort==NULL) { error("OpenComport %s", g_device.c_str()); return 1; } if (!SetCommParams(q.hPort, 115200, 8, NOPARITY, ONESTOPBIT)) { CloseHandle(q.hPort); error("SetCommParams"); return 1; } initqueue(); Sleep(100); debug("mainstart\n"); WriteCommand(q.hPort, "password asdadasasad\r"); WriteCommand(q.hPort, "ruuinfo\r"); WriteCommand(q.hPort, "info 2\r"); WriteCommand(q.hPort, "set 32 2\r"); WriteCommand(q.hPort, "set 0 0\r"); // no echo WriteCommand(q.hPort, "set 1 1\r"); // operation mode 1 = non-interactive mode WriteCommand(q.hPort, "set 2 1\r"); // backcolor WriteCommand(q.hPort, "set 5 ffff\r"); // background color WriteCommand(q.hPort, "set 6 ffff\r"); // screen color WriteCommand(q.hPort, "set 4 0000\r"); // front color WriteCommand(q.hPort, "shmsg 2 2 \"xda2dmp\"\r"); WriteCommand(q.hPort, stringformat("shmsg 3 2 \"%08lx\"\r", dwOffset).c_str()); WriteCommand(q.hPort, stringformat("shmsg 4 2 \"%08lx\"\r", dwLength).c_str()); DumpMemoryToStdout(q.hPort, dwOffset, dwLength, bFromRadio); CloseHandle(q.hPort); if (f) fclose(f); return 0; } bool ReadMemoryBlock(HANDLE hPort, ByteVector& buffer, DWORD dwOffset, DWORD dwLength, bool bFromRadio) { buffer.clear(); WriteData(hPort, 1, stringformat("%srbmc tst %08lx %08lx\r", bFromRadio?"r":"", dwOffset, dwLength).c_str()); Sleep(100); ByteVector readbuffer; size_t htcs_offset; // wait for start of binary data while(true) { if (!ReadData(hPort, readbuffer, g_rd_memblock_per_read)) return false; if (readbuffer.empty()) { Sleep(200); printf("."); continue; } if (g_verbose>1) printf("read start: %d bytes\n", readbuffer.size()); if (g_verbose>2) printf("..........\n%s\n", ascdump(readbuffer).c_str()); htcs_offset= findstring(readbuffer, "HTCS"); if (htcs_offset!=readbuffer.size()) break; if (g_verbose>1) printf("pre-data: %s\n", ascdump(readbuffer).c_str()); } htcs_offset += 4; if (g_verbose>1) printf("last pre-data: %s\n", ascdump(ByteVector(readbuffer.begin(), readbuffer.begin()+htcs_offset)).c_str()); DWORD nTotal= std::min((DWORD)readbuffer.size()-htcs_offset, dwLength); buffer.resize(nTotal); if (nTotal) std::copy(readbuffer.begin()+htcs_offset, readbuffer.begin()+htcs_offset+nTotal, buffer.begin()); size_t unreadptr= htcs_offset+nTotal; if (g_verbose>2) printf("read %d bytes, still %d to go, or %d left\n", nTotal, dwLength-nTotal, readbuffer.size()-unreadptr); // copy rest of binary data while (buffer.size() < dwLength) { if (!ReadData(hPort, readbuffer, g_rd_memblock_per_read)) return false; if (g_verbose>1) printf("read bin: %d bytes\n", readbuffer.size()); if (g_verbose>2) printf("..........\n%s\n", hexdump(readbuffer).c_str()); DWORD nValid= std::min((DWORD)readbuffer.size(), dwLength-nTotal); DWORD nBufEnd= buffer.size(); buffer.resize(buffer.size()+nValid); if (nValid) std::copy(readbuffer.begin(), readbuffer.begin()+nValid, buffer.begin()+nBufEnd); unreadptr= nValid; nTotal += nValid; } if (g_verbose>0) printf("%d bytes binary data\n", nTotal); if (g_verbose>2) printf("read %d bytes, %d left\n", nTotal, readbuffer.size()-unreadptr); if (readbuffer.size()-unreadptr < 8) { if (g_verbose>1) printf("only %d bytes of extra data\n", readbuffer.size()-unreadptr); ByteVector readextra; if (!ReadData(hPort, readextra, 8)) return false; std::copy(readextra.begin(), readextra.end(), readbuffer.end()); } if (g_verbose>1) printf("post-data: %s\n", ascdump(ByteVector(readbuffer.begin()+unreadptr, readbuffer.end())).c_str()); DWORD crc= *(DWORD*)(vectorptr(readbuffer)+unreadptr); DWORD calccrc= calccrc32(buffer); if (crc!=calccrc) { printf("!!! received crc= %08lx calced crc= %08lx\n", crc, calccrc); return false; } return true; } bool DumpMemoryToStdout(HANDLE hPort, DWORD dwOffset, DWORD dwLength, bool bFromRadio) { return CopyMemoryToFile(hPort, NULL, dwOffset, dwLength, bFromRadio); } bool CopyMemoryToFile(HANDLE hPort, FILE *f, DWORD dwOffset, DWORD dwLength, bool bFromRadio) { ByteVector buffer; while(dwLength) { if (!ReadMemoryBlock(hPort, buffer, dwOffset, std::min(g_rd_memblock_per_cmd, dwLength), bFromRadio)) return false; if (f) fwrite(vectorptr(buffer), 1, buffer.size(), f); else printf("%s", hexdump(dwOffset, vectorptr(buffer), buffer.size(), g_nDumpUnitSize, g_nMaxWordsPerLine).c_str()); if (g_verbose==0) putchar('.'); dwOffset += buffer.size(); dwLength -= buffer.size(); } if (g_verbose==0) putchar('\n'); return true; } bool StepMemoryToStdout(HANDLE hPort, DWORD dwOffset, DWORD dwLength, bool bFromRadio) { while (dwLength!=0) { ByteVector buffer; ReadMemoryBlock(hPort, buffer, dwOffset, std::min(dwLength, (DWORD)(g_nDumpUnitSize*g_nMaxWordsPerLine)), bFromRadio); /* ignore error */ if (buffer.size()) debug("%hs\n", hexdump(dwOffset, vectorptr(buffer), buffer.size(), g_nDumpUnitSize, g_nMaxWordsPerLine).c_str()); else debug("%08lx: -----\n", dwOffset); dwLength -= std::min(dwLength, (DWORD)g_nStepSize); dwOffset += std::min(dwLength, (DWORD)g_nStepSize); } return true; } bool WriteMemoryBlock(HANDLE hPort, const ByteVector& buffer, DWORD dwOffset, bool bFromRadio) { WriteCommand(hPort, stringformat("%swdata %08lx %08lx\r", bFromRadio?"r":"", dwOffset, buffer.size())); WriteCommand(hPort, "HTCS"); DWORD nWritten; WriteFile(hPort, vectorptr(buffer), buffer.size(), &nWritten, NULL); Sleep(100); DWORD calccrc= calccrc32(buffer); if (g_verbose) printf("crc = %08lx\n", calccrc); WriteFile(hPort, (BYTE*)&calccrc, sizeof(DWORD), &nWritten, NULL); Sleep(100); WriteCommand(hPort, "HTCE"); return true; } bool WriteMemoryFromFile(HANDLE hPort, FILE *f, DWORD dwOffset, DWORD dwLength, bool bFromRadio) { WriteCommand(hPort, stringformat("%serase %08lx %08lx\r", bFromRadio?"r":"", dwOffset, dwLength)); ByteVector buffer; while(dwLength) { buffer.resize(std::min(g_rd_memblock_per_cmd, dwLength)); fread(vectorptr(buffer), 1, buffer.size(), f); if (!WriteMemoryBlock(hPort, buffer, dwOffset, bFromRadio)) return false; if (g_verbose==0) putchar('.'); dwOffset += buffer.size(); dwLength -= buffer.size(); } if (g_verbose==0) putchar('\n'); return true; } HANDLE OpenComport(const std::string& portname) { DWORD tStart= GetTickCount(); HANDLE hPort = NULL; while (GetTickCount() - tStart < 30000) { hPort = CreateFile (portname.c_str(), GENERIC_READ | GENERIC_WRITE, 0,NULL, OPEN_EXISTING, 0, NULL); if (hPort!=NULL && hPort!=INVALID_HANDLE_VALUE) break; } debug("found port: %08lx\n", hPort); return hPort; } void log_dcb(DCB *dcb) { if (dcb->DCBlength != sizeof(DCB)) debug("DCB length = %04x, expected %04x\n", dcb->DCBlength, sizeof(DCB)); debug("DCB: bd=%d bin%d par%d outcts%d outdsr%d dtr%d dsr%d txcont%d outx%d inx%d errch%d nul%d rts%d abt%d dum%d\n", dcb->BaudRate, dcb->fBinary, dcb->fParity, dcb->fOutxCtsFlow, dcb->fOutxDsrFlow, dcb->fDtrControl, dcb->fDsrSensitivity, dcb->fTXContinueOnXoff, dcb->fOutX, dcb->fInX, dcb->fErrorChar, dcb->fNull, dcb->fRtsControl, dcb->fAbortOnError, dcb->fDummy2); debug("rsv=%04x xon=%04x xoff=%04x bs=%d pty=%d stop=%d xon=%02x xoff=%02x err=%02x eof=%02x evt=%02x\n", dcb->wReserved, dcb->XonLim, dcb->XoffLim, dcb->ByteSize, dcb->Parity, dcb->StopBits, dcb->XonChar, dcb->XoffChar, dcb->ErrorChar, dcb->EofChar, dcb->EvtChar); } bool SetCommParams(HANDLE hPort, int speed, int bits, int parity, int stopbits) { SetupComm(hPort, 0x8000, 0x8000); DCB dcb; dcb.DCBlength= sizeof(DCB); if (!GetCommState (hPort, &dcb)) { error("GetCommState"); return FALSE; } log_dcb(&dcb); dcb.BaudRate= speed; dcb.ByteSize= (BYTE)bits; dcb.Parity= (BYTE)parity; dcb.StopBits= (BYTE)stopbits; dcb.fOutxCtsFlow= 0; dcb.fDtrControl= DTR_CONTROL_ENABLE; dcb.fRtsControl= 0; dcb.fAbortOnError= 0; if (!SetCommState(hPort, &dcb)) { error("SetCommState"); return FALSE; } COMMTIMEOUTS to; if (!GetCommTimeouts(hPort, &to)) { error("GetCommTimeouts"); return FALSE; } debug("rto=%d rtomult=%d rtoconst=%d wtomult=%d wtoconst=%d\n", to.ReadIntervalTimeout, to.ReadTotalTimeoutMultiplier, to.ReadTotalTimeoutConstant, to.WriteTotalTimeoutMultiplier, to.WriteTotalTimeoutConstant); // read returns immediately to.ReadIntervalTimeout = MAXDWORD; to.ReadTotalTimeoutMultiplier = 0; to.ReadTotalTimeoutConstant = 0; to.WriteTotalTimeoutMultiplier =0; to.WriteTotalTimeoutConstant = 0; if (!SetCommTimeouts(hPort, &to)) { error("SetCommTimeouts"); return FALSE; } if (!SetCommMask(hPort, EV_RXCHAR)) { error("SetCommMask"); return FALSE; } return TRUE; } bool vWriteData(HANDLE hPort, int nChars, va_list ap); bool WriteData(HANDLE hPort, int nChars, ...) { va_list ap; va_start(ap, nChars); bool res= vWriteData(hPort, nChars, ap) ; va_end(ap); return res; } bool vWriteData(HANDLE hPort, int nChars, va_list ap) { for (int i=0 ; i=0) { BYTE c= (BYTE)arg; if (!WriteFile(hPort, &c, 1, &nWritten, NULL)) { error("error writing char %02x", c); return FALSE; } if (nWritten!=1) { debug("did not write char %02x\n", c); return FALSE; } } else { char* p= (char*)arg; if (!WriteFile(hPort, p, strlen(p), &nWritten, NULL)) { error("error writing char %hs", p); return FALSE; } if (nWritten!=strlen(p)) { debug("did not write %d chars of %hs\n", strlen(p)-nWritten, p); return FALSE; } if (g_verbose>0) printf("SENT: %s\n", p); } } return TRUE; } bool ReadData(HANDLE hPort, ByteVector& buffer, int bufsize) { debug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); buffer.resize(bufsize); DWORD nTotal= 0; while (nTotal0) printf("%s\n", ascdump(buffer).c_str()); return true; } size_t findstring(const ByteVector& buf, const std::string& str) { for (int i= 0 ; i