├── 1.Strings ├── Final Code.cs ├── README.md └── TestApp │ ├── Code.cs │ ├── TestApp-Obfuscated.exe │ └── TestApp-Original.exe ├── Protectors ├── README.md └── Yano.zip └── README.md /1.Strings/Final Code.cs: -------------------------------------------------------------------------------- 1 | using dnlib.DotNet; 2 | using dnlib.DotNet.Emit; 3 | using dnlib.DotNet.Writer; 4 | using System; 5 | using System.IO; 6 | 7 | class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | if (args.Length < 1) 12 | return; 13 | string modulePath = args[0]; 14 | ModuleDef module; 15 | try 16 | { 17 | module = ModuleDefMD.Load(modulePath); 18 | } 19 | catch { return; } 20 | 21 | MethodDef decryptionMethod = null; 22 | int? decryptionKey = null; 23 | 24 | foreach (var type in module.GetTypes()) 25 | foreach (var method in type.Methods) 26 | { 27 | if (!method.HasBody) 28 | continue; 29 | if (method.Signature.ToString() != "System.String (System.String,System.Int32)") 30 | continue; 31 | var instructions = method.Body.Instructions; 32 | if (instructions.Count < 15) 33 | continue; 34 | if (!instructions[0].IsLdcI4()) 35 | continue; 36 | if (!instructions[1].IsLdarg()) 37 | continue; 38 | if (instructions[2].OpCode != OpCodes.Add) 39 | continue; 40 | if (!instructions[3].IsStloc()) 41 | continue; 42 | if (!instructions[4].IsLdarg()) 43 | continue; 44 | if (instructions[5].OpCode != OpCodes.Call) 45 | continue; 46 | if (instructions[5].Operand.ToString() != "System.Char[] System.String::ToCharArray()") 47 | continue; 48 | if (!instructions[6].IsStloc()) 49 | continue; 50 | if (!instructions[7].IsLdcI4() || instructions[7].GetLdcI4Value() != 0) 51 | continue; 52 | if (!instructions[8].IsStloc()) 53 | continue; 54 | if (!instructions[9].IsLdloc()) 55 | continue; 56 | if (!instructions[10].IsLdloc()) 57 | continue; 58 | if (instructions[11].OpCode != OpCodes.Ldlen) 59 | continue; 60 | if (instructions[12].OpCode != OpCodes.Conv_I4) 61 | continue; 62 | if (instructions[13].OpCode != OpCodes.Clt) 63 | continue; 64 | decryptionKey = instructions[0].GetLdcI4Value(); 65 | decryptionMethod = method; 66 | break; 67 | } 68 | 69 | if (decryptionMethod == null || decryptionKey == null) 70 | return; 71 | 72 | int decrypted = 0; 73 | foreach (var type in module.GetTypes()) 74 | foreach (var method in type.Methods) 75 | { 76 | if (!method.HasBody) 77 | continue; 78 | var instructions = method.Body.Instructions; 79 | for (int i = 2; i < instructions.Count; i++) 80 | { 81 | if (instructions[i].OpCode != OpCodes.Call) 82 | continue; 83 | var calledMethod = instructions[i].Operand as MethodDef; 84 | if (calledMethod == null || calledMethod != decryptionMethod) 85 | continue; 86 | if (!instructions[i - 1].IsLdcI4() || instructions[i - 2].OpCode != OpCodes.Ldstr) 87 | continue; 88 | var strParameter = instructions[i - 2].Operand.ToString(); 89 | var intParameter = instructions[i - 1].GetLdcI4Value(); 90 | var decryptedString = Decrypt(strParameter, intParameter, decryptionKey.Value); 91 | 92 | Console.WriteLine(decryptedString); 93 | 94 | instructions[i].OpCode = OpCodes.Ldstr; 95 | instructions[i].Operand = decryptedString; 96 | instructions[i - 1].OpCode = OpCodes.Nop; 97 | instructions[i - 2].OpCode = OpCodes.Nop; 98 | 99 | decrypted++; 100 | } 101 | } 102 | Console.WriteLine("Decrypted {0} strings", decrypted); 103 | 104 | module.Types.Remove(decryptionMethod.DeclaringType); 105 | 106 | var newPath = FormatPath(modulePath, "_strDecrypted"); 107 | 108 | var moduleWriterOptions = new ModuleWriterOptions(module); 109 | moduleWriterOptions.Logger = DummyLogger.NoThrowInstance; 110 | module.Write(newPath, moduleWriterOptions); 111 | 112 | Console.WriteLine("Saved {0}", newPath); 113 | Console.ReadKey(); 114 | } 115 | static string FormatPath(string path, string sufix) 116 | { 117 | var extension = Path.GetExtension(path); 118 | return path.Substring(0, path.Length - extension.Length) + sufix + extension; 119 | } 120 | internal static string Decrypt(string text, int num, int key) 121 | { 122 | int num2 = key + num; 123 | char[] array = text.ToCharArray(); 124 | for (int i = 0; i < array.Length; i++) 125 | array[i] = (char)(((array[i] & 'ÿ') ^ num2++) << 8 | ((byte)((array[i] >> 8) ^ num2++))); 126 | return string.Intern(new string(array)); 127 | } 128 | } 129 | 130 | -------------------------------------------------------------------------------- /1.Strings/README.md: -------------------------------------------------------------------------------- 1 | # Tutorial 1 - Strings Decryption 2 | 3 | ## Intro 4 | String encryption is common protection in obfuscators and it encrypts strings to some gibberish code so we cant dechiper what was original text. 5 | 6 | ![image](https://user-images.githubusercontent.com/12687236/27516110-f72fb222-59b2-11e7-88cd-b73a35cd994a.png) 7 | 8 | Structure of string decryption routine is 9 | 1.Decryption Method 10 | 2.Parameters 11 | 12 | ![image](https://user-images.githubusercontent.com/12687236/27516142-dacb002c-59b3-11e7-860c-ce5c217ced15.png) 13 | 14 | ## How to decrypt 15 | There are 2 most common ways of creating string decryption: 16 | 17 | 1.Static decryption - Static decryption is when we copy decompiled method from obfsucated assembly and paste it in our code and use as it is. 18 | 19 | 2.Dynamic decryption - Dynamic decryption is when we invoke method from obfuscated assembly which is not 100% since it can also invoke some malware 20 | 21 | Ofcourse there could be some preventions for boath to work such as using name of method from where is called decryption method (with Stack Trace) or something like assigning some field outside of decryption method (mostly in Module.Cctor or EntryPoint) which is used in decryption method (All those can be fixed for static method but cannot for dynamic) 22 | 23 | ## Static Decryption 24 | In this example i will use files protected by Yano Obfsucator. 25 | So as i sad in static decryption we try to decompile Decryption method and use it in our decrypter code. 26 | 27 | ### 1.Decompiling decryption method 28 | First thing what we will do is to find decryption method and try to decompile it. 29 | ![image](https://user-images.githubusercontent.com/12687236/27516344-8302beb6-59b8-11e7-8792-9b3df12cc1ee.png) 30 | As we see on this picture we secssesfuly decompiled our decryption method. 31 | 32 | ### 2.Checking is decompiled method compilabe, optimizing it and testing it 33 | What we have to do now is to open our IDE and to paste decompiled method in it and if errors are present we will try to fix them 34 | ![image](https://user-images.githubusercontent.com/12687236/27516522-fcc0975c-59bb-11e7-9008-96a814617acd.png) 35 | 36 | And then we fix method and optimize it like this: 37 | ![image](https://user-images.githubusercontent.com/12687236/27516545-705e3002-59bc-11e7-8d25-09f9660d8459.png) 38 | 39 | And after that we can test if decryption method working 40 | ![image](https://user-images.githubusercontent.com/12687236/27516562-a3aaeedc-59bc-11e7-8fa5-24c9814a2a0e.png) 41 | 42 | ### 3.Checking for decryption keys 43 | Next thing to do is to search for Keys (constants like integer/strings etc..) that are unique for each obfscuated file. 44 | Best way to detect this is to compare decryption methods of 2 or more protected files 45 | ![image](https://user-images.githubusercontent.com/12687236/27516420-96d462ea-59b9-11e7-88a1-0be57857b637.png) 46 | > int num2 = key + num; 47 | 48 | And when we compare first decryption method and this one we can see that 1 integer constant is changed and we can assume that will be different each time, so that means we have find this key when we are detecting if decryption method is applied 49 | 50 | Also we shouldnt forget to add key parameter in our decryption method 51 | ![image](https://user-images.githubusercontent.com/12687236/27517266-edfc4e9c-59c9-11e7-96b4-ceb006d20e56.png) 52 | ``` 53 | internal static string Decrypt(string text, int num,int key) 54 | { 55 | int num2 = key + num; 56 | char[] array = text.ToCharArray(); 57 | for (int i = 0; i < array.Length; i++) 58 | array[i] = (char)(((array[i] & 'ÿ') ^ num2++) << 8 | ((byte)((array[i] >> 8) ^ num2++))); 59 | return string.Intern(new string(array)); 60 | } 61 | ``` 62 | 63 | ### 4.Static dcryption method detecting and key's parsing 64 | Ok now we are starting to code our string decryption and first thing we have to do is to create function that will find decryption method in obfsuacted assembly 65 | First what we will do is to create method that will loop through all methods in assembly 66 | ``` 67 | MethodDef decryptionMethod = null; //Creating locals for our decrpytion method and key for furter assigning 68 | int? decryptionKey = null; 69 | 70 | foreach (var type in module.GetTypes()) //Looping through all types (classes) 71 | foreach (var method in type.Methods) //Looping through all methods in that type 72 | { 73 | if (!method.HasBody) //Checking if method have body (instructions) 74 | continue; 75 | //Now we will check if method is matching needed signature ( signature is written like ReturnType(ParameterType,SecondParameterType...) ) 76 | if (method.Signature.ToString() != "System.String (System.String,System.Int32)") //that signature is for current case when it return string and have 2 parameters (string,int) 77 | continue; //Best way to get valid signature is with debugging 78 | var instructions = method.Body.Instructions; //Parsing method instructions as Array of instructions 79 | 80 | //Here we are checking if instructions corresponds to decrpytion instructions 81 | //if we find method and key we should assign them on decryptionMethod and decryptionKey 82 | 83 | } 84 | 85 | if (decryptionMethod == null || decryptionKey == null) if decryptionMethod or key arent assigned that means detecting failed 86 | return; 87 | ``` 88 | ![image](https://user-images.githubusercontent.com/12687236/27517058-698fb01c-59c5-11e7-8f6a-b080f19fd5fc.png) 89 | 90 | Than next thing to do is to check if method il body. Best way is to check first 10-15 instructions if are matching original like this 91 | ![image](https://user-images.githubusercontent.com/12687236/27517105-aa6c0742-59c6-11e7-8141-23d40faad28f.png) 92 | ``` 93 | if (instructions.Count < 15) 94 | continue; 95 | if (!instructions[0].IsLdcI4()) 96 | continue; 97 | if (!instructions[1].IsLdarg()) 98 | continue; 99 | if (instructions[2].OpCode != OpCodes.Add) 100 | continue; 101 | if (!instructions[3].IsStloc()) 102 | continue; 103 | if (!instructions[4].IsLdarg()) 104 | continue; 105 | if (instructions[5].OpCode != OpCodes.Call) 106 | continue; 107 | if (instructions[5].Operand.ToString() != "System.Char[] System.String::ToCharArray()") 108 | continue; 109 | if (!instructions[6].IsStloc()) 110 | continue; 111 | if (!instructions[7].IsLdcI4() || instructions[7].GetLdcI4Value() != 0) 112 | continue; 113 | if (!instructions[8].IsStloc()) 114 | continue; 115 | if (!instructions[9].IsLdloc()) 116 | continue; 117 | if (!instructions[10].IsLdloc()) 118 | continue; 119 | if (instructions[11].OpCode != OpCodes.Ldlen) 120 | continue; 121 | if (instructions[12].OpCode != OpCodes.Conv_I4) 122 | continue; 123 | if (instructions[13].OpCode != OpCodes.Clt) 124 | continue; 125 | ``` 126 | Also we shouldnt forget that we have to save key so we should determine where it is located 127 | ![image](https://user-images.githubusercontent.com/12687236/27517142-7d520486-59c7-11e7-9465-b7cbbb106e12.png) 128 | 129 | After we get location we should assign our decryptionMethod and decryptionKey fields 130 | ``` 131 | decryptionKey = instructions[0].GetLdcI4Value(); 132 | decryptionMethod = method; 133 | break; 134 | ``` 135 | 136 | ### 5.Decrypting strings 137 | So finaly we came to the end of journey where there there is left only to replace encrypted methods with decrypted strings. 138 | First thing we should do is to see how decryption method is called 139 | ![image](https://user-images.githubusercontent.com/12687236/27517215-579e420c-59c9-11e7-9c2e-ab2603d7a346.png) 140 | 141 | So we know that there are 3 Instructions for each call that we should change (1 call and 2 parameters) so what is left to do is to loop through each instruction in evry method and try to find those 3 instructions and to replace them with decrypted string 142 | ``` 143 | int decrypted = 0; 144 | foreach (var type in module.GetTypes()) 145 | foreach (var method in type.Methods) 146 | { 147 | if (!method.HasBody) 148 | continue; 149 | var instructions = method.Body.Instructions; 150 | for (int i = 2; i < instructions.Count; i++) //We are starting from i=2 because call needs 2 parameters so it cant start from 0 or 1 151 | { 152 | if (instructions[i].OpCode != OpCodes.Call) //checking if instruction is call 153 | continue; 154 | var calledMethod = instructions[i].Operand as MethodDef; 155 | if (calledMethod == null || calledMethod != decryptionMethod) //checking if decryptionMethod is called 156 | continue; 157 | if (!instructions[i - 1].IsLdcI4() || instructions[i - 2].OpCode != OpCodes.Ldstr) //checking if parameters are valid 158 | continue; 159 | var strParameter = instructions[i - 2].Operand.ToString(); //parsing value of first parameter 160 | var intParameter = instructions[i - 1].GetLdcI4Value(); //parsing value of second parameter 161 | var decryptedString = Decrypt(strParameter, intParameter,decryptionKey.Value); 162 | 163 | Console.WriteLine(decryptedString); //Logging decryptedString 164 | 165 | instructions[i].OpCode = OpCodes.Ldstr; 166 | instructions[i].Operand = decryptedString; //replacing call with ldstr (load string) and assigning to return decrypted string 167 | instructions[i - 1].OpCode = OpCodes.Nop; 168 | instructions[i - 2].OpCode = OpCodes.Nop; //nopping parameters 169 | 170 | decrypted++; //Logging how much calls got decrypted 171 | } 172 | } 173 | Console.WriteLine("Decrypted {0} strings", decrypted); 174 | ``` 175 | 176 | ### 6.Removing junk and saving assembly 177 | Now we can remove decryption method and also because its only method in Class (Type) we can remove whole Class 178 | ![image](https://user-images.githubusercontent.com/12687236/27517390-0d7ca36e-59cc-11e7-8593-c9d098a38e6c.png) 179 | ``` 180 | module.Types.Remove(decryptionMethod.DeclaringType); 181 | ``` 182 | Now we want to create new path save path and for that we can use simple method i created 183 | ``` 184 | static string FormatPath(string path, string sufix) 185 | { 186 | var extension = Path.GetExtension(path); 187 | return path.Substring(0,path.Length - extension.Length) + sufix + extension; 188 | } 189 | ``` 190 | And finaly we save deobfsucated assembly 191 | ``` 192 | var newPath = FormatPath(modulePath, "_strDecrypted"); 193 | 194 | var moduleWriterOptions = new ModuleWriterOptions(module); //this is just to prevent write methods from throwing error 195 | moduleWriterOptions.Logger = DummyLogger.NoThrowInstance; 196 | module.Write(newPath, moduleWriterOptions); //saving assemby 197 | 198 | Console.WriteLine("Saved {0}", newPath); //logging where its saved 199 | ``` 200 | 201 | ![image](https://user-images.githubusercontent.com/12687236/27517582-4bb1ec86-59cf-11e7-90b2-333e98a51a31.png) 202 | -------------------------------------------------------------------------------- /1.Strings/TestApp/Code.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TestAppStrings 4 | { 5 | class Program 6 | { 7 | static void Main(string[] args) 8 | { 9 | var password = Console.ReadLine(); 10 | if (password == "Tutorial 1") 11 | Console.WriteLine("Well Done"); 12 | else 13 | Console.WriteLine("Wrong Password"); 14 | Console.WriteLine("Press any key to exit..."); 15 | Console.ReadKey(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /1.Strings/TestApp/TestApp-Obfuscated.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheProxyRE/Deobfuscation-Tutorials/04db3bc4f00dc82af46f59ad83ce716b4d64fde0/1.Strings/TestApp/TestApp-Obfuscated.exe -------------------------------------------------------------------------------- /1.Strings/TestApp/TestApp-Original.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheProxyRE/Deobfuscation-Tutorials/04db3bc4f00dc82af46f59ad83ce716b4d64fde0/1.Strings/TestApp/TestApp-Original.exe -------------------------------------------------------------------------------- /Protectors/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheProxyRE/Deobfuscation-Tutorials/04db3bc4f00dc82af46f59ad83ce716b4d64fde0/Protectors/README.md -------------------------------------------------------------------------------- /Protectors/Yano.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheProxyRE/Deobfuscation-Tutorials/04db3bc4f00dc82af46f59ad83ce716b4d64fde0/Protectors/Yano.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deobfuscation Tutorials by TheProxy 2 | --------------------------------------------------------------------------------