0

so I am using following Code to read from Memory:

 public static extern bool ReadProcessMemory(IntPtr handle, IntPtr baseAddress, [Out] byte[] buffer, int size, out IntPtr numberOfBytesRead);

It outputs the memory Hex code as Byte Array using the code above:

buffer[0] = 01;
buffer[1] = 2D;
buffer[2] = F2;

I want to search in a certain range of the Hex Code for a certain Hex Array. To do that I would like to use the "KMP Algorithm for Pattern Searching".

Currently I am using the following code to achieve that:

byte[] moduleBytes = {0};
IntPtr bytesRead;
ReadProcessMemory(process.Handle, baseAddress, moduleBytes, moduleBytes.Length, out bytesRead);

string buffer = "";
foreach (byte bytesfrommemory in moduleBytes)
{
    buffer += bytesfrommemory.ToString("X");;
}

//algorithm
string data = buffer;
int[] value = SearchString(data, pattern);

foreach (int entry in value)
{
    Console.WriteLine(entry); //Outputs the offset where it found the code
}

The issue with that is that looping trough each byte to add it to the buffer string takes ages with +1000 bytes. Is there a faster way to "convert" the byte array from array to string without actually converting it as I still need the raw byte array just as string?

I tried it with the following code, but it converts it to something different:

char[] characters = moduleBytes.Select(o => (char)o).ToArray();
string buffer = new string(characters);

Thanks for any help :)

  • Appending to a string is quite slow, as you need to create an entirely new string each time. Give it a try with `var bufferBuilder = new StringBuilder(); foreach (byte moduleByte in moduleBytes) { bufferBuilder.Append(moduleByte.ToString("F")); } string data = bufferBuilder.ToString();` – Camilo Terevinto Oct 27 '21 at 19:13
  • 2
    You should be able to do a KMP implementation that uses byte arrays (and their lengths) as input. – 500 - Internal Server Error Oct 27 '21 at 19:17
  • 2
    @CamiloTerevinto Obviously OP already looked ["byte array to hex and back"](https://stackoverflow.com/questions/311165/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-and-vice-versa) questions (why their picked worst possible example to add to this question is hard to say, but it should not really matter) - they are asking for "no conversion" code. Somewhat confusing part is why they need string at all as all "string search" algorithms work on sequences of values and not `string` (ignoring once that try translation/extracting meaning of the string before search)... – Alexei Levenkov Oct 27 '21 at 19:18

1 Answers1

1

Alexei's comment is on point; you are converting bytes to a string to run a search algorithm that will convert the string to char array (i.e. a byte array, i.e. what you started with) in order to do its work. Finding a byte array within a byte array using KMP is the same as finding a string within a string

To demonstrate my point I casted around for an implementation of KMP that works on strings. I found one at Geeks For Geeks and swapped it from working on strings, to working on bytes, literally just just editing the type in the method calls; string has a Length and can be indexed like an array, byte array has a Length and can be indexed because it is an array etc - there is no more needed to make this version work:

// C# program for implementation of KMP pattern 
// searching algorithm 

using System; 

public class GFG { 

    void KMPSearch(byte[] pat, byte[] txt) 
    { 

        int M = pat.Length; 
        int N = txt.Length;   

        // create lps[] that will hold the longest 
        // prefix suffix values for pattern 

        int[] lps = new int[M]; 
        int j = 0; // index for pat[] 

        // Preprocess the pattern (calculate lps[] 
        // array) 

        computeLPSArray(pat, M, lps); 

        int i = 0; // index for txt[] 

        while (i < N) { 
            if (pat[j] == txt[i]) { 
                j++; 
                i++; 
            } 

            if (j == M) { 
                Console.Write("Found pattern "
                              + "at index " + (i - j)); 
                j = lps[j - 1]; 
            } 

            // mismatch after j matches 
            else if (i < N && pat[j] != txt[i]) { 
                // Do not match lps[0..lps[j-1]] characters, 
                // they will match anyway 
                if (j != 0) 
                    j = lps[j - 1]; 
                else
                    i = i + 1; 
            } 
        } 
    } 

    void computeLPSArray(byte[] pat, int M, int[] lps)
    { 
        // length of the previous longest prefix suffix 
        int len = 0; 
        int i = 1; 

        lps[0] = 0; // lps[0] is always 0 

        // the loop calculates lps[i] for i = 1 to M-1 
        while (i < M) { 

            if (pat[i] == pat[len]) { 
                len++; 
                lps[i] = len;  
                i++; 
            } 

            else // (pat[i] != pat[len]) 
            { 
                // This is tricky. Consider the example. 
                // AAACAAAA and i = 7. The idea is similar 
                // to search step. 

                if (len != 0) { 
                    len = lps[len - 1];   

                    // Also, note that we do not increment 
                    // i here 
                } 
                else // if (len == 0) 
                { 
                    lps[i] = len; 
                    i++; 
                } 
            } 
        } 
    } 

  

    // Driver program to test above function 

    public static void Main() 
    { 
        string txt = System.Text.Encoding.ASCII.GetBytes("ABABDABACDABABCABAB"); 
        string pat = System.Text.Encoding.ASCII.GetBytes("ABABCABAB"); 
        new GFG().KMPSearch(pat, txt); 
    } 
} 

  
// This code has been contributed by Amit Khandelwal. 

The biggest work (most number of keys typed) is using System.Text.Encoding.ASCII.GetBytes to get a pair of byte arrays to feed in

Take away point; don't convert your memory bytes at all - convert your search term to bytes and search it in the memory bytes

Disclaimer: I offer zero guarantee that this is a correct implementation of KMP that functions adequately for your use case. It seems to work, but I'm only pointing out that you don't need to convert to strings and back again to operate code that fundamentally can search bytes in exactly the same way as it searches strings

Caius Jard
  • 72,509
  • 5
  • 49
  • 80