// running in Indexing or UI thread private void UpdateUI(SearcherResult result) { try { if (result == null || result.SearchOptions == null || !result.SearchOptions.Equals(this.mainViewModel.SearchOptions)) { // this means that the thread was cancelled or SearchOptions have been changed in the meantime, so we need to ignore the result. return; } bool expandNewNodes = !String.IsNullOrWhiteSpace(this.mainViewModel.SearchText); if (Application.Current != null) { Application.Current.Dispatcher.Invoke(() => { this.treeViewModel.RefreshFromNode(result.ResultNode, result.Path, expandNewNodes); // when 'Sync with active document' is enabled and search results changed, we need to try to locate current document in the new search results this.syncWithActiveDocumentCommand.Execute(false); }); } } finally { this.mainViewModel.AddNumOfSearchingThreads(-1); } }
// running in Indexing or UI thread private void OnSearchingFinished(object sender, SearcherResult result) { try { if (result == null || result.SearchOptions == null || !result.SearchOptions.Equals(this.SearchOptions)) { // this means that the thread was cancelled or SearchOptions have been changed in the meantime, so we need to ignore the result. return; } bool expandNewNodes = !String.IsNullOrWhiteSpace(this.SearchText); Application.Current.Dispatcher.Invoke(() => { this.TreeViewModel.RefreshFromNode(result.ResultNode, result.Path, expandNewNodes); // when 'Sync with active document' is enabled and search results changed, we need to try to locate current document in the new search results this.ActiveDocumentPotentiallyChanged(); }); } finally { lock (this) { this.NumOfSearchingThreads--; } } }
private PointerEx[] CompareScan(SearcherResult item, byte[] finalPattern, byte[] mask) { Debug.Assert(mask.Length == finalPattern.Length); var buffer = Proc.GetBytes(item.BaseAddress, item.RegionSize); int result = -finalPattern.Length; List <PointerEx> ret = new List <PointerEx>(); unsafe { do { result = FindPattern(buffer, finalPattern, mask, result + finalPattern.Length); if (result >= 0) { ret.Add((long)item.BaseAddress + result); } } while (result != -1); } return(ret.ToArray()); }
// credit: https://github.com/erfg12/memory.dll/blob/master/Memory/memory.cs public Task <IEnumerable <PointerEx> > Search(string query, PointerEx start, PointerEx end, MemorySearchFlags flags) { return(Task.Run(() => { var Results = new List <SearcherResult>(); string[] patterns = query.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); byte[] finalPattern = new byte[patterns.Length]; byte[] mask = new byte[patterns.Length]; for (int i = 0; i < patterns.Length; i++) { string s = patterns[i]; if (s == "?") { mask[i] = 0; } else if (s.Length < 2) { if (s.HexByte(out byte b)) { finalPattern[i] = b; } mask[i] = 0xFF; } else { mask[i] = (byte)((s[0].IsHex() ? 0xF0 : 0) + (s[1].IsHex() ? 0x0F : 0)); if ((mask[i] & 0xF0) > 0) { finalPattern[i] += (byte)(s[0].HexByte() * 0x10); } if ((mask[i] & 0xF) > 0) { finalPattern[i] += s[1].HexByte(); } } } var sysInfo = new ProcessEx.SYSTEM_INFO(); ProcessEx.GetSystemInfo(out sysInfo); PointerEx proc_min_address = sysInfo.lpMinimumApplicationAddress; PointerEx proc_max_address = sysInfo.lpMaximumApplicationAddress; if (start < proc_min_address) { start = proc_min_address; } if (end > proc_max_address) { end = proc_max_address; } PointerEx cBase = start.Clone(); var memInfo = new ProcessEx.MEMORY_BASIC_INFORMATION(); while (ProcessEx.VirtualQueryEx(Proc.Handle, cBase, out memInfo, (uint)Marshal.SizeOf(memInfo)) && cBase < end && cBase + memInfo.RegionSize > cBase) { bool isValid = memInfo.State == ProcessEx.MEM_COMMIT; isValid &= memInfo.BaseAddress < proc_max_address; isValid &= ((memInfo.Protect & Native.PAGE_GUARD) == 0); isValid &= ((memInfo.Protect & Native.PAGE_NOACCESS) == 0); isValid &= (memInfo.Type == ProcessEx.MEM_PRIVATE) || (memInfo.Type == ProcessEx.MEM_IMAGE); if (isValid) { bool isReadable = (memInfo.Protect & Native.PAGE_READONLY) > 0; bool isWritable = ((memInfo.Protect & Native.PAGE_READWRITE) > 0) || ((memInfo.Protect & Native.PAGE_WRITECOPY) > 0) || ((memInfo.Protect & Native.PAGE_EXECUTE_READWRITE) > 0) || ((memInfo.Protect & Native.PAGE_EXECUTE_WRITECOPY) > 0); bool isExecutable = ((memInfo.Protect & Native.PAGE_EXECUTE) > 0) || ((memInfo.Protect & Native.PAGE_EXECUTE_READ) > 0) || ((memInfo.Protect & Native.PAGE_EXECUTE_READWRITE) > 0) || ((memInfo.Protect & Native.PAGE_EXECUTE_WRITECOPY) > 0); isReadable &= ((byte)flags & (byte)MemorySearchFlags.Read) > 0; isWritable &= ((byte)flags & (byte)MemorySearchFlags.Write) > 0; isExecutable &= ((byte)flags & (byte)MemorySearchFlags.Execute) > 0; isValid &= isReadable || isWritable || isExecutable; } cBase = memInfo.BaseAddress + memInfo.RegionSize; if (!isValid) { continue; } SearcherResult result = new SearcherResult { BaseAddress = cBase - memInfo.RegionSize, RegionSize = memInfo.RegionSize, RegionBase = memInfo.BaseAddress }; if (Results.Count > 0) { var previousRegion = Results[Results.Count - 1]; if ((previousRegion.RegionBase + previousRegion.RegionSize) == memInfo.BaseAddress) { Results[Results.Count - 1] = new SearcherResult { BaseAddress = previousRegion.BaseAddress, RegionBase = previousRegion.RegionBase, RegionSize = previousRegion.RegionSize + memInfo.RegionSize }; continue; } } Results.Add(result); } // end while ConcurrentBag <PointerEx> bagResult = new ConcurrentBag <PointerEx>(); Parallel.ForEach(Results, (item, parallelLoopState, index) => { PointerEx[] compareResults = CompareScan(item, finalPattern, mask); foreach (PointerEx result in compareResults) { bagResult.Add(result); } }); return bagResult.ToList().OrderBy(c => c).AsEnumerable(); })); }