Windows CE's CESH Utility by Andrew Tucker Listing One /* Function declarations and defines for CESH remote I/O functions */ #ifdef __cplusplus extern "C" { #endif /* stolen from pkfuncs.h */ int U_ropen(const WCHAR *, UINT); int U_rread(int, BYTE *, int); int U_rwrite(int, BYTE *, int); int U_rlseek(int, int, int); int U_rclose(int); #ifdef __cplusplus } #endif /* defines stolen from the desktop VC++ header file io.h */ #define _O_RDONLY 0x0000 /* open for reading only */ #define _O_WRONLY 0x0001 /* open for writing only */ #define _O_RDWR 0x0002 /* open for reading and writing */ #define _O_APPEND 0x0008 /* writes done at eof */ #define _O_CREAT 0x0100 /* create and open file */ #define _O_TRUNC 0x0200 /* open and truncate */ #define _O_EXCL 0x0400 /* open if file doesn't exist */ /* sequential/random access hints */ #define _O_SEQUENTIAL 0x0020 /* file access is sequential */ #define _O_RANDOM 0x0010 /* file access is random */ Listing Two /* Simple utility to dump a the registry on a Windows CE device to a desktop file via the CESH remote file I/O APIs */ #include #include "ceshio.h" /* print a debug message to the CESH console on the desktop machine */ void DbgOut(LPSTR psz) { int fh = U_ropen(L"con", _O_CREAT | _O_WRONLY | _O_TRUNC ); U_rwrite(fh, (PBYTE)psz, strlen(psz)); U_rclose(fh); } /* Dump a single registry value by type */ #define LONIBBLE(x) ((x) & 0x0f) #define HINIBBLE(x) (((x) & 0xf0) >> 4) BOOL DumpRegValue(HKEY hkey, int nIndentSize, LPSTR pszValueName, DWORD dwType, PBYTE pbValueData, DWORD dwDataSize, int fh) { while ( nIndentSize-- ) U_rwrite(fh, (PBYTE)" ", 1); U_rwrite(fh,(PBYTE)pszValueName, strlen(pszValueName)); LPSTR pszType; LPSTR pszData = NULL; switch( dwType ) { case REG_BINARY: { pszType = "(BINARY)"; const char *pcszHex = "0123456789abcdef"; pszData = (LPSTR)malloc((dwDataSize * 3) + 1); for ( DWORD i = 0; i < dwDataSize; i++ ) { pszData[i*3] = pcszHex[HINIBBLE(pbValueData[i])]; pszData[i*3+1] = pcszHex[LONIBBLE(pbValueData[i])]; pszData[i*3+2] = ' '; } pszData[dwDataSize*3] = 0; } break; case REG_DWORD_BIG_ENDIAN: case REG_DWORD: // same value as REG_DWORD_LITTLE_ENDIAN { if ( dwType == REG_DWORD_BIG_ENDIAN) pszType = "(DWORD_BIG_ENDIAN)"; else pszType = "(DWORD)"; wchar_t wchBuf[16]; pszData = (LPSTR)malloc(16); wsprintf(wchBuf, _T("0x%x"), *(DWORD*)pbValueData); wcstombs(pszData, wchBuf, wcslen(wchBuf)+1); } break; case REG_MULTI_SZ: { pszType = "(MULTI_SZ)"; LPWSTR pwsz = (LPWSTR)pbValueData; pszData = (LPSTR)malloc(dwDataSize+1); pszData[0] = 0; LPSTR pszIter = pszData; while ( *pwsz ) { wcstombs(pszIter, pwsz, wcslen(pwsz)+1); pwsz += wcslen(pwsz) + 1; if ( *pwsz ) { strcat(pszIter, "\\0"); // make sure you overwrite previous zero terminator pszIter += strlen(pszIter); } else strcat(pszIter, "\\0\\0"); } } break; case REG_EXPAND_SZ: case REG_LINK: case REG_RESOURCE_LIST: case REG_SZ: { if ( dwType == REG_EXPAND_SZ ) pszType = "(EXPAND_SZ)"; else if ( dwType == REG_LINK ) pszType = "(LINK)"; else if ( dwType == REG_RESOURCE_LIST ) pszType = "(RESOURCE_LIST)"; else pszType = "(SZ)"; if ( dwDataSize && pbValueData ) { //NOTE: have to handle specially be // cause string is not zero terminated? LPWSTR pwsz = (LPWSTR)pbValueData; int numchars = (dwDataSize/2)+1; pszData = (LPSTR)malloc(numchars); wcstombs(pszData, pwsz, numchars); pszData[numchars-1] = 0; } } break; case REG_NONE: pszType = "(NONE)"; break; default: pszType = "(UNKNOWN)"; break; } U_rwrite(fh,(PBYTE)": ", 2); U_rwrite(fh, (PBYTE)pszType, strlen(pszType)); if ( pszData ) { U_rwrite(fh,(PBYTE)" ", 1); U_rwrite(fh,(PBYTE)pszData, strlen(pszData)); free(pszData); } U_rwrite(fh,(PBYTE)"\r\n", 2); return TRUE; } /* Dump reg key values and recursively dump all subkeys */ BOOL DumpRegKey(HKEY hkey, int fh) { BOOL bSuccess = FALSE; DWORD dwMaxSubkeys; DWORD dwMaxValues; DWORD dwMaxSubkeyLen; DWORD dwMaxValueNameLen; DWORD dwMaxValueLen; static int s_iCurIndent = 0; if ( RegQueryInfoKey(hkey, NULL, NULL, NULL, &dwMaxSubkeys,&dwMaxSubkeyLen, NULL, &dwMaxValues,&dwMaxValueNameLen, &dwMaxValueLen,NULL,NULL) == ERROR_SUCCESS ) { // dump this key's values... DWORD dwValueNameLen = (dwMaxValueNameLen+1)*sizeof(wchar_t); LPTSTR pszValueName = (LPTSTR)malloc(dwValueNameLen); LPSTR pszValueNameA = (LPSTR)malloc(dwValueNameLen); PBYTE pbValueData = (PBYTE)malloc(dwMaxValueLen); DWORD dwIndex = 0; while ( dwIndex < dwMaxValues ) { DWORD dwSize = dwMaxValueNameLen+1; DWORD dwDataSize = dwMaxValueLen; DWORD dwType; if ( RegEnumValue(hkey, dwIndex, pszValueName, &dwSize, NULL, &dwType, pbValueData, &dwDataSize) != ERROR_SUCCESS ) break; wcstombs(pszValueNameA, pszValueName, wcslen(pszValueName)+1); if ( !DumpRegValue(hkey, s_iCurIndent, pszValueNameA, dwType, pbValueData, dwDataSize, fh) ) break; dwIndex++; } free(pszValueName); free(pszValueNameA); free(pbValueData); // only succeeded if we did all the values bSuccess = ( dwIndex == dwMaxValues ); if ( bSuccess ) { // ...then enumerate other keys DWORD dwKeyNameLen = (dwMaxSubkeyLen+1)*sizeof(wchar_t); LPTSTR pszKeyName = (LPTSTR)malloc(dwKeyNameLen); LPSTR pszKeyNameA = (LPSTR)malloc(dwKeyNameLen); dwIndex = 0; while ( dwIndex < dwMaxSubkeys ) { DWORD dwSize = dwMaxSubkeyLen+1; if ( RegEnumKeyEx(hkey, dwIndex, pszKeyName, &dwSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS ) break; strcpy(pszKeyNameA, "["); wcstombs(pszKeyNameA+1, pszKeyName, wcslen(pszKeyName)+1); strcat(pszKeyNameA,"]\r\n"); if ( s_iCurIndent ) { int i = s_iCurIndent; while ( i-- ) U_rwrite(fh, (PBYTE)" ", 1); } if ( U_rwrite(fh, (PBYTE)pszKeyNameA, strlen(pszKeyNameA))!=(int)strlen(pszKeyNameA) ) break; // recurse into the key if we can open it HKEY hSubkey; if ( RegOpenKeyEx(hkey, pszKeyName, 0,0,&hSubkey) == ERROR_SUCCESS ) { s_iCurIndent += 4; BOOL b = DumpRegKey(hSubkey, fh); s_iCurIndent -= 4; RegCloseKey(hSubkey); if ( !b ) break; } else { DbgOut("ERROR: could not open registry key '"); DbgOut(pszKeyNameA); DbgOut("'\n"); } dwIndex++; } free(pszKeyName); free(pszKeyNameA); // only succeeded if we did all the keys bSuccess = ( dwIndex == dwMaxSubkeys ); } } // do an extra crlf if we're finishing the top-level key if ( !s_iCurIndent ) U_rwrite(fh, (PBYTE)"\r\n", 2); return bSuccess; } int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { int fh; fh = U_ropen(L"regdump.txt", _O_CREAT | _O_WRONLY | _O_TRUNC ); if ( fh == -1 ) { DbgOut("error creating file\r\n"); } else { #define RKENTRY(x) { #x "\r\n", strlen(#x) + 2, x } struct RKEntry { LPSTR psz; int len; HKEY hkey; } RegKeys[] = { RKENTRY( HKEY_LOCAL_MACHINE ), RKENTRY( HKEY_CURRENT_USER ), RKENTRY( HKEY_USERS ), RKENTRY( HKEY_CLASSES_ROOT ), }; int nEntries = sizeof(RegKeys)/sizeof(RKEntry); // iterate the list of top level reg keys and dump each one for ( int i = 0; i < nEntries; i++ ) { if ( (U_rwrite(fh, (PBYTE)RegKeys[i].psz, RegKeys[i].len) != RegKeys[i].len) || !DumpRegKey(RegKeys[i].hkey, fh) ) { DbgOut("ERROR dumping key\r\n"); } } U_rclose(fh); } return 0; } Listing Three /* Example code to show how to programmatically pass cmds to CESH */ #include #include #include #include int main(int argc, char **argv) { char szFSAUXIN[_MAX_PATH]; char szCmd[_MAX_PATH] = {0}; // catenate the cmd into a single string up to the max length if ( argc > 1 ) { int iCurCmdLen = 0; for ( int i = 1; i < argc; i++ ) { if ( (iCurCmdLen + strlen(argv[i]) + 2) > _MAX_PATH-1 ) { printf("Error: cmd string is too long. " "Max size is %d\n", _MAX_PATH-1); exit(EXIT_FAILURE); } sprintf(&szCmd[iCurCmdLen], "%s ", argv[i]); iCurCmdLen += strlen(argv[i]) + 1; } strcat(szCmd, "\r"); } else { printf("syntax: ceshexec \n"); exit(EXIT_FAILURE); } // make sure we have a _FLATRELEASEDIR LPCSTR pcszFRD = getenv("_FLATRELEASEDIR"); if ( !pcszFRD ) { printf("Error: Environment variable " "_FLATRELEASEDIR must be set\n"); exit(EXIT_FAILURE); } // build path to FSAUXIN, avoiding double slashes if ( pcszFRD[strlen(pcszFRD)-1] != '\\' ) sprintf(szFSAUXIN, "%s\\fsauxin", pcszFRD); else sprintf(szFSAUXIN, "%sfsauxin", pcszFRD); int fh = open(szFSAUXIN, _O_WRONLY | _O_APPEND); if ( fh != -1 ) { write(fh, szCmd, strlen(szCmd)); close(fh); } else printf("Error: could not open '%s'\n", szFSAUXIN); return 0; } Listing Four /* Sample code to show how to get the IP and MAC address of the desktop machine connected via Ethernet to CESH */ #include #include "ethdbg.h" #include "halether.h" int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { IP_INFO IpInfo; DWORD dwAddrType; DWORD dwLen = 0; dwAddrType = IPINFO_DOWNLOAD; memset(&IpInfo, 0, sizeof(IpInfo)); if (KernelIoControl(IOCTL_HAL_GET_IP_ADDR, &dwAddrType, sizeof(dwAddrType), &IpInfo, sizeof(IpInfo), &dwLen)) { if ( IpInfo.dwIP == 0 ) { NKDbgPrintfW(L"No peer address information available. " "Probably connected over a parallel port " "link\n"); } else { NKDbgPrintfW(L"CESH peer address info: IP:%hs, " "MAC:0x%02X:%02X:%02X:%02X:%02X:%02X\n", inet_ntoa(IpInfo.dwIP),IpInfo.MAC[0], IpInfo.MAC[1],IpInfo.MAC[2], IpInfo.MAC[3], IpInfo.MAC[4],IpInfo.MAC[5]); } } else NKDbgPrintfW(L"Error getting peer address info: %u\n", GetLastError()); return 0; } 7