cob_258

tuto Mono.cecil pour débutant

3 posts in this topic

Salam,

C’est un petit tuto qui explique comment utiliser la librairie mono.cecil, c’est une explication basé sur ma propre utilisation, je ne vais pas tout expliquer, uniquement les base (c’est tout ce que je sais d'ailleurs).

Quelque information ne sont pas à jour donc voici le lien des changements entre versions

Une partie de ce que je vais dire je l'ai appris du code source de Confuser, je vous conseil de le voir.

 

1 – Le départ :

On commence par ajouter mono.cecil.dll au référence (clique droit sur référence > ajouter une référence) puis écrire cet linge avant l’espace du nom

>
using Mono.Cecil;

On ouvre le programme à explorer/modifié avec la méthode ReadAssembly de la classe AssemblyDefinition

>
AssemblyDefinition asm = AssemblyDefinition. ReadAssembly(CheminDuProgramme) ;

Pour enregistrer le programme on utilise

>
asm.Write(CheminDuNouveauFichier);

 

2 – Trouver / modifier les Type :

Pour modifier le Type il faut d’abord le trouver, si vous avez son nom complet utilisez :

>
TypeDefinition t =  asm.GetType(NomCompletDuType);
// Ou bien : 
TypeDefinition t =  asm.GetType(NameSpace,NomDuType);

Si vous n’êtes pas sûr du nom du Type ou vous voulez modifier tout les Types, utilisez le champ asm.MainModule.Types

>
TypeDefinition mytype = null;
foreach (TypeDefinition t in asm.MainModule.Types)
{
if (t.Name.StartsWith(DébutDuNom))
{
	mytype = t;
	break;
}
} 

Exemple pour renommer les Types :

>
foreach (TypeDefinition t in asm.MainModule.Types)
{
if (!t.Name == "<Module>")
{
	t.Name = new Random().Next().ToString();
	t.Attributes = TypeAttributes.Public; // inutile, c’est juste un exemple
}
}
// remarque : pour que le programme ne crash pas fixer les noms des resources

Vous pouvez modifier autre chose, maintenant vous savez ou trouver les Types, à vous de jouer.

 

3 – Trouver / modifier les méthodes :

C’est presque la même chose avec les Type mais les méthodes se trouvent dans

>
t.Methods

Pour trouver la méthode voulue utiliser le code suivant

>
MethodDefinition mymethod = null;
foreach (MethodDefinition m in t.Methods) // t est un Type
{
if (m.Name == NomDeLaMethod)
{
	mymethod = m;
	break;
}
}

Pour ajouter une nouvelle méthode il faut créer une avec

>
MethodDefinition (string name, MethodAttributes attributes, TypeReference returnType)

Exemple

>
MethodDefinition newmethod = new MethodDefinition(NomDeLaNouvelleMethod,
							MethodAttributes.Private, // choisissez l(es) attribue(s) qui vous convient(nent)
							asm.MainModule
							asm.MainModule.Import(typeof(void))) // remplace void avec le type de retour voulue

On a notre méthode, on peut ajouter des variables :

>
m.Body.Variables.Add(new VariableDefinition(asm.MainModule.Import(typeof(IntPtr)))); // remplacez IntPtr avec le Type voulu

Des paramètre

>
m.Parameters.Add(new ParameterDefinition(asm.MainModule.Import(typeof(string))));

On ajoute la méthode au Type

>
t.Methods.Add(m);

 

4 – Modifier / ajouter des instruction

Les instructions se trouvent dans :

>
m.Body.Instructions

Pour pouvoir modifier les instructions ajouter cet ligne :

>
using Mono.Cecil.Cil;

Trouver une instruction :

>
Instruction myinstruction = null;
foreach (Instruction inst in m.Body.Instructions)
{
if (inst.OpCode == OpCodes.Ldstr)
{
	myinstruction = inst;
	break;
}
}

Remarque : pour éviter les exceptions vérifier si la méthode a un Body avec m.HasBody

 

Exemple : trouver une valeur "intéressante"

>
TypeDefinition Module = asm.MainModule.GetType("<Module>");
int DecryptionConst = 0;
foreach (MethodDefinition m in Module.Methods)
{
if (m.HasBody && m.ReturnType.FullName == typeof(string).FullName && m.Parameters.Count == 1 && m.Parameters[0].ParameterType.FullName == typeof(string).FullName)
{
	foreach (Instruction inst in m.Body.Instructions)
	{
		if (inst.OpCode == OpCodes.Ldc_I4 && inst.Next != null && inst.Next.OpCode == OpCodes.Xor)
		{
			DecryptionConst = (int)inst.Operand;
			break;
		}
	}
	break;
}
}

Ajouter une instruction :

>
m.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4, 123456));

Remplacer une instruction (Exemple : patcher un return false en return true):

>
for (int i =0 ;i<m.Body.Instructions.Count ;i++)
{
if (m.Body.Instructions[i].OpCode == OpCodes.Ldc_I4_0 && m.Body.Instructions[i].Next != null && m.Body.Instructions[i].Next.OpCode == OpCodes.Ret)
{
	m.Body.Instructions[i] = Instruction.Create(OpCodes.Ldc_I4_1);
}
}

 

Voici un exemple pour ajouter un anti debug à un assembly en utilisant ILProcessor

>
TypeDefinition t = asm.MainModule.GetType("<Module>");
MethodDefinition cctor = null; // <Module>.cctor
foreach (MethodDefinition m in t.Methods)
{
if (m.Name == ".cctor" && m.IsConstructor)
{
	cctor = m;
	break;
}
}
if (cctor == null) // si aucun constructeur trouvé, créer un nouveau
{
cctor = new MethodDefinition(
	".cctor",
	Mono.Cecil.MethodAttributes.Private |
	Mono.Cecil.MethodAttributes.Static |
	Mono.Cecil.MethodAttributes.HideBySig |
	Mono.Cecil.MethodAttributes.SpecialName |
	Mono.Cecil.MethodAttributes.RTSpecialName
	, assembly.MainModule.Import(typeof(void)));
t.Methods.Add(cctor);
}
if (cctor.Body.Instructions.Count > 0 && cctor.Body.Instructions.Last<Instruction>().OpCode == OpCodes.Ret)
{
cctor.Body.Instructions.Remove(cctor.Body.Instructions.Last<Instruction>()); // si le cctor existé déjà supprimer le dernier retour
}
MethodDefinition AntiDebug = new MethodDefinition(// Method anti debugger (managed) qui sera exécuté dans une nouvelle thread
"AntiDebug",
Mono.Cecil.MethodAttributes.Static |
Mono.Cecil.MethodAttributes.Private,
assembly.MainModule.Import(typeof(void)));

// ajouter le code qui crée la nouvelle thread au cctor
//  new Thread(new ThreadStart(<Module>.AntiDebug)).Start();
ILProcessor CtorProcessor = cctor.Body.GetILProcessor();
CtorProcessor.Append(CtorProcessor.Create(OpCodes.Ldnull));
CtorProcessor.Append(CtorProcessor.Create(OpCodes.Ldftn, AntiDebug));
CtorProcessor.Append(CtorProcessor.Create(OpCodes.Newobj,
assembly.MainModule.Import(typeof(ThreadStart).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) })))); // si plusieurs méthodes portent le même nom on spécifie le(s) Type(s) de(s) paramètre(s)
CtorProcessor.Append(CtorProcessor.Create(OpCodes.Newobj, assembly.MainModule.Import(typeof(Thread).GetConstructor(new Type[] { typeof(ThreadStart) }))));
CtorProcessor.Append(CtorProcessor.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Thread).GetMethod("Start", Type.EmptyTypes))));
CtorProcessor.Append(CtorProcessor.Create(OpCodes.Ret));

// ajouter le code de la méthode AntiDebug
/* while (true)
   {
       if (Debugger.IsAttached || Debugger.IsLogging())
       {
           break;
       }
       Thread.Sleep(1000);
   }
   Environment.Exit(0);
*/
ILProcessor AntiProcessor = AntiDebug.Body.GetILProcessor();
Instruction First = AntiProcessor.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Debugger).GetMethod("get_IsAttached")));
Instruction Exit = AntiProcessor.Create(OpCodes.Ldc_I4_0);
AntiProcessor.Append(First);
AntiProcessor.Append(AntiProcessor.Create(OpCodes.Brtrue_S, Exit));
AntiProcessor.Append(AntiProcessor.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Debugger).GetMethod("IsLogging"))));
AntiProcessor.Append(AntiProcessor.Create(OpCodes.Brtrue_S, Exit));
AntiProcessor.Append(AntiProcessor.Create(OpCodes.Ldc_I4, 1000));
AntiProcessor.Append(AntiProcessor.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Thread).GetMethod("Sleep", new Type[] { typeof(Int32) }))));
AntiProcessor.Append(AntiProcessor.Create(OpCodes.Br_S, First));
AntiProcessor.Append(Exit);
AntiProcessor.Append(AntiProcessor.Create(OpCodes.Call, assembly.MainModule.Import(typeof(Environment).GetMethod("Exit", new Type[] { typeof(int) }))));
AntiProcessor.Append(AntiProcessor.Create(OpCodes.Ret));
t.Methods.Add(AntiDebug);

 

5 – Ressources

Les ressources se trouvent dans

>
asm.MainModule.Resources

Vous savez comment trouver une ressource, pour en ajouter une utilisez

>
assembly.MainModule.Resources.Add(Resource item) ;

Vous devez d'abord créer une resource avec

>
EmbeddedResource (string name, ManifestResourceAttributes attributes, byte [] data)
// oubien
public LinkedResource (string name, ManifestResourceAttributes flags, string file)

Exemple

>
asm.MainModule.Resources.Add(new EmbeddedResource(
                                   NomDeLaResource, // nom
                                   ManifestResourceAttributes.Public, // attribue
                                   File.ReadAllBytes(Data))); // byte[]

 

C’est mon premier tuto écrit (d’habitude je fait des demo flash) alors j’espère qu’il n’est pas ennuyeux et que vous le trouver utile,

Enfin si vous copiez / collez ce tuto ailleurs ou si vous utilisez une partie ou la totalité des codes veuillez citer la source et l’auteur, merci.

Tuto & code par COB

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now