public static IFunction <T> CreateFunction <T>(string pattern) { var compiledPattern = new CompiledScanPattern(pattern); Vanara.PInvoke.Kernel32.MEMORY_BASIC_INFORMATION m; var process = Process.GetCurrentProcess(); var address = (ulong)process.MainModule.BaseAddress; while (Vanara.PInvoke.Kernel32.VirtualQueryEx(process, ( IntPtr )address, ( IntPtr )(&m), ( uint )Marshal.SizeOf(typeof(Vanara.PInvoke.Kernel32.MEMORY_BASIC_INFORMATION))).Value > 0) { if ((m.Protect & (( uint )Vanara.PInvoke.Kernel32.MEM_PROTECTION.PAGE_EXECUTE | ( uint )Vanara.PInvoke.Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READ | ( uint )Vanara.PInvoke.Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE | ( uint )Vanara.PInvoke.Kernel32.MEM_PROTECTION.PAGE_EXECUTE_WRITECOPY)) != 0) { var scanner = new Scanner((byte *)m.BaseAddress, m.RegionSize); var result = scanner.CompiledFindPattern(compiledPattern); if (result.Found) { return(Services.Get <IReloadedHooks>().CreateFunction <T>(( long )(m.BaseAddress + result.Offset))); } } address = ( ulong )m.BaseAddress + m.RegionSize.Value; } return(null); }
private List <PatternScanResult> GetPointerPatterns(int targetOffset) { // Now find all pointers to file name pattern. byte[] offsetBytes = Struct.GetBytes(targetOffset); var scanPattern = new CompiledScanPattern(Utilities.Utilities.BytesToScanPattern(offsetBytes)); return(Utilities.Utilities.FindAllPatterns(_scanner, scanPattern)); }
private List <PatternScanResult> FindFileNamePatterns(string datFileName) { // We're using ASCII so byte per character. byte[] fileNameBytes = new byte[datFileName.Length + 1]; Encoding.ASCII.GetBytes(datFileName, fileNameBytes); // Pattern to find. var scanPattern = new CompiledScanPattern(Utilities.Utilities.BytesToScanPattern(fileNameBytes)); return(Utilities.Utilities.FindAllPatterns(_scanner, scanPattern)); }
/// <summary> /// Returns a list of all patterns inside a given block of data. /// </summary> /// <param name="scanner">The scanner for which to find all patterns in.</param> /// <param name="scanPattern">The pattern to be scanned.</param> /// <returns>All occurrences of the pattern.</returns> public static List <PatternScanResult> FindAllPatterns(Scanner scanner, CompiledScanPattern scanPattern) { var results = new List <PatternScanResult>(); var result = new PatternScanResult(-1); do { result = scanner.CompiledFindPattern(scanPattern, result.Offset + 1); if (result.Found) { results.Add(result); } }while (result.Found); return(results); }
public static List <PatternScanResult> FindAllPatterns(this Scanner scanner, string pattern, int max = -1) { var results = new List <PatternScanResult>(); var result = new PatternScanResult(-1); var scanPattern = new CompiledScanPattern(pattern); do { result = scanner.CompiledFindPattern(scanPattern, result.Offset + 1); if (result.Found) { results.Add(result); } }while (result.Found && (max < 0 || results.Count < max)); return(results); }
private void overwrite(SongObject song) { if (song.newName == null) { return; } string newName = shortenName(song.newName); byte[] hexOriginalName = Encoding.ASCII.GetBytes(song.originalName); byte[] hexNewName = newEncode(newName); // Add null byte to make I'll Face Myself unique if (song.originalName.Equals("I'll Face Myself")) { byte[] tempArray = new byte[hexOriginalName.Length + 1]; Array.Copy(hexOriginalName, tempArray, hexOriginalName.Length); hexOriginalName = tempArray; } if (hexOriginalName.Length > hexNewName.Length) { byte[] tempArray = new byte[hexOriginalName.Length]; Array.Copy(hexNewName, tempArray, hexNewName.Length); hexNewName = tempArray; } string songBytePattern = BitConverter.ToString(hexOriginalName).Replace("-", " "); var pattern = new CompiledScanPattern(songBytePattern); var result = scanner.CompiledFindPattern(pattern, songsOffset); if (result.Found) { mMem.SafeWriteRaw(mBaseAddr + result.Offset, hexNewName); mLogger.WriteLine("[HeeHeeHo Music Renamer] Renamed \"" + song.originalName + "\" to \"" + newName + "\""); } else { mLogger.WriteLine("[HeeHeeHo Music Renamer] Couldn't find song name \"" + song.originalName + "\""); } }
/// <summary> /// Attempts to find a given pattern inside the memory region this class was created with. /// This method generally works better when the expected offset is bigger than 4096. /// </summary> /// <param name="pattern"> /// The compiled pattern to look for inside the given region. /// </param> /// <param name="startingIndex">The index to start searching at.</param> /// <returns>A result indicating an offset (if found) of the pattern.</returns> public PatternScanResult CompiledFindPattern(CompiledScanPattern pattern, int startingIndex = 0) { int numberOfInstructions = pattern.NumberOfInstructions; byte *dataBasePointer = _dataPtr; byte *currentDataPointer; int lastIndex = _dataLength - Math.Max(pattern.Length, sizeof(long)) + 1; // Note: All of this has to be manually inlined otherwise performance suffers, this is a bit ugly though :/ fixed(GenericInstruction *instructions = pattern.Instructions) { var firstInstruction = instructions[0]; /* * There is an optimization going on in here apart from manual inlining which is why * this function is a tiny mess of more goto statements than it seems necessary. * * Basically, it is considerably faster to reference a variable on the stack, than it is on the heap. * * This is because the compiler can address the stack bound variable relative to the current stack pointer, * as opposing to having to dereference a pointer and then take an offset from the result address. * * This ends up being considerably faster, which is important in a scenario where we are entirely CPU bound. */ int x = startingIndex; while (x < lastIndex) { currentDataPointer = dataBasePointer + x; var compareValue = *(ulong *)currentDataPointer & firstInstruction.Mask; if (compareValue != firstInstruction.LongValue) { goto singleInstructionLoopExit; } if (numberOfInstructions <= 1) { return(new PatternScanResult(x)); } /* When NumberOfInstructions > 1 */ currentDataPointer += sizeof(ulong); int y = 1; do { compareValue = *(ulong *)currentDataPointer & instructions[y].Mask; if (compareValue != instructions[y].LongValue) { goto singleInstructionLoopExit; } currentDataPointer += sizeof(ulong); y++; }while (y < numberOfInstructions); return(new PatternScanResult(x)); singleInstructionLoopExit :; x++; } // Check last few bytes in cases pattern was not found and long overflows into possibly unallocated memory. return(SimpleFindPattern(pattern.Pattern, lastIndex)); // PS. This function is a prime example why the `goto` statement is frowned upon. // I have to use it here for performance though. } }
/// <summary> /// Attempts to find a given pattern inside the memory region this class was created with. /// This method generates a list of instructions, which more efficiently determine at any array index if pattern is found. /// This method generally works better when the expected offset is bigger than 4096. /// </summary> /// <param name="pattern"> /// The pattern to look for inside the given region. /// Example: "11 22 33 ?? 55". /// Key: ?? represents a byte that should be ignored, anything else if a hex byte. i.e. 11 represents 0x11, 1F represents 0x1F /// </param> /// <returns>A result indicating an offset (if found) of the pattern.</returns> public PatternScanResult CompiledFindPattern(string pattern) { var instructionSet = new CompiledScanPattern(pattern); return(CompiledFindPattern(instructionSet)); }