/// <summary> /// Will load all the memory region information of the program into a list for faster scanning /// </summary> private void LoadMemoryRegions() { // the current address being scanned var address = new IntPtr(); _memoryRegionsSortedIndices = new SortedList <Int32, int>(); var count = 0; while (true) { // get the memory information for the first region var memInfo = new MemoryApi.MemoryBasicInformation(); int result = MemoryApi.VirtualQueryEx(_process.Handle, address, out memInfo, (uint)Marshal.SizeOf(memInfo)); // virtualqueryex will return 0 when we're out of range of the application if (0 == result) { break; } // filter out any that don't have commit or aren't writable if (0 != (memInfo.State & MemCommit) && 0 != (memInfo.Protect & Writable) && 0 == (memInfo.Protect & PageGuard)) { // store the information MemoryRegions.Add(memInfo); _memoryRegionsSortedIndices.Add(memInfo.BaseAddress.ToInt32(), count++); } // move to the next memory region address = new IntPtr(memInfo.BaseAddress.ToInt32() + memInfo.RegionSize); } }
/// <summary> /// <para>Searches the loaded process for the given byte signature.</para> /// <para>Uses the character ? as a wildcard</para> /// </summary> /// <param name="signature">The hex pattern to search for</param> /// <param name="startAddress">An startAddress to add to the pointer VALUE</param> /// <param name="searchType">What type of result to return</param> /// <returns>The pointer found at the matching location</returns> public IntPtr FindSignature(string signature, int startAddress, ScanResultType searchType) { // make sure we have a valid signature if (signature.Length == 0 || signature.Length % 2 != 0) { throw new Exception("FindSignature(): Invalid signature"); } for (var index = 0; index < _memoryRegionsSortedIndices.Count; index++) { int workingIndex = _memoryRegionsSortedIndices.Values[index]; MemoryApi.MemoryBasicInformation region = MemoryRegions[_memoryRegionsSortedIndices.Values[index]]; // Skip memory regions until we find one that contains the startAddress but startAddress of zero means skip none if (startAddress > 0) { if (region.BaseAddress.ToInt32() + region.RegionSize < startAddress || region.BaseAddress.ToInt32() > startAddress) { continue; } } var buffer = new byte[region.RegionSize]; var bytesRead = 0; // ReadProcessMemory will return 0 if some form of error occurs if ( !MemoryApi.ReadProcessMemory(_process.Handle, region.BaseAddress, buffer, (int)region.RegionSize, out bytesRead)) { // get the error code thrown from ReadProcessMemory int errorCode = Marshal.GetLastWin32Error(); // For now, if error reading, we will still search what amount was able to be read so no exception throwing. } var bufferOffset = 0; if (startAddress > 0 && region.BaseAddress.ToInt32() < startAddress && region.BaseAddress.ToInt32() + bytesRead > startAddress) { // Since requested startAddress is somewhere in the current regions address space, set startAddress from beginning of region bufferOffset = startAddress - region.BaseAddress.ToInt32(); } IntPtr searchResult = FindSignature(buffer, signature, bufferOffset, searchType); // If we found our signature, we're done if (IntPtr.Zero == searchResult) { continue; } // if we passed the ! flag we want the beginning address of where it found the sig if (ScanResultType.AddressStartOfSig == searchType) { searchResult = new IntPtr(region.BaseAddress.ToInt32() + searchResult.ToInt32()); } return(searchResult); } return(IntPtr.Zero); }