Quale tecnica utilizza Snoop per ispezionare un'applicazione WPF
-
21-12-2019 - |
Domanda
Snoop, l'utilità Spy, utilizza una tecnica potente (probabilmente una sorta di riflessione) per ispezionare un'applicazione WPF in esecuzione.Più interessante è il fatto che SnNOP è in grado di leggere l'intera struttura dell'oggetto.
pochi giorni fa ho scaricato il codice sorgente snoop e ho trascorso un po 'di tempo per studiare il comportamento interno.Sfortunatamente, non riuscivo a scoprire che come snoop sta facendo queste cose, quindi spero che qualcuno possa aiutarmi.
Al lavoro attualmente sto scrivendo un framework-quadro dell'interfaccia utente codificato e sarebbe fantastico se avessi accesso alle strutture dell'oggetto dell'applicazione perché questo mi consentirebbe di non solo affermare lo stato dell'interfaccia utente.
Aggiornamento:
Questo è il codice necessario:
string filePath = "WpfApp.exe";
AppDomain appDomain = AppDomain.CurrentDomain;
byte[] bytes = System.IO.File.ReadAllBytes(filePath);
Assembly ass = appDomain.Load(bytes);
ass.EntryPoint.Invoke(null, new object[] { });
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
Window w = System.Windows.Interop.HwndSource.FromHwnd(handle).RootVisual as Window;
.
Questo è già un grande aiuto per me, ma è anche interessante scoprire, come snoop si inietta in un altro processo.
Soluzione
È possibile eseguire ciò che snoop esegue il WPF VisualtreeHelper e / o il logicoLreeHelper.Una volta ottenuta una presa di qualsiasi elemento visivo, puoi praticamente attraversare il suo intero albero visivo per vedere tutti gli elementi con cui contiene.Visual Tree Helper qui
Window window = (Window)System.Windows.Interop.HwndSource.FromHwnd(process.MainWindowHandle).RootVisual;
. Altri suggerimenti
Aggiornamento:
Okay, ho trovato la posizione di codice di base, che viene utilizzata da Snoop per fornire la capacità di iniezione.Per il mio stupore che il codice è scritto C. Probabilmente c'è una ragione per.
E questo è il codice (spero che sia bene postarlo qui):
//-----------------------------------------------------------------------------
//Spying Process functions follow
//-----------------------------------------------------------------------------
void Injector::Launch(System::IntPtr windowHandle, System::String^ assembly, System::String^ className, System::String^ methodName)
{
System::String^ assemblyClassAndMethod = assembly + "$" + className + "$" + methodName;
pin_ptr<const wchar_t> acmLocal = PtrToStringChars(assemblyClassAndMethod);
HINSTANCE hinstDLL;
if (::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&MessageHookProc, &hinstDLL))
{
LogMessage("GetModuleHandleEx successful", true);
DWORD processID = 0;
DWORD threadID = ::GetWindowThreadProcessId((HWND)windowHandle.ToPointer(), &processID);
if (processID)
{
LogMessage("Got process id", true);
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if (hProcess)
{
LogMessage("Got process handle", true);
int buffLen = (assemblyClassAndMethod->Length + 1) * sizeof(wchar_t);
void* acmRemote = ::VirtualAllocEx(hProcess, NULL, buffLen, MEM_COMMIT, PAGE_READWRITE);
if (acmRemote)
{
LogMessage("VirtualAllocEx successful", true);
::WriteProcessMemory(hProcess, acmRemote, acmLocal, buffLen, NULL);
_messageHookHandle = ::SetWindowsHookEx(WH_CALLWNDPROC, &MessageHookProc, hinstDLL, threadID);
if (_messageHookHandle)
{
LogMessage("SetWindowsHookEx successful", true);
::SendMessage((HWND)windowHandle.ToPointer(), WM_GOBABYGO, (WPARAM)acmRemote, 0);
::UnhookWindowsHookEx(_messageHookHandle);
}
::VirtualFreeEx(hProcess, acmRemote, 0, MEM_RELEASE);
}
::CloseHandle(hProcess);
}
}
::FreeLibrary(hinstDLL);
}
}
. Snoop non ispeziona un WPF dall'esterno.Si inienta nell'applicazione e effettivamente aggiunge la finestra di ingrandimento o snoop.Questo è anche il motivo per cui quando esci da snoop le finestre di ispezione rimangono in realtà aperte.
Quindi il codice "Ispezione" ispeziona semplicemente la finestra che desidera e può utilizzare tutte le funzioni Avabili WPF per farlo.Come il VisualtreeHelper e LogaltreeHelper come menzionato qui prima.
Per un piccolo framework di prova Costruire il codice iniettato per aggiungere un piccolo oggetto proxy in modo da poter controllare facilmente l'applicazione (premere i pulsanti, i valori di modifica, eseguire funzioni su viewModels ecc.).
La risposta sopra non funziona per me.Sembra un po 'vago.Ho ampliato una risposta accettata un po 'con questo codice:
var allProcesses = Process.GetProcesses();
var filteredProcess = allProcesses.Where(p => p.ProcessName.Contains(ProcessSearchText)).First();
var windowHandle = filteredProcess.MainWindowHandle;
var hwndSource = HwndSource.FromHwnd(windowHandle);
.
Questa risposta sembra più completa e lavorerà per gli altri se la risposta accettata funziona per nessuno.Tuttavia, questo l'ultima riga di questo codice restituisce NULL per me.