Cracking HawkEye Keylogger Reborn

Datetime:2016-08-22 22:52:13          Topic: Assembler  .Net           Share

I had never heard of ‘HawkEye Keylogger’ until I’ve read the following blog post from Trustwave. I’ve found the amount of features quite interesting and I was curious to have a closer look at the source code. After some research it seems this Keylogger has been successfully used in some campaigns in the past and it is still being actively used .

Actually ‘HawkEye’ is best known in the AV industry by ‘Golroted’ . In fact it seems that ‘HawkEye’ was using a different name before, ‘Predator Keylogger’, as you can see in this post from stopmalvertising. I’m not sure if the author(s) behind them are the same. The source code might have been shared/sold among some malicious software writers.

After a bit of digging I could also find some previous versions of ‘HawkEye’ cracked. However, it seemed, at first, that the previous versions were a bit different from the latest ‘Reborn’ version. ‘HawkEye’ didn’t look an advanced piece of malware and the authors/sellers apparently are doing a sloppy job. The lesson here is even a sloppy malware writers can make a profit without hiding themselves that much.

While searching the web I’ve found a few ‘HawkEye’ technical analysis (see references at the end of this blog post), and while poking around I ended on the home page of ‘HawkEye’. It is sold for more or less $35, depending on each type of license you are interested in. At the time of this writing the home page is down, it should come up again at some point. During the last month I noticed that it goes down and comes back from time to time.

I noticed one interesting thing though. Maybe due to a misconfiguration (or not) I could download ‘HawkEye Keylogger Reborn’ and some other malicious software that the same author is selling. From http://hawkspy.net/hawkeye-keylogger-reborn/ I was redirected to http://selfypay.org/HawkSpy/ and… guess what? All their software belongs to us…

‘HawkEye Keylogger - Reborn.exe’

SHA256: c8164521267263190900e1f62494068e994b053ae720d678da542e80286b5f46

So I had access to the “potential” builder and not only to the samples that were collected on the wild and mentioned on the technical articles I’ve found. So I decided to have a look and opened it in CFF Explorer.

CFF Explorer is like PEStudio for .net assemblies and it tells us that this file is indeed a .net binary.

Dynamic Analysis

So I downloaded it and ran it on a VM. No anti-VM techniques were in use, at least none able to detected my VMware based virtual lab. If ‘HawkEye’ doesn’t have access to the Internet the program will throw an Exception and writes a file ‘loader.log’ on the same directory from where the exe was launched.

8/1/2016 6:41:35 PM

The operation has timed out
   at System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request)
   at System.Net.WebClient.DownloadString(Uri address)
   at System.Net.WebClient.DownloadString(String address)
   at HawkEyeKeyloggerReborn.License.DownloadChecksums()
   at HawkEyeKeyloggerReborn.License.Initialize()

Since I was monitoring the DNS queries I could see that it tries to resolve the host ‘seal.nimoru.com’. Ok, I fired up my Tor Proxy VM and this time I was presented with a login form, as shown below.

I did a quick search for ‘Net Seal’ (shown in the title bar of the login dialog box) but at this time I didn’t find anything (more on this later).

Reverse Engineering Managed Code

Managed code decompilers are the way to go when analysing .NET assemblies since they allow us to decompile the binary into source code. However, if the binary is obfuscated, this process can be a nightmare. Besides the managed code decompilers are not as amazing as you may think if you are dealing with complex projects. Almost all of them allow you to export the code, even to Visual Studio projects. Getting this projects to compile is a complete different story though. Based on my experience 99% of times it will not build and you have to deal with too many errors. Most of the errors are completely ‘alien’. Still, decompilers are great.

So I loaded ‘HawkEye Keylogger - Reborn.exe’ in ILSpy, I could see the file was encrypted/obfuscated with a module called ‘MindZero v0.5.0-custom’.

I looked around but I couldn’t find any reference to MindZero .net code obfuscator or anything close on the Internet. I tried a couple of tools in order to try to identify the packer/obfuscator used. Some wrongly indicated that Confuser was used.

The only methods exposed, as you can see bellow, were ZeroMind(), Zero(), Mind(), Decompress(), and a few others.

The method Zero() and ZeroMind() were quite interesting. One of the immediate things I noticed was the use of Reflection and LoadModule. More on this later.

// <Module>
[System.STAThread, System.STAThread]
private static int Zero(string[] array)
{
    uint[] array2 = new uint[]
    {
        3154793535u,
        2510551337u,
        1068474031u,
        3134659130u,
        1935703431u,
        3462704481u,
        729329793u,
(** LARGE ARRAY CUT **)
        1847557079u,
        2466235288u,
        4233368770u,
        1709265185u,
        3912996699u,
        1356851460u
    };
    System.Reflection.Assembly executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
    System.Reflection.Module manifestModule = executingAssembly.ManifestModule;
    System.Runtime.InteropServices.GCHandle gCHandle = <Module>.Mind(array2, 640387902u);
    byte[] array3 = (byte[])gCHandle.Target;
    System.Reflection.Module module = executingAssembly.LoadModule("MZ", array3);
    System.Array.Clear(array3, 0, array3.Length);
    gCHandle.Free();
    System.Array.Clear(array2, 0, array2.Length);
    <Module>.key = manifestModule.ResolveSignature(285212673);
    System.AppDomain.CurrentDomain.AssemblyResolve += new System.ResolveEventHandler(<Module>.ZeroMind);
    module.GetTypes();
    System.Reflection.MethodBase methodBase = module.ResolveMethod((int)<Module>.key[0] | (int)<Module>.key[1] << 8 | (int)<Module>.key[2] << 16 | (int)<Module>.key[3] << 24);
    object[] array4 = new object[methodBase.GetParameters().Length];
    if (array4.Length != 0)
    {
        array4[0] = array;
    }
    object obj = methodBase.Invoke(null, array4);
    if (obj is int)
    {
        return (int)obj;
    }
    return 0;
}

After reading quite a lot about .net binaries Reverse Engineering (see the ‘References’) I decided to use first a memory dumper and then go from there.

So I used ‘MegaDumper 1.0 by CodeCracker / SnD’. You can find it in some Reverse Engineering Forums. Basically I executed ‘HawkEye Keylogger - Reborn.exe’, fired ‘MegaDumper’, selected the process corresponding to ‘HawkEye’ (stuck on the ‘Net Seal’ login prompt) and selected the option to dump the loaded assembly.

The result was an interesting collection of executable and dll files.

I loaded almost every file in ILSpy and found some interesting things. The ‘Cure.exe’ was the vacine to ‘HawkEye’. Meaning if you infected a computer and you want to clean it you should run this file. Here’s the interesting code showing some of the IOCs already mentioned in some of the articles I mentioned before.

Bellow is the code with the most interesting methods for Blue Teams.

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                this.seekanddestroy("vbc");
                Thread.Sleep(300);
                this.seekanddestroy("temp");
                Thread.Sleep(300);
                this.seekanddestroy("Pin");
                Thread.Sleep(300);
                this.seekanddestroy("Windows Update");
                Thread.Sleep(300);
                this.seekanddestroy("WindowsUpdate");
                Thread.Sleep(500);
                this.seekanddestroy("Microsoft");
            }
            catch (Exception expr_83)
            {
                ProjectData.SetProjectError(expr_83);
                ProjectData.ClearProjectError();
            }
            try
            {
                bool flag = !File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\pid.txt");
                if (!flag)
                {
                    int processId = Conversions.ToInteger(File.ReadAllText(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\pid.txt"));
                    Process.GetProcessById(processId).Kill();
                    Thread.Sleep(500);
                }
            }
            catch (Exception arg_EC_0)
            {
                ProjectData.SetProjectError(arg_EC_0);
                ProjectData.ClearProjectError();
            }
            try
            {
                bool flag = !File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\pidloc.txt");
                if (!flag)
                {
                    string path = File.ReadAllText(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\pidloc.txt");
                    flag = File.Exists(path);
                    if (flag)
                    {
                        File.Delete(path);
                    }
                }
                flag = File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\pid.txt");
                if (flag)
                {
                    File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\pid.txt");
                }
                flag = File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\pidloc.txt");
                if (flag)
                {
                    File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\pidloc.txt");
                }
            }
            catch (Exception expr_1B5)
            {
                ProjectData.SetProjectError(expr_1B5);
                ProjectData.ClearProjectError();
            }
            Thread thread = new Thread(new ThreadStart(this.builderclean));
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start();
            Thread thread2 = new Thread(new ThreadStart(this.serverclean));
            thread2.SetApartmentState(ApartmentState.STA);
            thread2.IsBackground = true;
            thread2.Start();
            checked
            {
                try
                {
                    DirectoryInfo directoryInfo = new DirectoryInfo("C:\\Users\\" + this.User + "\\AppData\\Roaming\\jagex_cache\\regPin");
                    FileInfo[] files = directoryInfo.GetFiles();
                    bool flag;
                    for (int i = 0; i < files.Length; i++)
                    {
                        FileInfo fileInfo = files[i];
                        flag = fileInfo.Extension.Equals(".jpeg");
                        if (flag)
                        {
                            fileInfo.Delete();
                        }
                    }
                    Thread.Sleep(1000);
                    flag = Directory.Exists("C:\\Users\\" + this.User + "\\AppData\\Roaming\\jagex_cache\\regPin");
                    if (flag)
                    {
                        Directory.Delete("C:\\Users\\" + this.User + "\\AppData\\Roaming\\jagex_cache\\regPin");
                    }
                    DirectoryInfo directoryInfo2 = new DirectoryInfo("C:\\Users\\" + this.User + "\\AppData\\Roaming\\jagex_cache\\reg");
                    FileInfo[] files2 = directoryInfo2.GetFiles();
                    for (int j = 0; j < files2.Length; j++)
                    {
                        FileInfo fileInfo2 = files2[j];
                        flag = fileInfo2.Extension.Equals(".jpeg");
                        if (flag)
                        {
                            fileInfo2.Delete();
                        }
                    }
                    Thread.Sleep(3000);
                    flag = Directory.Exists("C:\\Users\\" + this.User + "\\AppData\\Roaming\\jagex_cache\\reg");
                    if (flag)
                    {
                        Directory.Delete("C:\\Users\\" + this.User + "\\AppData\\Roaming\\jagex_cache\\reg");
                    }
                    DirectoryInfo directoryInfo3 = new DirectoryInfo(Path.GetTempPath() + "screens");
                    FileInfo[] files3 = directoryInfo3.GetFiles();
                    for (int k = 0; k < files3.Length; k++)
                    {
                        FileInfo fileInfo3 = files3[k];
                        flag = fileInfo3.Extension.Equals(".jpeg");
                        if (flag)
                        {
                            fileInfo3.Delete();
                        }
                    }
                    Thread.Sleep(3000);
                    flag = Directory.Exists(Path.GetTempPath() + "screens");
                    if (flag)
                    {
                        Directory.Delete(Path.GetTempPath() + "screens");
                    }
                }
                catch (Exception expr_40F)
                {
                    ProjectData.SetProjectError(expr_40F);
                    ProjectData.ClearProjectError();
                }
                this.SelfDestruct();
            }
        }

        public void builderclean()
        {
            try
            {
                bool flag = File.Exists(this.Tempclean + "temp.exe");
                if (flag)
                {
                    File.Delete(this.Tempclean + "temp.exe");
                }
                flag = File.Exists(Application.StartupPath + "\\assemblychange.exe");
                if (flag)
                {
                    File.Delete(Application.StartupPath + "\\assemblychange.exe");
                }
                Thread.Sleep(1000);
                flag = File.Exists(Application.StartupPath + "\\assemblychange.res");
                if (flag)
                {
                    File.Delete(Application.StartupPath + "\\assemblychange.res");
                }
                flag = File.Exists(Application.StartupPath + "\\ResHacker.exe");
                if (flag)
                {
                    File.Delete(Application.StartupPath + "\\ResHacker.exe");
                }
                Thread.Sleep(1000);
                flag = File.Exists(Application.StartupPath + "\\ResHacker.ini");
                if (flag)
                {
                    File.Delete(Application.StartupPath + "\\ResHacker.ini");
                }
                flag = File.Exists(Application.StartupPath + "\\ResHacker.log");
                if (flag)
                {
                    File.Delete(Application.StartupPath + "\\ResHacker.log");
                }
            }
            catch (Exception expr_12A)
            {
                ProjectData.SetProjectError(expr_12A);
                ProjectData.ClearProjectError();
            }
        }

        public void serverclean()
        {
            try
            {
                bool flag = File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\WindowsUpdate.exe");
                if (flag)
                {
                    File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\WindowsUpdate.exe");
                }
                flag = File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\WindowsUpdate.exe");
                if (flag)
                {
                    File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\WindowsUpdate.exe");
                }
                flag = File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Windows Update.exe");
                if (flag)
                {
                    File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Windows Update.exe");
                }
                flag = File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Pin.exe");
                if (flag)
                {
                    File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Pin.exe");
                }
                Thread.Sleep(1000);
                flag = File.Exists(Path.GetTempPath() + "SysInfo.txt");
                if (flag)
                {
                    File.Delete(Path.GetTempPath() + "SysInfo.txt");
                }
                flag = File.Exists(this.Tempclean + "wallet.dat");
                if (flag)
                {
                    File.Delete(this.Tempclean + "wallet.dat");
                }
                flag = File.Exists(this.Tempclean + MyProject.Computer.Name + "_wallet.dat");
                if (flag)
                {
                    File.Delete(this.Tempclean + MyProject.Computer.Name + "_wallet.dat");
                }
                flag = File.Exists(this.Tempclean + "firstfile.exe");
                if (flag)
                {
                    File.Delete(this.Tempclean + "firstfile.exe");
                }
                Thread.Sleep(1000);
                flag = File.Exists(this.Tempclean + "firstfile.txt");
                if (flag)
                {
                    File.Delete(this.Tempclean + "firstfile.txt");
                }
                flag = File.Exists(this.Tempclean + "secondfile.exe");
                if (flag)
                {
                    File.Delete(this.Tempclean + "secondfile.exe");
                }
                flag = File.Exists(this.Tempclean + "secondfile.txt");
                if (flag)
                {
                    File.Delete(this.Tempclean + "secondfile.txt");
                }
                Thread.Sleep(1000);
                flag = File.Exists(Path.GetTempPath() + "CLog.txt");
                if (flag)
                {
                    File.Delete(Path.GetTempPath() + "CLog.txt");
                }
                flag = File.Exists(this.Tempclean + "holdermail.txt");
                if (flag)
                {
                    File.Delete(this.Tempclean + "holdermail.txt");
                }
                flag = File.Exists(this.Tempclean + "holderwb.txt");
                if (flag)
                {
                    File.Delete(this.Tempclean + "holderwb.txt");
                }
            }
            catch (Exception expr_2CD)
            {
                ProjectData.SetProjectError(expr_2CD);
                ProjectData.ClearProjectError();
            }
        }

Other interesting file was ‘License.dll’. I loaded it in ILSpy and got the following message:

So it seems ‘SmartAssembly 6.9.0.114 obfuscator’ was used, at least in some PE files that are part of the whole package. However, even after cleaning it I couldn’t make much sense of the code… The amount of goto’s indicates that the file is still obfuscated, so or either SmartAssembly was incorrectly detected or the deobfuscator didn’t work. I didn’t spend much time with this though.

One of the dumped ‘HawkEye Keylogger - Reborn.exe’ files was smaller than the original, however after loading it in ILSpy I could see it was still packed/encrypted and all his functionality appeared the same. By running it I was again stuck in the ‘Net Seal’ login prompt.

It is interesting to notice that if this file was using some evasion techniques it would have exited long before we have finished. So this behaviour led me to conclude that if this ‘HawkEye’ version was using evasion techniques they were most likely not implemented correctly.

WinDBG to the rescue

In order to debug .net assemblies the best option is WinDBG with SOS and SOSEX together. However there is no IL code steping and it might be a bit hard to get into it. The IL opcodes are a bit scary, at least at first. Besides reversing .net malware is not well documented on the internet.

Before you start make sure you load Microsoft debugging symbols. Set your symbol path to Microsoft symbol server or just download the symbols locally. I usually have the symbols installed locally for obvious reasons, but it is completely up to you. I’m not going to show how to do it since this is widely documented. However this step is not optional.

The SOS extension is part of the .net framework and the SOSEX extension can be downloaded from here . You can install it anywhere you want, after firing WinDBG you need to load it the following way:

.load "F:\\sosex_32\\sosex.dll"

I’ll skip the steps to load and use SOS because you can do everything with SOSEX. However in a initial phase it was quite useful to get a better insight of this .net assembly.

As I mentioned before, one of the things I noticed when I first looked at the .net assembly in ILSpy was the use of Reflection and LoadModule. This method loads a Byte Array, hopefully unecrypted/deofuscated I thought. So with the help of SOSEX is quite easy to set a breakpoint on any method matching a pattern. So I decided to set a breakpoint on any method matching the pattern Assembly.Load :

!mbm *Assembly.Load*

When we run the binary CLR is initialized and WinDBG places breakpoints on all methods matching the pattern above. After the first breakpoint is hit you can see a complete list of breakpoints with:

0:000> bl
 0 e 71f37591     0001 (0001)  0:**** mscorlib_ni+0x327591
 1 e 71f0cb45     0001 (0001)  0:**** mscorlib_ni+0x2fcb45
 3 e 72647e69     0001 (0001)  0:**** mscorlib_ni+0xa37e69
 4 e 72647e95     0001 (0001)  0:**** mscorlib_ni+0xa37e95
 5 e 71f357d1     0001 (0001)  0:**** mscorlib_ni+0x3257d1
 6 e 72647f0d     0001 (0001)  0:**** mscorlib_ni+0xa37f0d
 7 e 71fa6009     0001 (0001)  0:**** mscorlib_ni+0x396009
 8 e 71f0cb6d     0001 (0001)  0:**** mscorlib_ni+0x2fcb6d
 9 e 72647f31     0001 (0001)  0:**** mscorlib_ni+0xa37f31
10 e 72647f70     0001 (0001)  0:**** mscorlib_ni+0xa37f70
11 e 72647fac     0001 (0001)  0:**** mscorlib_ni+0xa37fac
12 e 7264800f     0001 (0001)  0:**** mscorlib_ni+0xa3800f
13 e 72648047     0001 (0001)  0:**** mscorlib_ni+0xa38047
14 e 726480a5     0001 (0001)  0:**** mscorlib_ni+0xa380a5
15 e 72648122     0001 (0001)  0:**** mscorlib_ni+0xa38122
16 e 72648175     0001 (0001)  0:**** mscorlib_ni+0xa38175
17 e 726485a9     0001 (0001)  0:**** mscorlib_ni+0xa385a9
18 e 726485c1     0001 (0001)  0:**** mscorlib_ni+0xa385c1
19 e 72648b1c     0001 (0001)  0:**** mscorlib_ni+0xa38b1c
20 e 72648bda     0001 (0001)  0:**** mscorlib_ni+0xa38bda
21 e 71f5f9c7     0001 (0001)  0:**** mscorlib_ni+0x34f9c7
23 e 72648de1     0001 (0001)  0:**** mscorlib_ni+0xa38de1

After some hits and some exceptions we land exactly where we want.

0:000> g
ModLoad: 70ec0000 70ed3000   C:\Windows\Microsoft.NET\Framework\v4.0.30319\nlssorting.dll
Breakpoint 11 hit
eax=00000000 ebx=021d447c ecx=0fbc1030 edx=003e0400 esi=0fbc1030 edi=021c3f8c
eip=72647fac esp=0034ee2c ebp=0034ee34 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
mscorlib_ni+0xa37fac:
72647fac e883c5fdff      call    mscorlib_ni+0xa14534 (72624534)
0:000> dd ecx
0fbc1030  72052518 003e0400 00905a4d 00000003
0fbc1040  00000004 0000ffff 000000b8 00000000
0fbc1050  00000040 00000000 00000000 00000000
0fbc1060  00000000 00000000 00000000 00000000
0fbc1070  00000000 00000080 0eba1f0e cd09b400
0fbc1080  4c01b821 685421cd 70207369 72676f72
0fbc1090  63206d61 6f6e6e61 65622074 6e757220
0fbc10a0  206e6920 20534f44 65646f6d 0a0d0d2e

If we check ECX register we should have our Byte Array ready to be dumped. The second DWORD (003e0400) corresponds to size of the Byte Array and the third DWORD (00905a4d) corresponds to the .net assembly. To dump this assembly we can use the ‘writemem’ command as follows:

.writemem F:\sample.decrypted.exe 00905a4d L? 003e0400

But there’s an easier and 1337 way by using the poi() function. Pointer of integer function is used to get pointer-sized data. Think about the * operator for C and C++. By using poi() we just provide ecx+4 as its parameter and it will automatically take the value at that address and use it, rather than just using the value of ecx+4:

.writemem F:\sample.decrypted.exe @ecx+8 L?poi(@ecx+4)

I loaded the assembly in ILSpy and Bingo.

I now have access to the whole code. Under ‘Keylogger’ we can find the code for the ‘Builder’ of the samples that have been collected on the wild. As we can see, by looking only at the methods, the ‘Builder’ has loads of ‘cool’ stuff. ‘NewsFeed’, ‘Tutorial’, ‘BugReport’, ‘Bazaar’… it almost looks like a legit software.

After running the new binary I’m still stuck at the ‘Net Seal’ prompt login though. But now I have access to the code!

In case you missed something here’s the full WinDBG session.

CommandLine: "C:\Users\rui\Desktop\HawkEyeKeyloggerReborn\HawkEye Keylogger - Reborn\HawkEye Keylogger - Reborn.exe"

************* Symbol Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       srv*

************* Symbol Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       SRV*F:\symbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: SRV*F:\symbols*http://msdl.microsoft.com/download/symbols
Executable search path is: srv*
ModLoad: 00a40000 00b72000   image00a40000
ModLoad: 77240000 773c0000   ntdll.dll
ModLoad: 735b0000 735fa000   C:\Windows\SysWOW64\MSCOREE.DLL
ModLoad: 75240000 75350000   C:\Windows\syswow64\KERNEL32.dll
ModLoad: 76d20000 76d67000   C:\Windows\syswow64\KERNELBASE.dll
(9a8.c94): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=08960000 edx=0017dda8 esi=fffffffe edi=00000000
eip=772e103b esp=0034f8c8 ebp=0034f8f4 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!LdrpDoDebuggerBreak+0x2c:
772e103b cc              int     3
0:000> .load "F:\\sosex_32\\sosex.dll"
0:000> !mbm *Assembly.Load*
The CLR has not yet been initialized in the process.
Breakpoint resolution will be attempted when the CLR is initialized.
0:000> g
ModLoad: 76b70000 76c10000   C:\Windows\syswow64\ADVAPI32.dll
ModLoad: 764d0000 7657c000   C:\Windows\syswow64\msvcrt.dll
ModLoad: 767f0000 76809000   C:\Windows\SysWOW64\sechost.dll
ModLoad: 76820000 76910000   C:\Windows\syswow64\RPCRT4.dll
ModLoad: 74bd0000 74c30000   C:\Windows\syswow64\SspiCli.dll
ModLoad: 74bc0000 74bcc000   C:\Windows\syswow64\CRYPTBASE.dll
ModLoad: 73530000 735a9000   C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscoreei.dll
ModLoad: 761e0000 76237000   C:\Windows\syswow64\SHLWAPI.dll
ModLoad: 76ad0000 76b60000   C:\Windows\syswow64\GDI32.dll
ModLoad: 76940000 76a40000   C:\Windows\syswow64\USER32.dll
ModLoad: 767d0000 767da000   C:\Windows\syswow64\LPK.dll
ModLoad: 76580000 7661d000   C:\Windows\syswow64\USP10.dll
ModLoad: 76a70000 76ad0000   C:\Windows\SysWOW64\IMM32.DLL
ModLoad: 76d70000 76e3c000   C:\Windows\syswow64\MSCTF.dll
ModLoad: 73520000 73529000   C:\Windows\SysWOW64\VERSION.dll
ModLoad: 72e60000 73511000   C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
ModLoad: 72d60000 72e55000   C:\Windows\SysWOW64\MSVCR120_CLR0400.dll
(9a8.c94): Unknown exception - code 04242420 (first chance)
ModLoad: 71c10000 72d5a000   C:\Windows\assembly\NativeImages_v4.0.30319_32\mscorlib\225759bb87c854c0fff27b1d84858c21\mscorlib.ni.dll
Breakpoint set at System.Reflection.Assembly.LoadFrom(System.String) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.LoadFrom(System.String, System.Security.Policy.Evidence) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.LoadFrom(System.String, System.Security.Policy.Evidence, Byte[], System.Configuration.Assemblies.AssemblyHashAlgorithm) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.LoadFrom(System.String, Byte[], System.Configuration.Assemblies.AssemblyHashAlgorithm) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.Load(System.String) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.Load(System.String, System.Security.Policy.Evidence) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.Load(System.Reflection.AssemblyName) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.Load(System.Reflection.AssemblyName, System.Security.Policy.Evidence) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.LoadWithPartialName(System.String) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.LoadWithPartialName(System.String, System.Security.Policy.Evidence) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.Load(Byte[]) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.Load(Byte[], Byte[]) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.Load(Byte[], Byte[], System.Security.SecurityContextSource) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.Load(Byte[], Byte[], System.Security.Policy.Evidence) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.LoadFile(System.String) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.LoadFile(System.String, System.Security.Policy.Evidence) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.LoadModule(System.String, Byte[]) in AppDomain 00368190.
Breakpoint set at System.Reflection.Assembly.LoadModule(System.String, Byte[], Byte[]) in AppDomain 00368190.
Breakpoint set at System.Reflection.RuntimeAssembly.LoadWithPartialNameHack(System.String, Boolean) in AppDomain 00368190.
Breakpoint set at System.Reflection.RuntimeAssembly.LoadWithPartialNameInternal(System.String, System.Security.Policy.Evidence, System.Threading.StackCrawlMark ByRef) in AppDomain 00368190.
Breakpoint set at System.Reflection.RuntimeAssembly.LoadWithPartialNameInternal(System.Reflection.AssemblyName, System.Security.Policy.Evidence, System.Threading.StackCrawlMark ByRef) in AppDomain 00368190.
Breakpoint set at System.Reflection.RuntimeAssembly.LoadModule(System.String, Byte[], Byte[]) in AppDomain 00368190.
ModLoad: 74f60000 750bc000   C:\Windows\syswow64\ole32.dll
ModLoad: 70490000 70510000   C:\Windows\SysWOW64\uxtheme.dll
ModLoad: 71b30000 71bae000   C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll
ModLoad: 76010000 7609f000   C:\Windows\syswow64\OLEAUT32.dll
*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_32\mscorlib\225759bb87c854c0fff27b1d84858c21\mscorlib.ni.dll
Breakpoint 23 hit
eax=ffffff00 ebx=00000000 ecx=00368190 edx=0034f280 esi=021a3084 edi=021a23d0
eip=72648de1 esp=0034f27c ebp=0034f290 iopl=0         nv up ei ng nz ac pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000297
mscorlib_ni+0xa38de1:
72648de1 33d2            xor     edx,edx
0:000> bl
 0 e 71f37591     0001 (0001)  0:**** mscorlib_ni+0x327591
 1 e 71f0cb45     0001 (0001)  0:**** mscorlib_ni+0x2fcb45
 3 e 72647e69     0001 (0001)  0:**** mscorlib_ni+0xa37e69
 4 e 72647e95     0001 (0001)  0:**** mscorlib_ni+0xa37e95
 5 e 71f357d1     0001 (0001)  0:**** mscorlib_ni+0x3257d1
 6 e 72647f0d     0001 (0001)  0:**** mscorlib_ni+0xa37f0d
 7 e 71fa6009     0001 (0001)  0:**** mscorlib_ni+0x396009
 8 e 71f0cb6d     0001 (0001)  0:**** mscorlib_ni+0x2fcb6d
 9 e 72647f31     0001 (0001)  0:**** mscorlib_ni+0xa37f31
10 e 72647f70     0001 (0001)  0:**** mscorlib_ni+0xa37f70
11 e 72647fac     0001 (0001)  0:**** mscorlib_ni+0xa37fac
12 e 7264800f     0001 (0001)  0:**** mscorlib_ni+0xa3800f
13 e 72648047     0001 (0001)  0:**** mscorlib_ni+0xa38047
14 e 726480a5     0001 (0001)  0:**** mscorlib_ni+0xa380a5
15 e 72648122     0001 (0001)  0:**** mscorlib_ni+0xa38122
16 e 72648175     0001 (0001)  0:**** mscorlib_ni+0xa38175
17 e 726485a9     0001 (0001)  0:**** mscorlib_ni+0xa385a9
18 e 726485c1     0001 (0001)  0:**** mscorlib_ni+0xa385c1
19 e 72648b1c     0001 (0001)  0:**** mscorlib_ni+0xa38b1c
20 e 72648bda     0001 (0001)  0:**** mscorlib_ni+0xa38bda
21 e 71f5f9c7     0001 (0001)  0:**** mscorlib_ni+0x34f9c7
23 e 72648de1     0001 (0001)  0:**** mscorlib_ni+0xa38de1
0:000> dd ecx
00368190  72e63014 00000001 00368190 001f3f7c
003681a0  00000010 00000000 00000000 00369150
003681b0  00000000 00000000 00000000 baadf000
003681c0  00368fa0 ffffffff 00000000 00000000
003681d0  00000000 00000000 c0000020 00000001
003681e0  00000001 00000000 00368e88 ffffffff
003681f0  00000000 00000000 00000000 00000000
00368200  c0000000 00368ec0 ffffffff 00000000
0:000> g
ModLoad: 711a0000 71b27000   C:\Windows\assembly\NativeImages_v4.0.30319_32\System\52cca48930e580e3189eac47158c20be\System.ni.dll
(9a8.c94): CLR exception - code e0434352 (first chance)
Breakpoint 11 hit
eax=00000000 ebx=0034e5b0 ecx=021b9924 edx=00000025 esi=021b9924 edi=021b1a7c
eip=72647fac esp=0034e4a4 ebp=0034e4ac iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
mscorlib_ni+0xa37fac:
72647fac e883c5fdff      call    mscorlib_ni+0xa14534 (72624534)
0:000> dd ecx
021b9924  72052518 00000800 00905a4d 00000003
021b9934  00000004 0000ffff 000000b8 00000000
021b9944  00000040 00000000 00000000 00000000
021b9954  00000000 00000000 00000000 00000000
021b9964  00000000 00000080 0eba1f0e cd09b400
021b9974  4c01b821 685421cd 70207369 72676f72
021b9984  63206d61 6f6e6e61 65622074 6e757220
021b9994  206e6920 20534f44 65646f6d 0a0d0d2e
0:000> g
(9a8.c94): CLR exception - code e0434352 (first chance)
(9a8.c94): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000000c ebx=00000000 ecx=121a0000 edx=00000005 esi=15cb899f edi=121a0000
eip=0045cd2b esp=0034e478 ebp=0034e4c0 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
0045cd2b 8b0407          mov     eax,dword ptr [edi+eax] ds:002b:121a000c=????????
0:000> g
(9a8.c94): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000000c ebx=00000000 ecx=0b06799c edx=00000005 esi=15cb899f edi=0b06799c
eip=0045cd2b esp=0034e478 ebp=0034e4c0 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
0045cd2b 8b0407          mov     eax,dword ptr [edi+eax] ds:002b:0b0679a8=????????
0:000> g
(9a8.c94): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000000c ebx=00000000 ecx=00004e20 edx=00000005 esi=15cb899f edi=00004e20
eip=0045cd2b esp=0034e478 ebp=0034e4c0 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
0045cd2b 8b0407          mov     eax,dword ptr [edi+eax] ds:002b:00004e2c=????????
0:000> g
(9a8.c94): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000000c ebx=00000000 ecx=00001000 edx=00000005 esi=15cb899f edi=00001000
eip=0045cd2b esp=0034e478 ebp=0034e4c0 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
0045cd2b 8b0407          mov     eax,dword ptr [edi+eax] ds:002b:0000100c=????????
0:000> g
(9a8.c94): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000000c ebx=00000000 ecx=0000002c edx=00000005 esi=15cb899f edi=0000002c
eip=0045cd2b esp=0034e478 ebp=0034e4c0 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
0045cd2b 8b0407          mov     eax,dword ptr [edi+eax] ds:002b:00000038=????????
0:000> g
(9a8.c94): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000000c ebx=00000000 ecx=00000008 edx=00000005 esi=15cb899f edi=00000008
eip=0045cd2b esp=0034e478 ebp=0034e4c0 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
0045cd2b 8b0407          mov     eax,dword ptr [edi+eax] ds:002b:00000014=????????
0:000> g
(9a8.c94): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000000c ebx=00000000 ecx=00000008 edx=00000005 esi=15cb899f edi=00000008
eip=0045cd2b esp=0034e478 ebp=0034e4c0 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
0045cd2b 8b0407          mov     eax,dword ptr [edi+eax] ds:002b:00000014=????????
0:000> g
(9a8.c94): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000000c ebx=00000000 ecx=0000000c edx=00000005 esi=15cb899f edi=0000000c
eip=0045cd2b esp=0034e478 ebp=0034e4c0 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
0045cd2b 8b0407          mov     eax,dword ptr [edi+eax] ds:002b:00000018=????????
0:000> g
ModLoad: 70ec0000 70ed3000   C:\Windows\Microsoft.NET\Framework\v4.0.30319\nlssorting.dll
Breakpoint 11 hit
eax=00000000 ebx=021d447c ecx=0fbc1030 edx=003e0400 esi=0fbc1030 edi=021c3f8c
eip=72647fac esp=0034ee2c ebp=0034ee34 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
mscorlib_ni+0xa37fac:
72647fac e883c5fdff      call    mscorlib_ni+0xa14534 (72624534)
0:000> dd ecx
0fbc1030  72052518 003e0400 00905a4d 00000003
0fbc1040  00000004 0000ffff 000000b8 00000000
0fbc1050  00000040 00000000 00000000 00000000
0fbc1060  00000000 00000000 00000000 00000000
0fbc1070  00000000 00000080 0eba1f0e cd09b400
0fbc1080  4c01b821 685421cd 70207369 72676f72
0fbc1090  63206d61 6f6e6e61 65622074 6e757220
0fbc10a0  206e6920 20534f44 65646f6d 0a0d0d2e
0:000> .writemem f:\sample.decrypted.exe @ecx+8 L?poi(@ecx+4)
Writing 3e0400 bytes............................

Cracking HawkEye Keylogger Reborn

So I need to bypass this login prompt which I guess it validates the license. Which options do I have? I can try to export the code and build it on Visual Studio…

Well, I tried… 738 errors! Good luck with that…

The only option is to patch the binary. Even though I’ll be dealing with IL code and not assembly code… it looks more fun than fix 738 build errors. Luckily there’s a really nice plugin for ILSpy and Reflector called Reflexil that allows you to binary patch the IL code “easily”.

I used ILSpy since it is free. I tried Reflector too but I couldn’t find any feature worth the 59£. So stick with ILSpy. After poking around the code for a while I’ve found an interesting method inside the class ‘License’ called ‘Initialize()’. It seems I’ll need to modify it.

There are two ways you can modify the code with Reflexil. An easy one and a hard one. The easy one allows you to modify directly the code in C# (or Visual Basic). The hard one allows you to modify directly the IL opcodes.

Of course I went for the easy way! But that didn’t work quite well…

It looks I’ll have to learn some IL code. I have tried to build some really small PoCs on Visual Studio to figure out the IL opcodes for simple things like:

return true;

Which is basically:

ldc.i4.1
ret

However Reflexil makes it really easy, after poking around the code for a little while it looked like I only needed to delete instructions and not actually write any IL code.

So I deleted all the IL instructions from the methods ‘Initialize()’ and ‘Initialize(string)’ and saved the new file.

I’ve run it and… voila. Cracked?

Well… kind of. Because, if you try to use the ‘builder’… it does’t work.

The newest version of ‘HawkEye Keylogger’ has one big difference to the older ones that makes it a bit harder to crack. While the other cracked versions of ‘HawkEye Keylogger’ that I could find on-line (I mean the ones that work, because some don’t…) have the actual keylogger embedded as a Resource. However this ‘Reborn’ version doesn’t have the keylogger binary embedded as a Resource any more. Instead, during runtime the keylogger executable is downloaded from ‘ http://seal.nimoru.com/Base/getFile.php ’. The author’s intention is clearly avoid cracking. Look at the following ‘builder’ code under the ‘Menu’ class.

As we can see the download of the file depends on code from the ‘Net Seal’ authentication mechanism that we bypassed since we don’t have an account. Anyway we can see what’s going on here by looking at the ‘Cloud’ method.

public byte[] Cloud(string Url)
{
    byte[] result;
    try
    {
        result = this.Decompress(Convert.FromBase64String(Url));
        return result;
    }
    catch (Exception expr_13)
    {
        ProjectData.SetProjectError(expr_13);
        ProjectData.ClearProjectError();
    }
    result = new byte[0];
    return result;
}

I started looking around the code again to see what I could do. I though the easiest way was using a local sample of the keylogger and read its bytes directly into ‘MyProject.Forms.Keylogger.stubBytes’. To do this I need to find a proper place and write some IL code. It seems I can’t go away without writing IL code. Fun.

I used the same approach as before, launched Visual Studio and wrote more or less what I needed:

using System;
using System.IO;

namespace StubTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = @"f:\stub.exe";
            byte[] byteArray = File.ReadAllBytes(path);
        }
    }
}

Then I loaded it on ILSpy and looked at the IL instructions.

Then I started looking at the IL instructions of ‘GetStub’ method from the ‘Menu’ class…

I’ve found what it looked like a possible place for my IL code at ‘Menu_Load’ method on the ‘Menu’ class and rewrote it as shown bellow:

Saved the new file and gave it a try…

Yes, now it works. You need to place the ‘keylogger’ sample on ‘C:\pwned.exe’, you can change it but I’ll leave that as an exercise for you. Note that you also need ‘Mono.Cecil.dll’ installed on your system or simply on the same directory as our final cracked version or the program will crash with an ‘System.IO.FileNotFoundException’. If you use Procmon you can easily identify what’s missing…

You already have ‘Mono.Cecil.dll’, look at the dumps from ‘MegaDumper’ so… Mission Accomplished!

I’m not sharing the cracked version. However, you can visit the links I mention above and with all the information here you should be able to get the ‘job done’ or even do a better job.

HawkEye Builder Features and Code

The builder presents the user with multiple options. We can contact support via email as shown bellow.

Here’s the code from sending an email and “ask a favour”!

private void AskFavour()
        {
            this.Invoke(new VB$AnonymousDelegate_0(delegate
            {
                try
                {
                    this.btnSend.Enabled = false;
                    this.btnSend.Text = "Wait...";
                    this.sBarLabel.Text = "We are submitting your report, please wait...";
                    this.communication = LicenseGlobal.Seal.GetVariable("communication").Split(new char[]
                    {
                        '|'
                    });
                    MailMessage mailMessage = new MailMessage();
                    mailMessage.From = new MailAddress(this.communication[0]);
                    bool flag = Operators.CompareString(this.cboSubject.Text, "Technical Support", false) == 0;
                    if (flag)
                    {
                        string addresses = string.Concat(new string[]
                        {
                            this.communication[0],
                            ",",
                            this.communication[4],
                            ",",
                            this.communication[5],
                            ",",
                            this.txtEmail.Text
                        });
                        mailMessage.To.Add(addresses);
                    }
                    else
                    {
                        flag = (Operators.CompareString(this.cboSubject.Text, "Sales Support", false) == 0);
                        if (flag)
                        {
                            string addresses2 = this.communication[2] + "," + this.txtEmail.Text;
                            mailMessage.To.Add(addresses2);
                        }
                        else
                        {
                            flag = (Operators.CompareString(this.cboSubject.Text, "Others", false) == 0);
                            if (flag)
                            {
                                string addresses3 = this.communication[1] + "," + this.txtEmail.Text;
                                mailMessage.To.Add(addresses3);
                            }
                        }
                    }
                    mailMessage.Subject = this.cboSubject.Text;
                    mailMessage.Subject = this.cboSubject.Text;
                    mailMessage.Body = string.Concat(new string[]
                    {
                        "Username: ",
                        LicenseGlobal.Seal.Username.ToString(),
                        "\r\nProduct: HawkEye Keylogger - Reborn\r\nLicense Type: ",
                        LicenseGlobal.Seal.LicenseType.ToString(),
                        "\r\nCustomer's Email: ",
                        this.txtEmail.Text,
                        "\r\n\r\n\r\n\r\nSubject: \r\n",
                        this.cboSubject.Text,
                        "\r\n\r\nBody: \r\n",
                        this.txtBody.Text
                    });
                    new SmtpClient("mail.hawkspy.net")
                    {
                        Port = 25,
                        DeliveryMethod = SmtpDeliveryMethod.Network,
                        UseDefaultCredentials = false,
                        Credentials = new NetworkCredential(this.communication[0], this.communication[6] + "\\${"),
                        EnableSsl = false
                    }.Send(mailMessage);
                    CustomMsgBox.Show("Success! One of our Team Member will contact you shortly.");
                    this.btnSend.Enabled = true;
                    this.btnSend.Text = "Send";
                    this.sBarLabel.Text = "Idle...";
                }
                catch (Exception expr_305)
                {
                    ProjectData.SetProjectError(expr_305);
                    Exception ex = expr_305;
                    CustomMsgBox.Show(ex.Message.ToString());
                    this.btnSend.Enabled = true;
                    this.btnSend.Text = "Send";
                    this.sBarLabel.Text = "Idle...";
                    ProjectData.ClearProjectError();
                }
            }

You can check the status of your subscription too.

        public void Account()
        {
            this.txtBoxGlobalMessage.Text = LicenseGlobal.Seal.GlobalMessage;
            this.Username.Text = "Username: " + LicenseGlobal.Seal.Username;
            this.Label1.Text = "Update Available: " + LicenseGlobal.Seal.UpdateAvailable.ToString();
            this.Expiration.Text = "Expiration Date: " + LicenseGlobal.Seal.ExpirationDate.ToString();
            this.Time.Text = "Time Remaining: " + LicenseGlobal.Seal.TimeRemaining.ToString();
            this.License.Text = "License Type: " + LicenseGlobal.Seal.LicenseType.ToString();
            this.Unlimited.Text = "Unlimited Time: " + LicenseGlobal.Seal.UnlimitedTime.ToString();
            this.Label2.Text = "Your IP: " + LicenseGlobal.Seal.IPAddress.ToString();
            this.Label3.Text = "Product Version: " + LicenseGlobal.Seal.ProductVersion.ToString();
            this.GUID.Text = "GUID: " + LicenseGlobal.Seal.GUID;
        }

There’s even a news feed. Where I think the author publishes some… news!?

The vaccine to clean the infected machine as we saw earlier.

The lovely and caring Bug Report feature.

As you can see code reuse is not mandatory…

public void SendBugReport()
        {
            try
            {
                this.Invoke(new MethodInvoker(delegate
                {
                    this.btnReportBug.Enabled = false;
                }));
                this.Invoke(new MethodInvoker(delegate
                {
                    this.btnReportBug.Text = "Wait...";
                }));
                this.Invoke(new MethodInvoker(delegate
                {
                    this.sBarLabel.Text = "We are submitting your report, please wait...";
                }));
                this.communication = LicenseGlobal.Seal.GetVariable("communication").Split(new char[]
                {
                    '|'
                });
                MailMessage mailMessage = new MailMessage();
                mailMessage.From = new MailAddress(this.communication[0]);
                string addresses = this.communication[1] + "," + this.txtReportEmail.Text;
                mailMessage.To.Add(addresses);
                mailMessage.Subject = "HawkEye Keylogger - Reborn - Report A Bug";
                mailMessage.Body = string.Concat(new string[]
                {
                    "Username: ",
                    LicenseGlobal.Seal.Username.ToString(),
                    "\r\nProduct: HawkEye Keylogger - Reborn\r\nLicense Type: ",
                    LicenseGlobal.Seal.LicenseType.ToString(),
                    "\r\nCustomer's Email: ",
                    this.txtReportEmail.Text,
                    "\r\n\r\n\r\n\r\nSubject: \r\nHawkEye Keylogger - Reborn - Report A Bug\r\n\r\nBody: \r\n",
                    this.txtReportBody.Text
                });
                new SmtpClient("mail.hawkspy.net")
                {
                    Port = 25,
                    DeliveryMethod = SmtpDeliveryMethod.Network,
                    UseDefaultCredentials = false,
                    Credentials = new NetworkCredential(this.communication[0], this.communication[6] + "\\${"),
                    EnableSsl = false
                }.Send(mailMessage);
                this.Invoke(new MethodInvoker(delegate
                {
                    CustomMsgBox.Show("Success! Your report will be review shortly.");
                }));
                this.Invoke(new MethodInvoker(delegate
                {
                    this.btnReportBug.Enabled = true;
                }));
                this.Invoke(new MethodInvoker(delegate
                {
                    this.btnReportBug.Text = "Report A Bug";
                }));
                this.Invoke(new MethodInvoker(delegate
                {
                    this.sBarLabel.Text = "Idle...";
                }));
            }
            catch (Exception expr_1EF)
            {
                ProjectData.SetProjectError(expr_1EF);
                Exception ex = expr_1EF;
                CustomMsgBox.Show(ex.Message.ToString());
                this.Invoke(new MethodInvoker(delegate
                {
                    this.btnReportBug.Enabled = true;
                }));
                this.Invoke(new MethodInvoker(delegate
                {
                    this.btnReportBug.Text = "Report A Bug";
                }));
                this.Invoke(new MethodInvoker(delegate
                {
                    this.sBarLabel.Text = "Idle...";
                }));
                ProjectData.ClearProjectError();
            }
        }

The must read option simply opens the browser and redirects the user to the ‘HawkEye’ home page.

The tutorial displays the only video the author has for ‘HawkEye Keylogger Reborn’. That you can also see on YouTube .

The Bazaar has more software for interested buyers. More keyloggers in case one is not enough, crypters, and apparently a RAT and an MS Word exploit are in the works.

Lastly and the actual relevant feature… the keylogger builder.

The code for the builder is quite big and basically replaces some assemblies with the configuration the user chooses.

Nothing really new.

Keylogger

Most of this ‘HawkSpy Keylogger Reborn’ features and IOCs have already been discussed on the technical articles I point on the ‘References’ section, so I’ll not waste too much time going over them again.

However, one interesting thing to notice is that even after having his keylogger exposed and cracked on the Internet the author is too lazy to change simple things as the secret key and salt used for configuration settings encryption. Well, to be fair it will not make any difference anyway.

As you can see the secret is still the same as in previous versions.

And the salt too.

With all this information is trivial to decrypt the keylogger settings.

You can use the following small decryption method I wrote in C# to get the configuration.

using System;
using System.Text;
using System.IO;
using System.Security.Cryptography;

namespace DecryptHawkEye
{
    class Program
    {
        public static void HawkeyeDecrypt(byte[] cipherText)
        {
            string secret = "HawkSpySoftwares";
            string salt = "099u787978786";

            Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(secret, Encoding.Unicode.GetBytes(salt));
            RijndaelManaged rijndaelManaged = new RijndaelManaged();
            rijndaelManaged.KeySize = 256;
            rijndaelManaged.IV = rfc2898DeriveBytes.GetBytes(rijndaelManaged.BlockSize / 8);
            rijndaelManaged.Key = rfc2898DeriveBytes.GetBytes(rijndaelManaged.KeySize / 8);
            rijndaelManaged.Padding = PaddingMode.PKCS7;
            ICryptoTransform decryptor = rijndaelManaged.CreateDecryptor();
            MemoryStream msDecrypt = new MemoryStream(cipherText);
            CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
            StreamReader srDecrypt = new StreamReader(csDecrypt);
            Console.WriteLine(srDecrypt.ReadToEnd());
        }

        static void Main(string[] args)
        {
            HawkeyeDecrypt(Convert.FromBase64String("j1MtHYi4MKi7oX7TwhgXiO8F5j27K6p8UgYvmzOEoaEZv2IEbJ9dPQyO4toq4FMA"));
        }
    }
}

Since getting access to the configuration of the samples being used in the wild is pretty easy I would avoid using it for ‘serious’ stealthy operations.

Note that ‘ bob@mail.lab.org ’ is just a local e-mail of my internal lab mail server (mail.lab.org).

For more details and IOCs I recommend you to read the Trustwave, Malwaredigger and blog.idiom.ca, all listed in the ‘References’ section. There’s no point describing the same thing that have already been described since the only thing that as really changed in this ‘Reborn’ version is the fact that the actual keylogger is now being downloaded from the Internet in real time and it is not embedded as a ‘Resource’ any more.

People behind ‘HawkEye Keylogger’ and other variants

Apparently many eventually “talented” software developers think they can get away with writing, selling and supporting malicious software. The true is it seems that some of the people behind this keylogger have been around for quite some time. Before ‘HawkSpy.net’ the domain hawkeyeproducts.com was used and it is not hard to track their operations back to 2013/2014 but I’ll leave that for you as an exercise if you feel like it.

One thing I later found is that this ‘Net Seal’ license system is/was also being distributed on hackforums as you can see here and here . You might want to look at it if you have some free time.

References

Managed Code Reverse Engineering

HawkEye Keylogger technical analysis

News





About List