Eset ChallengeME 2013 Solution

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:

http://www.joineset.com

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.

1

and

2

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:

3

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:

4
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:

5
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.

6

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”

7

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:

8

This file was a .NET file which was obfuscated:

9

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.

10

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

Comments

  1. tonyweb says:

    Great job!
    Really good walk-through … awesome 🙂

    Thank you.

    Regards,
    Tony

  2. Great write-up, thanks!