About a month ago I got a link to ESET’s ChallengeMe from a friend, yesterday I had some free time to work on that, and finally I solved it. You can get the crackme from the link below:
ESET Crackme #1
I have also attached all files to the post as they might be removed after some time. The file name is EsetCrackme2013.exe.
and
As you can see the file is packed with UPX, so let’s unpack it first. HWBP on access on ESP to get oep, and then rebuild imports with ImportRec.
OEP: 0000463C RVA: 0000C074 Size: 000000DC
The story begins from 00407B9C where application has written the data to screen, and now tries to call some anti-debug function:
seg000:00407B9C push eax ; lpOutputString seg000:00407B9D call j_OutputDebugStringA seg000:00407BA2 push offset LibFileName ; "kernel32.dll" seg000:00407BA7 call j_LoadLibraryA seg000:00407BAC mov ebx, eax seg000:00407BAE test ebx, ebx seg000:00407BB0 jnz short loc_407BB9 seg000:00407BB2 push 0 ; uExitCode seg000:00407BB4 call j_ExitProcess_0 seg000:00407BB9 push offset aShell32_dll ; "shell32.dll" seg000:00407BBE call j_LoadLibraryA seg000:00407BC3 mov hModule, eax seg000:00407BC8 cmp hModule, 0 seg000:00407BCF jnz short loc_407BD8 seg000:00407BD1 push 0 ; uExitCode seg000:00407BD3 call j_ExitProcess_0 seg000:00407BD8 push offset aUrlmon_dll ; "urlmon.dll" seg000:00407BDD call j_LoadLibraryA seg000:00407BE2 mov esi, eax seg000:00407BE4 test esi, esi seg000:00407BE6 jnz short loc_407BEF seg000:00407BE8 push 0 ; uExitCode seg000:00407BEA call j_ExitProcess_0 seg000:00407BEF push offset aWininet_dll ; "Wininet.dll" seg000:00407BF4 call j_LoadLibraryA seg000:00407BF9 mov edi, eax seg000:00407BFB test edi, edi seg000:00407BFD jnz short loc_407C06 seg000:00407BFF push 0 ; uExitCode seg000:00407C01 call j_ExitProcess_0 seg000:00407C06 push offset ProcName ; "URLDownloadToFileA" seg000:00407C0B push esi ; hModule seg000:00407C0C call j_GetProcAddress seg000:00407C11 mov dword_40B070, eax seg000:00407C16 push offset aShellexecutea ; "ShellExecuteA" seg000:00407C1B mov eax, hModule seg000:00407C20 push eax ; hModule seg000:00407C21 call j_GetProcAddress seg000:00407C26 mov esi, eax seg000:00407C28 push offset aInternetgetcon ; "InternetGetConnectedState" seg000:00407C2D push edi ; hModule seg000:00407C2E call j_GetProcAddress seg000:00407C33 mov esi, eax seg000:00407C35 push offset aIsdebuggerpres ; "IsDebuggerPresent" seg000:00407C3A push ebx ; hModule seg000:00407C3B call j_GetProcAddress seg000:00407C40 mov edi, eax seg000:00407C42 mov esi, edi seg000:00407C44 test edi, edi seg000:00407C46 jz short loc_407C55 seg000:00407C48 call esi seg000:00407C4A cmp al, 1 seg000:00407C4C jnz short loc_407C55 seg000:00407C4E push 0 ; uExitCode seg000:00407C50 call j_ExitProcess_0 seg000:00407C55 mov eax, large fs:18h seg000:00407C5C mov eax, [eax+30h] seg000:00407C5F movzx eax, byte ptr [eax+2] seg000:00407C63 cmp eax, 1 seg000:00407C66 jnz short loc_407C6F seg000:00407C68 push 0 ; uExitCode seg000:00407C6A call j_ExitProcess_0
The first anti-debug it’s OllyDbg-specific, if you use Olly you can bypass it using some plugins or manually you can change push eax to push 0 🙂
This API is being called by
%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s
It’s kind of format string exploit and causes a crash in Ollydbg.
After that application calls LoadLibraryA to load some DLLs and then tries to get API addresses using GetProcAddress, most of these APIs are widely used in malwares, but there isn’t any point here, so maybe the author has put these APIs here to tell us that “You should pay attention to here” 😀
here is the junk code used by author:
seg000:00407C6F push eax seg000:00407C70 add eax, 42h seg000:00407C73 sub eax, 41h seg000:00407C76 cmp eax, 44h seg000:00407C79 cmp eax, 5Fh seg000:00407C7C mov eax, 46h seg000:00407C81 shl eax, 4Fh seg000:00407C84 shr eax, 4Fh seg000:00407C87 cmp eax, 44h seg000:00407C8A mov eax, 2Dh seg000:00407C8F shl eax, 42h seg000:00407C92 sar eax, 41h seg000:00407C95 cmp eax, 44h seg000:00407C98 rcl eax, 5Fh seg000:00407C9B mov eax, 46h seg000:00407CA0 ror eax, 4Fh seg000:00407CA3 rol eax, 4Fh seg000:00407CA6 rcr eax, 44h seg000:00407CA9 pop eax
I converted those hex values to ASCII values and I got this string:
“BAD_FOOD-BAD_FOOD”
After these codes I can see some WriteConsoleA, GetTickCount and ExitProcess functions, so I decided to force the application, to avoid exiting, by changing some jump flags and finally I got the following messages:
- Â Hidden part #1. Text picked from the following URL:
- Â http://www.virusradar.com/en/Win32_Virut.E/description
O noon of life! O time to celebrate!
O summer garden!
Relentlessly happy and expectant, standing: –
Watching all day and night, for friends I wait:
Where are you, friends? Come! It is time! It’s late!
- Hidden part #2. Text picked from the following URL:
- http://www.virusradar.com/en/Win32_Ridnu.NAA/description
DEAR MY PRINCESS
WHEN THE STARS FILL THE SKY I WILL MEET YOU MY LOVELY PRINCESS
I MISS YOU SO MUCH MY PRINCESS
IN MY DEAREST MEMORY I SEE YOU REACHING OUT TO ME
I WILL REMEMBER YOU AS LONG AS YOU REMEMBER ME
IN YOUR DEAREST MEMORY DO YOU REMEMBER LOVING ME
PLEASE DO NOT FORGET OUR PAST
DID YOU KNOW THAT I HAD MIND ON YOU
I NEVER WISH TO LOSE YOU AGAIN
SHALL I BE THE ONE FOR YOU
I WANNA TAKE YOU TO MY PALACE
I WILL TAKE YOU TO OUR UTOPIA
I AM FALLING IN LOVE WITH YOU
I WILL BE WAITING FOR YOU
I DO NOT WANT TO SAY GOOD BYE TO YOU
PLEASE DO NOT FORGET YOUR PRINCE
I SAW YOU SMILING AT ME WAS IT REAL OR JUST MY FANTASY
YOU WILL ALWAYS IN MY HEART
YOU ALWAYS IN MY DREAMS
I ALWAYS SEE YOU IN MY DREAMS
I HAVE BEEN POISONED BY YOUR LOVE
I MISS YOU I AM STILL LOOKING FOR YOU
I WILL BE THERE I WILL BE WAITING FOR YOU
PLEASE COME BACK TO OUR BEAUTY ISLAND
I MISS YOUR CUTE SMILE
- Â Hidden part #3.
ESET Crackme #2
Let’s go with the next crackme, that could be downloaded here:
http://www.joineset.com/download/bmV4dF9maWxl/crack_me_2.zip
After downloading ESET Crackme 2, I started to inspect it by checking the presence of packers via PEiD:
As you see our software is packed with RLPack and needs to be unpacked. Also section names are UPX1… to fool analyzer.
Crackme appears as follows:
So first of all we should unpack crackme. You can use the method you’ve used for UPX but this time you should Rebuild your unpacked file with LordPE to make it run.
OEP: 00008043 RVA: 00020FFC Size: 00000194
So in crackme_2 we have two Text Boxes, if you look at API calls there is GetWindowTextA, which copies the text of a specified windows control into a buffer, so I simply set a breakpoint on that and entered fake serial:
0040431C PUSH EAX ; |Buffer 0040431D PUSH 3E9 ; |/ControlID = 3E9 (1001.) 00404322 PUSH EDI ; ||hWnd 00404323 CALL ESI ; |\GetDlgItem 00404325 PUSH EAX ; |hWnd 00404326 CALL DWORD PTR DS:[421178] ; \GetWindowTextA 0040432C PUSH crack_me.00425F84 ; /String2 = "Pigs are filthy animals" 00404331 LEA ECX,DWORD PTR SS:[EBP-94] ; | 00404337 PUSH ECX ; |String1 00404338 CALL DWORD PTR DS:[421044] ; \lstrcmpA
So first serial TextBox should be “Pigs are filthy animals” and following the same method for second Text Box:
004043CB PUSH 80 ; /Count = 80 (128.) 004043D0 LEA EAX,DWORD PTR SS:[EBP-94] ; | 004043D6 PUSH EAX ; |Buffer 004043D7 PUSH 3EA ; |/ControlID = 3EA (1002.) 004043DC PUSH EDI ; ||hWnd 004043DD CALL ESI ; |\GetDlgItem 004043DF PUSH EAX ; |hWnd 004043E0 CALL DWORD PTR DS:[421178] ; \GetWindowTextA 004043E6 CMP DWORD PTR DS:[EBX+4],0 004043EA JE crack_me.00404489 004043F0 MOV EBX,DWORD PTR DS:[EBX] 004043F2 PUSH EBX ; /String2 004043F3 LEA ECX,DWORD PTR SS:[EBP-94] ; | 004043F9 PUSH ECX ; |String1 004043FA CALL DWORD PTR DS:[421044] ; \lstrcmpA
The serial for second TextBox is: “I did it!” and after that the Message Box appears:
So we should find some other information about crackme !!!
I started analyzing the file by putting some breakpoints to important APIs such as CreateFileA,WriteFileA,VirtualAlloc. In 0040484E app calls CreateFileW and looks for a pipe called “Vincent_Vega”. As there isn’t any pipe called Vincent_Vega, CreateFileW returns -1.
0040481E PUSH 0 ; /hTemplateFile = NULL 00404820 PUSH 40000000 ; |Attributes = OVERLAPPED 00404825 PUSH 3 ; |Mode = OPEN_EXISTING 00404827 PUSH 0 ; |pSecurity = NULL 00404829 PUSH 1 ; |ShareMode = FILE_SHARE_READ 0040482B MOV EBX,ECX ; | 0040482D PUSH 80000000 ; |Access = GENERIC_READ 00404832 PUSH crack_me.00426028 ; |FileName = "\\.\pipe\Vincent_Vega" 00404837 MOV BYTE PTR SS:[EBP-25E],1 ; | 0040483E MOV DWORD PTR DS:[EBX],0 ; | 00404844 MOV DWORD PTR DS:[EBX+20C],0 ; | 0040484E CALL DWORD PTR DS:[421068] ; \CreateFileW 00404854 MOV ECX,EBX 00404856 MOV EDI,EAX 00404858 CALL crack_me.00404690 0040485D CMP EDI,-1 00404860 JE crack_me.0040493B 00404866 MOV ESI,DWORD PTR DS:[421070] ; kernel32.ReadFile 0040486C PUSH 0 ; /pOverlapped = NULL 0040486E LEA EAX,DWORD PTR SS:[EBP-268] ; | 00404874 PUSH EAX ; |pBytesRead 00404875 PUSH 1 ; |BytesToRead = 1 00404877 LEA ECX,DWORD PTR SS:[EBP-25D] ; | 0040487D PUSH ECX ; |Buffer 0040487E PUSH EDI ; |hFile 0040487F MOV BYTE PTR SS:[EBP-25E],0 ; | 00404886 MOV BYTE PTR SS:[EBP-25D],0 ; | 0040488D CALL ESI ; \ReadFile
I continued debugging by hitting F9 and execution flow stopped at CreateFileW again, here is the Stack View:
0012FB58 7C835B8C /CALL to CreateFileW from kernel32.7C835B87 0012FB5C 0012FCA4 |FileName = "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\7.tmp" 0012FB60 80000000 |Access = GENERIC_READ 0012FB64 00000000 |ShareMode = 0 0012FB68 00000000 |pSecurity = NULL 0012FB6C 00000001 |Mode = CREATE_NEW 0012FB70 00000080 |Attributes = NORMAL 0012FB74 00000000 \hTemplateFile = NULL
The crackme is going to create a file called 7.tmp.
By taking a look at 004046D0 I saw the app is trying to decrypt one of its resources named 83h=131d
Decryption key is:
“T2ggbWFuLEkgc2hvdCBNYXJ2aW4gaW4gdGhlIGZhY2U=”
which is in Base64 mode and if you decode it, you’ll get:
“Oh man,I shot Marvin in the face”
I opened the created tmp file with an hexeditor and observed that it’s a Exe file. So I have changed the file extension to .exe and executed it:
This file was a .NET file which was obfuscated:
If you take a look at class “a” in decompiled file you’ll see that pipe server is being created with this file:
public class a { // Fields public const string a = "Vincent_Vega"; private ManualResetEvent a; private volatile bool a = true; private D.d A; private D.E A; private NamedPipeServerStream A; public const string A = "EASTER EGG PIPE SERVER IS READY!"; public ManualResetEvent A; private volatile bool A = false; private const int A = 0x400; private byte[] A = new byte[0x400]; private static readonly object A = new object(); private Thread A = null; // Methods public a(D.d d1, D.E e1) { this.A = d1; this.A = e1; this.a = new ManualResetEvent(false); this.A = new ManualResetEvent(false); this.A = new Thread(new ParameterizedThreadStart(this.A)); this.A.Start(); } private void a(IAsyncResult result1) { B asyncState = result1.AsyncState as B; int num = 0; try { num = asyncState.a().EndRead(result1); if (num <= 0) { goto Label_007B; } asyncState.a(num); if (!asyncState.C()) { goto Label_007B; } this.A(asyncState.b()); lock (A) { this.a = true; } } catch (IOException) { asyncState.a().Close(); } return; Label_007B: if (num > 0) { try { asyncState.a().BeginRead(asyncState.A(), 0, asyncState.A().Length, new AsyncCallback(this.a), asyncState); return; } catch (IOException) { asyncState.a().Close(); return; } } int count = asyncState.b().Count; asyncState.a().Close(); lock (A) { this.a = true; } } public void A() { this.A = true; this.a.Set(); } private void A(IAsyncResult result1) { try { this.A.EndWaitForConnection(result1); this.a.Set(); } catch (OperationCanceledException) { Console.WriteLine(.B()); } } private void A(object) { try { while (!this.A) { this.A = new NamedPipeServerStream(.a(), PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); this.a.Reset(); try { this.A.BeginWaitForConnection(new AsyncCallback(this.A), null); this.a.WaitOne(); if (this.A.IsConnected) { this.A(); } while (!this.A && this.A.IsConnected) { if (this.a) { lock (A) { this.a = false; } this.A.BeginRead(this.A, 0, this.A.Length, new AsyncCallback(this.a), new B(this.A, this.A)); } Thread.Sleep(200); } if ((this.A != null) && this.A.IsConnected) { this.A.Close(); } continue; } catch (Exception) { if (this.A != null) { this.A.Close(); } continue; } } } catch (IOException) { } finally { if ((this.A != null) && this.A.IsConnected) { this.A.Close(); } } this.A.Set(); } public bool A(string text1) { bool flag = false; try { if (this.A.IsConnected) { new b(this.A).A(text1); flag = true; } } catch (Exception) { } return flag; } }
For better understanding the code, you need to DeObfuscate the exe. To do this you can use de4dot or deobfuscators. I have deobfuscted the exe whit my simple tool and then fixed it whit de4dot, ofc after deobfuscation exe won’t run any more because some functions are destroyed but at least it will help us the code better. (my tool+deobfuscated exe are attached).
First of all it creates a Pipe server.It’s name is “Vincent_Vega” According to Microsoft:
A pipe is a section of shared memory that processes use for communication. The process that creates a pipe is the pipe server. A process that connects to a pipe is a pipe client. One process writes information to the pipe, then the other process reads the information from the pipe. This overview describes how to create, manage, and use pipes.
Pipe server is created with this code:
this.A = new NamedPipeServerStream(.a(), PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
a() is the pipe servers name, but all names here are encrypted and stored in another class. App reference to them by numbers, for example here a() is:
public static string a() { Â Â Â return ([1] ?? (1, 1, 12)); }
Then it creates thread to verify that pipe server is running.
So I ran pipe server and restarted Crackme_2.exe by putting bp on CreateFileW. This time CreateFileW didn’t return -1 🙂
Pipe server returns a string:
“Le Big Mac”
and in 00404900 it’s being compared with
“Royale with Cheese”
which was decrypted from “Um95YWxlIHdpdGggQ2hlZXNl”.
In 00404900 strings which are located in EAX and ESI are being compared byte by byte:
@crack_me_00404900:
MOV CL,BYTE PTR DS:[EAX] CMP CL,BYTE PTR DS:[ESI] JNZ @crack_me_00404920 TEST CL,CL JE @crack_me_0040491C MOV CL,BYTE PTR DS:[EAX+1] CMP CL,BYTE PTR DS:[ESI+1] JNZ @crack_me_00404920 ADD EAX,2 ADD ESI,2 TEST CL,CL JNZ @crack_me_00404900
@crack_me_0040491C:
XOR EAX,EAX JMP @crack_me_00404925
@crack_me_00404920:
SBB EAX,EAX SBB EAX,-1
@crack_me_00404925:
TEST EAX,EAX
if they are be same a Message Box will be shown:
00404929 PUSH EAX ; /Style 0040492A PUSH crack_me.0042605C ; |Title = "Hamburger message" 0040492F PUSH crack_me.00426070 ; |Text = "Hamburgers. The cornerstone of any nutritious breakfast!" 00404934 PUSH EAX ; |hOwner 00404935 CALL DWORD PTR DS:[421174] ; \MessageBoxA
in 004049ED another Base64 encoded string will be decrypted “TUFMQ0hPLkRMTA==”. It’s “MALCHO.DLL” and after that app try to load that by LoadLibraryA and then try to execute one its functions named : “Z2V0UGFzc3dvcmQ=”.
So we should make that DLL, for this reason we need to come back to our .NET and analyze it more in depth and then find a 32 char password.
First operation performed it’s a pipe server as shown above but interesting part is when it tries to create a thread, thread opcodes are built dynamically, whole operation is performed in 3 methods, one of these methods are shown below:
Field_17 is an array which should hold ILOpcodes and defined as:
protected ArrayList Field_17;
Function_String_xx refers to address of Opcode, and again these strings are also encrypted like pipe server name.
protected void Procedure_8() { this.Field_17.Add(new Class_14_Object(OpCodes.Ldarg_1, null, Function_String_14())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldloc_0, null, Function_String_15())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldloc_2, null, Function_String_16())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldarg_0, null, Function_String_17())); this.Field_17.Add(new Class_14_Object(OpCodes.Nop, null, Function_String_18())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldloc_2, null, Function_String_19())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4_1, null, Function_String_20())); this.Field_17.Add(new Class_14_Object(OpCodes.Add, null, Function_String_21())); this.Field_17.Add(new Class_14_Object(OpCodes.Stloc_2, null, Function_String_22())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldlen, null, Function_String_23())); this.Field_17.Add(new Class_14_Object(OpCodes.Conv_I4, null, Function_String_24())); this.Field_17.Add(new Class_14_Object(OpCodes.Nop, null, Function_String_25())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldarg_0, null, Function_String_26())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldloc_2, null, Function_String_27())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldelem_U1, null, Function_String_28())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4_0, null, Function_String_29())); this.Field_17.Add(new Class_14_Object(OpCodes.Stloc_3, null, Function_String_30())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldloc_1, null, Function_String_31())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldloc_0, null, Function_String_32())); this.Field_17.Add(new Class_14_Object(OpCodes.Sub, null, Function_String_33())); this.Field_17.Add(new Class_14_Object(OpCodes.Add, null, Function_String_34())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4_0, null, Function_String_35())); this.Field_17.Add(new Class_14_Object(OpCodes.Stloc_0, null, Function_String_36())); this.Field_17.Add(new Class_14_Object(OpCodes.Stloc_0, null, Function_String_37())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldloc_0, null, Function_String_38())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldarg_1, null, Function_String_39())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldlen, null, Function_String_40())); this.Field_17.Add(new Class_14_Object(OpCodes.Conv_I4, null, Function_String_41())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4_1, null, Function_String_42())); this.Field_17.Add(new Class_14_Object(OpCodes.Sub, null, Function_String_43())); this.Field_17.Add(new Class_14_Object(OpCodes.Ceq, null, Function_String_44())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4_0, null, Function_String_45())); this.Field_17.Add(new Class_14_Object(OpCodes.Ceq, null, Function_String_46())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4_1, null, Function_String_47())); this.Field_17.Add(new Class_14_Object(OpCodes.Stloc_3, null, Function_String_48())); this.Field_17.Add(new Class_14_Object(OpCodes.Stloc_S, 4, Function_String_49())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldloc_S, 4, Function_String_50())); this.Field_17.Add(new Class_14_Object(OpCodes.Clt, null, Function_String_51())); this.Field_17.Add(new Class_14_Object(OpCodes.Stloc_S, 4, Function_String_52())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldloc_S, 4, Function_String_53())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldelem_U1, null, Function_String_54())); this.Field_17.Add(new Class_14_Object(OpCodes.Ceq, null, Function_String_55())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4_0, null, Function_String_56())); this.Field_17.Add(new Class_14_Object(OpCodes.Ceq, null, Function_String_57())); this.Field_17.Add(new Class_14_Object(OpCodes.Nop, null, Function_String_58())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4_0, null, Function_String_59())); this.Field_17.Add(new Class_14_Object(OpCodes.Stloc_0, null, Function_String_60())); this.Field_17.Add(new Class_14_Object(OpCodes.Stloc_1, null, Function_String_61())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4_0, null, Function_String_62())); this.Field_17.Add(new Class_14_Object(OpCodes.Stloc_2, null, Function_String_63())); this.Field_17.Add(new Class_14_Object(OpCodes.Stloc_S, 4, Function_String_64())); this.Field_17.Add(new Class_14_Object(OpCodes.Nop, null, Function_String_65())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldloc_S, 4, Function_String_66())); this.Field_17.Add(new Class_14_Object(OpCodes.Nop, null, Function_String_67())); this.Procedure_5(); this.Field_17.Add(new Class_14_Object(OpCodes.Ldloc_0, null, Function_String_68())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4_1, null, Function_String_69())); }
after building IL opcodes, and sorting all of them according to their addresses, we will have something like this:
L_000000000: Nop L_000000010: Ldc.I4.0 L_000000020: Stloc.0 L_000000030: Ldc.I4,var1 L_000000031: Ldc.I4,var2 L_000000032: Xor L_000000080: Stloc.1 L_000000090: Ldc.I4.0 L_0000000A0: Stloc.2 L_0000000B0: br.s label L_0000000CF: label6 L_0000000D0: Nop L_0000000E0: Ldarg.0 L_0000000F0: Ldloc.2 L_000000100: Ldelem.U1 L_000000110: Ldloc.1 L_000000120: Ldloc.0 L_000000130: Sub L_000000140: xor L_000000150: Ldarg.1 L_000000160: Ldloc.0 L_000000170: Ldelem.U1 L_000000180: Ceq L_0000001A0: Ldc.I4.0 L_0000001B0: Ceq L_0000001D0: Stloc.S,4 L_0000001F0: Ldloc.S,4 L_000000210: brtrue.s label2 L_000000230: Nop L_000000240: ldloc.0 L_000000250: ldc.i4.1 L_000000260: Add L_000000270: Stloc.0 L_000000280: Ldloc.0 L_000000290: Ldarg.1 L_0000002A0: Ldlen L_0000002B0: Conv.I4 L_0000002C0: Ldc.I4.1 L_0000002D0: Sub L_0000002E0: Ceq L_000000300: Ldc.I4.0 L_000000310: Ceq L_000000330: Stloc.S,4 L_000000350: Ldloc.S,4 L_000000370: brtrue.s label3 L_000000390: Ldc_I4.1 L_0000003A0: Stloc.3 L_0000003B0: Br.s label4 L_0000003CF: label3 L_0000003D0: Nop L_0000003E0: br.s label5 L_0000003FF: label2 L_000000400: Ldc_I4.0 L_000000410: Stloc.0 L_000000420: Nop L_000000430: Ldloc.2 L_000000440: Ldc_I4.1 L_000000450: Add L_000000460: Stloc.2 L_000000470: Ldloc.2 L_000000480: Ldarg.0 L_000000490: Ldlen L_0000004A0: Conv.I4 L_00000041F: label5 L_00000046F: label L_0000004B0: Clt L_0000004D0: Stloc_S,4 L_0000004F0: Ldloc_S,4 L_000000510: brtrue.s label6 L_000000530: Ldc_I4_0 L_000000540: Stloc_3 L_000000550: br.s label4 L_00000056F: label4 L_000000570: ldloc.3 L_000000580: Ret
var1 and var2 are 1 byte variables and something like CRC.
App adds them to array list with the codes below:
this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4, this.Field_9 & 0xff, Function_String_11())); this.Field_17.Add(new Class_14_Object(OpCodes.Ldc_I4, this.Field_10 & 0xff, Function_String_12()));
Field_9 and Field_10 are assigned here:
 if (!Debugger.IsAttached && !Debugger.IsLogging())        {            new Thread(new ParameterizedThreadStart(this.Procedure_6)) { IsBackground = true }.Start(null);            this.Field_9 = this.Function_Int32_7(MethodBase.GetCurrentMethod());            this.Field_12.WaitOne();            this.Procedure_8();            this.Procedure_9();            this.Field_4 = new Class_3_Object(new Class_9_MulticastDelegate(this.Procedure_3), new Class_10_MulticastDelegate(this.Procedure_4));            new Thread(new ThreadStart(this.Procedure_1)).Start();        }
And
   if (thread == null)        {            thread = new Thread(new ParameterizedThreadStart(this.Procedure_6)) {                IsBackground = true            };            thread.Start(Thread.CurrentThread);            this.Field_10 = this.Function_Int32_7(MethodBase.GetCurrentMethod());            this.Field_12.Set();            Thread.Sleep(500);        }
Where Function_Int32_7 is:
 private int Function_Int32_7(MethodBase methodBase_0) {    byte[] iLAsByteArray = methodBase_0.GetMethodBody().GetILAsByteArray();    int num = 0;    foreach (byte num2 in iLAsByteArray)    {        num += num2;    }    return num; }
Ass you see in Function_Int32_7 it calculates the values for Field_9 and Field_10 using IL Bytes.
But the important function is here:
public void Procedure_1() { while (!this.Field_5) { try { Thread.Sleep(500); this.Procedure_11("iexplore"); continue; } catch (Exception) { continue; } } this.Field_13.Set(); }
public void Procedure_11(string string_0) { Â Â Â this.Field_7 = false; Â Â Â foreach (Process process in Process.GetProcessesByName(string_0)) Â Â Â { Â Â Â Â Â Â Â this.Procedure_13(process.MainWindowHandle); Â Â Â } Â Â Â lock (Field_0) Â Â Â { Â Â Â Â Â Â Â this.Field_6 = this.Field_7; Â Â Â } } public void Procedure_13(IntPtr intptr_0) { Â Â Â Class_13_MulticastDelegate delegate2 = new Class_13_MulticastDelegate(this.Function_Boolean_15); Â Â Â EnumChildWindows(intptr_0, delegate2, IntPtr.Zero); }
here it looks to internet explorer windows and tries to find “/ download/bmV4dF9maWxl/cGEkJHdk.txt”
If we append it to joineset.com we will get:
http://www.joineset.com/download/bmV4dF9maWxl/cGEkJHdk.txt
and this url contains a sentence:
Jules:You read the bible, Ringo?
It’s length is 32 so let’s make our dll and run the crackme_2 again.
Wow this time it decrypts the second resource file in temp folder. If you open it with notepad, you will see that it’s a java class. So let’s decompile it by Luyten (My favorite java decompiler):
public class Bible { public static void main(final String[] args) { System.out.println("Ezekiel 25:17"); System.out.println("-----------------------------------------------------------------------------------------------------------------"); System.out.println("The path of the righteous man is beset on all sides by the inequities of the selfish and the tyranny of evil men."); System.out.println("Blessed is he, who in the name of charity and good will, shepherds the weak through the valley of darkness,"); System.out.println("for he is truly his brother's keeper and the finder of lost children."); System.out.println("And I will strike down upon thee with great vengeance and furious anger those who would attempt to poison"); System.out.println("and destroy my brothers.And you will know my name is the Lord when I lay my vengeance upon thee."); System.out.println("-----------------------------------------------------------------------------------------------------------------"); System.out.println("Great! You found all easter eggs!"); } }
It’s seems we’ve done it 🙂
Conclusion
I hope you enjoyed this article. A big thanks goes to all UIC members especially evilcry and quequero. Special thanks to Ida Naderian who had helped me in process of analyzing and coding.
Deobfuscated
Crackmes
Password: eset
Great job!
Really good walk-through … awesome 🙂
Thank you.
Regards,
Tony
Great write-up, thanks!