View Sidebar
Яндекс.Метрика
 
Программный «патч» на C#

Программный «патч» на C#

29.05.2016 15:080 comments

Недавно понадобилось мне изменить несколько байт в одной dll библиотеке. HEX редактором это сделать просто, но каждый раз править руками байты в dll после автообновления программы не захотелось. Пришлось написать простой патчер на C#, который меняет байты в бинарном файле. Делюсь кодом патчера (крекера) на C#.

binary-patcher

Постановка задачи патча файлов

Есть исходный файл test.dll (его можно скачать в архиве в конце статьи). Пусть, начиная со смещения 0x000000d6 (или с 214 байта от начала файла), требуется изменить эти 4 байта «0d 03 a4 e0» на эти «a0 b1 c2 d3».

patch-с-sharp-1

На рисунке эти байты выделены красной рамкой.

Можно конечно не писать свой код на C#, а сгенерировать патч специальной утилитой для создания патчей и креков, но быстро найти чего-то подходящего мне не удалось.

Удобное изменение слов в бинарном файле на C#

По условию будем считать, что нужные нам байты НЕобязательно начинаются со смещения 214, а могут «плавать» по файлу в зависимости от версии dll библиотеки, но ближайшее их окружение всегда будет постоянным.

Давайте выберем кусочек из нашего файла побольше. На рисунке кусочек выделен оранжевой рамкой, его мы будем использовать для поиска нужной позиции в файле.

patch-с-sharp-2

Как только мы найдем позицию этого куска «30 20 40 81 c1 c1 0d 03 a4 e0 e0 80 81 03 36 84», считай больше чем полдела уже сделано.

Кода я писал код, мне захотелось, чтобы строку поиска можно было указывать в символьном представлении шестнадцатеричных кодов. Так, как нам отображает любой HEX-редактор («30 20 40 81 c1 c1 0d 03 a4 e0 e0 80 81 03 36 84»). И эту строку можно было бы прям скопировать из редактора и вставить в код программы-патчера.

И для изменения байтов тоже бы и хотелось указать сами байты на которые меняем в виде символьной шестнадцатеричной строки («a0 b1 c2 d3»).

Разбор кода изменения байтов на C#

После открытия файла для чтения и записи, функцией SearchPos находим смещение, по которому находиться «30 20 40 81 c1 c1 0d 03 a4 e0 e0 80 81 03 36 84» и запоминаем это смещение в переменную pos.


var fi = @"C:\test.dll";
var fs = new FileStream(fi, FileMode.Open, FileAccess.ReadWrite);

fs.Seek(0, SeekOrigin.Begin);

var str = "30 20 40 81 c1 c1 0d 03 a4 e0 e0 80 81 03 36 84";

var pos = SearchPos(fs, str);

if (pos != -1)
{
fs.Position = pos + 6;
str = "a0 b1 c2 d3";
WriteBytes(fs, str);
Console.WriteLine("Файл изменен успешно");
}
else
{
Console.WriteLine("Изменить файл не удалось");
}

fs.Close();
Console.ReadKey();

Если указанную последовательность байт найти удалось, то начина со смещения pos+6 процедурой WriteBytes записываем последовательность байт «a0 b1 c2 d3» в файл. Затем закрываем файл.

Исполнив этот код, наши байты изменятся и будет как на рисунке.

patch-с-sharp-3

Реализация вспомогательных процедур функций

Как вы понимаете, SearchPos и WriteBytes это не стандартные функции C#, а реализованные мной.
В совою очередь, эти функции вызывают другие совсем простые.

Например, LitToByte переводит шестнадцатеричный символ в число.

//Переводит шестнадцатиричный символ в число byte
static byte LitToByte(char s)
{
const string z = "0123456789abcdef";
return (byte) z.IndexOf(s);
}

Если передать в неё «1» или «2», то на выходе получим соответственно число 1 или 2. Если передать «a» или «b», то получим 10 или 11 соответственно.

Функция StrToByte переводит уже строку из двух символов шестнадцатеричного представления в десятичное. Т.е. «a1» даст на выходе число 161.

 
//Переводит шестнадцатиричное символьное представление в число byte
 static byte StrToByte(string s)
 {
 return (byte)(LitToByte(s[0]) * 16 + LitToByte(s[1]));
 }

Кто не понял, воспользуйтесь стандартным калькулятором Windows в режиме «Программист» )))

Функция StrToArrByte из строки «a0 b1 c2 d3» сделает массив байт: «160, 177, 194, 211».

//Преобразует строку с последовательностью символьных шестнадцатиричных предсавлений в массив байтов
private static byte[] StrToArrByte(string str)
{
str = str.ToLower(); //Приводим строку к нижнему регистру

const char delimiter = ' '; //Разделитель пробел
var arr = str.Split(delimiter); //Разбиваем строку в массив по 2 символа

long length = arr.Length;
var rArr = new byte[length];

for (long i = 0; i < length; i++)
{
rArr[i] = StrToByte(arr[i]); //Переводим шестнадцатиричное символьное представление в число
}

return rArr;
}

Осталась еще тройка функций для осуществления поиска в бинарном файле и записи в файл из массива. Описывать их не буду, просто привожу ниже.

Ну вот и всё!

Скачать весь код и тестовый dll тут в архиве zip

Да, не забудь оставить свой комментарий…

Добавить комментарий


css.php