├── README.md
├── SkaterStrFiner.csproj
└── Program.cs
/README.md:
--------------------------------------------------------------------------------
1 | # Skater.NetDeobfuscator
2 | Deobfuscator for RustemSoft Skater.Net Obfuscator
3 |
4 | :round_pushpin: This tool is able to decrypt strings from Native DLL of the latest version of Skater.Net Obfuscator (9.1.34)
5 |
6 |
7 | :round_pushpin: Control Flow is also handled
8 |
9 | ```Thanks to XenocodeRCE for his help ``` :triangular_ruler:
10 |
--------------------------------------------------------------------------------
/SkaterStrFiner.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {32EB2EA4-E5B3-40C1-88F7-36F428E36DC4}
8 | Exe
9 | SkaterStrFiner
10 | SkaterStrFiner
11 | v4.7.2
12 | 512
13 | true
14 |
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 | False
38 | ..\..\..\Documents\MEGAsync Downloads\MEGAsync\Reverse Engineering\Deobfuscateurs\ConfuserEx\de4dot ConfuserEx\bin\de4dot.blocks.dll
39 |
40 |
41 | False
42 | ..\..\..\Documents\MEGAsync Downloads\MEGAsync\Reverse Engineering\Deobfuscateurs\ConfuserEx\de4dot ConfuserEx\bin\dnlib.dll
43 |
44 |
45 | False
46 | bin\Debug\PEReader.dll
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Program.cs:
--------------------------------------------------------------------------------
1 | using AlphaOmega.Debug;
2 | using de4dot.blocks;
3 | using de4dot.blocks.cflow;
4 | using dnlib.DotNet;
5 | using dnlib.DotNet.Emit;
6 | using dnlib.DotNet.Writer;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.IO;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Diagnostics;
13 |
14 | namespace SkaterStrFiner
15 | {
16 | class Program
17 | {
18 | #region "Methods to deal with bytes in section"
19 | public static string ByteArrayToString(byte[] ba)
20 | {
21 | StringBuilder hex = new StringBuilder(ba.Length * 2);
22 | foreach (byte b in ba)
23 | hex.AppendFormat("{0:x2}", b);
24 | return hex.ToString();
25 | }
26 |
27 | public static byte[] StringToByteArray(String hex)
28 | {
29 | int NumberChars = hex.Length;
30 | byte[] bytes = new byte[NumberChars / 2];
31 | for (int i = 0; i < NumberChars; i += 2)
32 | bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
33 | return bytes;
34 | }
35 | #endregion
36 |
37 | public static byte[] dataSectionContent = null;
38 |
39 | static void Main(string[] args)
40 | {
41 | Console.WriteLine("Skater.net Deobfuscator \n \n");
42 |
43 | int nombreDeStringEncodée = 0;
44 | ModuleDefMD module = ModuleDefMD.Load(args[0]);
45 | //Type which contains String Initialization
46 | TypeDef InitialType = null;
47 | //We grab native method to count all of them
48 | List ListOfNativeMeths = new List();
49 | Stopwatch stopWatch = new Stopwatch();
50 | stopWatch.Start();
51 | foreach (TypeDef t in module.GetTypes())
52 | {
53 | foreach (MethodDef m in t.Methods)
54 | {
55 | if (m.Name.Contains("OOOOlx"))
56 | {
57 | ListOfNativeMeths.Add(m);
58 | }
59 | }
60 | }
61 | nombreDeStringEncodée = ListOfNativeMeths.Count();
62 | //We grab the type to find cctor afterwards
63 | InitialType = ListOfNativeMeths.First().DeclaringType;
64 | string DLLName = ListOfNativeMeths.First().ImplMap.Module.Name;
65 | Console.WriteLine("Native DLL Name : " + DLLName);
66 | //We stock strings in a list
67 | List deHexedstring = new List();
68 |
69 |
70 | //Reading PE
71 | using (PEFile file = new PEFile(StreamLoader.FromFile(Path.GetDirectoryName(args[0]) + @"\" + DLLName)))
72 | {
73 | var section = file.Header.Sections;
74 | foreach (var item in section)
75 | {
76 | var realName = new string(item.Name);
77 | //Strings are stored in .data section
78 | if (realName.Contains(".data"))
79 | {
80 | //offset of the beginning of the section
81 | var start = item.PointerToRawData;
82 | //calculation of section's size
83 | var length = item.PointerToRawData + item.SizeOfRawData;
84 |
85 | //We copy all bytes into a list
86 | List b = new List();
87 | using (FileStream fsSourceDDS = new FileStream(Path.GetDirectoryName(args[0]) + @"\" + DLLName, FileMode.Open, FileAccess.Read))
88 | using (BinaryReader binaryReader = new BinaryReader(fsSourceDDS))
89 | {
90 | fsSourceDDS.Seek(start, SeekOrigin.Begin);
91 | while (start < length)
92 | {
93 | byte y = binaryReader.ReadByte();
94 | b.Add(y);
95 | start++;
96 | }
97 | }
98 | dataSectionContent = b.ToArray();
99 |
100 | string input = ByteArrayToString(dataSectionContent);
101 |
102 | //we split the whole strings
103 | string[] datacontent = input.Split(new string[] { "00" }, StringSplitOptions.None);
104 |
105 | //We remove empty results
106 | datacontent = datacontent.Where(x => !string.IsNullOrEmpty(x)).ToArray();
107 |
108 |
109 | //We only need values associated to strings
110 | string[] encodedstring = datacontent.Take(nombreDeStringEncodée).Select(i => i.ToString()).ToArray();
111 |
112 |
113 | foreach (var hexedstring in encodedstring)
114 | {
115 | deHexedstring.Add(Encoding.UTF8.GetString(StringToByteArray(hexedstring)));
116 | }
117 | }
118 | }
119 | }
120 | //That's why we needed to find the type
121 | MethodDef cctor = InitialType.FindStaticConstructor();
122 | if (cctor == null)
123 | {
124 | Console.WriteLine("Impossible to find Method which initialize strings");
125 | return;
126 | }
127 | //We make a dictionnary to replace values of field
128 | Dictionary FieldValue = new Dictionary();
129 | for (int i = 0; i < cctor.Body.Instructions.Count - 1; i++)
130 | {
131 | if (cctor.Body.Instructions[i].OpCode == OpCodes.Ldsfld && cctor.Body.Instructions[i + 1].OpCode == OpCodes.Call && cctor.Body.Instructions[i + 2].OpCode == OpCodes.Stsfld)
132 | {
133 | cctor.Body.Instructions[i].OpCode = OpCodes.Nop;
134 | cctor.Body.Instructions[i + 1].OpCode = OpCodes.Ldstr;
135 | string decrypted = smethod_0(deHexedstring[0]);
136 | cctor.Body.Instructions[i + 1].Operand = decrypted;
137 | FieldValue.Add((FieldDef)cctor.Body.Instructions[i + 2].Operand, decrypted);
138 | deHexedstring.RemoveAt(0);
139 | }
140 | }
141 | int DecryptedStrings = 0;
142 | //Replacing field values
143 | foreach (TypeDef type in module.Types)
144 | {
145 | foreach (MethodDef method in type.Methods)
146 | {
147 | if (method.HasBody && method.Body.HasInstructions)
148 | {
149 | Cleaner(method);
150 | for (int i = 0; i < method.Body.Instructions.Count - 1; i++)
151 | {
152 | try
153 | {
154 | if (method.Body.Instructions[i].OpCode == OpCodes.Ldsfld)
155 | {
156 | FieldDef fld = (FieldDef)method.Body.Instructions[i].Operand;
157 | if (FieldValue.Keys.Contains(fld))
158 | {
159 | method.Body.Instructions[i].OpCode = OpCodes.Ldstr;
160 | method.Body.Instructions[i].Operand = FieldValue[fld];
161 | DecryptedStrings++;
162 | }
163 | }
164 | }
165 | catch
166 | {
167 |
168 | }
169 | }
170 | }
171 | }
172 | }
173 | stopWatch.Stop();
174 | Console.WriteLine("Done ! Elapsed time : " + stopWatch.Elapsed.TotalSeconds);
175 | //Saving ASM
176 | string SavingPath = module.Kind == ModuleKind.Dll ? args[0].Replace(".dll", "-Deobfuscated.dll") : args[0].Replace(".exe", "-Deobfuscated.exe");
177 | var opts = new ModuleWriterOptions(module);
178 | opts.MetaDataOptions.Flags = MetaDataFlags.PreserveAll;
179 | opts.Logger = DummyLogger.NoThrowInstance;
180 | module.Write(SavingPath, opts);
181 | Console.WriteLine("Sucessfully decrypted {0} strings", DecryptedStrings);
182 | Console.WriteLine("Control Flow removed", DecryptedStrings);
183 | Console.ReadLine();
184 | }
185 |
186 | //Removing Control Flow
187 | public static void Cleaner(MethodDef method)
188 | {
189 | BlocksCflowDeobfuscator blocksCflowDeobfuscator = new BlocksCflowDeobfuscator();
190 | Blocks blocks = new Blocks(method);
191 | blocksCflowDeobfuscator.Initialize(blocks);
192 | blocksCflowDeobfuscator.Deobfuscate();
193 | blocks.RepartitionBlocks();
194 | IList list;
195 | IList exceptionHandlers;
196 | blocks.GetCode(out list, out exceptionHandlers);
197 | DotNetUtils.RestoreBody(method, list, exceptionHandlers);
198 | }
199 |
200 | #region "Skater static string decoding"
201 |
202 | public static string smethod_0(string string_8)
203 | {
204 | string text = string.Empty;
205 | double value = 3.1415;
206 | string[] array = string_8.Split(new char[]
207 | {
208 | ' '
209 | });
210 | int num = 0;
211 | int upperBound = array.GetUpperBound(0);
212 | checked
213 | {
214 | for (int i = num; i <= upperBound; i += 3)
215 | {
216 | if ((double)Convert.ToInt32(array[i + 2]) / (double)Convert.ToInt32(value) == unchecked(11.0 * (double)Convert.ToInt32(value)))
217 | {
218 | text += char.ConvertFromUtf32(Convert.ToInt32(unchecked(Convert.ToDouble(array[i]) + Convert.ToDouble(255))) * smethod_1(Convert.ToInt32(array[i + 1])));
219 | }
220 | else
221 | {
222 | text += char.ConvertFromUtf32(Convert.ToInt32(array[i]) * smethod_1(Convert.ToInt32(array[i + 1])));
223 | }
224 | }
225 | return text;
226 | }
227 | }
228 |
229 | public static int smethod_1(int int_0)
230 | {
231 | int result;
232 | if ((double)int_0 / Convert.ToDouble(2) == (double)Convert.ToInt32((double)int_0 / Convert.ToDouble(2)))
233 | {
234 | result = 2;
235 | }
236 | else
237 | {
238 | result = 1;
239 | }
240 | return result;
241 | }
242 |
243 | #endregion
244 | }
245 | }
246 |
--------------------------------------------------------------------------------