//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996. // // File: tlink.cxx // // Contents: Utility to create/mend links and move files with notify // // Classes: // // Functions: // // // // History: 18-Nov-96 BillMo Created. // // Notes: // // Codework: // //-------------------------------------------------------------------------- #include #pragma hdrstop #define TRKDATA_ALLOCATE // This is the main module, trigger trkwks.hxx to do definitions #include #include #include #include #include DWORD g_Debug = TRKDBG_ERROR; #define CB_LINK_CLIENT_MAX 256 // Implicitely load shell32.dll, rather than waiting for the CoCreate of IShellLink, // in order to make it easier to debug in windbg. #pragma comment( lib, "shell32.lib" ) enum EXTRAFLAGS { EXTRAFLAG_SHOW_IDS = 1 }; extern "C" IID IID_ISLTracker #ifdef TRKDATA_ALLOCATE = { /* 7c9e512f-41d7-11d1-8e2e-00c04fb9386d */ 0x7c9e512f, 0x41d7, 0x11d1, {0x8e, 0x2e, 0x00, 0xc0, 0x4f, 0xb9, 0x38, 0x6d} }; #else ; #endif class ISLTracker : public IUnknown { public: STDMETHOD(QueryInterface) (REFIID riid, LPVOID * ppvObj) PURE; STDMETHOD_(ULONG,AddRef) () PURE; STDMETHOD_(ULONG,Release) () PURE; STDMETHOD(Resolve)(HWND hwnd, DWORD fFlags, DWORD TrackerRestrictions) PURE; STDMETHOD(GetIDs)(CDomainRelativeObjId *pdroidBirth, CDomainRelativeObjId *pdroidLast, CMachineId *pmcid) PURE; }; // interface ISLTracker void EnumObjects() { CObjIdEnumerator oie; __try { CObjId aobjid[1000]; CDomainRelativeObjId adroid[1000]; int cSources=0; const int FirstDrive = 'c'; const int LastDrive = 'z'; for (int Drive = FirstDrive-'a'; Drive < LastDrive-'a'+1; Drive ++) { // fill up the array with ids from all the drives if (oie.Initialize(CVolumeDeviceName(Drive))) { if (oie.FindFirst(aobjid, adroid)) { BOOL fGotOne = FALSE; do { do { CDomainRelativeObjId droidBirth; TCHAR tszObjId[256]; TCHAR tszBirthLink[256]; TCHAR tszPath[MAX_PATH+1]; TCHAR * ptszObjId = tszObjId; StringizeGuid(*(GUID*)&aobjid[cSources], ptszObjId); FindLocalPath( Drive, aobjid[cSources], &droidBirth, &tszPath[2]); tszPath[0] = VolChar(Drive); tszPath[1] = TEXT(':'); _tprintf(TEXT("%s %s %s\n"), tszObjId, adroid[cSources].Stringize(tszBirthLink,256), tszPath); cSources ++; } while (cSources < sizeof(aobjid)/sizeof(aobjid[0]) && (fGotOne = oie.FindNext(&aobjid[ cSources ], &adroid[ cSources ]))); TrkAssert(cSources > 0); cSources = 0; } while (fGotOne); } } } } __except(BreakOnDebuggableException()) { } oie.UnInitialize(); } void AttackDC() { CMachineId mcidDomain(MCID_DOMAIN); CRpcClientBinding rcConnect; rcConnect.RcInitialize(mcidDomain, s_tszTrkSvrRpcProtocol, s_tszTrkSvrRpcEndPoint); TRKSVR_MESSAGE_UNION m; CObjId objidCurrent; CDomainRelativeObjId droidBirth, droidNew; CVolumeId volid; m.MessageType = MOVE_NOTIFICATION; m.Priority = PRI_0; m.MoveNotification.cNotifications = 0; m.MoveNotification.pvolid = &volid; m.MoveNotification.rgobjidCurrent = &objidCurrent; m.MoveNotification.rgdroidBirth = &droidBirth; m.MoveNotification.rgdroidNew = &droidNew; while (1) { LnkSvrMessage( rcConnect, &m); } rcConnect.UnInitialize(); } void DoCreateLink(IShellLink * pshlink, const TCHAR *ptszLink, const TCHAR *ptszSrc) { HRESULT hr; IPersistFile *pPersistFile = NULL; __try { DWORD dwWritten; BYTE rgb[ CB_LINK_CLIENT_MAX ]; ULONG cbPersist = 0; memset( rgb, 0, sizeof(rgb) ); hr = pshlink->QueryInterface( IID_IPersistFile, (void**) &pPersistFile ); if( FAILED(hr) ) { TrkLog((TRKDBG_ERROR, TEXT("Couldn't QI IShellLink for IPersistFile") )); TrkRaiseException( hr ); } hr = pshlink->SetPath( ptszSrc ); _tprintf( TEXT("IShellLink::SetPath returned %08X (%s)\n"), hr, 0==hr ? TEXT("no error") : GetErrorString(hr)); if( S_OK != hr ) { TrkRaiseException( hr ); } hr = pPersistFile->Save( ptszLink, TRUE ); if( FAILED(hr) ) { TrkLog((TRKDBG_ERROR, TEXT("Couldn't persist IShellLink") )); TrkRaiseException( hr ); } pPersistFile->SaveCompleted( ptszLink ); RELEASE_INTERFACE( pPersistFile ); } __except( BreakOnDebuggableException() ) { RELEASE_INTERFACE( pPersistFile ); } } TCHAR * GetRestrict(DWORD r) { static TCHAR tszError[256]; tszError[0] = 0; if (r == TRK_MEND_DEFAULT) { _tcscpy(tszError, TEXT("TRK_MEND_DEFAULT ")); } if (r & TRK_MEND_DONT_USE_LOG) { _tcscat(tszError, TEXT("TRK_MEND_DONT_USE_LOG ")); } if (r & TRK_MEND_DONT_USE_DC) { _tcscat(tszError, TEXT("TRK_MEND_DONT_USE_DC ")); } if (r & TRK_MEND_SLEEP_DURING_MEND) { _tcscat(tszError, TEXT("TRK_MEND_SLEEP_DURING_SEARCH ")); } if (r & TRK_MEND_DONT_SEARCH_ALL_VOLUMES) { _tcscat(tszError, TEXT("TRK_MEND_DONT_SEARCH_ALL_VOLUMES ")); } if (r & TRK_MEND_DONT_USE_VOLIDS) { _tcscat(tszError, TEXT("TRK_MEND_DONT_USE_VOLIDS ")); } return(tszError); } void DisplayIDs( ISLTracker *ptracker ) { HRESULT hr = S_OK; CDomainRelativeObjId droidBirth, droidLast; CMachineId mcid; TCHAR tsz[ MAX_PATH ]; TCHAR *ptsz = tsz; hr = ptracker->GetIDs( &droidBirth, &droidLast, &mcid ); if( FAILED(hr) ) { TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get IDs") )); TrkRaiseException( hr ); } droidBirth.Stringize( tsz, sizeof(tsz) ); _tprintf( TEXT("Birth =\t%s\n"), tsz ); droidLast.Stringize( tsz, sizeof(tsz) ); _tprintf( TEXT("Last =\t%s\n"), tsz ); ptsz = tsz; mcid.Stringize(ptsz); _tprintf( TEXT("Machine =\t%s\n"), tsz ); } void DoResolveLink(IShellLink * pshlink, const TCHAR * ptszLink, DWORD r, DWORD dwSLR, DWORD grfExtra ) { IPersistFile * pPersistFile = NULL; ISLTracker * ptracker = NULL; __try { DWORD dwRead; HRESULT hr; WCHAR wszPath[MAX_PATH+1]; ULONG cbPath = sizeof(wszPath); WIN32_FIND_DATA fd; hr = pshlink->QueryInterface( IID_IPersistFile, (void**) &pPersistFile ); if( FAILED(hr) ) { TrkLog((TRKDBG_ERROR, TEXT("Couldn't QI for IPersistFile"))); TrkRaiseException( hr ); } hr = pPersistFile->Load( ptszLink, STGM_SHARE_EXCLUSIVE | STGM_READWRITE ); if( FAILED(hr) ) { TrkLog((TRKDBG_ERROR, TEXT("Couldn't load IShellLink"))); TrkRaiseException( hr ); } RELEASE_INTERFACE( pPersistFile ); // Track it (within 30 seconds). if( TRK_MEND_DEFAULT == r && 0 == grfExtra ) { hr = pshlink->Resolve( GetDesktopWindow(), 0xfffe0000 | dwSLR | SLR_ANY_MATCH ); } else { hr = pshlink->QueryInterface( IID_ISLTracker, (void**) &ptracker ); if( FAILED(hr) ) { TrkLog((TRKDBG_ERROR, TEXT("Couldn't QI for ISLTracker"))); TrkRaiseException( hr ); } if( EXTRAFLAG_SHOW_IDS & grfExtra ) DisplayIDs( ptracker ); hr = ptracker->Resolve( GetDesktopWindow(), 0x00100000 /*0xfffe0000*/ | dwSLR | SLR_ANY_MATCH, r ); if( EXTRAFLAG_SHOW_IDS & grfExtra ) DisplayIDs( ptracker ); } pshlink->GetPath( wszPath, cbPath, &fd, 0 ); _tprintf( TEXT("%ws %08X (%s) %s\n"), wszPath, hr, GetErrorString(hr), GetRestrict(r) ); RELEASE_INTERFACE( ptracker ); } __except( BreakOnDebuggableException() ) { RELEASE_INTERFACE( pPersistFile ); RELEASE_INTERFACE( ptracker ); } } void SignalLockVolume() { HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("LOCK_VOLUMES")); if (hEvent != NULL) { SetEvent(hEvent); CloseHandle(hEvent); } else { TrkLog((TRKDBG_ERROR, TEXT("Couldn't open LOCK_VOLUMES event %d\n"), GetLastError())); } } void DoTestWksSvcUp(TCHAR * ptszMachine) { CRpcClientBinding rc; CMachineId mcid(ptszMachine); BOOL fCalledMachine = FALSE; __try { rc.RcInitialize(mcid); if (E_NOTIMPL == LnkRestartDcSynchronization(rc)) fCalledMachine = TRUE; } __except(EXCEPTION_EXECUTE_HANDLER) { } TrkLog((TRKDBG_ERROR, TEXT("%successfully called machine %s\n"), fCalledMachine ? TEXT("S") : TEXT("Uns"), ptszMachine)); } typedef BOOL (WINAPI *PFNMoveFileWithProgress)( LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL, LPVOID lpData OPTIONAL, DWORD dwFlags ); #ifndef MOVEFILE_FAIL_IF_NOT_TRACKABLE #define MOVEFILE_FAIL_IF_NOT_TRACKABLE 0x00000020 #endif #ifndef UNICODE #error Unicode required for wszFullPath #endif EXTERN_C void __cdecl _tmain(int argc, TCHAR **argv) { BOOL fError = FALSE; HRESULT hr; CMachineId mcid(MCID_LOCAL); int ArgC = argc; TCHAR ** ArgV = argv; DWORD r = TRK_MEND_DEFAULT; DWORD grfExtra = 0; DWORD dwSLR = 0; // SLR_ flags IShellLink *pshlink = NULL; WCHAR wszFullPath[ MAX_PATH + 1 ]; DWORD dwMoveFlags = MOVEFILE_FAIL_IF_NOT_TRACKABLE | MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING; TrkDebugCreate( TRK_DBG_FLAGS_WRITE_TO_DBG | TRK_DBG_FLAGS_WRITE_TO_STDOUT, "TLink" ); CoInitialize( NULL ); hr = CoCreateInstance( CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLink, (void**)&pshlink ); if( FAILED(hr) ) { printf( "Couldn't get an IShellLink (%08x)\n", hr ); goto Exit; } ArgC--; ArgV++; if (ArgC == 0) { fError = TRUE; } while (!fError && ArgC > 0) { fError = TRUE; if (ArgV[0][0] == TEXT('-') || ArgV[0][0] == TEXT('/')) { switch (ArgV[0][1]) { case TEXT('a'): case TEXT('A'): fError = FALSE; ArgC --; ArgV ++; AttackDC(); break; case TEXT('e'): case TEXT('E'): fError = FALSE; ArgC --; ArgV ++; EnumObjects(); break; case TEXT('v'): case TEXT('V'): fError = FALSE; ArgC --; ArgV ++; SignalLockVolume(); break; case TEXT('m'): case TEXT('M'): if (ArgC >= 3) { PFNMoveFileWithProgress pfnMoveFileWithProgress = NULL; HMODULE hmodKernel32; for( int i = 2; ArgV[0][i] != TEXT('\0'); i++ ) { switch(ArgV[0][i]) { case TEXT('f'): case TEXT('F'): dwMoveFlags &= ~ MOVEFILE_FAIL_IF_NOT_TRACKABLE; break; case TEXT('n'): case TEXT('N'): dwMoveFlags &= ~ MOVEFILE_COPY_ALLOWED; break; case TEXT('o'): case TEXT('O'): dwMoveFlags &= ~ MOVEFILE_REPLACE_EXISTING; break; default: _tprintf( TEXT("Bad Move switch: %c\n"), ArgV[0][i] ); goto Exit; } // switch } // for hmodKernel32 = GetModuleHandle( TEXT("kernel32.dll") ); if( NULL == hmodKernel32 ) { TrkLog((TRKDBG_ERROR, TEXT("Failed GetModuleHeader for kernel32.dll") )); TrkRaiseLastError( ); } pfnMoveFileWithProgress = (PFNMoveFileWithProgress) GetProcAddress( hmodKernel32, "MoveFileWithProgressW" ); if( NULL == pfnMoveFileWithProgress ) { TrkLog((TRKDBG_ERROR, TEXT("Couldn't get MoveFileWithProgress export"))); TrkRaiseLastError( ); } if( !pfnMoveFileWithProgress( ArgV[1], ArgV[2], NULL, NULL, dwMoveFlags )) { _tprintf( TEXT("Failed MoveFileWithProgress (%lu)\n"), GetLastError() ); } ArgC -= 3; ArgV += 3; fError = FALSE; } break; case TEXT('c'): case TEXT('C'): if (ArgC >= 3) { if( MAX_PATH < RtlGetFullPathName_U( ArgV[2], sizeof(wszFullPath), wszFullPath, NULL )) { TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get full path name") )); TrkRaiseWin32Error( ERROR_BAD_PATHNAME ); } DoCreateLink( pshlink, ArgV[1], wszFullPath ); ArgC -= 3; ArgV += 3; fError = FALSE; } break; case TEXT('r'): case TEXT('R'): if (ArgC >= 2) { for( int i = 2; ArgV[0][i] != TEXT('\0'); i++ ) { switch(ArgV[0][i]) { case TEXT('l'): case TEXT('L'): r |= TRK_MEND_DONT_USE_LOG; break; case TEXT('d'): case TEXT('D'): r |= TRK_MEND_DONT_USE_DC; break; case TEXT('i'): case TEXT('I'): r |= TRK_MEND_DONT_USE_VOLIDS; break; case TEXT('m'): case TEXT('M'): r |= TRK_MEND_DONT_SEARCH_ALL_VOLUMES; break; case TEXT('s'): case TEXT('S'): dwSLR |= SLR_NOSEARCH; break; case TEXT('t'): case TEXT('T'): dwSLR |= SLR_NOTRACK; break; case TEXT('u'): case TEXT('U'): dwSLR |= SLR_NO_UI; break; case TEXT('x'): case TEXT('X'): grfExtra |= EXTRAFLAG_SHOW_IDS; break; case TEXT('z'): case TEXT('Z'): r |= TRK_MEND_SLEEP_DURING_MEND; break; default: _tprintf( TEXT("Bad Resolve switch: %c\n"), ArgV[0][i] ); goto Exit; } // switch } // for DoResolveLink( pshlink, ArgV[1], r, dwSLR, grfExtra ); ArgC -= 2; ArgV += 2; fError = FALSE; } break; case TEXT('t'): case TEXT('T'): if (ArgC >= 2) { DoTestWksSvcUp( ArgV[1] ); ArgC -= 2; ArgV += 2; fError = FALSE; } break; default: break; } } } Exit: if (fError) { printf("Usage: \n"); printf(" Operation Params\n"); printf(" --------- ------\n"); printf(" AttackDC -a\n"); printf(" MoveFileWP -m \n"); printf(" where may use: -f = NO fail if not trackable flag\n"); printf(" -n = NO copy-allowed flag\n"); printf(" -o = NO overwrite existing flag\n"); printf(" CreateLink -c \n"); printf(" EnumObjects -e\n"); printf(" SignalLockVolume -v\n"); printf(" ResolveLink -r \n"); printf(" where may use: -l = don't use log\n"); printf(" -d = don't use dc\n"); printf(" -i = don't use volids\n"); printf(" -m = don't scan all volumes on a machine\n"); printf(" -s = no search (SLR_NOSEARCH)\n"); printf(" -t = no track (SLR_NOTRACK)\n"); printf(" -x = show before/after droids\n"); printf(" -u = no UI (SLR_NOUI)\n"); printf(" -z = sleep in CTrkWksSvc::Mend\n"); printf("E.g.:\n"); printf(" tlink -c l1 t1\n"); printf(" tlink -mf t1 t1a\n"); printf(" tlink -r l1\n"); printf(" tlink -rd l1\n"); } RELEASE_INTERFACE( pshlink ); return; }