Поиск и изменение с увеличением или уменьшением в бинарном файле [Решено]
Цитата: --- НЛО --- от 13.05.2022, 22:29Поиск и изменение с увеличением или уменьшением в бинарном файле.
Здравствуйте. Хочется автоматизировать 1 задачу, которую довольно часто приходится выполнять в шестнадцатеричном редакторе для файла. (Скажем так. Написать свой чит к 1 игре, а именно автоматизированный редактор сохранений).
Но вот не могу найти инфы по тому, как вообще можно делать поиск и уж тем более заменять найденное значение на большее или меньшее. Из того что логично предположить это работать с массивом байтов. Может кто показать желательно на примере.
Например, в бинарном файле есть такой набор байтов в такой последовательности:
08 00 00 00 67 6F 6C 64 3D 35 32 31
И заменить на такой:
0B 00 00 00 67 6F 6C 64 3D 39 39 39 39 39 39
[MNotice]Для перехода на новую строку используйте просто Enter, а неShift+Enter[/MNotice]
Поиск и изменение с увеличением или уменьшением в бинарном файле.
Здравствуйте. Хочется автоматизировать 1 задачу, которую довольно часто приходится выполнять в шестнадцатеричном редакторе для файла. (Скажем так. Написать свой чит к 1 игре, а именно автоматизированный редактор сохранений).
Но вот не могу найти инфы по тому, как вообще можно делать поиск и уж тем более заменять найденное значение на большее или меньшее. Из того что логично предположить это работать с массивом байтов. Может кто показать желательно на примере.
Например, в бинарном файле есть такой набор байтов в такой последовательности:
08 00 00 00 67 6F 6C 64 3D 35 32 31
И заменить на такой:
0B 00 00 00 67 6F 6C 64 3D 39 39 39 39 39 39
Комментарий модератора:
Для перехода на новую строку используйте просто Enter, а не
Цитата: Adler от 14.05.2022, 11:36Добрый день.
Для чтения и записи используйте BinaryWriter и BinaryReader. Как ими пользоваться загуглите сами.
Для быстрого поиска бинарных сигнатур есть класс, ссылку на который дам позже, когда найду его исходник.Например, в бинарном файле есть такой набор байтов в такой последовательности:
08 00 00 00 67 6F 6C 64 3D 35 32 31
И заменить на такой:
0B 00 00 00 67 6F 6C 64 3D 39 39 39 39 39 39А вы тут точно ничего не путаете? Обычно в бинарных данных не допускается изменение длины. Можно ссылку на данный мануал, по которому вы это делаете?
P.S. Например вот. Или можете поискать другие реализации алгоритма Boyer-Moore.
Так же где-то был исходник поиска по маске, но пока не вспомню, где я его использовал, что бы найти в исходниках.
Добрый день.
Для чтения и записи используйте BinaryWriter и BinaryReader. Как ими пользоваться загуглите сами.
Для быстрого поиска бинарных сигнатур есть класс, ссылку на который дам позже, когда найду его исходник.
Например, в бинарном файле есть такой набор байтов в такой последовательности:
08 00 00 00 67 6F 6C 64 3D 35 32 31
И заменить на такой:
0B 00 00 00 67 6F 6C 64 3D 39 39 39 39 39 39
А вы тут точно ничего не путаете? Обычно в бинарных данных не допускается изменение длины. Можно ссылку на данный мануал, по которому вы это делаете?
P.S. Например вот. Или можете поискать другие реализации алгоритма Boyer-Moore.
Так же где-то был исходник поиска по маске, но пока не вспомню, где я его использовал, что бы найти в исходниках.
Цитата: Adler от 14.05.2022, 12:04В одном проекте использовал еще вот такой класс:
[spoiler title="Поиск в потоке первого вхождения"]public static class Search { /// <summary> /// Finds the first occurrence of <paramref name="pattern"/> in a stream /// </summary> /// <param name="s">The input stream</param> /// <param name="pattern">The pattern</param> /// <returns>The index of the first occurrence, or -1 if the pattern has not been found</returns> public static long IndexOf(Stream s, byte[] pattern) { // Prepare the bad character array is done once in a separate step var badCharacters = MakeBadCharArray(pattern); // We now repeatedly read the stream into a buffer and apply the Boyer-Moore-Horspool algorithm on the buffer until we get a match var buffer = new byte[Math.Max(2 * pattern.Length, 4096)]; long offset = 0; // keep track of the offset in the input stream while (true) { int dataLength; if (offset == 0) { // the first time we fill the whole buffer dataLength = s.Read(buffer, 0, buffer.Length); } else { // Later, copy the last pattern.Length bytes from the previous buffer to the start and fill up from the stream // This is important so we can also find matches which are partly in the old buffer Array.Copy(buffer, buffer.Length - pattern.Length, buffer, 0, pattern.Length); dataLength = s.Read(buffer, pattern.Length, buffer.Length - pattern.Length) + pattern.Length; } var index = IndexOf(buffer, dataLength, pattern, badCharacters); if (index >= 0) return offset + index; // found! if (dataLength < buffer.Length) break; offset += dataLength - pattern.Length; } return -1; } // --- Boyer-Moore-Horspool algorithm --- // (Slightly modified code from // https://stackoverflow.com/questions/16252518/boyer-moore-horspool-algorithm-for-all-matches-find-byte-array-inside-byte-arra) // Prepare the bad character array is done once in a separate step: private static int[] MakeBadCharArray(byte[] pattern) { var badCharacters = new int[256]; for (long i = 0; i < 256; ++i) badCharacters[i] = pattern.Length; for (var i = 0; i < pattern.Length - 1; ++i) badCharacters[pattern[i]] = pattern.Length - 1 - i; return badCharacters; } // Core of the BMH algorithm private static int IndexOf(byte[] value, int valueLength, byte[] pattern, int[] badCharacters) { int index = 0; while (index <= valueLength - pattern.Length) { for (var i = pattern.Length - 1; value[index + i] == pattern[i]; --i) { if (i == 0) return index; } index += badCharacters[value[index + pattern.Length - 1]]; } return -1; } }[/spoiler]
А вот и для поиска по маске нашел:
[spoiler title="Поиск по маске"]public static class Searcher { private const string _q = "?"; private static int largest(ref string[][] list) { int size = 0; for (int i = 0; i < list.Length; i++) size = (list[i].Length > size) ? list[i].Length : size; return size; } public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard, bool onlyOne) { int sl = searchBytes.Length; if (sl < 1 || bytes.Length < sl) return new int[] { }; byte[] sbytes = new byte[sl]; for (int i = 0; i < sl; i++) if (searchBytes[i] != wildcard) if (!Byte.TryParse(searchBytes[i], System.Globalization.NumberStyles.HexNumber, null, out sbytes[i])) return new int[] { }; List<int> locs = new List<int>(); int n = bytes.Length - sl; int found = 0; for (var i = 0; i <= n; i++) { for (int j = 0; j < sl; j++) if (searchBytes[j] != wildcard) if (bytes[i + j] != sbytes[j]) goto nope; locs.Add(i); found++; if (onlyOne && found > 1) break; nope:; } return locs.ToArray(); } // (without wildcard) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, bool onlyOne) { return BinaryPatternSearch(ref bytes, searchBytes, _q, onlyOne); } // (return only 1) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard) { return BinaryPatternSearch(ref bytes, searchBytes, wildcard, true); } // (return only 1 and no wildcard) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes) { return BinaryPatternSearch(ref bytes, searchBytes, _q, true); } }[/spoiler]
Маска задается в строке, примерно так "BA ? 8D 0D ? ? E8 BA"
В одном проекте использовал еще вот такой класс:
public static class Search
{
/// <summary>
/// Finds the first occurrence of <paramref name="pattern"/> in a stream
/// </summary>
/// <param name="s">The input stream</param>
/// <param name="pattern">The pattern</param>
/// <returns>The index of the first occurrence, or -1 if the pattern has not been found</returns>
public static long IndexOf(Stream s, byte[] pattern)
{
// Prepare the bad character array is done once in a separate step
var badCharacters = MakeBadCharArray(pattern);
// We now repeatedly read the stream into a buffer and apply the Boyer-Moore-Horspool algorithm on the buffer until we get a match
var buffer = new byte[Math.Max(2 * pattern.Length, 4096)];
long offset = 0; // keep track of the offset in the input stream
while (true)
{
int dataLength;
if (offset == 0)
{
// the first time we fill the whole buffer
dataLength = s.Read(buffer, 0, buffer.Length);
}
else
{
// Later, copy the last pattern.Length bytes from the previous buffer to the start and fill up from the stream
// This is important so we can also find matches which are partly in the old buffer
Array.Copy(buffer, buffer.Length - pattern.Length, buffer, 0, pattern.Length);
dataLength = s.Read(buffer, pattern.Length, buffer.Length - pattern.Length) + pattern.Length;
}
var index = IndexOf(buffer, dataLength, pattern, badCharacters);
if (index >= 0)
return offset + index; // found!
if (dataLength < buffer.Length)
break;
offset += dataLength - pattern.Length;
}
return -1;
}
// --- Boyer-Moore-Horspool algorithm ---
// (Slightly modified code from
// https://stackoverflow.com/questions/16252518/boyer-moore-horspool-algorithm-for-all-matches-find-byte-array-inside-byte-arra)
// Prepare the bad character array is done once in a separate step:
private static int[] MakeBadCharArray(byte[] pattern)
{
var badCharacters = new int[256];
for (long i = 0; i < 256; ++i)
badCharacters[i] = pattern.Length;
for (var i = 0; i < pattern.Length - 1; ++i)
badCharacters[pattern[i]] = pattern.Length - 1 - i;
return badCharacters;
}
// Core of the BMH algorithm
private static int IndexOf(byte[] value, int valueLength, byte[] pattern, int[] badCharacters)
{
int index = 0;
while (index <= valueLength - pattern.Length)
{
for (var i = pattern.Length - 1; value[index + i] == pattern[i]; --i)
{
if (i == 0)
return index;
}
index += badCharacters[value[index + pattern.Length - 1]];
}
return -1;
}
}
А вот и для поиска по маске нашел:
public static class Searcher
{
private const string _q = "?";
private static int largest(ref string[][] list)
{
int size = 0;
for (int i = 0; i < list.Length; i++)
size = (list[i].Length > size) ? list[i].Length : size;
return size;
}
public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard, bool onlyOne)
{
int sl = searchBytes.Length;
if (sl < 1 || bytes.Length < sl)
return new int[] { };
byte[] sbytes = new byte[sl];
for (int i = 0; i < sl; i++)
if (searchBytes[i] != wildcard)
if (!Byte.TryParse(searchBytes[i], System.Globalization.NumberStyles.HexNumber, null, out sbytes[i]))
return new int[] { };
List<int> locs = new List<int>();
int n = bytes.Length - sl;
int found = 0;
for (var i = 0; i <= n; i++)
{
for (int j = 0; j < sl; j++)
if (searchBytes[j] != wildcard)
if (bytes[i + j] != sbytes[j])
goto nope;
locs.Add(i);
found++;
if (onlyOne && found > 1)
break;
nope:;
}
return locs.ToArray();
}
// (without wildcard)
public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, bool onlyOne)
{
return BinaryPatternSearch(ref bytes, searchBytes, _q, onlyOne);
}
// (return only 1)
public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard)
{
return BinaryPatternSearch(ref bytes, searchBytes, wildcard, true);
}
// (return only 1 and no wildcard)
public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes)
{
return BinaryPatternSearch(ref bytes, searchBytes, _q, true);
}
}
Маска задается в строке, примерно так "BA ? 8D 0D ? ? E8 BA"
Цитата: --- НЛО --- от 14.05.2022, 18:48Цитата: Adler от 14.05.2022, 11:36Добрый день.
Для чтения и записи используйте BinaryWriter и BinaryReader. Как ими пользоваться загуглите сами.
Для быстрого поиска бинарных сигнатур есть класс, ссылку на который дам позже, когда найду его исходник.Например, в бинарном файле есть такой набор байтов в такой последовательности:
08 00 00 00 67 6F 6C 64 3D 35 32 31
И заменить на такой:
0B 00 00 00 67 6F 6C 64 3D 39 39 39 39 39 39А вы тут точно ничего не путаете? Обычно в бинарных данных не допускается изменение длины. Можно ссылку на данный мануал, по которому вы это делаете?
P.S. Например вот. Или можете поискать другие реализации алгоритма Boyer-Moore.
Так же где-то был исходник поиска по маске, но пока не вспомню, где я его использовал, что бы найти в исходниках.Вот подробная инструкция
Число 08 это длинна. Дальше 3 нулевых байта и идёт значение gold=521
Я меняю на 0B 00 00 00 67 6F 6C 64 3D 39 39 39 39 39 39
Тоесть длинна 11. Дальше 3 нулевых байта не изменяется и gold=999999
Длинна gold=521 равняется 8 а gold=999999 уже 11 поэтому 1 байт с 8 нужно менять на 11 в шестнадцатеричном виде 0B
Цитата: Adler от 14.05.2022, 11:36Добрый день.
Для чтения и записи используйте BinaryWriter и BinaryReader. Как ими пользоваться загуглите сами.
Для быстрого поиска бинарных сигнатур есть класс, ссылку на который дам позже, когда найду его исходник.Например, в бинарном файле есть такой набор байтов в такой последовательности:
08 00 00 00 67 6F 6C 64 3D 35 32 31
И заменить на такой:
0B 00 00 00 67 6F 6C 64 3D 39 39 39 39 39 39А вы тут точно ничего не путаете? Обычно в бинарных данных не допускается изменение длины. Можно ссылку на данный мануал, по которому вы это делаете?
P.S. Например вот. Или можете поискать другие реализации алгоритма Boyer-Moore.
Так же где-то был исходник поиска по маске, но пока не вспомню, где я его использовал, что бы найти в исходниках.
Вот подробная инструкция
Число 08 это длинна. Дальше 3 нулевых байта и идёт значение gold=521
Я меняю на 0B 00 00 00 67 6F 6C 64 3D 39 39 39 39 39 39
Тоесть длинна 11. Дальше 3 нулевых байта не изменяется и gold=999999
Длинна gold=521 равняется 8 а gold=999999 уже 11 поэтому 1 байт с 8 нужно менять на 11 в шестнадцатеричном виде 0B
Цитата: --- НЛО --- от 15.05.2022, 10:33Цитата: Adler от 14.05.2022, 12:04В одном проекте использовал еще вот такой класс:
[spoiler title="Поиск в потоке первого вхождения"]public static class Search{/// <summary>/// Finds the first occurrence of <paramref name="pattern"/> in a stream/// </summary>/// <param name="s">The input stream</param>/// <param name="pattern">The pattern</param>/// <returns>The index of the first occurrence, or -1 if the pattern has not been found</returns>public static long IndexOf(Stream s, byte[] pattern){// Prepare the bad character array is done once in a separate stepvar badCharacters = MakeBadCharArray(pattern);// We now repeatedly read the stream into a buffer and apply the Boyer-Moore-Horspool algorithm on the buffer until we get a matchvar buffer = new byte[Math.Max(2 * pattern.Length, 4096)];long offset = 0; // keep track of the offset in the input streamwhile (true){int dataLength;if (offset == 0){// the first time we fill the whole bufferdataLength = s.Read(buffer, 0, buffer.Length);}else{// Later, copy the last pattern.Length bytes from the previous buffer to the start and fill up from the stream// This is important so we can also find matches which are partly in the old bufferArray.Copy(buffer, buffer.Length - pattern.Length, buffer, 0, pattern.Length);dataLength = s.Read(buffer, pattern.Length, buffer.Length - pattern.Length) + pattern.Length;}var index = IndexOf(buffer, dataLength, pattern, badCharacters);if (index >= 0)return offset + index; // found!if (dataLength < buffer.Length)break;offset += dataLength - pattern.Length;}return -1;}// --- Boyer-Moore-Horspool algorithm ---// (Slightly modified code from// https://stackoverflow.com/questions/16252518/boyer-moore-horspool-algorithm-for-all-matches-find-byte-array-inside-byte-arra)// Prepare the bad character array is done once in a separate step:private static int[] MakeBadCharArray(byte[] pattern){var badCharacters = new int[256];for (long i = 0; i < 256; ++i)badCharacters[i] = pattern.Length;for (var i = 0; i < pattern.Length - 1; ++i)badCharacters[pattern[i]] = pattern.Length - 1 - i;return badCharacters;}// Core of the BMH algorithmprivate static int IndexOf(byte[] value, int valueLength, byte[] pattern, int[] badCharacters){int index = 0;while (index <= valueLength - pattern.Length){for (var i = pattern.Length - 1; value[index + i] == pattern[i]; --i){if (i == 0)return index;}index += badCharacters[value[index + pattern.Length - 1]];}return -1;}}public static class Search { /// <summary> /// Finds the first occurrence of <paramref name="pattern"/> in a stream /// </summary> /// <param name="s">The input stream</param> /// <param name="pattern">The pattern</param> /// <returns>The index of the first occurrence, or -1 if the pattern has not been found</returns> public static long IndexOf(Stream s, byte[] pattern) { // Prepare the bad character array is done once in a separate step var badCharacters = MakeBadCharArray(pattern); // We now repeatedly read the stream into a buffer and apply the Boyer-Moore-Horspool algorithm on the buffer until we get a match var buffer = new byte[Math.Max(2 * pattern.Length, 4096)]; long offset = 0; // keep track of the offset in the input stream while (true) { int dataLength; if (offset == 0) { // the first time we fill the whole buffer dataLength = s.Read(buffer, 0, buffer.Length); } else { // Later, copy the last pattern.Length bytes from the previous buffer to the start and fill up from the stream // This is important so we can also find matches which are partly in the old buffer Array.Copy(buffer, buffer.Length - pattern.Length, buffer, 0, pattern.Length); dataLength = s.Read(buffer, pattern.Length, buffer.Length - pattern.Length) + pattern.Length; } var index = IndexOf(buffer, dataLength, pattern, badCharacters); if (index >= 0) return offset + index; // found! if (dataLength < buffer.Length) break; offset += dataLength - pattern.Length; } return -1; } // --- Boyer-Moore-Horspool algorithm --- // (Slightly modified code from // https://stackoverflow.com/questions/16252518/boyer-moore-horspool-algorithm-for-all-matches-find-byte-array-inside-byte-arra) // Prepare the bad character array is done once in a separate step: private static int[] MakeBadCharArray(byte[] pattern) { var badCharacters = new int[256]; for (long i = 0; i < 256; ++i) badCharacters[i] = pattern.Length; for (var i = 0; i < pattern.Length - 1; ++i) badCharacters[pattern[i]] = pattern.Length - 1 - i; return badCharacters; } // Core of the BMH algorithm private static int IndexOf(byte[] value, int valueLength, byte[] pattern, int[] badCharacters) { int index = 0; while (index <= valueLength - pattern.Length) { for (var i = pattern.Length - 1; value[index + i] == pattern[i]; --i) { if (i == 0) return index; } index += badCharacters[value[index + pattern.Length - 1]]; } return -1; } }public static class Search { /// <summary> /// Finds the first occurrence of <paramref name="pattern"/> in a stream /// </summary> /// <param name="s">The input stream</param> /// <param name="pattern">The pattern</param> /// <returns>The index of the first occurrence, or -1 if the pattern has not been found</returns> public static long IndexOf(Stream s, byte[] pattern) { // Prepare the bad character array is done once in a separate step var badCharacters = MakeBadCharArray(pattern); // We now repeatedly read the stream into a buffer and apply the Boyer-Moore-Horspool algorithm on the buffer until we get a match var buffer = new byte[Math.Max(2 * pattern.Length, 4096)]; long offset = 0; // keep track of the offset in the input stream while (true) { int dataLength; if (offset == 0) { // the first time we fill the whole buffer dataLength = s.Read(buffer, 0, buffer.Length); } else { // Later, copy the last pattern.Length bytes from the previous buffer to the start and fill up from the stream // This is important so we can also find matches which are partly in the old buffer Array.Copy(buffer, buffer.Length - pattern.Length, buffer, 0, pattern.Length); dataLength = s.Read(buffer, pattern.Length, buffer.Length - pattern.Length) + pattern.Length; } var index = IndexOf(buffer, dataLength, pattern, badCharacters); if (index >= 0) return offset + index; // found! if (dataLength < buffer.Length) break; offset += dataLength - pattern.Length; } return -1; } // --- Boyer-Moore-Horspool algorithm --- // (Slightly modified code from // https://stackoverflow.com/questions/16252518/boyer-moore-horspool-algorithm-for-all-matches-find-byte-array-inside-byte-arra) // Prepare the bad character array is done once in a separate step: private static int[] MakeBadCharArray(byte[] pattern) { var badCharacters = new int[256]; for (long i = 0; i < 256; ++i) badCharacters[i] = pattern.Length; for (var i = 0; i < pattern.Length - 1; ++i) badCharacters[pattern[i]] = pattern.Length - 1 - i; return badCharacters; } // Core of the BMH algorithm private static int IndexOf(byte[] value, int valueLength, byte[] pattern, int[] badCharacters) { int index = 0; while (index <= valueLength - pattern.Length) { for (var i = pattern.Length - 1; value[index + i] == pattern[i]; --i) { if (i == 0) return index; } index += badCharacters[value[index + pattern.Length - 1]]; } return -1; } }[/spoiler]
А вот и для поиска по маске нашел:
[spoiler title="Поиск по маске"]public static class Searcher{private const string _q = "?";private static int largest(ref string[][] list){int size = 0;for (int i = 0; i < list.Length; i++)size = (list[i].Length > size) ? list[i].Length : size;return size;}public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard, bool onlyOne){int sl = searchBytes.Length;if (sl < 1 || bytes.Length < sl)return new int[] { };byte[] sbytes = new byte[sl];for (int i = 0; i < sl; i++)if (searchBytes[i] != wildcard)if (!Byte.TryParse(searchBytes[i], System.Globalization.NumberStyles.HexNumber, null, out sbytes[i]))return new int[] { };List<int> locs = new List<int>();int n = bytes.Length - sl;int found = 0;for (var i = 0; i <= n; i++){for (int j = 0; j < sl; j++)if (searchBytes[j] != wildcard)if (bytes[i + j] != sbytes[j])goto nope;locs.Add(i);found++;if (onlyOne && found > 1)break;nope:;}return locs.ToArray();}// (without wildcard)public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, bool onlyOne){return BinaryPatternSearch(ref bytes, searchBytes, _q, onlyOne);}// (return only 1)public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard){return BinaryPatternSearch(ref bytes, searchBytes, wildcard, true);}// (return only 1 and no wildcard)public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes){return BinaryPatternSearch(ref bytes, searchBytes, _q, true);}}public static class Searcher { private const string _q = "?"; private static int largest(ref string[][] list) { int size = 0; for (int i = 0; i < list.Length; i++) size = (list[i].Length > size) ? list[i].Length : size; return size; } public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard, bool onlyOne) { int sl = searchBytes.Length; if (sl < 1 || bytes.Length < sl) return new int[] { }; byte[] sbytes = new byte[sl]; for (int i = 0; i < sl; i++) if (searchBytes[i] != wildcard) if (!Byte.TryParse(searchBytes[i], System.Globalization.NumberStyles.HexNumber, null, out sbytes[i])) return new int[] { }; List<int> locs = new List<int>(); int n = bytes.Length - sl; int found = 0; for (var i = 0; i <= n; i++) { for (int j = 0; j < sl; j++) if (searchBytes[j] != wildcard) if (bytes[i + j] != sbytes[j]) goto nope; locs.Add(i); found++; if (onlyOne && found > 1) break; nope:; } return locs.ToArray(); } // (without wildcard) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, bool onlyOne) { return BinaryPatternSearch(ref bytes, searchBytes, _q, onlyOne); } // (return only 1) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard) { return BinaryPatternSearch(ref bytes, searchBytes, wildcard, true); } // (return only 1 and no wildcard) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes) { return BinaryPatternSearch(ref bytes, searchBytes, _q, true); } }public static class Searcher { private const string _q = "?"; private static int largest(ref string[][] list) { int size = 0; for (int i = 0; i < list.Length; i++) size = (list[i].Length > size) ? list[i].Length : size; return size; } public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard, bool onlyOne) { int sl = searchBytes.Length; if (sl < 1 || bytes.Length < sl) return new int[] { }; byte[] sbytes = new byte[sl]; for (int i = 0; i < sl; i++) if (searchBytes[i] != wildcard) if (!Byte.TryParse(searchBytes[i], System.Globalization.NumberStyles.HexNumber, null, out sbytes[i])) return new int[] { }; List<int> locs = new List<int>(); int n = bytes.Length - sl; int found = 0; for (var i = 0; i <= n; i++) { for (int j = 0; j < sl; j++) if (searchBytes[j] != wildcard) if (bytes[i + j] != sbytes[j]) goto nope; locs.Add(i); found++; if (onlyOne && found > 1) break; nope:; } return locs.ToArray(); } // (without wildcard) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, bool onlyOne) { return BinaryPatternSearch(ref bytes, searchBytes, _q, onlyOne); } // (return only 1) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard) { return BinaryPatternSearch(ref bytes, searchBytes, wildcard, true); } // (return only 1 and no wildcard) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes) { return BinaryPatternSearch(ref bytes, searchBytes, _q, true); } }[/spoiler]
Маска задается в строке, примерно так "BA ? 8D 0D ? ? E8 BA"Не понял как замену делать. К слову вот что мне необходимо автоматизировать:
Цитата: Adler от 14.05.2022, 12:04В одном проекте использовал еще вот такой класс:
Поиск в потоке первого вхожденияpublic static class Search{/// <summary>/// Finds the first occurrence of <paramref name="pattern"/> in a stream/// </summary>/// <param name="s">The input stream</param>/// <param name="pattern">The pattern</param>/// <returns>The index of the first occurrence, or -1 if the pattern has not been found</returns>public static long IndexOf(Stream s, byte[] pattern){// Prepare the bad character array is done once in a separate stepvar badCharacters = MakeBadCharArray(pattern);// We now repeatedly read the stream into a buffer and apply the Boyer-Moore-Horspool algorithm on the buffer until we get a matchvar buffer = new byte[Math.Max(2 * pattern.Length, 4096)];long offset = 0; // keep track of the offset in the input streamwhile (true){int dataLength;if (offset == 0){// the first time we fill the whole bufferdataLength = s.Read(buffer, 0, buffer.Length);}else{// Later, copy the last pattern.Length bytes from the previous buffer to the start and fill up from the stream// This is important so we can also find matches which are partly in the old bufferArray.Copy(buffer, buffer.Length - pattern.Length, buffer, 0, pattern.Length);dataLength = s.Read(buffer, pattern.Length, buffer.Length - pattern.Length) + pattern.Length;}var index = IndexOf(buffer, dataLength, pattern, badCharacters);if (index >= 0)return offset + index; // found!if (dataLength < buffer.Length)break;offset += dataLength - pattern.Length;}return -1;}// --- Boyer-Moore-Horspool algorithm ---// (Slightly modified code from// Prepare the bad character array is done once in a separate step:private static int[] MakeBadCharArray(byte[] pattern){var badCharacters = new int[256];for (long i = 0; i < 256; ++i)badCharacters[i] = pattern.Length;for (var i = 0; i < pattern.Length - 1; ++i)badCharacters[pattern[i]] = pattern.Length - 1 - i;return badCharacters;}// Core of the BMH algorithmprivate static int IndexOf(byte[] value, int valueLength, byte[] pattern, int[] badCharacters){int index = 0;while (index <= valueLength - pattern.Length){for (var i = pattern.Length - 1; value[index + i] == pattern[i]; --i){if (i == 0)return index;}index += badCharacters[value[index + pattern.Length - 1]];}return -1;}}public static class Search { /// <summary> /// Finds the first occurrence of <paramref name="pattern"/> in a stream /// </summary> /// <param name="s">The input stream</param> /// <param name="pattern">The pattern</param> /// <returns>The index of the first occurrence, or -1 if the pattern has not been found</returns> public static long IndexOf(Stream s, byte[] pattern) { // Prepare the bad character array is done once in a separate step var badCharacters = MakeBadCharArray(pattern); // We now repeatedly read the stream into a buffer and apply the Boyer-Moore-Horspool algorithm on the buffer until we get a match var buffer = new byte[Math.Max(2 * pattern.Length, 4096)]; long offset = 0; // keep track of the offset in the input stream while (true) { int dataLength; if (offset == 0) { // the first time we fill the whole buffer dataLength = s.Read(buffer, 0, buffer.Length); } else { // Later, copy the last pattern.Length bytes from the previous buffer to the start and fill up from the stream // This is important so we can also find matches which are partly in the old buffer Array.Copy(buffer, buffer.Length - pattern.Length, buffer, 0, pattern.Length); dataLength = s.Read(buffer, pattern.Length, buffer.Length - pattern.Length) + pattern.Length; } var index = IndexOf(buffer, dataLength, pattern, badCharacters); if (index >= 0) return offset + index; // found! if (dataLength < buffer.Length) break; offset += dataLength - pattern.Length; } return -1; } // --- Boyer-Moore-Horspool algorithm --- // (Slightly modified code from // https://stackoverflow.com/questions/16252518/boyer-moore-horspool-algorithm-for-all-matches-find-byte-array-inside-byte-arra) // Prepare the bad character array is done once in a separate step: private static int[] MakeBadCharArray(byte[] pattern) { var badCharacters = new int[256]; for (long i = 0; i < 256; ++i) badCharacters[i] = pattern.Length; for (var i = 0; i < pattern.Length - 1; ++i) badCharacters[pattern[i]] = pattern.Length - 1 - i; return badCharacters; } // Core of the BMH algorithm private static int IndexOf(byte[] value, int valueLength, byte[] pattern, int[] badCharacters) { int index = 0; while (index <= valueLength - pattern.Length) { for (var i = pattern.Length - 1; value[index + i] == pattern[i]; --i) { if (i == 0) return index; } index += badCharacters[value[index + pattern.Length - 1]]; } return -1; } }public static class Search { /// <summary> /// Finds the first occurrence of <paramref name="pattern"/> in a stream /// </summary> /// <param name="s">The input stream</param> /// <param name="pattern">The pattern</param> /// <returns>The index of the first occurrence, or -1 if the pattern has not been found</returns> public static long IndexOf(Stream s, byte[] pattern) { // Prepare the bad character array is done once in a separate step var badCharacters = MakeBadCharArray(pattern); // We now repeatedly read the stream into a buffer and apply the Boyer-Moore-Horspool algorithm on the buffer until we get a match var buffer = new byte[Math.Max(2 * pattern.Length, 4096)]; long offset = 0; // keep track of the offset in the input stream while (true) { int dataLength; if (offset == 0) { // the first time we fill the whole buffer dataLength = s.Read(buffer, 0, buffer.Length); } else { // Later, copy the last pattern.Length bytes from the previous buffer to the start and fill up from the stream // This is important so we can also find matches which are partly in the old buffer Array.Copy(buffer, buffer.Length - pattern.Length, buffer, 0, pattern.Length); dataLength = s.Read(buffer, pattern.Length, buffer.Length - pattern.Length) + pattern.Length; } var index = IndexOf(buffer, dataLength, pattern, badCharacters); if (index >= 0) return offset + index; // found! if (dataLength < buffer.Length) break; offset += dataLength - pattern.Length; } return -1; } // --- Boyer-Moore-Horspool algorithm --- // (Slightly modified code from // https://stackoverflow.com/questions/16252518/boyer-moore-horspool-algorithm-for-all-matches-find-byte-array-inside-byte-arra) // Prepare the bad character array is done once in a separate step: private static int[] MakeBadCharArray(byte[] pattern) { var badCharacters = new int[256]; for (long i = 0; i < 256; ++i) badCharacters[i] = pattern.Length; for (var i = 0; i < pattern.Length - 1; ++i) badCharacters[pattern[i]] = pattern.Length - 1 - i; return badCharacters; } // Core of the BMH algorithm private static int IndexOf(byte[] value, int valueLength, byte[] pattern, int[] badCharacters) { int index = 0; while (index <= valueLength - pattern.Length) { for (var i = pattern.Length - 1; value[index + i] == pattern[i]; --i) { if (i == 0) return index; } index += badCharacters[value[index + pattern.Length - 1]]; } return -1; } }
А вот и для поиска по маске нашел:
Поиск по маскеpublic static class Searcher{private const string _q = "?";private static int largest(ref string[][] list){int size = 0;for (int i = 0; i < list.Length; i++)size = (list[i].Length > size) ? list[i].Length : size;return size;}public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard, bool onlyOne){int sl = searchBytes.Length;if (sl < 1 || bytes.Length < sl)return new int[] { };byte[] sbytes = new byte[sl];for (int i = 0; i < sl; i++)if (searchBytes[i] != wildcard)if (!Byte.TryParse(searchBytes[i], System.Globalization.NumberStyles.HexNumber, null, out sbytes[i]))return new int[] { };List<int> locs = new List<int>();int n = bytes.Length - sl;int found = 0;for (var i = 0; i <= n; i++){for (int j = 0; j < sl; j++)if (searchBytes[j] != wildcard)if (bytes[i + j] != sbytes[j])goto nope;locs.Add(i);found++;if (onlyOne && found > 1)break;nope:;}return locs.ToArray();}// (without wildcard)public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, bool onlyOne){return BinaryPatternSearch(ref bytes, searchBytes, _q, onlyOne);}// (return only 1)public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard){return BinaryPatternSearch(ref bytes, searchBytes, wildcard, true);}// (return only 1 and no wildcard)public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes){return BinaryPatternSearch(ref bytes, searchBytes, _q, true);}}public static class Searcher { private const string _q = "?"; private static int largest(ref string[][] list) { int size = 0; for (int i = 0; i < list.Length; i++) size = (list[i].Length > size) ? list[i].Length : size; return size; } public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard, bool onlyOne) { int sl = searchBytes.Length; if (sl < 1 || bytes.Length < sl) return new int[] { }; byte[] sbytes = new byte[sl]; for (int i = 0; i < sl; i++) if (searchBytes[i] != wildcard) if (!Byte.TryParse(searchBytes[i], System.Globalization.NumberStyles.HexNumber, null, out sbytes[i])) return new int[] { }; List<int> locs = new List<int>(); int n = bytes.Length - sl; int found = 0; for (var i = 0; i <= n; i++) { for (int j = 0; j < sl; j++) if (searchBytes[j] != wildcard) if (bytes[i + j] != sbytes[j]) goto nope; locs.Add(i); found++; if (onlyOne && found > 1) break; nope:; } return locs.ToArray(); } // (without wildcard) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, bool onlyOne) { return BinaryPatternSearch(ref bytes, searchBytes, _q, onlyOne); } // (return only 1) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard) { return BinaryPatternSearch(ref bytes, searchBytes, wildcard, true); } // (return only 1 and no wildcard) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes) { return BinaryPatternSearch(ref bytes, searchBytes, _q, true); } }public static class Searcher { private const string _q = "?"; private static int largest(ref string[][] list) { int size = 0; for (int i = 0; i < list.Length; i++) size = (list[i].Length > size) ? list[i].Length : size; return size; } public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard, bool onlyOne) { int sl = searchBytes.Length; if (sl < 1 || bytes.Length < sl) return new int[] { }; byte[] sbytes = new byte[sl]; for (int i = 0; i < sl; i++) if (searchBytes[i] != wildcard) if (!Byte.TryParse(searchBytes[i], System.Globalization.NumberStyles.HexNumber, null, out sbytes[i])) return new int[] { }; List<int> locs = new List<int>(); int n = bytes.Length - sl; int found = 0; for (var i = 0; i <= n; i++) { for (int j = 0; j < sl; j++) if (searchBytes[j] != wildcard) if (bytes[i + j] != sbytes[j]) goto nope; locs.Add(i); found++; if (onlyOne && found > 1) break; nope:; } return locs.ToArray(); } // (without wildcard) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, bool onlyOne) { return BinaryPatternSearch(ref bytes, searchBytes, _q, onlyOne); } // (return only 1) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes, string wildcard) { return BinaryPatternSearch(ref bytes, searchBytes, wildcard, true); } // (return only 1 and no wildcard) public static int[] BinaryPatternSearch(ref byte[] bytes, string[] searchBytes) { return BinaryPatternSearch(ref bytes, searchBytes, _q, true); } }
Маска задается в строке, примерно так "BA ? 8D 0D ? ? E8 BA"
Не понял как замену делать. К слову вот что мне необходимо автоматизировать:
Цитата: --- НЛО --- от 15.05.2022, 15:16Много перерыл сайтов. Не нашел как менять набор байтов на больший но подумал а что если преоброзовать набор байтов строку и желательно так чтоб не испортил данные. Короче нашел и написал:
[spoiler title="Мой код"]private static byte[] getBytes(TypeData typeData, int num) { var bytesString = ""; switch (typeData) { case TypeData.tdGold: bytesString = "gold=" + num.ToString(); break; case TypeData.tdGem: bytesString = "gem=" + num.ToString(); break; case TypeData.tdCIB: bytesString = "cib=" + num.ToString(); break; default: return new byte[0]; } var byteslength = Convert.ToByte(bytesString.Length); var retBytes = new byte[4 + bytesString.Length]; retBytes[0] = byteslength; retBytes[3] = retBytes[2] = retBytes[1] = 0; for (var i = 4; i < retBytes.Length; i++) { retBytes[i] = Convert.ToByte(bytesString[i - 4]); } return retBytes; } private static byte[] FromHex(string hex) { hex = hex.Replace("-", ""); byte[] raw = new byte[hex.Length / 2]; for (int i = 0; i < raw.Length; i++) { raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); } return raw; } public static void EditGold(string fileName, int searchGold, int newGold) { var searchBytesGold = getBytes(TypeData.tdGold, searchGold); var newBytesGold = getBytes(TypeData.tdGold, newGold); var dataFile = BitConverter.ToString(File.ReadAllBytes(fileName)); dataFile = dataFile.Replace(BitConverter.ToString(searchBytesGold), BitConverter.ToString(newBytesGold)); var dataFileSave = FromHex(dataFile); File.Copy(fileName, fileName+ ".back"); File.WriteAllBytes(fileName, dataFileSave); }[/spoiler]
И как итог всё работает. Правда сам Replace не очень хорошо подходит так как меняет все вхождения а менять нужно только 1 раз а не везде. Такую ситуацию тоже нужно предусмотреть но именно сохранение не ломается и загружается.
Много перерыл сайтов. Не нашел как менять набор байтов на больший но подумал а что если преоброзовать набор байтов строку и желательно так чтоб не испортил данные. Короче нашел и написал:
private static byte[] getBytes(TypeData typeData, int num)
{
var bytesString = "";
switch (typeData)
{
case TypeData.tdGold: bytesString = "gold=" + num.ToString();
break;
case TypeData.tdGem: bytesString = "gem=" + num.ToString();
break;
case TypeData.tdCIB:
bytesString = "cib=" + num.ToString();
break;
default: return new byte[0];
}
var byteslength = Convert.ToByte(bytesString.Length);
var retBytes = new byte[4 + bytesString.Length];
retBytes[0] = byteslength;
retBytes[3] = retBytes[2] = retBytes[1] = 0;
for (var i = 4; i < retBytes.Length; i++)
{
retBytes[i] = Convert.ToByte(bytesString[i - 4]);
}
return retBytes;
}
private static byte[] FromHex(string hex)
{
hex = hex.Replace("-", "");
byte[] raw = new byte[hex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return raw;
}
public static void EditGold(string fileName, int searchGold, int newGold)
{
var searchBytesGold = getBytes(TypeData.tdGold, searchGold);
var newBytesGold = getBytes(TypeData.tdGold, newGold);
var dataFile = BitConverter.ToString(File.ReadAllBytes(fileName));
dataFile = dataFile.Replace(BitConverter.ToString(searchBytesGold), BitConverter.ToString(newBytesGold));
var dataFileSave = FromHex(dataFile);
File.Copy(fileName, fileName+ ".back");
File.WriteAllBytes(fileName, dataFileSave);
}
И как итог всё работает. Правда сам Replace не очень хорошо подходит так как меняет все вхождения а менять нужно только 1 раз а не везде. Такую ситуацию тоже нужно предусмотреть но именно сохранение не ломается и загружается.