[C#][Release] FindPatternSharp - CFindPattern Clone (Kinda) menu

User Tag List

Results 1 to 15 of 15
  1. #1
    Apoc's Avatar Angry Penguin
    Reputation
    1387
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/12
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [C#][Release] FindPatternSharp - CFindPattern Clone (Kinda)

    In short; I got tired of having to have a buttload of patterns hard-coded in my applications, so I decided to set out, and clone (to some degree at least) the awesome CFindPattern class from the GD forums.

    All credit for most of the original implementation goes to Dominik, Patrick, Bobbysing, etc, etc from GD. I simply ripped a good bit of code, and made the necessary changes to make it all work in .NET.

    The code is a bit ugly, but that's ok. It works, and until I have the energy to clean it up more, it'll stay ugly. It currently supports everything CFindPattern does, for the exception of 1 element type (<Set blah blah />, which I haven't found a solid use of to make it worth implementing). You can basically just take your old Patterns.xml (or rip the one from the WoWX source) and plug it into this system. It's written to work the same way CFindPattern does.

    Anyhow, it requires .NET 3.5 (since I don't really dev on any other version anymore), so if you can't allow the use of LINQ, you'll need to make the required edits for this to work properly for you.

    The FindPattern class:

    Code:
    // Copyright 2009 Apoc @ ApocDev.com | Apoc @ MMOwned.com | Apoc @ GameDeception.net
    #define X64
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Xml.Linq;
    
    namespace FindPatternSharp
    {
        /// <summary>
        /// Credits to Dominik, Patrick, Bobbysing, and whoever else I forgot, for most of the ripped code here!
        /// </summary>
        public class FindPattern
        {
    #if !X64
            private readonly Dictionary<string, uint> _patterns = new Dictionary<string, uint>();
    #else
            private readonly Dictionary<string, ulong> _patterns = new Dictionary<string, ulong>();
    #endif
            /// <summary>
            /// Creates a new instance of the <see cref="FindPattern"/> class. This class will read from a specified patterns XML file
            /// and search out those patterns in the specified process's memory.
            /// </summary>
            /// <param name="patternFile">The full path to the pattern XML file.</param>
            /// <param name="processHandle">An open process handle to the process to read memory from.</param>
            /// <param name="startAddr">The 'base' address of the process (or module)</param>
            /// <param name="endAddr">The 'end' of the process (or module). Eg; where to stop reading memory from.</param>
    #if !X64
            public FindPattern(string patternFile, IntPtr processHandle, uint startAddr, uint endAddr)
    #else
            public FindPattern(string patternFile, IntPtr processHandle, ulong startAddr, ulong endAddr)
    #endif
            {
                // Get a temporary set of data to work with. :)
                byte[] data = ReadBytes(processHandle, (IntPtr) startAddr, (int) (endAddr - startAddr));
                LoadFile(XElement.Load(patternFile), data, startAddr);
            }
    
            /// <summary>
            /// Retrieves an address from the found patterns stash.
            /// </summary>
            /// <param name="name">The name of the pattern, as per the XML file provided in the constructor of this class instance.</param>
            /// <returns></returns>
    #if !X64
            public uint this[string name]
    #else
            public ulong this[string name]
    #endif
            { get { return Get(name); } }
    
            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize,
                                                         out int lpNumberOfBytesRead);
    
            private static byte[] ReadBytes(IntPtr processHandle, IntPtr address, int count)
            {
                var ret = new byte[count];
                int numRead;
                if (ReadProcessMemory(processHandle, address, ret, count, out numRead) && numRead == count)
                {
                    return ret;
                }
                return null;
            }
    
            /// <summary>
            /// Retrieves an address from the found patterns stash.
            /// </summary>
            /// <param name="name">The name of the pattern, as per the XML file provided in the constructor of this class instance.</param>
            /// <returns></returns>
    #if !X64
            public uint Get(string name)
    #else
            public ulong Get(string name)
    #endif
            {
                return _patterns[name];
            }
    
    #if !X64
            private void LoadFile(XContainer file, byte[] data, uint start)
    #else
            private void LoadFile(XContainer file, byte[] data, ulong start)
    #endif
            {
                // Grab all the <Pattern /> elements from the XML.
                IEnumerable<XElement> pats = from p in file.Descendants("Pattern")
                                             select p;
    
                // Each Pattern element needs to be handled seperately.
                // The enumeration we're goinv over, is in document order, so attributes such as 'start'
                // should work perfectly fine.
                foreach (XElement pat in pats)
                {
    #if !X64
                    uint tmpStart = 0;
    #else
                    ulong tmpStart = 0;
    #endif
    
                    string name = pat.Attribute("desc").Value;
                    string mask = pat.Attribute("mask").Value;
                    byte[] patternBytes = GetBytesFromPattern(pat.Attribute("pattern").Value);
    
                    // Make sure we're not getting some sort of screwy XML data.
                    if (mask.Length != patternBytes.Length)
                        throw new Exception("Pattern and mask lengths do not match!");
    
                    // If we run into a 'start' attribute, we need to remember that we're working from a 0
                    // based 'memory pool'. So we just remove the 'start' from the address we found earlier.
                    if (pat.Attribute("start") != null)
                    {
                        tmpStart = Get(pat.Attribute("start").Value) - start + 1;
                    }
    
                    // Actually search for the pattern match...
    #if !X64
                    uint found = Find(data, mask, patternBytes, tmpStart);
    #else
                    ulong found = Find(data, mask, patternBytes, tmpStart);
    #endif
    
                    if (found == 0)
                        throw new Exception("FindPattern failed... figure it out ****tard!");
    
                    // Handle specific child elements for the pattern.
                    // <Lea> <Rel> <Add> <Sub> etc
                    foreach (XElement e in pat.Elements())
                    {
                        switch (e.Name.LocalName)
                        {
                            case "Lea":
    #if !X64
                                found = BitConverter.ToUInt32(data, (int) found);
    #else
                                found = BitConverter.ToUInt64(data, (int) found);
    #endif
                                break;
                            case "Rel":
                                uint instructionSize = uint.Parse(e.Attribute("size").Value, NumberStyles.HexNumber);
                                uint operandOffset = uint.Parse(e.Attribute("offset").Value, NumberStyles.HexNumber);
    #if !X64
                                found = (uint) (BitConverter.ToUInt32(data, (int) found) + found + instructionSize - operandOffset);
    #else
                                found = (BitConverter.ToUInt64(data, (int) found) + found + instructionSize - operandOffset);
    #endif
                                break;
                            case "Add":
                                found += uint.Parse(e.Attribute("value").Value, NumberStyles.HexNumber);
                                break;
                            case "Sub":
                                found -= uint.Parse(e.Attribute("value").Value, NumberStyles.HexNumber);
                                break;
                        }
                    }
    
                    _patterns.Add(name, found + start);
                }
            }
    
            private static byte[] GetBytesFromPattern(string pattern)
            {
                // Because I'm lazy, and this just makes life easier.
                string[] split = pattern.Split(new[] {'\\', 'x'}, StringSplitOptions.RemoveEmptyEntries);
                var ret = new byte[split.Length];
                for (int i = 0; i < split.Length; i++)
                {
                    ret[i] = byte.Parse(split[i], NumberStyles.HexNumber);
                }
                return ret;
            }
    
    #if !X64
            private static uint Find(byte[] data, string mask, byte[] byteMask, uint start)
    #else
            private static ulong Find(byte[] data, string mask, byte[] byteMask, ulong start)
    #endif
            {
                // There *has* to be a better way to do this stuff,
                // but for now, we'll deal with it.
    #if !X64
                for (uint i = start; i < data.Length; i++)
    #else
                for (ulong i = start; i < (ulong) data.Length; i++)
    #endif
                {
                    if (DataCompare(data, (int) i, byteMask, mask))
                        return i;
                }
                return 0;
            }
    
            private static bool DataCompare(byte[] data, int offset, byte[] byteMask, string mask)
            {
                // Only check for 'x' mismatches. As we'll assume anything else is a wildcard.
                for (int i = 0; i < mask.Length; i++)
                {
                    if (mask[i] == 'x' && byteMask[i] != data[i + offset])
                    {
                        return false;
                    }
                }
                return true;
            }
        }
    }
    Example XML file:

    Code:
    <Patterns>
        <Pattern desc="FrameScript_Execute" pattern="\x55\x8B\xEC\x51\x83\x05\xCC\x74\x32\x01\x01\xA1\xC8\x74\x32\x01\x89\x45\xFC\x74\x12\x83\x3D\xD0\x74\x32\x01\x00" mask="xxxxxx????xx????xxxxxxx????x" />
    </Patterns>
    And example usage:

    Code:
    // Copyright 2009 Apoc @ ApocDev.com | Apoc @ MMOwned.com | Apoc @ GameDeception.net
    
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;
    
    using FindPatternSharp;
    
    namespace FindPatternSharpTest
    {
        internal class Program
        {
            [DllImport("kernel32.dll")]
            private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);
    
            private static void Main()
            {
                Process.EnterDebugMode();
    
                int procId = Process.GetProcessesByName("Wow")[0].Id;
                IntPtr hProc = OpenProcess(0x001F0FFF, true, procId);
    
                var fp = new FindPattern("Patterns.xml", hProc, 0x401000, 0x800000);
    
                Console.WriteLine(fp.Get("FrameScript_Execute").ToString("X"));
    
                Console.ReadLine();
            }
        }
    }
    Notes; I didn't find the need to include any type of process handle opening and whatnot in the actual FindPatterns class, as it really isn't the job of that class. (I included RPM for brevity, and to make sure the code will work out of the box, with no issues.)

    Credits;
    Dominik
    Patrick
    Bobbysing
    Myself

    **** YEA! REAL FINDPATTERN!
    Last edited by Apoc; 09-08-2009 at 07:26 PM.

    [C#][Release] FindPatternSharp - CFindPattern Clone (Kinda)
  2. #2
    Robske's Avatar Contributor
    Reputation
    305
    Join Date
    May 2007
    Posts
    1,062
    Thanks G/R
    3/4
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Amazing, thanks Apoc!
    "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live." - Martin Golding
    "I cried a little earlier when I had to poop" - Sku

  3. #3
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1356
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/4
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Fail noob, it's x86 only.

  4. #4
    lanman92's Avatar Active Member
    Reputation
    50
    Join Date
    Mar 2007
    Posts
    1,033
    Thanks G/R
    0/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Why would you want to make it work for x64 as well? I don't see a reason yet since it's not very popular.

  5. #5
    Apoc's Avatar Angry Penguin
    Reputation
    1387
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/12
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    There ya go Cypher. Added x64 support. Happy now? (Not that it makes a hoot of a difference, since it's meant to be used out of process...)

  6. #6
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1356
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/4
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by lanman92 View Post
    Why would you want to make it work for x64 as well? I don't see a reason yet since it's not very popular.
    Why would you write platform-dependent code unnecessarily? That's just stupid. There are x64 games (Crysis, Far Cry, HL2, etc), and quite a few non-game applications for pattern-finding apps, many of which would require x64 support.

    I personally prefer to stay ahead of the curve rather than fall behind and be stuck rewriting half my code when x64 becomes mainstream (which is happening faster than you may think).

  7. #7
    barthen's Avatar Contributor Authenticator enabled
    Reputation
    84
    Join Date
    Apr 2007
    Posts
    111
    Thanks G/R
    4/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for sharing. I think you could improve it by checking for duplicate instances of the pattern (I mean the same pattern of bytes in different memory locations). Sometimes the patterns are not specific enough or big enough and after a patch you could have some problems.

  8. #8
    flo8464's Avatar Active Member
    Reputation
    30
    Join Date
    Apr 2009
    Posts
    434
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Maybe stupid question, but what makes a pattern-search function platform-dependend?

    I mean, a byte is a byte. Or do just mean using greater variables for storing addresses etc ?

  9. #9
    lanman92's Avatar Active Member
    Reputation
    50
    Join Date
    Mar 2007
    Posts
    1,033
    Thanks G/R
    0/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    On x64, addresses are 64 bits. Whereas on x86 they're 32-bits. That's the main difference. Correct me if I'm wrong. The opcodes are different, too. For further questions, Intel manual ftw?

  10. #10
    LegacyAX's Avatar Active Member
    Reputation
    21
    Join Date
    Apr 2009
    Posts
    193
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    nice class mate +Rep

    *Edit: need to spread :/

  11. #11
    amadmonk's Avatar Active Member
    Reputation
    124
    Join Date
    Apr 2008
    Posts
    772
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I really don't see native x64 apps taking off, Cypher (OS, yes, apps, no). By running WOW64, we get much of the benefits of 64 bit (lots of available RAM) without the biggest drawback (recompiling needed). Very, very few apps these days need more than 4gb of address space.

    Since MS's WOW64 works pretty well, I don't see native x64 apps really taking off for honestly another 5 years or more.

    Just my 2cents and part of why I never bother much with x64 support for non-kernel code.

    Edit: I know that there are other benefits to x64 over x86, for instance, the extra registers make the compiler's register allocator much, much, much more efficient. But the perf benefits of that are often outweighed by the costs of 64 bits per mem xfer vs 32 bits (which in turn is sometimes a benefit and sometimes a hindrance). When we were perf testing the VC++ compiler against GCC for the AMD64, we found that there's actually a small "x64 tax" in general that you pay (all else being algorithmically equal), so again... unless you really need 16 exabytes (or whatever it is) of address space, there's not really a compelling reason for vendors to recompile existing apps for x64, and not much of a reason for vendors to force their C/C++ coders (who, by nature, tend to be a tad resistant to change ) to start thinking bit-width-agnostic. For app writers, the primary benefit of x64 over x86 is the extra memory per process, and if you write your apps x86 the OS makes that magic "just work" for you.

    Edit edit: I'm freakin tired. I should sleep... plus, I'm flying to DC on Saturday. Urgh.
    Last edited by amadmonk; 09-18-2009 at 12:50 AM.
    Don't believe everything you think.

  12. #12
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1356
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/4
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by amadmonk View Post
    I really don't see native x64 apps taking off, Cypher (OS, yes, apps, no). By running WOW64, we get much of the benefits of 64 bit (lots of available RAM) without the biggest drawback (recompiling needed). Very, very few apps these days need more than 4gb of address space.

    Since MS's WOW64 works pretty well, I don't see native x64 apps really taking off for honestly another 5 years or more.

    Just my 2cents and part of why I never bother much with x64 support for non-kernel code.

    Edit: I know that there are other benefits to x64 over x86, for instance, the extra registers make the compiler's register allocator much, much, much more efficient. But the perf benefits of that are often outweighed by the costs of 64 bits per mem xfer vs 32 bits (which in turn is sometimes a benefit and sometimes a hindrance). When we were perf testing the VC++ compiler against GCC for the AMD64, we found that there's actually a small "x64 tax" in general that you pay (all else being algorithmically equal), so again... unless you really need 16 exabytes (or whatever it is) of address space, there's not really a compelling reason for vendors to recompile existing apps for x64, and not much of a reason for vendors to force their C/C++ coders (who, by nature, tend to be a tad resistant to change ) to start thinking bit-width-agnostic. For app writers, the primary benefit of x64 over x86 is the extra memory per process, and if you write your apps x86 the OS makes that magic "just work" for you.

    Edit edit: I'm freakin tired. I should sleep... plus, I'm flying to DC on Saturday. Urgh.
    Whilst that may be true for most 'normal' apps, I do a lot of low level OS-based programming (usermode rootkits, packers, shit like that). On x64 copies of Windows 99.99% of the OS core is native x64 so you really need to be able to hook into and interact with those to be able to implement stuff properly.

    Running in WoW64 is not an option because all of the OS core is 'unavailable'.

    I realize it's a fairly specialized case, however it's really not hard at all to write architecture-agnostic code, so why not just spend an extra 5 minutes here or there to do things the right way and take the portability as a bonus. Who knows, it might come in handy some day. I know that a lot of the libs I've written where I've thought "bah, I'll never need this on x64" I've ended up needing after all.

  13. #13
    LegacyAX's Avatar Active Member
    Reputation
    21
    Join Date
    Apr 2009
    Posts
    193
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Cypher View Post
    (usermode rootkits, packers, shit like that)
    Funny how you speak of your projects as something along the lines of "nothing special"

  14. #14
    Apoc's Avatar Angry Penguin
    Reputation
    1387
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/12
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by LegacyAX View Post
    Funny how you speak of your projects as something along the lines of "nothing special"
    With the projects he does on a daily basis, those aren't all that special.

  15. #15
    MaiN's Avatar Elite User
    Reputation
    335
    Join Date
    Sep 2006
    Posts
    1,047
    Thanks G/R
    0/10
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You still add the base (0x401000 for WoW) even though someone specified the <Lea /> element - that messes it up!
    Last edited by MaiN; 09-22-2009 at 03:23 PM.
    [16:15:41] Cypher: caus the CPU is a dick
    [16:16:07] kynox: CPU is mad
    [16:16:15] Cypher: CPU is all like
    [16:16:16] Cypher: whatever, i do what i want

Similar Threads

  1. A speed hack(kinda)
    By XxKajxX in forum World of Warcraft Bots and Programs
    Replies: 30
    Last Post: 11-27-2006, 10:50 PM
  2. [Release] Herbs to flag
    By Dave-evad in forum World of Warcraft Model Editing
    Replies: 9
    Last Post: 11-26-2006, 03:31 PM
  3. anti-warden Release #1
    By zhPaul in forum World of Warcraft Bots and Programs
    Replies: 40
    Last Post: 10-21-2006, 01:40 AM
  4. kindof an exploit, kinda a funny story
    By afiwarlord in forum WoW Scam Prevention
    Replies: 28
    Last Post: 08-25-2006, 08:59 PM
  5. Out of topic*kinda*
    By Arkon_WoW in forum World of Warcraft General
    Replies: 8
    Last Post: 08-09-2006, 04:37 AM
All times are GMT -5. The time now is 12:26 AM. Powered by vBulletin® Version 4.2.3
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search