├── README.md
├── XUnion
├── 4.0.0.cs
├── App.config
├── Deobfuscators
│ └── 4.0.0.cs
├── Program.cs
├── Unpackers
│ └── 4.0.0.cs
├── Updater.cs
├── Utils.cs
├── XORManager.cs
├── XUnion.csproj
└── dnlibUtils.cs
└── XUnionPE
├── App.config
├── Decompiler.cs
├── PEUtils.cs
├── Program.cs
├── Utils.cs
└── XUnionPE.csproj
/README.md:
--------------------------------------------------------------------------------
1 | # GruMinion
2 | Full Deobfuscator for PEUnion 4.0.0 (.NET & PE32)
3 |
4 | # Notes
5 |
6 | - This is my first deobfuscator for non-MSIL apps (messy ahh code)
7 | - Currently in beta
8 |
9 |
10 | # Info
11 | (stub deobfuscation were made just for fun :))
12 |
13 | Protection Name | Supported | Details
14 | ------------- | ------------- | -------------
15 | PE32 Stub | Yes (Padding included) | Compression support soon
16 | .NET Stub | Yes | Fully works
17 | PE32 Stub Deobfuscation | No |
18 | .NET Stub Deobfuscation | Yes | You likely won't need it
19 |
20 | # Credits
21 | 9ee1 - Capstone.NET (Engine to decompile x86 Assembly Code (XUnionPE))
22 | 0xd4d - dnlib (Engine to decompile MSIL Code (XUnion))
23 | bytecode77 - PEUnion
24 |
--------------------------------------------------------------------------------
/XUnion/4.0.0.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using dnlib.DotNet;
9 | using dnlib.DotNet.Emit;
10 |
11 | namespace XUnion
12 | {
13 | public class v4
14 | {
15 | public class SharedItems
16 | {
17 | public SharedItems(string Path)
18 | {
19 | path = Path;
20 | RawFile = File.ReadAllBytes(path);
21 | asm = ModuleDefMD.Load(RawFile);
22 | app = Assembly.Load(RawFile);
23 | }
24 |
25 | public bool Stage2Only,
26 | isCompressed;
27 |
28 | public string path;
29 | public byte[] RawFile,
30 | Stage2RawFile,
31 | OutputRawFile;
32 |
33 | public XORManager XORMng { get; set; }
34 |
35 | public ModuleDefMD asm,
36 | Stage2asm;
37 |
38 | public Assembly app,
39 | Stage2app;
40 |
41 | public MethodDef UnXorMethod_Main,
42 | UnXorMethod_IntPart,
43 | UnXorMethod_SelectPart,
44 | ResourceDecrypt,
45 | GZipStage2Method;
46 | }
47 |
48 | public XUnion.Deobfuscators.v4 Stage1Deobfuscator { get; set; }
49 | public XUnion.Deobfuscators.v4 Stage2Deobfuscator { get; set; }
50 | public XUnion.Unpackers.v4 Unpacker { get; set; }
51 | public XUnion.Unpackers.v4.Stage2 Stage2 { get; set; }
52 |
53 | public SharedItems Shared;
54 |
55 | public v4(ModuleDefMD asm, bool skipInit = false, bool isStage2ASM = false) { Shared = new SharedItems(asm.Location); if (!skipInit) { if (isStage2ASM) { Shared.Stage2Only = true; InitializeStage2(); } else { InitializeStage1(); } } }
56 | public v4(string path, bool skipInit = false, bool isStage2ASM = false) { Shared = new SharedItems(path); if (!skipInit) { if (isStage2ASM) { Shared.Stage2Only = true; InitializeStage2(); } else { InitializeStage1(); } } }
57 |
58 | public byte[] Unpack() { return Shared.OutputRawFile; }
59 | public void Unpack(string path) { File.WriteAllBytes(path, Shared.OutputRawFile); }
60 |
61 | private void IdentifyMethods (ModuleDefMD asm) { IdentifyMethods(asm, ref Shared); }
62 | private void InitializeXORManager(ModuleDefMD asm) { Shared.XORMng = InitializeXORManager(asm, ref Shared); }
63 |
64 | private void InitializeStage1()
65 | {
66 | IdentifyMethods(Shared.asm); // Sets Shared.UnXorMethod_Main, Shared.UnXorMethod_IntPart, Shared.UnXorMethod_SelectPart
67 | InitializeXORManager(Shared.asm); // Sets Shared.xor
68 |
69 | Unpacker = new XUnion.Unpackers.v4(ref Shared);
70 |
71 | Stage1Deobfuscator = new XUnion.Deobfuscators.v4(ref Shared, Shared.asm);
72 | //Stage1Deobfuscator.FixRenaming();
73 |
74 | Unpacker.GetStage2ASM(); // Sets Shared.Stage2asm, Shared.Stage2app & Shared.Stage2RawFile
75 | InitializeStage2();
76 | }
77 | private void InitializeStage2()
78 | {
79 | if (Shared.Stage2Only)
80 | {
81 | Shared.Stage2asm = Shared.asm;
82 | Shared.Stage2app = Assembly.Load(Shared.RawFile);
83 | IdentifyMethods(Shared.Stage2asm);
84 | InitializeXORManager(Shared.Stage2asm);
85 | }
86 |
87 | Stage2Deobfuscator = new XUnion.Deobfuscators.v4(ref Shared, Shared.Stage2asm);
88 | //Stage2Deobfuscator.FixRenaming();
89 |
90 | Stage2 = new Unpackers.v4.Stage2(ref Shared);
91 |
92 | Stage2.GetResDecryptMethod(); // Sets Shared.ResourceDecrypt
93 | Stage2.IsCompressed(); // Sets Shared.isCompressed and Shared.GZipStage2Method if found/detected
94 | Stage2.Fix(); // Sets Shared.OutputRawFile
95 | }
96 |
97 | private static ModuleDefMD IdentifyMethods(ModuleDefMD asm, ref SharedItems Shared)
98 | {
99 | ModuleDefMD resultAsm = asm;
100 | bool XorMethodFound = false;
101 |
102 | for (int x = 0; x < resultAsm.EntryPoint.DeclaringType.Methods.Count; x++)
103 | {
104 | if (XorMethodFound) { break; }
105 |
106 | MethodDef methods = resultAsm.EntryPoint.DeclaringType.Methods[x];
107 | if (!methods.HasBody) { continue; }
108 |
109 | Instruction[] insts = methods.Body.Instructions.ToArray();
110 |
111 | try
112 | {
113 | // Detects if current method is Int32 UnXor Function (int[2] -> int)
114 | if (insts[0].IsLdarg() &&
115 | insts[1].IsLdarg() &&
116 | insts[2].IsLdcI4() &&
117 | insts[3].OpCode == OpCodes.Xor &&
118 | insts[4].OpCode == OpCodes.Xor &&
119 | insts[5].OpCode == OpCodes.Ret)
120 | {
121 | Shared.UnXorMethod_IntPart = methods; if (Shared.UnXorMethod_Main != null) { XorMethodFound = true; } continue;
122 | }
123 |
124 | // Detects if current method is GZipDecompression
125 | if (insts[0].OpCode == OpCodes.Newobj &&
126 | insts[3].OpCode == OpCodes.Newobj &&
127 | insts[5].OpCode == OpCodes.Newobj &&
128 | insts[9].OpCode == OpCodes.Callvirt &&
129 | insts[9].Operand is MemberRef &&
130 | Utils.CompareNamespaceMemberRef(insts[9], typeof(Stream), "CopyTo", new Type[] { typeof(Stream) }))
131 | {
132 | methods.Parameters[0].Name = "compressedData";
133 | methods.Name = "DecompressProtectedApp";
134 | continue;
135 | }
136 |
137 | // Detects if current method is UInt16 UnXor Function (uint16 -> string)
138 | if (insts[10].Operand != null &&
139 | insts[14].Operand != null &&
140 | insts[7].IsLdcI4() &&
141 | insts[8].IsLdcI4() &&
142 | insts[10].Operand is MethodSpec &&
143 | insts[14].Operand is MethodSpec &&
144 | Utils.CompareNamespaceMethodSpec(insts[10], typeof(Enumerable), "Skip"))
145 | {
146 | Shared.UnXorMethod_Main = methods; if (Shared.UnXorMethod_IntPart != null) { XorMethodFound = true; } continue;
147 | }
148 | }
149 | catch { }
150 | }
151 |
152 | // Getting the foreach Linq loop (hidden method) present in the UInt16 UnXor method
153 | for (int x = 0; x < resultAsm.EntryPoint.DeclaringType.NestedTypes.Count; x++)
154 | {
155 | TypeDef nestedType = resultAsm.EntryPoint.DeclaringType.NestedTypes[x];
156 | if (nestedType.IsDelegate || !nestedType.HasFields) { continue; }
157 | for (int x_ = 0; x_ < nestedType.Methods.Count; x_++)
158 | {
159 | MethodDef nestedMethod = nestedType.Methods[x_];
160 | if (!nestedMethod.HasBody || nestedMethod.IsConstructor) { continue; }
161 | Instruction[] insts = nestedMethod.Body.Instructions.ToArray();
162 | if (insts[3].IsLdcI4() &&
163 | insts[4].IsLdcI4() &&
164 | insts[5].OpCode == OpCodes.Call &&
165 | insts[5].Operand is MethodDef &&
166 | insts[6].OpCode == OpCodes.Ldelem_U2 &&
167 | insts[7].OpCode == OpCodes.Xor &&
168 | insts[8].OpCode == OpCodes.Conv_U2)
169 | {
170 | Shared.UnXorMethod_SelectPart = nestedMethod; return resultAsm;
171 | }
172 | }
173 | }
174 | return null;
175 | }
176 | private static XORManager InitializeXORManager(ModuleDefMD asm, ref SharedItems Shared)
177 | {
178 | int[] MainUnXorValues = new int[4]
179 | {
180 | Shared.UnXorMethod_Main.Body.Instructions[7].GetLdcI4Value(),
181 | Shared.UnXorMethod_Main.Body.Instructions[8].GetLdcI4Value(),
182 | Shared.UnXorMethod_SelectPart.Body.Instructions[3].GetLdcI4Value(),
183 | Shared.UnXorMethod_SelectPart.Body.Instructions[4].GetLdcI4Value()
184 | };
185 |
186 | int IntXorValue = Shared.UnXorMethod_IntPart.Body.Instructions[2].GetLdcI4Value();
187 |
188 | return new XORManager(XORManager.ToInt(MainUnXorValues[0], MainUnXorValues[1], IntXorValue),
189 | XORManager.ToInt(MainUnXorValues[2], MainUnXorValues[3], IntXorValue),
190 | IntXorValue);
191 | }
192 |
193 | public static bool IsStage2ASM(ModuleDefMD asm) { return asm.EntryPoint.DeclaringType.Fields.Count == 2 ? true : false; }
194 | }
195 | }
--------------------------------------------------------------------------------
/XUnion/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/XUnion/Deobfuscators/4.0.0.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Runtime.InteropServices;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using dnlib.DotNet;
11 | using dnlib.DotNet.Emit;
12 |
13 | namespace XUnion.Deobfuscators
14 | {
15 | public class v4
16 | {
17 | private XUnion.v4.SharedItems SharedItems;
18 | private XORManager xor;
19 | private ModuleDefMD asm;
20 |
21 | public int XORFixCount, XORStringFixCount, RenameFixCount, DelegateFixCount;
22 |
23 | public v4(ModuleDefMD module, XORManager xorMng)
24 | {
25 | asm = module;
26 | xor = xorMng;
27 | }
28 | public v4(ref XUnion.v4.SharedItems sharedItems, ModuleDefMD module)
29 | {
30 | SharedItems = sharedItems;
31 | xor = sharedItems.XORMng;
32 | asm = module;
33 | }
34 |
35 | public void Deobfuscate()
36 | {
37 | FixRenaming();
38 | FixXOR();
39 | FixDelegates();
40 | }
41 |
42 | public void FixRenaming() // Renames Methods
43 | {
44 | asm.EntryPoint.DeclaringType.Name = "Program";
45 | asm.EntryPoint.Parameters[0].Name = "args";
46 | RenameFixCount += 2;
47 |
48 | if (SharedItems.ResourceDecrypt != null)
49 | {
50 | SharedItems.ResourceDecrypt.Name = "GetProtectedAppStream";
51 | SharedItems.ResourceDecrypt.Parameters[0].Name = "resourceName";
52 | RenameFixCount += 2;
53 | }
54 |
55 | List typesToCleanUp = new List();
56 | typesToCleanUp.AddRange(asm.Types);
57 | for (int x = 0; x < asm.EntryPoint.DeclaringType.NestedTypes.Count; x++)
58 | {
59 | TypeDef nestedType = asm.EntryPoint.DeclaringType.NestedTypes[x];
60 | if (nestedType.IsDelegate) { continue; }
61 | typesToCleanUp.Add(nestedType);
62 | }
63 |
64 | for (int x_type = 0; x_type < typesToCleanUp.Count; x_type++)
65 | {
66 | TypeDef type = typesToCleanUp[x_type];
67 | int delegateCount = 0;
68 |
69 | for (int x_nestedTypes = 0; x_nestedTypes < type.NestedTypes.Count; x_nestedTypes++)
70 | {
71 | TypeDef nestedType = type.NestedTypes[x_nestedTypes];
72 | if (nestedType.IsDelegate) { nestedType.Name = "Delegate_" + delegateCount++; RenameFixCount++; continue; }
73 | }
74 |
75 | for (int x_method = 0; x_method < type.Methods.Count; x_method++)
76 | {
77 | MethodDef methods = type.Methods[x_method];
78 |
79 | if (methods.HasImplMap)
80 | {
81 | methods.Name = methods.ImplMap.Module.FullName.Split('.')[0] + "." + methods.ImplMap.Name;
82 | switch (methods.Name)
83 | {
84 | case "kernel32.GetProcAddress": methods.Parameters[0].Name = "hModule";
85 | methods.Parameters[1].Name = "lpProcName" ; RenameFixCount += 2; break;
86 | case "kernel32.LoadLibraryA": methods.Parameters[0].Name = "lpLibFileName"; RenameFixCount++ ; break;
87 | }
88 | continue;
89 | }
90 |
91 | if (!methods.HasBody) { continue; }
92 | Instruction[] insts = methods.Body.Instructions.ToArray();
93 | try
94 | {
95 | if ((insts[0].OpCode == OpCodes.Ldarga_S || insts[0].OpCode == OpCodes.Ldarga) &&
96 | (insts[2].OpCode == OpCodes.Ldarga_S || insts[2].OpCode == OpCodes.Ldarga) &&
97 | insts[4].OpCode == OpCodes.Call &&
98 | insts[4].Operand is MethodSpec &&
99 | insts[5].OpCode == OpCodes.Ret &&
100 | Utils.CompareNamespaceMethodSpec(insts[4], typeof(Marshal), "GetDelegateForFunctionPointer", new Type[] { typeof(IntPtr) }))
101 | {
102 | methods.GenericParameters[0].Name = "TDelegate";
103 | methods.Parameters[0].Name = "moduleName";
104 | methods.Parameters[1].Name = "procName";
105 | methods.Name = "GetDelegateForPtr";
106 | RenameFixCount += 4;
107 | continue;
108 | }
109 |
110 | if (insts[0].IsLdarg() &&
111 | insts[1].IsLdarg() &&
112 | insts[2].IsLdcI4() &&
113 | insts[3].OpCode == OpCodes.Xor &&
114 | insts[4].OpCode == OpCodes.Xor &&
115 | insts[5].OpCode == OpCodes.Ret)
116 | {
117 | methods.Name = "Int32Xor";
118 | methods.Parameters[0].Name = "value1";
119 | methods.Parameters[1].Name = "value2";
120 | RenameFixCount += 3;
121 | continue;
122 | }
123 |
124 | if (insts[0].OpCode == OpCodes.Newobj &&
125 | insts[3].OpCode == OpCodes.Newobj &&
126 | insts[5].OpCode == OpCodes.Newobj &&
127 | insts[9].OpCode == OpCodes.Callvirt &&
128 | insts[9].Operand is MemberRef &&
129 | Utils.CompareNamespaceMemberRef(insts[9], typeof(Stream), "CopyTo", new Type[] { typeof(Stream) }))
130 | {
131 | methods.Parameters[0].Name = "compressedData";
132 | methods.Name = "DecompressProtectedApp";
133 | continue;
134 | }
135 |
136 | if (insts[7].IsLdcI4() &&
137 | insts[8].IsLdcI4() &&
138 | insts[10].Operand != null &&
139 | insts[10].Operand is MethodSpec &&
140 | insts[14].Operand != null &&
141 | insts[14].Operand is MethodSpec &&
142 | Utils.CompareNamespaceMethodSpec(insts[10], typeof(Enumerable), "Skip"))
143 | {
144 | methods.Name = "UnXorToString";
145 | methods.Parameters[0].Name = "data";
146 | RenameFixCount += 2;
147 | continue;
148 | }
149 |
150 | if (insts[15].OpCode == OpCodes.Callvirt &&
151 | insts[15].Operand is MemberRef &&
152 | insts[12].OpCode == OpCodes.Callvirt &&
153 | insts[12].Operand is MemberRef &&
154 | insts[6].OpCode == OpCodes.Ldftn &&
155 | insts[6].Operand is MethodDef &&
156 | Utils.CompareNamespaceMemberRef(insts[15], typeof(Thread), "Start", new Type[] { }) &&
157 | asm.EntryPoint.DeclaringType.NestedTypes.Contains(((MethodDef)insts[6].Operand).DeclaringType))
158 | {
159 | MethodDef nestedMethod = ((MethodDef)insts[6].Operand);
160 | if (nestedMethod.Body.Instructions[3].OpCode == OpCodes.Callvirt &&
161 | nestedMethod.Body.Instructions[3].Operand is MemberRef &&
162 | nestedMethod.Body.Instructions[10].OpCode == OpCodes.Ldsfld &&
163 | nestedMethod.Body.Instructions[10].Operand is FieldDef &&
164 | nestedMethod.Body.Instructions[13].OpCode == OpCodes.Callvirt &&
165 | nestedMethod.Body.Instructions[13].Operand is MemberRef &&
166 | Utils.CompareNamespaceMemberRef(nestedMethod.Body.Instructions[3], typeof(Assembly), "get_EntryPoint", new Type[] { }) &&
167 | Utils.CompareNamespaceMemberRef(nestedMethod.Body.Instructions[13], typeof(MethodBase), "Invoke", new Type[] { typeof(object), typeof(object[]) }))
168 | {
169 | methods.Name = "InvokeProtectedApp";
170 | methods.Parameters[0].Name = "rawProtectedApp";
171 | RenameFixCount += 2;
172 | continue;
173 | }
174 | }
175 | }
176 | catch { }
177 |
178 | for (int x = 0; x < insts.Length; x++)
179 | {
180 | if (insts[x].OpCode == OpCodes.Callvirt &&
181 | insts[x].Operand is MethodDef &&
182 | ((MethodDef)insts[x].Operand).DeclaringType.IsDelegate)
183 | {
184 | methods.Name = "InitializeDelegates";
185 | RenameFixCount++;
186 | break;
187 | }
188 |
189 | if (insts[x].OpCode == OpCodes.Stsfld &&
190 | insts[x].Operand is FieldDef &&
191 | insts[x - 1].OpCode == OpCodes.Call &&
192 | insts[x - 1].Operand is MethodSpec &&
193 | insts[x - 7].OpCode == OpCodes.Stsfld &&
194 | insts[x - 7].Operand is FieldDef &&
195 | Utils.CompareNamespaceMethodSpec(insts[x - 1], typeof(Enumerable), "ToArray") &&
196 | Utils.CompareNamespaceMethodSpec(insts[x - 2], typeof(Enumerable), "Skip"))
197 | {
198 | ((FieldDef)insts[x].Operand).Name = "protectedAppArgs";
199 | ((FieldDef)insts[x - 7].Operand).Name = "PEunionArgs";
200 | RenameFixCount += 2;
201 | break;
202 | }
203 | }
204 | }
205 | }
206 | }
207 | public void FixXOR() // Fixes XOR strings & integers
208 | {
209 | List typesToCleanUp = new List();
210 | typesToCleanUp.AddRange(asm.Types);
211 | for (int x = 0; x < asm.EntryPoint.DeclaringType.NestedTypes.Count; x++)
212 | {
213 | TypeDef nestedType = asm.EntryPoint.DeclaringType.NestedTypes[x];
214 | if (nestedType.IsDelegate) { continue; }
215 | typesToCleanUp.Add(nestedType);
216 | }
217 |
218 | for (int x_type = 0; x_type < typesToCleanUp.Count; x_type++)
219 | {
220 | TypeDef type = typesToCleanUp[x_type];
221 | for (int x_method = 0; x_method < type.Methods.Count; x_method++)
222 | {
223 | MethodDef methods = type.Methods[x_method];
224 | if (!methods.HasBody) { continue; }
225 | for (int x = 0; x < methods.Body.Instructions.Count; x++)
226 | {
227 | Instruction[] insts = methods.Body.Instructions.ToArray();
228 | Instruction inst = insts[x];
229 | if (inst.OpCode == OpCodes.Newarr &&
230 | inst.Operand is TypeRef &&
231 | ((TypeRef)inst.Operand).FullName == typeof(ushort).FullName)
232 | {
233 | Local arrLoc = insts[x + 1].GetLocal(methods.Body.Variables);
234 | MSILArray arr = MSILArray.ParseArray(insts, x - 1);
235 | methods.Body.Instructions[x - 1].OpCode = OpCodes.Ldstr;
236 | methods.Body.Instructions[x - 1].Operand = xor.Compute(Utils.ToUInt16(arr.ToArray()));
237 | for (int i = 0; i < arr.RawCount; i++) { methods.Body.Instructions.RemoveAt(x); }
238 | methods.Body.Variables.Remove(arrLoc);
239 | inst = methods.Body.Instructions[x];
240 | if (inst.OpCode == OpCodes.Call &&
241 | inst.Operand is MethodDef &&
242 | ((MethodDef)inst.Operand).Name == "UnXorToString") { methods.Body.Instructions.RemoveAt(x); }
243 | XORStringFixCount++;
244 | continue;
245 | }
246 |
247 | if (inst.OpCode == OpCodes.Call &&
248 | inst.Operand is MethodDef &&
249 | ((MethodDef)inst.Operand).Name == "Int32Xor" &&
250 | insts[x - 2].IsLdcI4() &&
251 | insts[x - 1].IsLdcI4())
252 | {
253 | methods.Body.Instructions[x - 2].Operand = xor.ToInt(insts[x - 2].GetLdcI4Value(), insts[x - 1].GetLdcI4Value());
254 | methods.Body.Instructions.RemoveAt(x - 1);
255 | methods.Body.Instructions.RemoveAt(x - 1);
256 | XORFixCount++;
257 | continue;
258 | }
259 | }
260 | }
261 | }
262 | }
263 | public void FixDelegates() // Removes unused delegates and renames used ones
264 | {
265 | for (int x_method = 0; x_method < asm.EntryPoint.DeclaringType.Methods.Count; x_method++)
266 | {
267 | MethodDef methods = asm.EntryPoint.DeclaringType.Methods[x_method];
268 | if (methods.Name != "InitializeDelegates") { continue; }
269 |
270 | Instruction[] insts = methods.Body.Instructions.ToArray();
271 | for (int x = 0; x < insts.Length; x++)
272 | {
273 | Instruction inst = insts[x];
274 |
275 | if (inst.OpCode == OpCodes.Call &&
276 | inst.Operand is MethodSpec &&
277 | ((MethodSpec)inst.Operand).Name == "GetDelegateForPtr" &&
278 | insts[x + 1].IsStloc() &&
279 | insts[x - 2].OpCode == OpCodes.Ldstr && // Requires FixXOR
280 | insts[x - 1].OpCode == OpCodes.Ldstr) // Requires FixXOR
281 | {
282 | Local tempLoc = insts[x + 1].GetLocal(methods.Body.Variables);
283 | ITypeDefOrRef delType;
284 | switch (insts[x - 1].Operand.ToString())
285 | {
286 | case "SetErrorMode": // kernel32.SetErrorMode
287 | case "VirtualAllocExNuma": // kernel32.VirtualAllocExNuma
288 | if (isLocalTypeDelegate(tempLoc, out delType)) { delType.Name = /*insts[x - 2].Operand.ToString().Split('.')[0] + "." + */ insts[x - 1].Operand.ToString(); }
289 | DelegateFixCount++;
290 | break;
291 | }
292 | }
293 | }
294 | }
295 |
296 | for (int x_nestedTypes = 0; x_nestedTypes < asm.EntryPoint.DeclaringType.NestedTypes.Count; x_nestedTypes++)
297 | {
298 | TypeDef nestedType = asm.EntryPoint.DeclaringType.NestedTypes[x_nestedTypes];
299 | if (nestedType.IsDelegate)
300 | {
301 | switch (nestedType.Name)
302 | {
303 | case "SetErrorMode":
304 | for (int x_method = 0; x_method < nestedType.Methods.Count; x_method++)
305 | {
306 | MethodDef method = nestedType.Methods[x_method];
307 | switch (method.Name)
308 | {
309 | case "Invoke":
310 | case "BeginInvoke":
311 | int offset = (method.Parameters[0].MethodSigIndex == -2) ? 1 : 0;
312 | method.Parameters[offset++].Name = "uMode"; break;
313 | }
314 | }
315 | break;
316 | case "VirtualAllocExNuma":
317 | for (int x_method = 0; x_method < nestedType.Methods.Count; x_method++)
318 | {
319 | MethodDef method = nestedType.Methods[x_method];
320 | switch (method.Name)
321 | {
322 | case "Invoke":
323 | case "BeginInvoke":
324 | int offset = (method.Parameters[0].MethodSigIndex == -2) ? 1 : 0;
325 | method.Parameters[offset++].Name = "hProcess";
326 | method.Parameters[offset++].Name = "IpAddress";
327 | method.Parameters[offset++].Name = "dwSize";
328 | method.Parameters[offset++].Name = "flAllocationType";
329 | method.Parameters[offset++].Name = "flProtect";
330 | method.Parameters[offset++].Name = "nndPreferred";
331 | break;
332 | }
333 | }
334 | break;
335 | default:
336 | asm.EntryPoint.DeclaringType.NestedTypes.RemoveAt(x_nestedTypes);
337 | x_nestedTypes--;
338 | break;
339 | }
340 | }
341 | }
342 | }
343 |
344 | private bool isLocalTypeDelegate(Local loc, out ITypeDefOrRef delegateType)
345 | {
346 | delegateType = null;
347 | if (loc.Type is TypeSig && ((TypeSig)loc.Type).IsTypeDefOrRef)
348 | {
349 | ITypeDefOrRef del = ((TypeSig)loc.Type).ToTypeDefOrRef();
350 | if (((TypeDef)del).IsDelegate) { delegateType = del; return true; }
351 | }
352 | return false;
353 | }
354 | }
355 | }
356 |
--------------------------------------------------------------------------------
/XUnion/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Windows.Forms;
9 | using dnlib.DotNet;
10 |
11 | namespace XUnion
12 | {
13 | class Program
14 | {
15 | private static bool _stg2Export = false, _fixXor = true, _fixNames = true, _fixDelegates = true;
16 | private static ConsoleColor back1 = ConsoleColor.Gray, back2 = ConsoleColor.DarkGray;
17 |
18 | static int SelectMode(int defaultSelect = 0)
19 | {
20 | int selection = defaultSelect;
21 | bool noStg2 = v4.IsStage2ASM(asm);
22 | SetColorsFromPosition();
23 | while (true)
24 | {
25 | string[] options = new string[]
26 | {
27 | "Unpack",
28 | "Deobfuscate",
29 | "",
30 | "Extract Stage 2"
31 | };
32 | for (int x = 0; x < options.Length; x++)
33 | {
34 | switch (x)
35 | {
36 | case 2: continue;
37 | case 3: if (noStg2) { continue; } break;
38 | }
39 | Console.SetCursorPosition(1, x+2);
40 | if (x == selection) { Console.Write(" > " + options[x] + "\n"); }
41 | else { Console.Write(" " + options[x] + "\n"); }
42 | }
43 | ConsoleKeyInfo key = Console.ReadKey();
44 | switch (key.Key)
45 | {
46 | case ConsoleKey.UpArrow: if (selection > 0) { if (selection - 1 == 2) { selection -= 2; } else { selection--; } } break;
47 | case ConsoleKey.DownArrow: if (selection <= (noStg2 ? 0 : options.Length - 2)) { if (selection + 1 == 2) { selection += 2; } else { selection++; } } break;
48 | case ConsoleKey.Enter: return selection;
49 | }
50 | }
51 | }
52 |
53 | // Working but scrapped since each deobfuscation layer requires each other.
54 | /*static int[] SelectDeobMode(int defaultSelect = 0)
55 | {
56 | int selection = -1;
57 | bool clear = true;
58 | Console.BackgroundColor = Console.CursorLeft < Console.WindowWidth / 2 ? back2 : back1;
59 | Console.ForegroundColor = Console.CursorLeft < Console.WindowWidth / 2 ? back1 : back2;
60 | while (true)
61 | {
62 | if (clear)
63 | {
64 | for (int y = 5; y < 10; y++)
65 | {
66 | Console.SetCursorPosition(2, y);
67 | Console.Write(" ");
68 | }
69 | if (selection != -1) { return new int[] { 0, selection }; }
70 | clear = false;
71 | selection = defaultSelect;
72 | }
73 | string[] options = new string[]
74 | {
75 | "%OPT%Fix XORs",
76 | "%OPT%Fix Names",
77 | "%OPT%Remove Delegates",
78 | "",
79 | "Start"
80 | };
81 | bool[] optionsValues = new bool[3] { _fixXor, _fixNames, _fixDelegates };
82 | for (int x = 0; x < options.Length; x++)
83 | {
84 | if (options[x] == "") { continue; }
85 | Console.SetCursorPosition(2, x + 5);
86 | ConsoleColor ogFore = Console.ForegroundColor;
87 | if (options[x].StartsWith("%OPT%"))
88 | {
89 | if (optionsValues[x])
90 | {
91 | //if (selection == x) { Console.Write("> "); } else { Console.Write(" "); }
92 | if (selection == x) { Console.ForegroundColor = ConsoleColor.Black; }
93 | Console.Write("[");
94 | if (selection == x) { Console.ForegroundColor = ConsoleColor.Magenta; } else { Console.ForegroundColor = ConsoleColor.Green; }
95 | Console.Write("x");
96 | if (selection == x) { Console.ForegroundColor = ConsoleColor.Black; } else { Console.ForegroundColor = ogFore; }
97 | Console.Write("] ");
98 | }
99 | else
100 | {
101 | if (selection == x) { Console.ForegroundColor = ConsoleColor.Black; }
102 | Console.Write("[ ] ");
103 | }
104 | Console.ForegroundColor = ogFore;
105 | Console.Write(options[x].Replace("%OPT%", null) + "\n");
106 | }
107 | else
108 | {
109 | if (x == selection) { Console.Write(" > " + options[x] + "\n"); }
110 | else { Console.Write(" " + options[x] + "\n"); }
111 | }
112 | }
113 | ConsoleKeyInfo key = Console.ReadKey();
114 | switch (key.Key)
115 | {
116 | case ConsoleKey.UpArrow: if (selection > 0) { if (selection - 1 == 3) { selection -= 2; } else { selection--; } } break;
117 | case ConsoleKey.DownArrow: if (selection <= options.Length - 2) { if (selection + 1 == 3) { selection += 2; } else { selection++; } } break;
118 | case ConsoleKey.Backspace: clear = true; continue;
119 | case ConsoleKey.Enter:
120 | if (options[selection].StartsWith("%OPT%"))
121 | {
122 | switch (selection)
123 | {
124 | case 0: _fixXor = !_fixXor; break;
125 | case 1: _fixNames = !_fixNames; break;
126 | case 2: _fixDelegates = !_fixDelegates; break;
127 | default: return new int[] { 1, selection };
128 | }
129 | }
130 | break;
131 | }
132 | }
133 | }*/
134 |
135 | static void InitConsole(bool clear = false)
136 | {
137 | Console.CursorVisible = false;
138 | SetColorsFromPosition();
139 | drawOnBottomCorner(' '); // no scrollbars
140 | if (clear) { Console.Clear(); }
141 | }
142 |
143 | /*static readonly decimal version = 1.00m;
144 | static readonly string appText = "XUnion v" + version + " - misonothx";
145 |
146 | private static void DrawAppText(ConsoleColor fore = ConsoleColor.Gray, ConsoleColor back = ConsoleColor.Blue)
147 | {
148 | Console.ForegroundColor = fore; Console.BackgroundColor = back;
149 | int topTextIndex = 0;
150 | for (int x = 0; x < Console.BufferWidth; x++)
151 | {
152 | char ch = x < (Console.BufferWidth / 2) - (appText.Length / 2) ? ' ' : (topTextIndex < appText.Length ? appText[topTextIndex++] : ' ');
153 | Console.Write(ch);
154 | }
155 | }
156 | private static void DrawSideFrame(ConsoleColor color1 = ConsoleColor.Blue, ConsoleColor color2 = ConsoleColor.Cyan)
157 | {
158 | for (int y = 0; y < Console.WindowHeight - 1; y++)
159 | {
160 | if (y % 2 == 1) { Console.BackgroundColor = color1; }
161 | else { Console.BackgroundColor = color2; }
162 | Console.SetCursorPosition(Console.WindowWidth - 1, y);
163 | Console.Write(' ');
164 | Console.SetCursorPosition(0, y);
165 | Console.Write(' ');
166 | }
167 | Console.SetCursorPosition(0, Console.WindowHeight - 1);
168 | Console.BackgroundColor = color1;
169 | for (int x = 0; x < Console.BufferWidth; x++) { Console.Write(' '); }
170 | }*/
171 |
172 | private static void AlternateColors()
173 | {
174 | Console.BackgroundColor = Console.BackgroundColor == ConsoleColor.Gray ? ConsoleColor.DarkGray : ConsoleColor.Gray;
175 | Console.ForegroundColor = Console.BackgroundColor == ConsoleColor.Gray ? ConsoleColor.DarkGray : ConsoleColor.Gray;
176 | }
177 | private static void SetColorsFromPosition()
178 | {
179 | Console.BackgroundColor = Console.CursorLeft < Console.WindowWidth / 2 ? back2 : back1;
180 | Console.ForegroundColor = Console.CursorLeft < Console.WindowWidth / 2 ? back1 : back2;
181 | }
182 |
183 | private static void DrawSide(int sideNum)
184 | {
185 | for (int x = 0; x < Console.WindowWidth; x++)
186 | {
187 | SetColorsFromPosition();
188 | for (int y = 0; y < Console.WindowHeight; y++)
189 | {
190 | Console.SetCursorPosition(x, y);
191 | Console.Write(' ');
192 | }
193 | }
194 | drawOnBottomCorner('▓');
195 | }
196 |
197 | private static void DrawLayout(int activeSide)
198 | {
199 | for (int x = 0; x < Console.WindowWidth; x++)
200 | {
201 | SetColorsFromPosition();
202 | if (x == (Console.WindowWidth / 2) - 1) { AlternateColors(); }
203 | for (int y = 0; y < Console.WindowHeight; y++)
204 | {
205 | Console.SetCursorPosition(x, y);
206 | if (activeSide == 1 && x < (Console.WindowWidth / 2)) { Console.Write(' '); }
207 | else
208 | {
209 | if (activeSide == 2 && x > (Console.WindowWidth / 2)) { Console.Write(' '); }
210 | Console.Write('▓');
211 | }
212 | }
213 | }
214 | drawOnBottomCorner('▓');
215 | /*Console.SetCursorPosition(0, 0);
216 | Console.BackgroundColor = back1;
217 | int drawHeight = 1;
218 | for (int x = 0; x < Console.WindowWidth-1; x++)
219 | {
220 | if (x == (Console.WindowWidth / 2) - 3 ||
221 | x == (Console.WindowWidth / 2) + 3)
222 | {
223 | Console.ForegroundColor = x > (Console.WindowWidth/2) + 1?back1:back2;
224 | for (int y = 1; y < Console.BufferHeight - drawHeight; y++)
225 | {
226 | Console.SetCursorPosition(x, y);
227 | Console.Write('│');
228 | }
229 | Console.SetCursorPosition(x, x == (Console.WindowWidth / 2) + 3 ? Console.BufferHeight - drawHeight : 0);
230 | }
231 |
232 | if (x == Console.WindowWidth / 2)
233 | {
234 | for (int y = 0; y < Console.BufferHeight - drawHeight; y++)
235 | {
236 | Console.BackgroundColor = y%2==1 ? back1 : back2;
237 | Console.SetCursorPosition(x, y);
238 | Console.Write(' ');
239 | }
240 | Console.SetCursorPosition(x, Console.BufferHeight - drawHeight);
241 | }
242 | Console.BackgroundColor = x >= Console.BufferWidth / 2?back2:back1;
243 | Console.Write(' ');
244 | }*/
245 | }
246 |
247 | private static void drawOnBottomCorner(char ch)
248 | {
249 | Console.SetBufferSize(Console.WindowWidth+1, Console.WindowHeight);
250 | Console.SetCursorPosition(Console.WindowWidth - 1, Console.WindowHeight - 1);
251 | Console.Write(ch);
252 | Console.SetBufferSize(Console.WindowWidth, Console.WindowHeight);
253 | }
254 |
255 | static ModuleDefMD asm;
256 | static v4 mng;
257 |
258 | static void CheckForUpdates()
259 | {
260 | if (!Updater.HasInternetConnection()) { return; }
261 | Updater update = new Updater(Updater.GetUpdate());
262 | string text = "New update available!\n\nCurrent Version: " + Updater.CurrentVersion + "\nLatest Version: " + update.LatestVersion + "\n\nChangelog:\n\n";
263 | foreach (string cl_text in update.ChangeLog) { text += cl_text + "\n"; }
264 | text += "\nDownload now?";
265 | if (!update.IsRunningLatest())
266 | {
267 | if (MessageBox.Show(text, "Update Available!", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information) == DialogResult.Yes)
268 | {
269 | update.DownloadUpdate();
270 | Application.Exit();
271 | }
272 | }
273 | }
274 |
275 | public static string path; // used by Updater.cs
276 |
277 | [STAThread]
278 | static void Main(string[] args)
279 | {
280 | path = Path.GetFullPath(args[0]);
281 | Console.SetWindowSize(50, 15);
282 | InitConsole(true);
283 | Console.SetCursorPosition(1, 1);
284 | CheckForUpdates();
285 | Console.WriteLine("Loading '" + Path.GetFileName(args[0]) + "'...");
286 | Console.WriteLine();
287 | try { ModuleDefMD tempAsm = ModuleDefMD.Load(Path.GetFullPath(args[0])); }
288 | catch (BadImageFormatException)
289 | {
290 | Console.WriteLine(" Native executable detected!");
291 | Console.WriteLine(" Loading 'XUnionPE.exe'...");
292 | Process.Start("XUnionPE.exe", '"' + Path.GetFullPath(args[0]) + '"').WaitForExit();
293 | return;
294 | }
295 | //DrawSideFrame();
296 | //DrawAppText();
297 | asm = ModuleDefMD.Load(Path.GetFullPath(args[0]));
298 | mng = new v4(asm, false, v4.IsStage2ASM(asm));
299 | int mode = 0/*, deobHover = 0*/;
300 | SaveFileDialog sfd = new SaveFileDialog();
301 | bool exit = false;
302 | Console.Clear();
303 | DrawLayout(1);
304 | drawOnBottomCorner(' ');
305 | while (!exit)
306 | {
307 | bool selectModeBackspace = false;
308 | mode = SelectMode(mode);
309 | switch (mode)
310 | {
311 | case 0:
312 | if (sfd.ShowDialog() == DialogResult.OK)
313 | {
314 | Console.Clear();
315 | Console.SetCursorPosition(0, 1);
316 | Console.WriteLine(" Unpacking '" + Path.GetFileName(mng.Shared.path) + "'...");
317 | mng.Unpack(sfd.FileName);
318 | Console.WriteLine("Successfully unpacked '" + Path.GetFileName(mng.Shared.path) + "'!");
319 | exit = true;
320 | }
321 | break;
322 | case 1:
323 | if (sfd.ShowDialog() == DialogResult.OK)
324 | {
325 | Deobfuscators.v4 deob = null;
326 | if (mng.Shared.Stage2Only)
327 | {
328 | mng.Stage2Deobfuscator.Deobfuscate();
329 | deob = mng.Stage2Deobfuscator;
330 | }
331 | else
332 | {
333 | mng.Stage1Deobfuscator.Deobfuscate();
334 | deob = mng.Stage1Deobfuscator;
335 | }
336 | Console.Clear();
337 | Console.SetCursorPosition(0, 1);
338 | Console.WriteLine(" Deobfuscating '" + Path.GetFileName(mng.Shared.path) + "'...");
339 | Console.WriteLine();
340 | //Console.SetCursorPosition((Console.BufferWidth / 2) + 2, 2);
341 | Console.ForegroundColor = ConsoleColor.White;
342 | Console.WriteLine(" " + deob.DelegateFixCount + " Delegates Removed");
343 | Console.WriteLine(" " + deob.XORStringFixCount + " Strings Fixed");
344 | Console.WriteLine(" " + deob.XORFixCount + " Numbers Fixed");
345 | Console.WriteLine(" " + deob.RenameFixCount + " Elements Renamed");
346 | Console.WriteLine();
347 | Console.WriteLine(" '" + Path.GetFileName(mng.Shared.path) + "' Successfully Deobfuscated!");
348 | Console.ForegroundColor = ConsoleColor.Gray;
349 | Console.WriteLine(" Saving Deobfuscated File...");
350 | mng.Shared.asm.Write(sfd.FileName);
351 | Console.ForegroundColor = ConsoleColor.White;
352 | Console.WriteLine();
353 | Console.WriteLine(" Deobfuscated File Successfully Saved!");
354 | exit = true;
355 | }
356 | break;
357 | case 3:
358 | if (sfd.ShowDialog() == DialogResult.OK)
359 | {
360 | Console.Clear();
361 | Console.SetCursorPosition(0, 1);
362 | Console.Write(" Exporting Stage 2... (" + mng.Shared.Stage2RawFile.Length + " bytes)");
363 | File.WriteAllBytes(sfd.FileName, mng.Shared.Stage2RawFile);
364 | Console.ForegroundColor = ConsoleColor.White;
365 | Console.Write(" Stage 2 Exported!");
366 | exit = true;
367 | }
368 | break;
369 | }
370 | if (selectModeBackspace) { continue; }
371 | }
372 |
373 | /*ModuleDefMD asm = ModuleDefMD.Load(Path.GetFullPath(args[0]));
374 | v4 mng = new v4(asm, false, v4.IsStage2ASM(asm));
375 | mng.Stage1Deobfuscator.Deobfuscate();
376 | mng.Stage2Deobfuscator.Deobfuscate();
377 | mng.Shared.asm.Write(Path.GetFileNameWithoutExtension(args[0]) + "-stg1-unpk_XUnion" + Path.GetExtension(args[0]));
378 | mng.Shared.Stage2asm.Write(Path.GetFileNameWithoutExtension(args[0]) + "-stg2-unpk_XUnion" + Path.GetExtension(args[0]));
379 | File.WriteAllBytes(Path.GetFileNameWithoutExtension(args[0]) + "-app-unpk_XUnion" + Path.GetExtension(args[0]), mng.Shared.OutputRawFile);*/
380 | Console.BackgroundColor = ConsoleColor.DarkGreen;
381 | Console.ForegroundColor = ConsoleColor.White;
382 | Console.SetCursorPosition(0, Console.BufferHeight - 1);
383 | for (int x = 0; x < Console.BufferWidth - 1; x++) { Console.Write(' '); }
384 | drawOnBottomCorner(' ');
385 | Console.SetCursorPosition(2, Console.BufferHeight - 1);
386 | Console.Write("Press any key to exit...");
387 | Console.ReadKey();
388 | }
389 | }
390 | }
391 |
--------------------------------------------------------------------------------
/XUnion/Unpackers/4.0.0.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using dnlib.DotNet.Emit;
7 | using dnlib.DotNet;
8 | using dnlib;
9 | using System.IO;
10 | using System.Reflection;
11 | using System.Resources;
12 | using System.IO.Compression;
13 |
14 | namespace XUnion.Unpackers
15 | {
16 | public class v4
17 | {
18 | public class Stage2
19 | {
20 | private XUnion.v4.SharedItems SharedItems;
21 |
22 | public Stage2(ref XUnion.v4.SharedItems sharedItems) { SharedItems = sharedItems; }
23 |
24 | public void GetResDecryptMethod()
25 | {
26 | for (int x = 0; x < SharedItems.Stage2asm.EntryPoint.DeclaringType.Methods.Count; x++)
27 | {
28 | MethodDef methods = SharedItems.Stage2asm.EntryPoint.DeclaringType.Methods[x];
29 | if (!methods.HasBody) { continue; }
30 | Instruction[] insts = methods.Body.Instructions.ToArray();
31 | for (int x_inst = 0; x_inst < insts.Length; x_inst++)
32 | {
33 | Instruction inst = insts[x_inst];
34 | try
35 | {
36 | if (inst.OpCode == OpCodes.Call &&
37 | inst.Operand is MemberRef &&
38 | insts[x_inst - 4].OpCode == OpCodes.Call &&
39 | insts[x_inst - 8].OpCode == OpCodes.Call &&
40 | insts[x_inst - 4].Operand is MethodDef &&
41 | insts[x_inst - 8].Operand is MethodDef &&
42 | Utils.CompareNamespaceMemberRef(inst, typeof(Buffer), "BlockCopy", new Type[] { typeof(Array), typeof(int), typeof(Array), typeof(int), typeof(int) }))
43 | {
44 | MethodDef intPart = ((MethodDef)insts[x_inst - 4].Operand);
45 |
46 | if (intPart.Body.Instructions[0].IsLdarg() &&
47 | intPart.Body.Instructions[1].IsLdarg() &&
48 | intPart.Body.Instructions[2].IsLdcI4() &&
49 | intPart.Body.Instructions[3].OpCode == OpCodes.Xor &&
50 | intPart.Body.Instructions[4].OpCode == OpCodes.Xor &&
51 | intPart.Body.Instructions[5].OpCode == OpCodes.Ret)
52 | {
53 | SharedItems.ResourceDecrypt = methods;
54 | return;
55 | }
56 | }
57 | }
58 | catch { }
59 | }
60 | }
61 | throw new Exception("Could not find ResourceDecryption Function!");
62 | }
63 | public int[] GetBufferValues()
64 | {
65 | int[] result = new int[4];
66 | Instruction[] insts = SharedItems.ResourceDecrypt.Body.Instructions.ToArray();
67 |
68 | for (int x_inst = 0; x_inst < insts.Length; x_inst++)
69 | {
70 | Instruction inst = insts[x_inst];
71 | if (inst.OpCode == OpCodes.Call &&
72 | inst.Operand is MethodDef &&
73 | inst.Operand == SharedItems.UnXorMethod_IntPart)
74 | {
75 | try
76 | {
77 | if (insts[x_inst - 4].OpCode == OpCodes.Callvirt &&
78 | insts[x_inst + 2].OpCode == OpCodes.Callvirt &&
79 | insts[x_inst - 4].Operand is MemberRef &&
80 | insts[x_inst + 2].Operand is MemberRef &&
81 | ((MemberRef)insts[x_inst - 2].Operand).DeclaringType.FullName == typeof(Assembly).FullName + "." + typeof(Assembly).GetMethod("GetManifestResourceName").Name &&
82 | ((MemberRef)insts[x_inst - 4].Operand).DeclaringType.FullName == typeof(Assembly).FullName + "." + typeof(Assembly).GetMethod("GetManifestResourceStream", new Type[] { typeof(string) }).Name)
83 | {
84 | result[0] = SharedItems.XORMng.ToInt(insts[x_inst - 2].GetLdcI4Value(), insts[x_inst - 1].GetLdcI4Value()); // Index of resource name
85 | }
86 |
87 | if (insts[x_inst + 1].OpCode == OpCodes.Sub &&
88 | insts[x_inst + 2].OpCode == OpCodes.Newarr &&
89 | insts[x_inst + 2].Operand is TypeRef &&
90 | ((TypeRef)insts[x_inst + 2].Operand).FullName == typeof(byte).FullName)
91 | {
92 | result[1] = SharedItems.XORMng.ToInt(insts[x_inst - 2].GetLdcI4Value(), insts[x_inst - 1].GetLdcI4Value()); // Size of output array
93 | }
94 |
95 | if (insts[x_inst - 6].OpCode == OpCodes.Sub &&
96 | insts[x_inst - 5].OpCode == OpCodes.Newarr &&
97 | insts[x_inst - 5].Operand is TypeRef &&
98 | ((TypeRef)insts[x_inst - 5].Operand).FullName == typeof(byte).FullName)
99 | {
100 | result[2] = SharedItems.XORMng.ToInt(insts[x_inst - 2].GetLdcI4Value(), insts[x_inst - 1].GetLdcI4Value()); // Buffer.BlockCopy startIndex
101 | }
102 |
103 | if (insts[x_inst - 10].OpCode == OpCodes.Sub &&
104 | insts[x_inst - 9].OpCode == OpCodes.Newarr &&
105 | insts[x_inst - 9].Operand is TypeRef &&
106 | ((TypeRef)insts[x_inst - 5].Operand).FullName == typeof(byte).FullName)
107 | {
108 | result[3] = SharedItems.XORMng.ToInt(insts[x_inst - 2].GetLdcI4Value(), insts[x_inst - 1].GetLdcI4Value()); // Buffer.BlockCopy count
109 | }
110 | }
111 | catch { }
112 | }
113 | }
114 |
115 | return result;
116 | }
117 | public void IsCompressed()
118 | {
119 | for (int x_methods = 0; x_methods < SharedItems.Stage2asm.EntryPoint.DeclaringType.Methods.Count; x_methods++)
120 | {
121 | MethodDef methods = SharedItems.Stage2asm.EntryPoint.DeclaringType.Methods[x_methods];
122 | if (!methods.HasBody) { continue; }
123 | Instruction[] insts = methods.Body.Instructions.ToArray();
124 | try
125 | {
126 | if (insts[0].OpCode == OpCodes.Newobj &&
127 | insts[3].OpCode == OpCodes.Newobj &&
128 | insts[5].OpCode == OpCodes.Newobj &&
129 | insts[9].OpCode == OpCodes.Callvirt &&
130 | insts[9].Operand is MemberRef &&
131 | Utils.CompareNamespaceMemberRef(insts[9], typeof(Stream), "CopyTo", new Type[] { typeof(Stream) }))
132 | {
133 | SharedItems.isCompressed = true;
134 | SharedItems.GZipStage2Method = methods;
135 | return;
136 | }
137 | } catch { }
138 | }
139 | }
140 |
141 | public void Fix()
142 | {
143 | MSILArray resNameArr = null;
144 |
145 | Instruction[] insts = SharedItems.Stage2asm.EntryPoint.Body.Instructions.ToArray();
146 | for (int x = 0; x < insts.Length; x++)
147 | {
148 | Instruction inst = insts[x];
149 |
150 | if (inst.OpCode == OpCodes.Newarr) { int.Parse("0"); }
151 |
152 | if (inst.OpCode == OpCodes.Newarr &&
153 | inst.Operand is TypeRef &&
154 | ((TypeRef)inst.Operand).FullName == typeof(ushort).FullName &&
155 | insts[x - 5].OpCode == OpCodes.Call &&
156 | insts[x - 5].Operand is MethodDef &&
157 | insts[x - 1].IsLdcI4())
158 | {
159 | if (((MethodDef)insts[x - 5].Operand).Body.Instructions[3].OpCode == OpCodes.Xor &&
160 | ((MethodDef)insts[x - 5].Operand).Body.Instructions[4].OpCode == OpCodes.Xor &&
161 | ((MethodDef)insts[x - 5].Operand).Body.Instructions[5].OpCode == OpCodes.Ret)
162 | {
163 | //SharedItems.UnXorMethod_IntPart = (MethodDef)insts[x - 5].Operand;
164 | resNameArr = MSILArray.ParseArray(insts, x - 1);
165 | }
166 | }
167 | }
168 |
169 | string resourceName = SharedItems.XORMng.Compute(Utils.ToUInt16(resNameArr.ToArray()));
170 |
171 | int[] bufVal = GetBufferValues();
172 | using (ResourceReader rr = new ResourceReader(SharedItems.Stage2app.GetManifestResourceStream(
173 | SharedItems.Stage2app.GetManifestResourceNames()[bufVal[0]])))
174 | {
175 | byte[] srcApp;
176 | string resType;
177 |
178 | rr.GetResourceData(resourceName, out resType, out srcApp);
179 |
180 | if (SharedItems.isCompressed)
181 | {
182 | byte[] decompSrc = new byte[srcApp.Length];
183 | bool offsetHeader = (srcApp[0] != 0x1F) && (srcApp[1] != 0x8B);
184 | Buffer.BlockCopy(srcApp, offsetHeader ? 4 : 0, decompSrc, 0, srcApp.Length - 4);
185 | MemoryStream tempMs = new MemoryStream();
186 | GZipStream decomp = new GZipStream(new MemoryStream(decompSrc), CompressionMode.Decompress);
187 | decomp.CopyTo(tempMs);
188 | srcApp = tempMs.ToArray();
189 | SharedItems.OutputRawFile = srcApp;
190 | }
191 | else
192 | {
193 | if (srcApp[0] != 0x4d && // PEunion sometimes just adds 4 junk bytes to the source file, causing the packed app to not
194 | srcApp[1] != 0x5a) // be usable, this fixes it.
195 | {
196 | SharedItems.OutputRawFile = new byte[(srcApp.Length - bufVal[1]) - 4];
197 | Buffer.BlockCopy(srcApp, bufVal[2] + 4, SharedItems.OutputRawFile, 0, SharedItems.OutputRawFile.Length - 4);
198 | }
199 | else
200 | {
201 | SharedItems.OutputRawFile = new byte[srcApp.Length - bufVal[1]];
202 | Buffer.BlockCopy(srcApp, bufVal[2], SharedItems.OutputRawFile, 0, SharedItems.OutputRawFile.Length);
203 | }
204 | }
205 | }
206 | }
207 | }
208 |
209 | private XUnion.v4.SharedItems SharedItems;
210 |
211 | public v4(ref XUnion.v4.SharedItems sharedItems) { SharedItems = sharedItems; }
212 |
213 | public long[] GetDecryptionValues()
214 | {
215 | long[] result = new long[6];
216 |
217 | Instruction[] insts = SharedItems.asm.EntryPoint.Body.Instructions.ToArray();
218 | for (int x_inst = 0; x_inst < insts.Length; x_inst++)
219 | {
220 | Instruction inst = insts[x_inst];
221 |
222 | try
223 | {
224 | if (inst.OpCode == OpCodes.Call &&
225 | inst.Operand is MethodDef &&
226 | insts[x_inst + 2].OpCode == OpCodes.Call &&
227 | insts[x_inst + 2].Operand is MemberRef &&
228 | (MethodDef)inst.Operand == SharedItems.UnXorMethod_IntPart &&
229 | ((MemberRef)insts[x_inst + 2].Operand).DeclaringType.FullName == typeof(Assembly).FullName)
230 | {
231 | result[0] = insts[x_inst - 6].GetLdcI4Value(); // Bitshift
232 | result[1] = insts[x_inst - 4].GetLdcI4Value(); // Bitshift
233 | result[4] = SharedItems.XORMng.ToInt(insts[x_inst - 2].GetLdcI4Value(),
234 | insts[x_inst - 1].GetLdcI4Value()); continue; // Offsets bitshift
235 | }
236 |
237 | if (inst.OpCode == OpCodes.Call &&
238 | insts[x_inst - 4].OpCode == OpCodes.Newarr &&
239 | insts[x_inst + 4].OpCode == OpCodes.Call &&
240 | inst.Operand is MethodDef &&
241 | insts[x_inst + 4].Operand is MethodDef &&
242 | insts[x_inst - 4].Operand is TypeRef &&
243 | (MethodDef)inst.Operand == SharedItems.UnXorMethod_IntPart &&
244 | (MethodDef)insts[x_inst + 4].Operand == SharedItems.UnXorMethod_IntPart &&
245 | ((ITypeDefOrRef)insts[x_inst - 4].Operand).FullName == typeof(byte).FullName)
246 | {
247 | result[2] = SharedItems.XORMng.ToInt(insts[x_inst - 2].GetLdcI4Value(),
248 | insts[x_inst - 1].GetLdcI4Value());
249 | result[3] = SharedItems.XORMng.ToInt(insts[x_inst + 2].GetLdcI4Value(),
250 | insts[x_inst + 3].GetLdcI4Value());
251 | result[5] = insts[x_inst - 7].GetLdcI4Value(); // Packed Assembly Size
252 | }
253 | }
254 | catch { }
255 | }
256 | return result;
257 | }
258 | public void GetStage2ASM()
259 | {
260 | Instruction[] insts = SharedItems.asm.EntryPoint.Body.Instructions.ToArray();
261 |
262 | MSILTryCatch hdex = MSILTryCatch.Parse(insts, SharedItems.asm.EntryPoint.Body.ExceptionHandlers[2]);
263 |
264 | int resNamArrStartIndex = -1;
265 |
266 | for (int x = 0; x < hdex.TryInstructions.Length; x++)
267 | {
268 | Instruction inst = hdex.TryInstructions[x];
269 | try
270 | {
271 | if (inst.IsStloc() &&
272 | hdex.TryInstructions[x - 1].OpCode == OpCodes.Newarr &&
273 | hdex.TryInstructions[x - 1].Operand is TypeRef &&
274 | ((TypeRef)hdex.TryInstructions[x - 1].Operand).FullName == typeof(ushort).FullName &&
275 | hdex.TryInstructions[x - 5].IsLdloc()) { resNamArrStartIndex = x - 2; break; }
276 | }
277 | catch { }
278 | }
279 |
280 | ushort[] nameArr = Utils.ToUInt16(MSILArray.ParseArray(hdex.TryInstructions).ToArray()),
281 | resourceNameArr = Utils.ToUInt16(MSILArray.ParseArray(hdex.TryInstructions, resNamArrStartIndex).ToArray());
282 |
283 | string name = SharedItems.XORMng.Compute(nameArr),
284 | resourceName = SharedItems.XORMng.Compute(resourceNameArr);
285 |
286 | long[] dVal = GetDecryptionValues();
287 |
288 | MemoryStream ms = new MemoryStream();
289 | SharedItems.app.GetManifestResourceStream(name).CopyTo(ms);
290 |
291 | using (ResourceReader rr = new ResourceReader(SharedItems.app.GetManifestResourceStream(name)))
292 | {
293 | byte[] encryptedApp;
294 | byte[] decryptedApp = new byte[dVal[5]];
295 |
296 | string resType;
297 |
298 | rr.GetResourceData(resourceName, out resType, out encryptedApp);
299 |
300 | for (long x = dVal[2]; x < dVal[5]; x++)
301 | {
302 | decryptedApp[x] = (byte)((uint)encryptedApp[dVal[3]++] ^ (uint)dVal[0]);
303 | if ((dVal[1] & 1U) == 1U) { dVal[3] += dVal[4]; }
304 | dVal[0] = ((uint)dVal[0] >> 5 | (uint)dVal[0] << 27) * 7U;
305 | dVal[1] = ((uint)dVal[1] >> 1 | (uint)dVal[1] << 31);
306 | }
307 |
308 | SharedItems.Stage2RawFile = decryptedApp;
309 | SharedItems.Stage2app = Assembly.Load(decryptedApp);
310 | SharedItems.Stage2asm = ModuleDefMD.Load(decryptedApp);
311 | }
312 | }
313 | }
314 | }
315 |
--------------------------------------------------------------------------------
/XUnion/Updater.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Security.Cryptography;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Net.NetworkInformation;
8 | using Microsoft.VisualBasic;
9 | using System.Diagnostics;
10 | using System.IO;
11 |
12 | namespace XUnion
13 | {
14 | class Updater
15 | {
16 | public Updater(byte[] updateFileStream)
17 | {
18 | string[] fileData = Encoding.Default.GetString(updateFileStream).Split("\n\n".ToArray());
19 | bool isChangelogData = false;
20 | List ChangeLogData = new List();
21 | foreach (string line in fileData)
22 | {
23 | if (line.StartsWith("##") || line.StartsWith("//") || line == "") { continue; }
24 | if (isChangelogData) { ChangeLogData.Add(line); continue; }
25 | if (line == "[CHANGELOG]") { isChangelogData = true; continue; }
26 | string p1 = line.Split("=".ToCharArray())[0].Replace("\t", null);
27 | string p2 = line.Split("=".ToCharArray())[1].Remove(0, 1);
28 | switch (p1)
29 | {
30 | case "AppName": AppName = p2; break;
31 | case "Version": LatestVersion = p2; break;
32 | case "DownloadLink": UpdateLink = p2; break;
33 | case "SHA256_Checksum": SHA256Checksum = FromHexString(p2.ToUpper()); break;
34 | case "UpdateSize": UpdateSize = p2; break;
35 | }
36 | }
37 | UpdateDownloadName = CurrentAppName + "-Update_v" + LatestVersion + ".zip";
38 | ChangeLog = ChangeLogData.ToArray();
39 | if (SHA256Checksum == null) { throw new Exception("Missing Checksum for Update!"); } // sekurity 101
40 | }
41 |
42 | private byte[] FromHexString(string hex)
43 | {
44 | return Enumerable.Range(0, hex.Length)
45 | .Where(x => x % 2 == 0)
46 | .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
47 | .ToArray();
48 | }
49 |
50 | public const string
51 | CurrentAppName = "XUnion",
52 | CurrentVersion = "b1.0",
53 | RepoLink = "https://github.com/miso-xyz/GruMinion",
54 | UpdateLogLink = "https://raw.githubusercontent.com/miso-xyz/GruMinion/main/latest.info";
55 |
56 | public string AppName { get; set; }
57 | public string LatestVersion { get; set; }
58 | public string[] ChangeLog { get; set; }
59 | public string UpdateLink { get; set; }
60 | public byte[] SHA256Checksum { get; set; }
61 | public string UpdateSize { get; set; }
62 | public string UpdateDownloadName { get; set; }
63 |
64 | public static bool HasInternetConnection() { try { new Ping().Send("github.com", 750); return true; } catch { return false; } }
65 |
66 | public bool IsRunningLatest() { return CurrentVersion == LatestVersion; }
67 | public bool VerifyChecksum(byte[] data) { return BitConverter.ToString(SHA256.Create().ComputeHash(data)) == BitConverter.ToString(SHA256Checksum); }
68 |
69 | public void DownloadUpdate()
70 | {
71 | using (WebClient wc = new WebClient())
72 | {
73 | wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadingUpdateEvent);
74 | wc.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(wc_DownloadFileCompleted);
75 | wc.DownloadFileAsync(new Uri(UpdateLink), UpdateDownloadName);
76 | }
77 | while (true) { Console.ReadKey(); }
78 | }
79 |
80 | void wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
81 | {
82 | //Process.Start(AppDomain.CurrentDomain.BaseDirectory + "UniShieldUpdateInstaller.exe", Path.GetFullPath(UpdateDownloadName) + " --restart " + Program.path);
83 | Console.Clear();
84 | Console.ForegroundColor = ConsoleColor.Green;
85 | Console.SetCursorPosition(1, 1);
86 | Console.Write("Comparing Checksums...");
87 | if (!VerifyChecksum(File.ReadAllBytes(AppDomain.CurrentDomain.BaseDirectory + UpdateDownloadName)))
88 | {
89 | Console.SetCursorPosition(1, 1);
90 | Console.ForegroundColor = ConsoleColor.DarkRed;
91 | Console.WriteLine("Invalid Checksum!");
92 | Console.ResetColor();
93 | Console.SetCursorPosition(1, 2);
94 | Console.WriteLine("Press any key to exit!");
95 | Console.ReadKey();
96 | Environment.Exit(0);
97 | }
98 | Console.SetCursorPosition(1, 1);
99 | Console.ForegroundColor = ConsoleColor.Green;
100 | Console.WriteLine("Valid Checksum!");
101 | Process p = new Process();
102 | p.StartInfo.FileName = "cmd";
103 | p.StartInfo.Arguments = "/K timeout /T 1 /nobreak && cd " + AppDomain.CurrentDomain.BaseDirectory + " && 7z.exe e -y " + UpdateDownloadName + " && start " + CurrentAppName + ".exe " + '"' + Program.path + '"' + " && exit";
104 | p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
105 | p.Start();
106 | Environment.Exit(0);
107 | //Process.Start(Path.GetFullPath(UpdateDownloadName));
108 | }
109 |
110 | void wc_DownloadingUpdateEvent(object sender, DownloadProgressChangedEventArgs e)
111 | {
112 | Console.ForegroundColor = ConsoleColor.Cyan;
113 | Console.Clear();
114 | Console.SetCursorPosition(1, 1);
115 | Console.Write(e.ProgressPercentage + "% (" + e.BytesReceived + "/" + e.TotalBytesToReceive + ")");
116 | }
117 |
118 | public static byte[] GetUpdate(string updateLink = UpdateLogLink) { ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; return new WebClient().DownloadData(updateLink); }
119 | }
120 | }
--------------------------------------------------------------------------------
/XUnion/Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using dnlib.DotNet;
7 | using dnlib.DotNet.Emit;
8 |
9 | namespace XUnion
10 | {
11 | class Utils
12 | {
13 | public static ushort[] ToUInt16(object[] src)
14 | {
15 | List result = new List();
16 | for (int x = 0; x < src.Length; x++) { result.Add(ushort.Parse(src[x].ToString())); }
17 | return result.ToArray();
18 | }
19 |
20 | public static bool CompareNamespaceMemberRef (Instruction srcInst, Type matchType, string methodName, Type[] methodArgs = null)
21 | {
22 | string instNamespace = ((MemberRef)srcInst.Operand).DeclaringType.FullName + "." + ((MemberRef)srcInst.Operand).Name,
23 | matchClassNamespace = matchType.FullName,
24 | matchMethodName = "";
25 | if (methodArgs == null) { matchMethodName = matchType.GetMethod(methodName).Name; }
26 | else { matchMethodName = matchType.GetMethod(methodName, methodArgs).Name; }
27 | return instNamespace == matchClassNamespace + "." + matchMethodName;
28 | }
29 | public static bool CompareNamespaceMethodSpec(Instruction srcInst, Type matchType, string methodName, Type[] methodArgs = null)
30 | {
31 | string instNamespace = ((MethodSpec)srcInst.Operand).DeclaringType.FullName + "." + ((MethodSpec)srcInst.Operand).Name,
32 | matchClassNamespace = matchType.FullName,
33 | matchMethodName = "";
34 | if (methodArgs == null) { matchMethodName = matchType.GetMethod(methodName).Name; }
35 | else { matchMethodName = matchType.GetMethod(methodName, methodArgs).Name; }
36 | return instNamespace == matchClassNamespace + "." + matchMethodName;
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/XUnion/XORManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace XUnion
8 | {
9 | public class XORManager
10 | {
11 | public XORManager(int skipVal, int arrVal, int intXor)
12 | {
13 | SkipValue = skipVal;
14 | ArrayValue = arrVal;
15 | IntXorValue = intXor;
16 | }
17 |
18 | public static int ToInt(int val1, int val2, int xorValue) { return val1 ^ (val2 ^ xorValue); }
19 | public int ToInt(int val1, int val2) { return ToInt(val1, val2, IntXorValue); }
20 |
21 | public string Compute(ushort[] src)
22 | {
23 | string result = "";
24 | foreach (ushort b in src.Skip(SkipValue)) { result += (char)(b ^ src[ArrayValue]); }
25 | return result;
26 | }
27 |
28 | public int SkipValue { get; set; }
29 | public int ArrayValue { get; set; }
30 | public int IntXorValue { get; set; }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/XUnion/XUnion.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {13F9CE4F-16F9-4313-BB8E-EC737BCD3898}
8 | Exe
9 | Properties
10 | XUnion
11 | XUnion
12 | v4.5
13 | 512
14 |
15 |
16 | x86
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | true
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 | ..\..\..\dlls\dnlib.dll
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
70 |
--------------------------------------------------------------------------------
/XUnion/dnlibUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using dnlib.DotNet.Emit;
7 | using dnlib.DotNet;
8 | using dnlib;
9 |
10 | namespace XUnion
11 | {
12 | class dnlibUtils
13 | {
14 | public static int IndexOf(Instruction[] insts, Instruction inst, bool throwIfInvalid = false)
15 | {
16 | if (insts.Contains(inst)) { return insts.ToList().IndexOf(inst); } else { if (throwIfInvalid) { new IndexOutOfRangeException(); } return -1; }
17 | }
18 | }
19 |
20 | class MSILArray
21 | {
22 | /* 0x00 = Array Length | ldc
23 | * 0x01 = Array Type | newarr
24 | * 0x02 = Set 0x00 and 0x01 to defined Array Stack Value/Local | stloc
25 | *
26 | * --- ITEM LAYOUT ---
27 | *
28 | * 0x00 = Load defined Array Stack Value/Local | ldloc
29 | * 0x01 = Index of current item | ldc
30 | * 0x02 = Data | OpCode with Operand of matching nature with Array Type
31 | * 0x03 = Replaces data at 0x01 to 0x02 | stelem */
32 |
33 | public MSILArray() { }
34 | public MSILArray(Instruction[] insts) { ParseArray(insts); }
35 | public MSILArray(Instruction[] insts, int index = 0) { ParseArray(insts, index); }
36 | public MSILArray(MethodDef method , int index = 0) { ParseArray(method.Body.Instructions.ToArray(), index); }
37 |
38 | public static MSILArray ParseArray(Instruction[] insts, int index = 0)
39 | {
40 | int ARR_SIZE = insts[index].GetLdcI4Value();
41 | Local ARR_VAL = (Local)insts[index + 2].Operand;
42 | ITypeDefOrRef ARR_TYPE = (ITypeDefOrRef)insts[index + 1].Operand;
43 |
44 | List arr = new List(ARR_SIZE);
45 | MSILArray result = new MSILArray();
46 |
47 | for (int x_item = index + 5; arr.Count < ARR_SIZE; x_item += 4)
48 | {
49 | Instruction CurrentItem = insts[x_item],
50 | IndexInstruction = insts[x_item-1];
51 |
52 | if (!IndexInstruction.IsLdcI4()) { break; }
53 |
54 | int CurrentIndex = IndexInstruction.GetLdcI4Value();
55 | if (IndexInstruction.GetLdcI4Value() != arr.Count)
56 | {
57 | for (int x_offset = arr.Count; x_offset < CurrentIndex; x_offset++)
58 | {
59 | if (IsLdcI4Array(ARR_TYPE)) { arr.Add( Instruction.CreateLdcI4(0)); }
60 | else { arr.Add(new Instruction(OpCodes.UNKNOWN1)); }
61 | }
62 | }
63 | arr.Add(insts[x_item]);
64 | }
65 |
66 | result.Type = ARR_TYPE;
67 | result.Items = arr.ToArray();
68 | result.LocalStack = ARR_VAL;
69 | result.RawSource = insts.ToList().GetRange(index, ARR_SIZE * 4).ToArray();
70 |
71 | return result;
72 | }
73 |
74 | private static bool IsLdcI4Array(ITypeDefOrRef srcType)
75 | {
76 | if (srcType.FullName == typeof(int).FullName ||
77 | srcType.FullName == typeof(short).FullName ||
78 | srcType.FullName == typeof(ushort).FullName ||
79 | srcType.FullName == typeof(byte).FullName ||
80 | srcType.FullName == typeof(long).FullName ||
81 | srcType.FullName == typeof(ulong).FullName ||
82 | srcType.FullName == typeof(uint).FullName)
83 | { return true; }
84 | return false;
85 | }
86 |
87 | public object[] ToArray()
88 | {
89 | object[] obj = new object[Items.Length];
90 | for (int x = 0; x < Items.Length; x++) { if (Items[x].IsLdcI4()) { obj[x] = Items[x].GetLdcI4Value(); } else { obj[x] = Items[x].Operand; } }
91 | return obj;
92 | }
93 |
94 | public int RawCount { get { return (Items.Length * 4) + 3; } }
95 | public Instruction[] RawSource { get; set; }
96 | public Instruction[] Items { get; set; }
97 | public ITypeDefOrRef Type { get; set; }
98 | public Local LocalStack { get; set; }
99 | }
100 |
101 | class MSILTryCatch
102 | {
103 | public MSILTryCatch() { }
104 | public MSILTryCatch(CilBody body , int exhdIndex ) { Parse(body.Instructions.ToArray(), body.ExceptionHandlers[exhdIndex]); }
105 | public MSILTryCatch(MethodDef method , int exhdIndex ) { Parse(method.Body.Instructions.ToArray(), method.Body.ExceptionHandlers[exhdIndex]); }
106 | public MSILTryCatch(Instruction[] insts, ExceptionHandler exhd) { Parse(insts, exhd); }
107 |
108 | public static MSILTryCatch Parse(Instruction[] insts, ExceptionHandler exhd)
109 | {
110 | List TryInstructions = new List(),
111 | HandlerInstructions = new List();
112 |
113 | // Try Instructions
114 | for (int x_tryInst = dnlibUtils.IndexOf(insts, exhd.TryStart , true); x_tryInst < dnlibUtils.IndexOf(insts, exhd.TryEnd); x_tryInst++) { TryInstructions.Add(insts[x_tryInst]); }
115 |
116 | // Handler Instructions
117 | for (int x_hdInst = dnlibUtils.IndexOf(insts, exhd.HandlerStart, true); x_hdInst < dnlibUtils.IndexOf(insts, exhd.HandlerEnd); x_hdInst++) { HandlerInstructions.Add(insts[x_hdInst]); }
118 |
119 | MSILTryCatch result = new MSILTryCatch()
120 | {
121 | TryInstructions = TryInstructions.ToArray(),
122 | HandlerInstructions = HandlerInstructions.ToArray(),
123 | CatchType = exhd.CatchType,
124 | HandlerType = exhd.HandlerType,
125 |
126 | TryStart = dnlibUtils.IndexOf(insts, exhd.TryStart),
127 | TryEnd = dnlibUtils.IndexOf(insts, exhd.TryEnd),
128 | HandlerStart = dnlibUtils.IndexOf(insts, exhd.HandlerStart),
129 | HandlerEnd = dnlibUtils.IndexOf(insts, exhd.HandlerEnd),
130 | FilterStart = dnlibUtils.IndexOf(insts, exhd.FilterStart)
131 | };
132 |
133 | return result;
134 | }
135 |
136 | public Instruction[] TryInstructions { get; set; }
137 | public Instruction[] HandlerInstructions { get; set; }
138 |
139 | public int TryStart, TryEnd, HandlerStart, HandlerEnd, FilterStart;
140 |
141 | public ExceptionHandlerType HandlerType;
142 | public ITypeDefOrRef CatchType;
143 | }
144 | }
--------------------------------------------------------------------------------
/XUnionPE/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/XUnionPE/Decompiler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Gee.External.Capstone;
8 | using Gee.External.Capstone.X86;
9 |
10 | namespace XUnionPE
11 | {
12 | class Decompiler
13 | {
14 | public Decompiler(string appPath)
15 | {
16 | AddressBook = new Dictionary();
17 |
18 | path = Path.GetFullPath(appPath);
19 | RawApp = File.ReadAllBytes(path);
20 |
21 | Headers = new PEUtils.Headers(RawApp);
22 | PEUtils.Headers.SectionHeader mainSection = Headers.GetSectionHeader(Headers.OptionalHdr.EntrypointAdr, true);
23 |
24 | byte[] RawInsts = new byte[mainSection.VirtSize + mainSection.VirtAdr];
25 | Array.Copy(RawApp, mainSection.RawAdr, RawInsts, 0, mainSection.RawSize);
26 |
27 | disasm = CapstoneDisassembler.CreateX86Disassembler(GetBitness());
28 | disasm.EnableInstructionDetails = true;
29 | disasm.DisassembleSyntax = DisassembleSyntax.Intel;
30 |
31 | //X86Instruction[] insts = disasm.Disassemble(RawInsts);
32 | }
33 |
34 | public enum MachineType : ushort { Native = 0, x86 = 0x014c, Itanium = 0x0200, x64 = 0x8664 }
35 |
36 | private string path;
37 | private byte[] RawApp, outputRaw;
38 | private CapstoneX86Disassembler disasm;
39 |
40 | public PEUtils.Headers Headers;
41 | public Dictionary AddressBook { get; set; }
42 |
43 | public X86DisassembleMode GetBitness()
44 | {
45 | switch (BitConverter.ToUInt16(RawApp, 0x4A))
46 | {
47 | case 0x6486: return X86DisassembleMode.Bit64;
48 | case 0x4c01: return X86DisassembleMode.Bit32;
49 | default: throw new Exception("Unsupporteed Bitness (must be x86_64)");
50 | }
51 | }
52 |
53 | public uint Stage2Entrypoint = uint.MaxValue,
54 | Stage1Entrypoint = uint.MaxValue,
55 | Stage2Size = uint.MaxValue,
56 | Stage2Key = uint.MaxValue,
57 | Stage2PaddingMask = uint.MaxValue,
58 | PaddingCount = uint.MaxValue;
59 |
60 | public void Unpack()
61 | {
62 | Console.WriteLine(" Checking if EXE is packed with PEUnion...");
63 | Console.WriteLine();
64 | if (!isPEUnionPacked())
65 | {
66 | Console.Write(" Invalid Executable! (Not packed using PEUnion)");
67 | Console.ReadKey();
68 | return;
69 | }
70 | Console.WriteLine(" PEUnion detected!");
71 | Console.WriteLine();
72 | X86Instruction[] insts = disasm.Disassemble(Utils.GetBuffer(RawApp, AddressBook["mainFunction"]));
73 | for (int x = 8; x < insts.Length; x++)
74 | {
75 | X86Instruction inst = insts[x];
76 | switch (inst.Id)
77 | {
78 | case X86InstructionId.X86_INS_IMUL:
79 | if (inst.Details.Operands[0].Type == X86OperandType.Register &&
80 | inst.Details.Operands[0].Register.Id == X86RegisterId.X86_REG_EDX &&
81 | inst.Details.Operands[1].Type == X86OperandType.Register &&
82 | inst.Details.Operands[1].Register.Id == X86RegisterId.X86_REG_EDX &&
83 | inst.Details.Operands[2].Type == X86OperandType.Immediate &&
84 | inst.Details.Operands[2].Immediate == 7)
85 | {
86 | for (int y = x; y < insts.Length; y++)
87 | {
88 | if (PaddingCount != uint.MaxValue) { break; }
89 | X86Instruction paddingCount = insts[y];
90 | switch (paddingCount.Id)
91 | {
92 | case X86InstructionId.X86_INS_TEST:
93 | if (paddingCount.Details.Operands[0].Type == X86OperandType.Register &&
94 | paddingCount.Details.Operands[0].Register.Id == X86RegisterId.X86_REG_EBX &&
95 | paddingCount.Details.Operands[1].Type == X86OperandType.Immediate)
96 | { PaddingCount = Convert.ToUInt32(paddingCount.Details.Operands[1].Immediate); }
97 | break;
98 | }
99 | }
100 | }
101 | break;
102 | case X86InstructionId.X86_INS_CALL:
103 | if (inst.Details.Operands[0].Type == X86OperandType.Memory &&
104 | inst.Details.Operands[0].Memory.Base != null &&
105 | inst.Details.Operands[0].Memory.Base.Id == X86RegisterId.X86_REG_EBP &&
106 | inst.Operand.EndsWith("0xc]") &&
107 | Utils.FromHexUInt32(insts[x - 1].Operand) == Headers.OptionalHdr.EntrypointAdr + Headers.OptionalHdr.ImageBase)
108 | {
109 | for (int y = x; y < insts.Length; y++)
110 | {
111 | if (Stage1Entrypoint != uint.MaxValue &&
112 | Stage2Entrypoint != uint.MaxValue &&
113 | Stage2Size != uint.MaxValue &&
114 | Stage2Key != uint.MaxValue &&
115 | Stage2PaddingMask != uint.MaxValue)
116 | { break; }
117 | inst = insts[y];
118 | switch (inst.Id)
119 | {
120 | case X86InstructionId.X86_INS_MOV:
121 | if (inst.Details.Operands.Length == 2 &&
122 | inst.Details.Operands[0].Type == X86OperandType.Register &&
123 | inst.Details.Operands[1].Type == X86OperandType.Immediate)
124 | {
125 | switch (inst.Details.Operands[0].Register.Id)
126 | {
127 | case X86RegisterId.X86_REG_EDI: Stage1Entrypoint = Headers.GetRawOffset((uint)inst.Details.Operands[1].Immediate, Headers.OptionalHdr.ImageBase); break;
128 | case X86RegisterId.X86_REG_ESI: Stage2Entrypoint = Headers.GetRawOffset((uint)inst.Details.Operands[1].Immediate, Headers.OptionalHdr.ImageBase); break;
129 | case X86RegisterId.X86_REG_ECX: Stage2Size = Convert.ToUInt32(inst.Details.Operands[1].Immediate); break;
130 | case X86RegisterId.X86_REG_EDX: Stage2Key = Convert.ToUInt32(inst.Details.Operands[1].Immediate); /*Utils.RightBitShift((int)inst.Details.Operands[1].Immediate, 5) * 7;*/ break;
131 | case X86RegisterId.X86_REG_EBX: Stage2PaddingMask = Convert.ToUInt32(inst.Details.Operands[1].Immediate); break;
132 | }
133 | }
134 | break;
135 | }
136 | }
137 | }
138 | break;
139 | }
140 | }
141 | List stage2Raw = new List();
142 | Console.WriteLine(" unXORing application...");
143 | using (BinaryReader br = new BinaryReader(new MemoryStream(RawApp)))
144 | {
145 | br.BaseStream.Position = Stage2Entrypoint;
146 | int curByte = -1;
147 | while ((curByte = (int)br.ReadByte()) != -1)
148 | {
149 | if (stage2Raw.Count == Stage2Size) { break; }
150 | stage2Raw.Add((byte)(curByte ^ BitConverter.GetBytes(Stage2Key)[0]));
151 | Stage2Key = Utils.RightBitShift(Stage2Key, 5) * 7;
152 | if ((Stage2PaddingMask & 1) == 1) { for (int y = 0; y < PaddingCount; y++) { curByte = br.ReadByte(); } }
153 | Stage2PaddingMask = Utils.RightBitShift(Stage2PaddingMask, 1);
154 | }
155 | }
156 | outputRaw = new byte[stage2Raw.Count];
157 | Array.Copy(stage2Raw.ToArray(), 0x700, outputRaw, 0, stage2Raw.Count - 0x700); // removes junk
158 | File.WriteAllBytes("output_pe32_xunion.exe", outputRaw.ToArray());
159 | Console.WriteLine(" Extracted application saved as 'output_pe32_xunion.exe'!");
160 | Console.ReadKey();
161 | }
162 |
163 | public bool isPEUnionPacked()
164 | {
165 | X86Instruction[] insts = disasm.Disassemble(Utils.GetBuffer(RawApp, Headers.GetRawOffset(Headers.OptionalHdr.EntrypointAdr)));
166 | if (insts[0].Id == X86InstructionId.X86_INS_CALL &&
167 | insts[1].Id == X86InstructionId.X86_INS_PUSH &&
168 | insts[2].Id == X86InstructionId.X86_INS_CALL &&
169 | insts[3].Id == X86InstructionId.X86_INS_RET)
170 | {
171 | PEUtils.Headers.ImportDll kernel32ExitPrc = Headers.GetImport(Headers.GetRawOffset((uint)PEUtils.InstructionUtils.GetCallAdr(insts[2], Headers.OptionalHdr.ImageBase)));
172 | if (kernel32ExitPrc != null &&
173 | kernel32ExitPrc.Name == "kernel32.dll" &&
174 | kernel32ExitPrc.Functions[0].Name == "ExitProcess")
175 | {
176 | AddressBook.Add("mainFunction", Headers.GetRawOffset(Utils.FromHexUInt32(insts[0].Operand)));
177 | return true;
178 | }
179 | }
180 | return false;
181 | }
182 | }
183 | }
--------------------------------------------------------------------------------
/XUnionPE/PEUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Gee.External.Capstone.X86;
8 |
9 | namespace XUnionPE
10 | {
11 | class PEUtils
12 | {
13 | public class Headers
14 | {
15 | public Headers(byte[] data)
16 | {
17 | DOSHdr = new DOSHeader();
18 | FileHdr = new FileHeader();
19 | OptionalHdr = new OptionalHeader();
20 |
21 | BinaryReader br = new BinaryReader(new MemoryStream(data));
22 |
23 | #region DOS Header
24 | DOSHdr.Magic = new string(br.ReadChars(2));
25 | DOSHdr.LastPageByteCount = br.ReadUInt16();
26 | DOSHdr.PageCount = br.ReadUInt16();
27 | DOSHdr.RelocationCount = br.ReadUInt16();
28 | DOSHdr.SizeOfHeaderParagraph = br.ReadUInt16();
29 | DOSHdr.MinExtraParagraph = br.ReadUInt16();
30 | DOSHdr.MaxExtraParagraph = br.ReadUInt16();
31 | DOSHdr.SSValue = br.ReadUInt16();
32 | DOSHdr.SPValue = br.ReadUInt16();
33 | DOSHdr.SPValue = br.ReadUInt16();
34 | DOSHdr.Checksum = br.ReadUInt16();
35 | DOSHdr.IPValue = br.ReadUInt16();
36 | DOSHdr.CSValue = br.ReadUInt16();
37 | DOSHdr.RelocationTableAdr = br.ReadUInt16();
38 | DOSHdr.OverlayNum = br.ReadUInt16();
39 |
40 | ushort[] reservedArr = new ushort[4];
41 | for (int x = 0; x < 4; x++) { reservedArr[x] = br.ReadUInt16(); }
42 | DOSHdr.ReservedWords1 = reservedArr;
43 |
44 | DOSHdr.OEMID = br.ReadUInt16();
45 | DOSHdr.OEMInfo = br.ReadUInt16();
46 |
47 | reservedArr = new ushort[10];
48 | for (int x = 0; x < 10; x++) { reservedArr[x] = br.ReadUInt16(); }
49 | DOSHdr.ReservedWords2 = reservedArr;
50 |
51 | DOSHdr.NewExeHeaderAdr = br.ReadUInt32();
52 | #endregion
53 | #region File Header
54 | // 0x40 -> 0x7F is DOS Stub, 0x80 is Start of File Header
55 | br.BaseStream.Position = 0x80;
56 |
57 | br.ReadUInt32(); // Skips Magic Signature
58 | FileHdr.Machine = br.ReadUInt16();
59 | FileHdr.SectionCount = br.ReadUInt16();
60 | FileHdr.Timestamp = new DateTime(br.ReadUInt32());
61 | FileHdr.SymbolTableAdr = br.ReadUInt32();
62 | FileHdr.SymbolCount = br.ReadUInt32();
63 | FileHdr.OptionalHeaderSize = br.ReadUInt16();
64 | FileHdr.Characteristics = br.ReadUInt16();
65 | #endregion
66 | #region Optional Header
67 | OptionalHdr.Magic = br.ReadUInt16();
68 | OptionalHdr.MajorLinkerVersion = br.ReadByte();
69 | OptionalHdr.MinorLinkerVersion = br.ReadByte();
70 | OptionalHdr.SizeOfCode = br.ReadUInt32();
71 | OptionalHdr.SizeOfInitializedData = br.ReadUInt32();
72 | OptionalHdr.SizeOfUnInitializedData = br.ReadUInt32();
73 | OptionalHdr.EntrypointAdr = br.ReadUInt32();
74 | OptionalHdr.BaseOfCode = br.ReadUInt32();
75 | OptionalHdr.BaseOfData = br.ReadUInt32();
76 | OptionalHdr.ImageBase = br.ReadUInt32();
77 | OptionalHdr.SectionAlign = br.ReadUInt32();
78 | OptionalHdr.FileAlign = br.ReadUInt32();
79 | OptionalHdr.MajorOSVersion = br.ReadUInt16();
80 | OptionalHdr.MinorOSVersion = br.ReadUInt16();
81 | OptionalHdr.MajorImageVersion = br.ReadUInt16();
82 | OptionalHdr.MinorImageVersion = br.ReadUInt16();
83 | OptionalHdr.MajorSubsystemVersion = br.ReadUInt16();
84 | OptionalHdr.MinorSubsystemVersion = br.ReadUInt16();
85 | OptionalHdr.Win32Version = br.ReadUInt32();
86 | OptionalHdr.SizeOfImage = br.ReadUInt32();
87 | OptionalHdr.SizeOfHeaders = br.ReadUInt32();
88 | OptionalHdr.Checksum = br.ReadUInt32();
89 | OptionalHdr.Subsystem = br.ReadUInt16();
90 | OptionalHdr.DLLCharacteristics = br.ReadUInt16();
91 | OptionalHdr.SizeOfStackReserve = br.ReadUInt32();
92 | OptionalHdr.SizeOfStackCommit = br.ReadUInt32();
93 | OptionalHdr.SizeOfHeapReverse = br.ReadUInt32();
94 | OptionalHdr.SizeOfHeapCommit = br.ReadUInt32();
95 | OptionalHdr.LoaderFlags = br.ReadUInt32();
96 | OptionalHdr.RVAAndSizeCount = br.ReadUInt32();
97 | #region Data Directories
98 | OptionalHdr.DataDirs.ExportDir = br.ReadUInt64();
99 | OptionalHdr.DataDirs.ImportDir = br.ReadUInt64();
100 | OptionalHdr.DataDirs.ResourceDir = br.ReadUInt64();
101 | OptionalHdr.DataDirs.ExceptionDir = br.ReadUInt64();
102 | OptionalHdr.DataDirs.SecurityDir = br.ReadUInt64();
103 | OptionalHdr.DataDirs.BaseRelocationTable = br.ReadUInt64();
104 | OptionalHdr.DataDirs.DebugDir = br.ReadUInt64();
105 | OptionalHdr.DataDirs.ArchitectureSpecificData = br.ReadUInt64();
106 | OptionalHdr.DataDirs.GlobalPtrRVA = br.ReadUInt64();
107 | OptionalHdr.DataDirs.TLSDir = br.ReadUInt64();
108 | OptionalHdr.DataDirs.LoadConfigDir = br.ReadUInt64();
109 | OptionalHdr.DataDirs.HeadersImportDirBound = br.ReadUInt64();
110 | OptionalHdr.DataDirs.ImportAdrTable = br.ReadUInt64();
111 | OptionalHdr.DataDirs.DelayLoadImportDescriptors = br.ReadUInt64();
112 | OptionalHdr.DataDirs.DotNetHeader = br.ReadUInt64();
113 | #endregion
114 | #endregion
115 | #region Section Headers
116 | br.ReadUInt64(); // 8 byte gap
117 | List SectionHdrsList = new List();
118 | for (int x = 0; x < FileHdr.SectionCount; x++)
119 | {
120 | SectionHeader sectionHdr = new SectionHeader();
121 |
122 | sectionHdr.Name = Encoding.Default.GetString(
123 | br.ReadBytes(sizeof(ulong)));
124 | sectionHdr.VirtSize = br.ReadUInt32();
125 | sectionHdr.VirtAdr = br.ReadUInt32();
126 | sectionHdr.RawSize = br.ReadUInt32();
127 | sectionHdr.RawAdr = br.ReadUInt32();
128 | sectionHdr.PtrToReloc = br.ReadUInt32();
129 | br.ReadUInt32(); // 4 byte gap
130 | sectionHdr.RelocCount = br.ReadUInt16();
131 | sectionHdr.LinenumCount = br.ReadUInt16();
132 | sectionHdr.Characteristics = br.ReadUInt32();
133 |
134 | SectionHdrsList.Add(sectionHdr);
135 | }
136 | SectionHdrs = SectionHdrsList.ToArray();
137 | #endregion
138 | #region Imports
139 | uint idataStart = 0xFFFFFFFF;
140 | foreach (SectionHeader sectionHeader in SectionHdrs) { if (sectionHeader.Name.StartsWith(".idata")) { idataStart = sectionHeader.RawAdr; break; } }
141 |
142 | br.BaseStream.Position = idataStart;
143 | List importsList = new List();
144 | for (byte[] x = br.ReadBytes(20);
145 | x[0] != 0x00;
146 | x = br.ReadBytes(20))
147 | {
148 | ImportDll impDll = new ImportDll();
149 | impDll.OriginalFirstThunk = GetRawOffset(BitConverter.ToUInt32(x, 0));
150 | impDll.TimedateStamp = BitConverter.ToUInt32(x, 4);
151 | impDll.Forwarder = BitConverter.ToUInt32(x, 8);
152 | impDll.NameRVA = GetRawOffset(BitConverter.ToUInt32(x, 12));
153 | impDll.FirstThunk = GetRawOffset(BitConverter.ToUInt32(x, 16));
154 |
155 | using (BinaryReader callViaBr = new BinaryReader(new MemoryStream(data)))
156 | {
157 | callViaBr.BaseStream.Position = impDll.FirstThunk;
158 |
159 | List impFuncList = new List();
160 | while (true)
161 | {
162 | ImportDll.Function impFunc = new ImportDll.Function();
163 | impFunc.CallViaAdr = (uint)callViaBr.BaseStream.Position;
164 | uint callviaAdr = callViaBr.ReadUInt32();
165 | if (callviaAdr == 0) { break; }
166 | impFunc.OriginalThunk = impFunc.Thunk = GetRawOffset(callviaAdr);
167 | impFuncList.Add(impFunc);
168 | }
169 | impDll.Functions = impFuncList.ToArray();
170 | }
171 | importsList.Add(impDll);
172 | }
173 |
174 | string[] dllNames = null;
175 | for (int x_dll = 0; x_dll < importsList.Count; x_dll++)
176 | {
177 | ImportDll impDll = importsList[x_dll];
178 | string[] functionNames = null;
179 |
180 | int[] nullSkip = null;
181 |
182 | if (dllNames == null) { dllNames = GetStrings(br, importsList.Count); }
183 | if (impDll.Name == null) { impDll.Name = dllNames[x_dll]; }
184 |
185 | using (BinaryReader impFuncBr = new BinaryReader(new MemoryStream(data)))
186 | {
187 | for (int x = 0; x < impDll.Functions.Length; x++)
188 | {
189 | ImportDll.Function impFunc = impDll.Functions[x];
190 |
191 | impFuncBr.BaseStream.Position = impFunc.CallViaAdr;
192 | uint ThunkAdr = GetRawOffset(impFuncBr.ReadUInt32());
193 | impFuncBr.BaseStream.Position = ThunkAdr;
194 | if (functionNames == null) { functionNames = GetStrings(impFuncBr, impDll.Functions.Length, out nullSkip); impFuncBr.BaseStream.Position = ThunkAdr; }
195 |
196 | impFunc.Hint = impFuncBr.ReadUInt16();
197 | impFunc.Name = functionNames[x];
198 |
199 | impFuncBr.BaseStream.Position += functionNames[x].Length + nullSkip[x];
200 | }
201 | }
202 | }
203 |
204 | Imports = importsList.ToArray();
205 | #endregion
206 | }
207 |
208 | public class DOSHeader
209 | {
210 | public string Magic;
211 |
212 | public ushort LastPageByteCount,
213 | PageCount,
214 | RelocationCount,
215 | SizeOfHeaderParagraph,
216 | MinExtraParagraph,
217 | MaxExtraParagraph,
218 | SSValue,
219 | SPValue,
220 | Checksum,
221 | IPValue,
222 | CSValue,
223 | RelocationTableAdr,
224 | OverlayNum,
225 | OEMID,
226 | OEMInfo;
227 |
228 | public uint NewExeHeaderAdr;
229 |
230 | public ushort[] ReservedWords1 = new ushort[4],
231 | ReservedWords2 = new ushort[10];
232 | }
233 | public class FileHeader
234 | {
235 | public ushort Machine,
236 | SectionCount,
237 | OptionalHeaderSize,
238 | Characteristics;
239 |
240 | public DateTime Timestamp;
241 |
242 | public uint SymbolTableAdr,
243 | SymbolCount;
244 | }
245 | public class OptionalHeader
246 | {
247 | public OptionalHeader() { DataDirs = new DataDirectory(); }
248 |
249 | public class DataDirectory
250 | {
251 | public ulong ExportDir,
252 | ImportDir,
253 | ResourceDir,
254 | ExceptionDir,
255 | SecurityDir,
256 | BaseRelocationTable,
257 | DebugDir,
258 | ArchitectureSpecificData,
259 | GlobalPtrRVA,
260 | TLSDir,
261 | LoadConfigDir,
262 | HeadersImportDirBound,
263 | ImportAdrTable,
264 | DelayLoadImportDescriptors,
265 | DotNetHeader;
266 | }
267 |
268 | public ushort Magic;
269 |
270 | public byte MajorLinkerVersion,
271 | MinorLinkerVersion;
272 |
273 | public ushort MajorOSVersion,
274 | MinorOSVersion,
275 | MajorImageVersion,
276 | MinorImageVersion,
277 | MajorSubsystemVersion,
278 | MinorSubsystemVersion,
279 | Subsystem,
280 | DLLCharacteristics;
281 |
282 | public uint SizeOfCode,
283 | SizeOfInitializedData,
284 | SizeOfUnInitializedData,
285 | EntrypointAdr,
286 | BaseOfCode,
287 | BaseOfData,
288 | ImageBase,
289 | SectionAlign,
290 | FileAlign,
291 | Win32Version,
292 | SizeOfImage,
293 | SizeOfHeaders,
294 | Checksum,
295 | SizeOfStackReserve,
296 | SizeOfStackCommit,
297 | SizeOfHeapReverse,
298 | SizeOfHeapCommit,
299 | LoaderFlags,
300 | RVAAndSizeCount;
301 |
302 | public DataDirectory DataDirs { get; set; }
303 | }
304 | public class SectionHeader
305 | {
306 | public string Name;
307 |
308 | public ushort RelocCount,
309 | LinenumCount;
310 |
311 | public uint VirtSize,
312 | VirtAdr,
313 | RawSize,
314 | RawAdr,
315 | PtrToReloc,
316 | Characteristics;
317 | }
318 | public class ImportDll
319 | {
320 | public class Function
321 | {
322 | public string Name;
323 |
324 | public uint OriginalThunk, Thunk, CallViaAdr;
325 |
326 | public ushort Hint;
327 | }
328 |
329 | public string Name;
330 |
331 | public uint OriginalFirstThunk,
332 | TimedateStamp,
333 | Forwarder,
334 | NameRVA,
335 | FirstThunk;
336 |
337 | public bool IsBound { get { return TimedateStamp == 0xFFFFFFFF; } }
338 |
339 | public Function[] Functions { get; set; }
340 | }
341 |
342 | public DOSHeader DOSHdr { get; set; }
343 | public FileHeader FileHdr { get; set; }
344 | public OptionalHeader OptionalHdr { get; set; }
345 | public SectionHeader[] SectionHdrs { get; set; }
346 | public ImportDll[] Imports { get; set; }
347 |
348 | private string[] GetStrings(BinaryReader br, int expectedCount)
349 | {
350 | int[] nullSkip = null;
351 | return GetStrings(br, expectedCount, out nullSkip);
352 | }
353 | private string[] GetStrings(BinaryReader br, int expectedCount, out int[] nullSkip)
354 | {
355 | string[] result = new string[expectedCount];
356 | nullSkip = new int[expectedCount];
357 | string tempString = "";
358 | int arrPos = 0;
359 | for (byte x = br.ReadByte(); arrPos != expectedCount; x = br.ReadByte())
360 | {
361 | if (arrPos == expectedCount) { break; }
362 | if (x == 0x00)
363 | {
364 | string filter = tempString.Replace("\0", null);
365 | if (filter == "") { continue; }
366 | nullSkip[arrPos] = tempString.Split("\0".ToCharArray()).Length;
367 | result[arrPos] = filter;
368 | tempString = "";
369 | arrPos++;
370 | }
371 | tempString += (char)x;
372 | }
373 | return result.ToArray();
374 | }
375 |
376 | public SectionHeader GetSectionHeader(uint adr, bool rawCompare = false)
377 | {
378 | foreach (SectionHeader sectionHdr in SectionHdrs)
379 | {
380 | if (rawCompare)
381 | {
382 | if (sectionHdr.RawAdr <= adr &&
383 | sectionHdr.RawAdr + sectionHdr.RawSize > adr)
384 | {
385 | return sectionHdr;
386 | }
387 | }
388 | else
389 | {
390 | if (sectionHdr.VirtAdr <= adr &&
391 | sectionHdr.VirtAdr + sectionHdr.VirtSize > adr)
392 | {
393 | return sectionHdr;
394 | }
395 | }
396 | }
397 | return null;
398 | }
399 | public ImportDll GetImport(uint RAWadr)
400 | {
401 | ImportDll result = new ImportDll();
402 | foreach (ImportDll impDll in Imports)
403 | {
404 | foreach (ImportDll.Function impFunc in impDll.Functions)
405 | {
406 | if (impFunc.CallViaAdr == RAWadr)
407 | {
408 | result = impDll;
409 | List impFuncs = result.Functions.ToList();
410 | impFuncs.Clear();
411 | impFuncs.Add(impFunc);
412 | result.Functions = impFuncs.ToArray();
413 | return result;
414 | }
415 | }
416 | }
417 | return null;
418 | }
419 |
420 | /*public ulong ToRVA(ulong adr) { return adr + OptionalHdr.ImageBase; }
421 | public ulong ToVA (ulong adr) { return adr - OptionalHdr.ImageBase; }*/
422 |
423 | public uint GetRawOffset(uint adr)
424 | {
425 | SectionHeader sectionHdr = GetSectionHeader(adr);
426 | return (adr - sectionHdr.VirtAdr) + sectionHdr.RawAdr;
427 | }
428 |
429 | public uint GetRawOffset(uint adr, uint imageBase) { return GetRawOffset(adr - imageBase); }
430 | }
431 |
432 | public class InstructionUtils
433 | {
434 | public static long GetCallAdr(X86Instruction callInst, uint imageBase = 0xFFFFFFFF)
435 | {
436 | if (callInst.HasDetails) { return imageBase != 0xFFFFFFFF ? callInst.Details.Displacement - imageBase : callInst.Details.Displacement; }
437 | else
438 | {
439 | if (callInst.Operand.Contains(" ptr ["))
440 | {
441 | foreach (string str in callInst.Operand.Split('['))
442 | {
443 | try { return imageBase != 0xFFFFFFFF ? Utils.FromHexInt64(str) - imageBase : Utils.FromHexInt64(str); }
444 | catch { }
445 | }
446 | throw new Exception("Could not process call operand!");
447 | }
448 | else { return imageBase != 0xFFFFFFFF ? Utils.FromHexInt64(callInst.Operand) - imageBase : Utils.FromHexInt64(callInst.Operand); }
449 | }
450 | }
451 | }
452 | }
453 | }
454 |
--------------------------------------------------------------------------------
/XUnionPE/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Gee.External.Capstone;
9 | using Gee.External.Capstone.X86;
10 |
11 | namespace XUnionPE
12 | {
13 | class Program
14 | {
15 | static void Main(string[] args)
16 | {
17 | Console.SetWindowSize(50, 15);
18 | Console.CursorVisible = false;
19 | Console.BackgroundColor = ConsoleColor.DarkGray;
20 | Console.ForegroundColor = ConsoleColor.Gray;
21 | drawOnBottomCorner(' ');
22 | Console.Clear();
23 | Console.WriteLine();
24 | new Decompiler(Path.GetFullPath(args[0])).Unpack();
25 | }
26 |
27 | private static void drawOnBottomCorner(char ch)
28 | {
29 | Console.SetBufferSize(Console.WindowWidth + 1, Console.WindowHeight);
30 | Console.SetCursorPosition(Console.WindowWidth - 1, Console.WindowHeight - 1);
31 | Console.Write(ch);
32 | Console.SetBufferSize(Console.WindowWidth, Console.WindowHeight);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/XUnionPE/Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Globalization;
7 |
8 | namespace XUnionPE
9 | {
10 | class Utils
11 | {
12 | public static short FromHexInt16(string hexInt) { return short.Parse(hexInt.Replace("0x", null), NumberStyles.HexNumber); }
13 | public static ushort FromHexUInt16(string hexInt) { return ushort.Parse(hexInt.Replace("0x", null), NumberStyles.HexNumber); }
14 | public static int FromHexInt32(string hexInt) { return int.Parse(hexInt.Replace("0x", null), NumberStyles.HexNumber); }
15 | public static uint FromHexUInt32(string hexInt) { return uint.Parse(hexInt.Replace("0x", null), NumberStyles.HexNumber); }
16 | public static long FromHexInt64(string hexInt) { return long.Parse(hexInt.Replace("0x", null), NumberStyles.HexNumber); }
17 | public static ulong FromHexUInt64(string hexInt) { return ulong.Parse(hexInt.Replace("0x", null), NumberStyles.HexNumber); }
18 |
19 | public static uint RightBitShift(uint value, int bits)
20 | {
21 | bits &= 31;
22 | return value >> bits | value << 32 - bits;
23 | }
24 |
25 | public static uint LeftBitShift(uint value, int bits)
26 | {
27 | bits &= 31;
28 | return value << bits | value >> 32 - bits;
29 | }
30 |
31 | public static byte[] GetBuffer(byte[] srcData, long keyAdr) { return GetBuffer(srcData, keyAdr, srcData.Length - keyAdr); }
32 | public static byte[] GetBuffer(byte[] srcData, long keyAdr, long keySize)
33 | {
34 | List result = new List();
35 | for (int x = 0; x < keySize; x++) { result.Add(srcData[Convert.ToInt32(keyAdr) + x]); }
36 | return result.ToArray();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/XUnionPE/XUnionPE.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {9F2136EC-4F47-4EC7-89D6-FAA2A0F33856}
8 | Exe
9 | Properties
10 | XUnionPE
11 | XUnionPE
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 | true
36 | bin\x86\Debug\
37 | DEBUG;TRACE
38 | full
39 | x86
40 | prompt
41 | MinimumRecommendedRules.ruleset
42 | true
43 |
44 |
45 | bin\x86\Release\
46 | TRACE
47 | true
48 | pdbonly
49 | x86
50 | prompt
51 | MinimumRecommendedRules.ruleset
52 | true
53 |
54 |
55 |
56 | ..\..\..\dlls\Gee.External.Capstone.dll
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
84 |
--------------------------------------------------------------------------------