• XSS.stack #1 – первый литературный журнал от юзеров форума

Подскажите исходник билдера для своей программы на dnlib?

McCoder

RAID-массив
Забанен
Регистрация
23.06.2021
Сообщения
62
Реакции
-1
Пожалуйста, обратите внимание, что пользователь заблокирован
шапка.
С CodeDom работать умею, но он меня не устраивает, тк там .NET 2.0-4.0 поддерживается.
Пытался сам разобраться с dnlib(изменение параметров на свои) как в CodeDom, и не выходит :(
Подскажите как это можно сделать? или подкиньте исходник. Буду очень сильно благодарен =)
 
Билдер:
C#:
using System;         

//Подключаем dnlib

using dnlib.DotNet;   
using dnlib.DotNet.Emit;

namespace Patcher
{
    class cMain
    {
        static void Main(string[] args)
        {
            /*
                Для начала загрузим .exe который будем патчить.

                В ModuleDefMD.Load можно передать:
                    1.Путь к .exe
                    2.Бинарник(byte[] самого .exe)
             */
            ModuleDefMD mdModule = ModuleDefMD.Load("Stub.exe");   

            //Перебираем все классы которые есть в .exe
            foreach(TypeDef tdType in mdModule.Types)
            {
                Console.WriteLine(tdType.Name);
                //Находим класс конфига(замени на свой)
                if(tdType.Name == "cConfig")
                {
                    //Перебираем все методы в классе
                    foreach(MethodDef mdMethod in tdType.Methods)
                    {
                        //Проверяем, является ли метод конструктором класса cConfig
                        if(mdMethod.Name == ".cctor")
                        {
                            Console.WriteLine("sss");
                            //Перебираем все инструкции в конструкторе
                            for(int i = 0; i < mdMethod.Body.Instructions.Count; i++)
                            {
                                //Если идет объявление строки
                                if(mdMethod.Body.Instructions[i].OpCode == OpCodes.Ldstr && mdMethod.Body.Instructions[i].Operand.ToString() == "[MESSAGE_FOR_PATCHER]")
                                {
                                    mdMethod.Body.Instructions[i].Operand = "Patched!!!";
                                }
                            }

                            break; //Выходим
                        }
                    }
                }
            }

            mdModule.Write("patched[.]exe");
            Console.ReadLine();

        }
    }
}
Стаб:
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MsgBoxStub
{
    //Обрати внимание, данный класс используется билдером!!!
    class cConfig
    {
        public static string sMsg = "[MESSAGE_FOR_PATCHER]";   //По строке [MESSAGE_FOR_PATCHER] идентифицируем что будем патчить
    }
    class cMain
    {
        public static void Main()
        {
            System.Windows.Forms.MessageBox.Show(cConfig.sMsg);
        }
    }
}

И немного теории:
При объявлении глобальной переменной, ее значение находится в <имя класса>..cctor
И выглядит это определение вот так
1624805989262.png

Имеется опкод ldstr, и его параметр "[MESSAGE_FOR_PATCHER]".По этому параметру мы определяем, что патчим.Можно написать , например, [LINK] и [TOKEN] и сделать доп. if в билдере P.S: Писал на скорую руку, если будут баги/непонятки с твоей стороны - говори:)
 
- Чуть Дополню)
[!] Информацию по библиотеки dnlib можно посмотреть тут: https://github.com/0xd4d/dnlib
[!] Установить можно через nuget или скачать через любой другой источник.

Не забываем использовать using при загрузке файла (нужен для освобождения самого файла после использования).
Пример:
C#:
public static readonly string CurrDir = Environment.CurrentDirectory; // Путь до текущей директории (папки)
using var module = ModuleDefMD.Load(Path.Combine(CurrDir, "Stub.exe")); // Версия C# 8.0+
//using (var module = ModuleDefMD.Load(Path.Combine(CurrDir, "Stub.exe")) {...}; // Версия C# -7.3

Чтобы не было лишних ошибок типо:
Error calculating max stack value. If the method's obfuscated, set CilBody.KeepOldMaxStack or MetadataOptions.Flags (KeepOldMaxStack, global option) to ignore this error
Перевод:
Ошибка при вычислении максимального значения стека. Если метод запутан, установите CilBody.KeepOldMaxStack или MetadataOptions.Flags (KeepOldMaxStack, глобальный параметр), чтобы игнорировать эту ошибку.
Используем код ниже, чтобы обойти эту ошибку
C#:
var writerOptions = new ModuleWriterOptions(module);
writerOptions.MetadataOptions.Flags |= dnlib.DotNet.Writer.MetadataFlags.KeepOldMaxStack;
module.Write(path, writerOptions);

Для упрощений инструкций нужна оптимизация ( чтобы во время записи изменённого файла не было ошибок в виде:
dnlib.dotnet.writer.modulewriterexception: target instruction far away short branch. use long branch or call cilbody.simplifybranches() , cilbody.optimizebranches()
Используем следующее:
C#:
for (int i = 0; i < mdMethod.Body.Instructions.Count; i++)
{
   //Если идет объявление строки
   if (mdMethod.Body.Instructions[i].OpCode == OpCodes.Ldstr && mdMethod.Body.Instructions[i].Operand.ToString() == "[MESSAGE_FOR_PATCHER]")
   {
      mdMethod.Body.Instructions[i].Operand = "Patched!!!";
   }
   // Оптимизация и упрощение инструкций
   mdMethod.Body.Instructions.SimplifyBranches(); // Упрощение инструкций(br.s -> br)
   mdMethod.Body.Instructions.OptimizeBranches(); // Оптимизация всех условий,  "впаивание" наших IL-инструкций в тело метода.
   // mdMethod.Body.Instructions.OptimizeMacros(); // Оптимизация макросов  (используется, если используется SimplifyMacros )
   mdMethod.Body.Instructions.UpdateInstructionOffsets(); // Обновляет все смещения инструкций
 }

Ещё можно так:

C#:
// Загружаем файл
using var module = ModuleDefMD.Load(Path.Combine(CurrDir, "Stub.exe"));
// Перебираем все классы
foreach (TypeDef type in module.GetTypes())
{
   // Перебираем все методы
   foreach (MethodDef method in type.Methods)
   {
      // Перебираем все инструкции
      foreach (Instruction inst in method.Body.Instructions)
      {
        // Ищем строку с названием [MESSAGE_FOR_PATCHER] - ищет по всем классам и если находит совпадения...
        if (inst.OpCode == OpCodes.Ldstr && inst.Operand.ToString().Contains("[MESSAGE_FOR_PATCHER]"))
        {
           inst.Operand = "This_is_my_Text"; // Заменяет строку на нашу
        }
        // Оптимизация и упрощение инструкций
        method.Body.Instructions.SimplifyBranches(); // Упрощение инструкций(br.s -> br)
        method.Body.Instructions.OptimizeBranches(); // Оптимизация всех условий,  "впаивание" наших IL-инструкций в тело метода.
        method.Body.Instructions.UpdateInstructionOffsets(); // Обновляет все смещения инструкций
      }
    }
  }
  module.Write(Path.Combine(CurrDir, "patched[.]exe")); // Сохраняем изменённый билд файл
}

P.S: Если где-то ошибся - исправьте)
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Кстати есть еще https://github.com/jbevain/cecil - в принципе тоже самое, какие-то интерфейсы проще в dnlib, какие-то проще в Mono.Cecil.
 
Кстати есть еще https://github.com/jbevain/cecil - в принципе тоже самое, какие-то интерфейсы проще в dnlib, какие-то проще в Mono.Cecil.
Ты сам в обзоре StormKitty говорил, что dnlib тебе больше нравится:rolleyes:


Ну а в целом, Mono.Cecil чаще используют, тк много кто копипастил из BlackNet-а
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Ты сам в обзоре StormKitty говорил, что dnlib тебе больше нравится:rolleyes:


Ну а в целом, Mono.Cecil чаще используют, тк много кто копипастил из ********-а
Мону тоже пробовал. Ну хз.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Билдер:
C#:
using System;        

//Подключаем dnlib

using dnlib.DotNet;  
using dnlib.DotNet.Emit;

namespace Patcher
{
    class cMain
    {
        static void Main(string[] args)
        {
            /*
                Для начала загрузим .exe который будем патчить.

                В ModuleDefMD.Load можно передать:
                    1.Путь к .exe
                    2.Бинарник(byte[] самого .exe)
             */
            ModuleDefMD mdModule = ModuleDefMD.Load("Stub.exe");  

            //Перебираем все классы которые есть в .exe
            foreach(TypeDef tdType in mdModule.Types)
            {
                Console.WriteLine(tdType.Name);
                //Находим класс конфига(замени на свой)
                if(tdType.Name == "cConfig")
                {
                    //Перебираем все методы в классе
                    foreach(MethodDef mdMethod in tdType.Methods)
                    {
                        //Проверяем, является ли метод конструктором класса cConfig
                        if(mdMethod.Name == ".cctor")
                        {
                            Console.WriteLine("sss");
                            //Перебираем все инструкции в конструкторе
                            for(int i = 0; i < mdMethod.Body.Instructions.Count; i++)
                            {
                                //Если идет объявление строки
                                if(mdMethod.Body.Instructions[i].OpCode == OpCodes.Ldstr && mdMethod.Body.Instructions[i].Operand.ToString() == "[MESSAGE_FOR_PATCHER]")
                                {
                                    mdMethod.Body.Instructions[i].Operand = "Patched!!!";
                                }
                            }

                            break; //Выходим
                        }
                    }
                }
            }

            mdModule.Write("patched[.]exe");
            Console.ReadLine();

        }
    }
}
Стаб:
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MsgBoxStub
{
    //Обрати внимание, данный класс используется билдером!!!
    class cConfig
    {
        public static string sMsg = "[MESSAGE_FOR_PATCHER]";   //По строке [MESSAGE_FOR_PATCHER] идентифицируем что будем патчить
    }
    class cMain
    {
        public static void Main()
        {
            System.Windows.Forms.MessageBox.Show(cConfig.sMsg);
        }
    }
}

И немного теории:
При объявлении глобальной переменной, ее значение находится в <имя класса>..cctor
И выглядит это определение вот так
Посмотреть вложение 24001
Имеется опкод ldstr, и его параметр "[MESSAGE_FOR_PATCHER]".По этому параметру мы определяем, что патчим.Можно написать , например, [LINK] и [TOKEN] и сделать доп. if в билдере P.S: Писал на скорую руку, если будут баги/непонятки с твоей стороны - говори:)
подскажи плс. Где происходит замена твоего параметра на, тот который нужен? Не понимаю где происходит замена переменной?
1624875459733.png
 
Пожалуйста, обратите внимание, что пользователь заблокирован
подскажи плс. Где происходит замена твоего параметра на, тот который нужен? Не понимаю где происходит замена переменной? Посмотреть вложение 24032
попытался так, и это так не работает( Вот не могу понять где происходит замена?
1624875602852.png

Пытаюсь через replace и не выходит.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
- Чуть Дополню)
[!] Информацию по библиотеки dnlib можно посмотреть тут: https://github.com/0xd4d/dnlib
[!] Установить можно через nuget или скачать через любой другой источник.

Не забываем использовать using при загрузке файла (нужен для освобождения самого файла после использования).
Пример:
C#:
public static readonly string CurrDir = Environment.CurrentDirectory; // Путь до текущей директории (папки)
using var module = ModuleDefMD.Load(Path.Combine(CurrDir, "Stub.exe")); // Версия C# 8.0+
//using (var module = ModuleDefMD.Load(Path.Combine(CurrDir, "Stub.exe")) {...}; // Версия C# -7.3

Чтобы не было лишних ошибок типо:

Перевод:

Используем код ниже, чтобы обойти эту ошибку
C#:
var writerOptions = new ModuleWriterOptions(module);
writerOptions.MetadataOptions.Flags |= dnlib.DotNet.Writer.MetadataFlags.KeepOldMaxStack;
module.Write(path, writerOptions);

Для упрощений инструкций нужна оптимизация ( чтобы во время записи изменённого файла не было ошибок в виде:

Используем следующее:
C#:
for (int i = 0; i < mdMethod.Body.Instructions.Count; i++)
{
   //Если идет объявление строки
   if (mdMethod.Body.Instructions[i].OpCode == OpCodes.Ldstr && mdMethod.Body.Instructions[i].Operand.ToString() == "[MESSAGE_FOR_PATCHER]")
   {
      mdMethod.Body.Instructions[i].Operand = "Patched!!!";
   }
   // Оптимизация и упрощение инструкций
   mdMethod.Body.Instructions.SimplifyBranches(); // Упрощение инструкций(br.s -> br)
   mdMethod.Body.Instructions.OptimizeBranches(); // Оптимизация всех условий,  "впаивание" наших IL-инструкций в тело метода.
   // mdMethod.Body.Instructions.OptimizeMacros(); // Оптимизация макросов  (используется, если используется SimplifyMacros )
   mdMethod.Body.Instructions.UpdateInstructionOffsets(); // Обновляет все смещения инструкций
 }

Ещё можно так:

C#:
// Загружаем файл
using var module = ModuleDefMD.Load(Path.Combine(CurrDir, "Stub.exe"));
// Перебираем все классы
foreach (TypeDef type in module.GetTypes())
{
   // Перебираем все методы
   foreach (MethodDef method in type.Methods)
   {
      // Перебираем все инструкции
      foreach (Instruction inst in method.Body.Instructions)
      {
        // Ищем строку с названием [MESSAGE_FOR_PATCHER] - ищет по всем классам и если находит совпадения...
        if (inst.OpCode == OpCodes.Ldstr && inst.Operand.ToString().Contains("[MESSAGE_FOR_PATCHER]"))
        {
           inst.Operand = "This_is_my_Text"; // Заменяет строку на нашу
        }
        // Оптимизация и упрощение инструкций
        method.Body.Instructions.SimplifyBranches(); // Упрощение инструкций(br.s -> br)
        method.Body.Instructions.OptimizeBranches(); // Оптимизация всех условий,  "впаивание" наших IL-инструкций в тело метода.
        method.Body.Instructions.UpdateInstructionOffsets(); // Обновляет все смещения инструкций
      }
    }
  }
  module.Write(Path.Combine(CurrDir, "patched[.]exe")); // Сохраняем изменённый билд файл
}

P.S: Если где-то ошибся - исправьте)
спасибо. В твоём коде тоже разобрался. благодарен =)
 
попытался так, и это так не работает( Вот не могу понять где происходит замена?Посмотреть вложение 24036
Пытаюсь через replace и не выходит.
Смотри, создаешь в своем трое класс cConfig(или любой другой, изменить можно в билдере), потом значение ставишь на то, по которому билдер будет определять что будет патчить...

Напиши лучше в пм, все объясню

Реплейс происходит вот тут
mdMethod.Body.Instructions[i].Operand = "Patched!!!";
Мы изменяем параметр инстукции
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Смотри, создаешь в своем трое класс cConfig(или любой другой, изменить можно в билдере), потом значение ставишь на то, по которому билдер будет определять что будет патчить...

Напиши лучше в пм, все объясню

Реплейс происходит вот тут
mdMethod.Body.Instructions[i].Operand = "Patched!!!";
Мы изменяем параметр инстукции
да уже разобрался. Интересная библиотеак.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх