Vous êtes sur la page 1sur 18

[.NET] Decrypt Confuser 1.

9 methods Written By 0xd4d and Written PDF By Alcatraz3222

Many people have asked me how to decrypt methods which have been encrypted by Confuser v1.9. I'll show you how to do it. One of the reasons is that yck1509 has gotten lazy this past couple of months and he hasn't updated his Confuser protection :), so let's see if this will wake him up. The unpackme is a simple .NET 4.0 WinForm assembly with Confuser 1.9 max settings enabled, including the packer. The default method encryption algorithm is used, which is the weakest one since it decrypts all methods when the assembly is loaded. It's vulnerable to memory dumping. I'll show you one way of doing it. There's most certainly easier ways of doing this than what I'll show, but you'll probably learn more from doing it this way. Tools used (sorted by first use): * WinDbg (32-bit) with SOS extension * de4dot (v2 or later) * Simple Assembly Explorer (SAE) * CFF Explorer

The file was obfuscated with Confuser 1.9, r76974, which is the latest version as of this writing. Source code (click the Download link) The file was obfuscated with Confuser 1.9, r76974, which is the latest version as of this writing. Source code (click the Download link) Tested OS: Windows 7 x64 with .NET 4.5 installed Files: Attached. See the end of this post Start WinDbg (32-bit) and load Confuser_UnpackMe.exe. If WinDbg fails to load it, it's probably an AnyCpu file and was loaded as a 64-bit process. See this pic on how to fix it:

If you haven't done so already, setup the symbol path in WinDbg. Press Ctrl+S and enter this, but replace C:\websymbols with your own path SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols

Set a breakpoint on the first function that gets executed if it's a .NET EXE file. This is a .NET 4.0 file, so the function is located in clr.dll, but if you don't know whether it's .NET 2.0-3.5 or .NET 4.x, then set a breakpoint in both clr and mscorwks. bu must be used since clr/mscorwks.dll haven't been loaded yet.

0:000> bu clr!_CorExeMain 0:000> bu mscorwks!_CorExeMain 0:000> bl 0 eu 0001 (0001) (clr!_CorExeMain) 1 eu 0001 (0001) (mscorwks!_CorExeMain) Now run it until _CorExeMain gets executed

0:000> g ModLoad: 75eb0000 75f50000 C:\Windows\syswow64\ADVAPI32.dll ModLoad: 74ef0000 74f9c000 C:\Windows\syswow64\msvcrt.dll ModLoad: 75f60000 75f79000 C:\Windows\SysWOW64\sechost.dll ModLoad: 762d0000 763c0000 C:\Windows\syswow64\RPCRT4.dll ModLoad: 74be0000 74c40000 C:\Windows\syswow64\SspiCli.dll ModLoad: 74bd0000 74bdc000 C:\Windows\syswow64\CRYPTBASE.dll ModLoad: 74300000 7437a000 C:\Windows\Microsoft.NET\Framework\v4.0.30319 \mscoreei.dll ModLoad: 76b20000 76b77000 C:\Windows\syswow64\SHLWAPI.dll ModLoad: 74c40000 74cd0000 C:\Windows\syswow64\GDI32.dll ModLoad: 768a0000 769a0000 C:\Windows\syswow64\USER32.dll ModLoad: 74cd0000 74cda000 C:\Windows\syswow64\LPK.dll ModLoad: 760a0000 7613d000 C:\Windows\syswow64\USP10.dll ModLoad: 769a0000 76a00000 C:\Windows\SysWOW64\IMM32.DLL ModLoad: 76510000 765dc000 C:\Windows\syswow64\MSCTF.dll ModLoad: 65180000 65812000 C:\Windows\Microsoft.NET\Framework\v4.0.30319 \clr.dll ModLoad: 74090000 74163000 C:\Windows\SysWOW64\MSVCR110_CLR0400.dll Breakpoint 0 hit eax=0048c700 ebx=7efde000 ecx=7430f52f edx=00480174 esi=00000000 edi=00000000 eip=652d414e esp=0021fca8 ebp=0021fce4 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 clr!_CorExeMain: 652d414e 6a14 push 14h

Here we see that it's .NET 4.0 since clr.dll was loaded and not mscorwks.dll Now load the SOS (Son of Strike) extension since it will help us. Replace clr with mscorwks if mscorwks.dll was loaded instead of clr.dll: 0:000> .loadby sos clr Now we want to execute some SOS commands, but those won't work yet because the CLR hasn't been loaded yet: 0:000> !name2ee mscorlib.dll System.Runtime.InteropServices.Marshal.GetHINSTANCE Failed to obtain AppDomain data. Failed to request module list. To solve this, set the BP @ ExecuteMainMethod because the CLR has initialized more data and our SOS commands should work. Use /1 to set a one-time breakpoint: 0:000> bp /1 SystemDomain::ExecuteMainMethod 0:000> g (14f8.1944): Unknown exception - code 04242420 (first chance) ModLoad: 60190000 6114f000 C:\Windows\assembly\NativeImages_v4.0.30319_32 \mscorlib\51e2934144ba15628ba5a31be2dae7dc\mscorlib.ni.dll Breakpoint 2 hit eax=0021fbe4 ebx=7efde000 ecx=00ed0000 edx=004cfe80 esi=00000000 edi=00ed0000 eip=652d183b esp=0021fbd0 ebp=0021fc28 iopl=0 nv up ei pl nz na po nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202 clr!SystemDomain::ExecuteMainMethod: 652d183b 55 push ebp Now we need to set a BP on Marshal.GetHINSTANCE() since that's a method Confuser's AntiTamperMem::Initialize() calls at the start of that method. The next command will list one or two GetHINSTANCE() methods, but we're only interested in the one that takes a System.Reflection.Module as the first arg

0:000> !name2ee mscorlib.dll System.Runtime.InteropServices.Marshal.GetHINSTANCE Module: 60191000 Assembly: mscorlib.dll Token: 06003e0a MethodDesc: 60196428 Name: System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Module) JITTED Code Address: 604d307c ----------------------Token: 06003e7f MethodDesc: 601959d4 Name: System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.RuntimeModule) Not JITTED yet. Use !bpmd -md 601959d4 to break on run. Set a BP at the jitted code address, which on my machine is 604d307c 0:000> bp /1 604d307c *** WARNING: Unable to verify checksum for C:\Windows\assembly \NativeImages_v4.0.30319_32\mscorlib\51e2934144ba15628ba5a31be2dae7dc \mscorlib.ni.dll 0:000> bl 0 e 652d414e 0001 (0001) 0:**** clr!_CorExeMain 1 eu 0001 (0001) (mscorwks!_CorExeMain) 2 e 604d307c /1 0001 (0001) 0:**** mscorlib_ni+0x34307c 0:000> g ModLoad: 76140000 7629c000 C:\Windows\syswow64\ole32.dll ModLoad: 70a60000 70ae0000 C:\Windows\SysWOW64\uxtheme.dll ModLoad: 72f90000 72fa6000 C:\Windows\SysWOW64\CRYPTSP.dll ModLoad: 72f50000 72f8b000 C:\Windows\SysWOW64\rsaenh.dll ModLoad: 729f0000 72a5e000 C:\Windows\Microsoft.NET\Framework\v4.0.30319 \clrjit.dll ModLoad: 63570000 63ee9000 C:\Windows\assembly\NativeImages_v4.0.30319_32 \System\f82dad169c524366301b2224fe123045\System.ni.dll Breakpoint 2 hit eax=02361b94 ebx=0021ea88 ecx=02361b94 edx=004cfe80 esi=00000000 edi=02361b94 eip=604d307c esp=0021e850 ebp=0021e934 iopl=0 nv up ei pl nz na po nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202 mscorlib_ni+0x34307c: 604d307c 55 push ebp We're now in GetHINSTANCE() and called by AntiTamperMem::Initialize(). We're now going to set a breakpoint (BP) at AntiTamperMem::Initialize()'s return address. When AntiTamperMem::Initialize() has returned, everything is decrypted. We can use the SOS !clrstack command to get the .NET call stack.

0:000> !clrstack OS Thread Id: 0x1944 (0) Child SP IP Call Site 0021e850 604d307c System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Module) 0021e854 00400603 *** ERROR: Module load completed but symbols could not be loaded for image00ed0000 <<<GARBAGE>>>() 0021e93c 0040007c <<<<<<<<GARBAGE>>>>>>>>>> 0021eb40 65182652 [GCFrame: 0021eb40] 0021f734 65182652 [DebuggerClassInitMarkFrame: 0021f734] The first row (0021e850 604d307c ...) is the info about the current method, which is GetHINSTANCE. The 2nd row (0021e854 00400603 ...) is Confuser's decryption method. The 3rd row (0021e93c 0040007c ...) is what we're interested in. The 2nd dword is the return address. It's 0040007c on my machine 0:000> bp 0040007c 0:000> g ModLoad: 74060000 74072000 C:\Windows\Microsoft.NET\Framework\v4.0.30319 \nlssorting.dll ModLoad: 75260000 75eaa000 C:\Windows\syswow64\shell32.dll ModLoad: 73680000 7368b000 C:\Windows\SysWOW64\profapi.dll ModLoad: 6ffd0000 6ffe7000 C:\Windows\SysWOW64\bcrypt.dll Breakpoint 2 hit eax=00401343 ebx=0021ea88 ecx=023f28c4 edx=00000000 esi=00000000 edi=0021e9c4 eip=0040007c esp=0021e93c ebp=0021e9c8 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 0040007c c745d40d000000 mov dword ptr [ebp-2Ch],0Dh ss:002b:0021e99c=00000000 We're done! All methods have been decrypted in memory and all we have to do is dump the module to disk. To get a list of all loaded modules, use lm 0:000> lm start end module name 00ed0000 00f58000 image00ed0000 (no symbols) 60190000 6114f000 mscorlib_ni C (pdb symbols) 63570000 63ee9000 System_ni (deferred) 65180000 65812000 clr (pdb symbols) 6ffd0000 6ffe7000 bcrypt (deferred) 70a60000 70ae0000 uxtheme (deferred) The .NET module is unnamed, but it's the first one. Its start address happens to be 00ed0000 on my machine. Now dump it:

0:000> !savemodule 00ed0000 d:\unpackme\decrypted1.exe 4 sections in file section 0 - VA=2000, VASize=73bc4, FileAddr=400, FileSize=73c00 section 1 - VA=76000, VASize=600, FileAddr=74000, FileSize=600 section 2 - VA=78000, VASize=c, FileAddr=74600, FileSize=200 section 3 - VA=7a000, VASize=c728, FileAddr=74800, FileSize=c800 Now you can use de4dot to deobfuscate control flow and rename symbols. We can't rename all symbols, though, since the method proxy code uses the names of fields in delegate types. We can use the --keep-names d option to keep all field names in delegate types. All the other symbols are renamed. In order to patch three initialization methods, we will first use de4dot followed by SAE to figure out the metadata tokens of these methods. We'll then use CFF Explorer to do the actual editing of the methods. d:\unpackme>de4dot --keep-names d decrypted1.exe -o decrypted2.exe Detected Confuser (not supported) (decrypted1.exe) Cleaning decrypted1.exe Renaming all obfuscated symbols Saving decrypted2.exe Open decrypted2.exe in SAE. If it fails (see pic),

then open decrypted2.exe in CFF Explorer and make sure that the File table's only element does not contain any metadata. See pic.

Now open decrypted2.exe in SAE again. Go to <Module>::.cctor() and you'll find the three init methods. See pic.

Click each method and hover the mouse over the method name and SAE will show you the method's metadata token, eg. 060000C8. See pic.

This is what I got: 060000C1 = decrypts methods 060000BF = anti dump init method 060000C8 = anti debug init method The first 06 means that it's a method, and the remaining 3 bytes (eg. 0000C1) is the index into the method table. Now open decrypted1.exe (not decrypted2.exe) with CFF Explorer. Let's start with method 060000C1 (it decrypts all methods). We want the row id (aka RID), and it's 0000C1 (hex) or 193 decimal. Go to method 193 in CFF Explorer (see pic).

This method happens to have RVA 0xCABC in my file. We need to modify it to just return immediately. I'm not going to go into too much detail about the method body header structure, other than that there are two different headers, a tiny one (1-byte header) and a fat one (at least, and almost always, a 12 byte header). We want the method to return immediately so all we need is a 1-byte RET instruction. RET is 2A (hex). The format of the tiny header is this: the upper 6 bits of the byte is the number of bytes of code, the lowest two bits are always 2 (i.e., 10 in binary). The 10 identifies it as a tiny header (fat headers have a value of 3 or 11 in binary). Since our code will be just a onebyte RET, the code size will be 1. The tiny header will then be (1 << 2) | 2 (it's the same thing as 1*4 + 2), which is 06 (hex). The method body will be 06 2A. See pics

Now do the same thing for method 060000BF (RID = 0xBF = 191) and method 060000C8 (RID = 0xC8 = 200). The file still won't run, and the reason is that AddressOfEntryPoint is invalid in the dumped file. Open the original file in CFF Explorer and copy its AddressOfEntryPoint (see pic).

Update AddressOfEntryPoint and save it as decrypted3.exe. Now you can successfully run it. If the file was not packed with Confuser's packer, you're done. But this crackme was protected with the packer so we can't stop yet. The packer will decrypt the original (and obfuscated) assembly, and then load it. In order to dump it, you'll have to do all the above again, with slight modifications. To dump it with WinDbg, load decrypted3.exe and break on mscorlib/clr load as before...

0:000> bu clr!_CorExeMain 0:000> bu mscorwks!_CorExeMain 0:000> g ModLoad: 75eb0000 75f50000 C:\Windows\syswow64\ADVAPI32.dll ModLoad: 74ef0000 74f9c000 C:\Windows\syswow64\msvcrt.dll ModLoad: 75f60000 75f79000 C:\Windows\SysWOW64\sechost.dll ModLoad: 762d0000 763c0000 C:\Windows\syswow64\RPCRT4.dll ModLoad: 74be0000 74c40000 C:\Windows\syswow64\SspiCli.dll ModLoad: 74bd0000 74bdc000 C:\Windows\syswow64\CRYPTBASE.dll ModLoad: 74300000 7437a000 C:\Windows\Microsoft.NET\Framework\v4.0.30319 \mscoreei.dll ModLoad: 76b20000 76b77000 C:\Windows\syswow64\SHLWAPI.dll ModLoad: 74c40000 74cd0000 C:\Windows\syswow64\GDI32.dll ModLoad: 768a0000 769a0000 C:\Windows\syswow64\USER32.dll ModLoad: 74cd0000 74cda000 C:\Windows\syswow64\LPK.dll ModLoad: 760a0000 7613d000 C:\Windows\syswow64\USP10.dll ModLoad: 769a0000 76a00000 C:\Windows\SysWOW64\IMM32.DLL ModLoad: 76510000 765dc000 C:\Windows\syswow64\MSCTF.dll ModLoad: 65180000 65812000 C:\Windows\Microsoft.NET\Framework\v4.0.30319 \clr.dll ModLoad: 74090000 74163000 C:\Windows\SysWOW64\MSVCR110_CLR0400.dll Breakpoint 0 hit eax=004bc600 ebx=7efde000 ecx=7430f52f edx=004b0174 esi=00000000 edi=00000000 eip=652d414e esp=0033f958 ebp=0033f990 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 clr!_CorExeMain: 652d414e 6a14 push 14h The packer will call LoadModule() to load the packed and encrypted module. This is a module without an assembly manifest so it can't be executed without an assembly.

0:000> bp AssemblyNative::LoadModule 0:000> g (c38.e80): Unknown exception - code 04242420 (first chance) ModLoad: 60190000 6114f000 C:\Windows\assembly\NativeImages_v4.0.30319_32 \mscorlib\51e2934144ba15628ba5a31be2dae7dc\mscorlib.ni.dll ModLoad: 76140000 7629c000 C:\Windows\syswow64\ole32.dll ModLoad: 70a60000 70ae0000 C:\Windows\SysWOW64\uxtheme.dll ModLoad: 72f90000 72fa6000 C:\Windows\SysWOW64\CRYPTSP.dll ModLoad: 72f50000 72f8b000 C:\Windows\SysWOW64\rsaenh.dll ModLoad: 729f0000 72a5e000 C:\Windows\Microsoft.NET\Framework\v4.0.30319 \clrjit.dll ModLoad: 63570000 63ee9000 C:\Windows\assembly\NativeImages_v4.0.30319_32 \System\f82dad169c524366301b2224fe123045\System.ni.dll ModLoad: 74060000 74072000 C:\Windows\Microsoft.NET\Framework\v4.0.30319 \nlssorting.dll ModLoad: 6ffd0000 6ffe7000 C:\Windows\SysWOW64\bcrypt.dll ModLoad: 75260000 75eaa000 C:\Windows\syswow64\shell32.dll ModLoad: 73680000 7368b000 C:\Windows\SysWOW64\profapi.dll Breakpoint 2 hit eax=6037c674 ebx=02595c48 ecx=0051bb38 edx=654b49e3 esi=004ce1a0 edi=03dab330 eip=654b49e3 esp=0033ede4 ebp=0033ee44 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 clr!AssemblyNative::LoadModule: 654b49e3 684c040000 push 44Ch *** WARNING: Unable to verify checksum for C:\Windows\assembly \NativeImages_v4.0.30319_32\mscorlib\51e2934144ba15628ba5a31be2dae7dc \mscorlib.ni.dll We need to know the size of the loaded module so we can dump it later. The question is, where is it? Let's check the arguments on the stack: 0:000> dd esp L 4 0033ede4 60aeb292 0051bb38 02595c48 03dab330 0:000> dd 03dab330 - 4 L 4 03dab32c 00038200 00905a4d 00000003 00000004 The 4th dword (03dab330, but will be different for you) is the pointer to the byte[], and the dword before that address (00038200) appears to be the size of the whole thing. To dump the decrypted methods this time, I'll choose a different way. I showed you previously to set a BP @ Marshal.GetHINSTANCE(), but we could also set a BP @ Assembly.Load(), since I know that the resources are encrypted in the netmodule. The resources are decrypted right after the methods have been decrypted. The resources are decrypted because the constants decrypter needs to read the encrypted constants from a resource. Set a BP @ Assembly.Load():

0:000> bl 0 e 652d414e 0001 (0001) 0:**** clr!_CorExeMain 1 eu 0001 (0001) (mscorwks!_CorExeMain) 2 e 654b49e3 0001 (0001) 0:**** clr!AssemblyNative::LoadModule 0:000> bp AssemblyNative::LoadImage 0:000> g (c38.e80): CLR exception - code e0434352 (first chance) Breakpoint 3 hit eax=0033da8c ebx=02525190 ecx=025316f4 edx=00000000 esi=025316f4 edi=0252f414 eip=654b3c3a esp=0033da78 ebp=0033da94 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 clr!AssemblyNative::LoadImage: 654b3c3a 688c000000 push 8Ch We've stopped at AssemblyNative::LoadImage() and that program is trying to load the decrypted resources. We'll need these so we must dump the resource assembly. 0:000> dd ecx L 4 025316f4 6058d244 00000a00 00905a4d 00000003 0:000> .writemem d:\unpackme\resources.dll ecx+8 L 00000a00 Writing a00 bytes.. As you can see, the data starts at ECX+8, and the size is at ECX+4. We now again need the help of SOS (Son of Strike), so load it: 0:000> .loadby sos clr 0:000> !dumpdomain ... Assembly: 0051b6a8 [D:\unpackme\decrypted3.exe] ClassLoader: 0051b7a8 SecurityDescriptor: 0051bbe0 Module Name 00352e94 D:\unpackme\decrypted3.exe 00358088 Confuser_UnpackMe, Version=1.0.0.0, Culture=neutral We're looking for the assembly with TWO modules (very uncommon :) ) It's the second module (00358088) we wish to dump. Now how the hell do we find its address in memory? I don't know the best way, but this is what I did:

0:000> !dumpmodule 00358088 Name: Confuser_UnpackMe, Version=1.0.0.0, Culture=neutral Attributes: PEFile Assembly: 0051b6a8 LoaderHeap: 00000000 TypeDefToMethodTableMap: 004687e4 TypeRefToMethodTableMap: 004688ac MethodDefToDescMap: 00468a38 FieldDefToDescMap: 00468d10 MemberRefToDescMap: 00468dc0 FileReferencesMap: 004690bc AssemblyReferencesMap: 004690c0 MetaData start address: 005fd5e0 (118900 bytes) The interesting thing here is the last address, the metadata start address. It's somewhere in the PE image, so we can figure out the base address of the module in memory. Let's search for it. I'll assume it's somewhere in the previous 0x20000 bytes, but if you come up empty, try something bigger, eg. 40000, etc... 0:000> s -a 005fd5e0 L- 20000 "MZ" 005f0000 4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00 MZ.............. It starts at address 005f0000 0:000> !savemodule 005f0000 d:\unpackme\netmodule.dll 005f0000 is not a Module or base address That didn't work... We know the size of this as a raw file when we set a BP @ LoadModule(). The size is 00038200, so let's try again: 0:000> .writemem d:\unpackme\netmodule.dll 005f0000 L 00038200 Writing 38200 bytes..............................................................................

This file is still obfuscated, but all methods have been decrypted. This dumped file won't run because it's a .NET module and not an assembly. To convert it to an assembly, we'll use a little utility I wrote called nm2asm. d:\unpackme>nm2asm\nm2asm.exe netmodule.dll windows resources.dll unpacked1.exe unpacked 1.0.0.0 unpacked1.exe is now the netmodule converted to an assembly. Use de4dot again to clean it up so it's easier to read the code in SAE:

d:\unpackme>de4dot.exe --keep-names d unpacked1.exe -o unpacked2.exe Detected Confuser (not supported) (D:\unpackme\unpacked1.exe) Cleaning D:\unpackme\unpacked1.exe Renaming all obfuscated symbols Saving unpacked2.exe We can now use SAE + CFF Explorer to once again patch the init methods in unpacked2.exe. These are the tokens I got this time: 060000AC = decrypts methods (method 172) 060000AA = anti dump init method (method 170) 060000B3 = anti debug init method (method 179) Use CFF explorer to write 06 2A (a ret method body) to those three methods and save it as unpacked3.exe Fixing all proxy delegate calls and decrypting all constants is once again left as an exercise for the reader. That's not something you'd want to do by hand.

Special Thank to 0xd4d of tuts4you.com Link of the tutorial in tuts4you https://forum.tuts4you.com/topic/30207-net-decrypt-confuser-19-methods/

Vous aimerez peut-être aussi