예제 #1
0
        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);
        }
예제 #2
0
        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));
        }
예제 #3
0
        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));
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
        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));
        }