Skip to main content

Malware Analysis of a Cryptocurrency Miner — Part 3

 Static code analysis

In this write-up, we’ll load the binary file into IDA (free version) to disassemble it and do a static code analysis. And where to being then…

Start

Ok, I’ve loaded the binary file into IDA:






So we can see it calls a subroutine (aka function) sub_401000:

; Input SHA256 : 807126CBAE47C03C99590D081B82D5761E0B9C57A92736FC8516CF41BC564A7D
; Input MD5 : ABA2D86ED17F587EB6D57E6C75F64F05
; Input CRC32 : 7944603F

Format : Portable executable for 80386 (PE)
; Imagebase : 400000
; Timestamp : 56B664A6 (Sat Feb 06 21:24:54 2016)
; Section 1. (virtual address 00001000)
; Virtual size : 000137D0 ( 79824.)
; Section size in file : 00013800 ( 79872.)
; Offset to raw data for section: 00000400
; Flags 60500060: Text Data Executable Readable
; Alignment : 16 bytes

.text:00401000 sub_401000 proc near
.text:00401000
.text:00401000 lpTopLevelExceptionFilter= dword ptr -3Ch
.text:00401000 var_38= dword ptr -38h
.text:00401000 var_34= dword ptr -34h
.text:00401000 var_30= dword ptr -30h
.text:00401000 var_2C= dword ptr -2Ch
.text:00401000 var_14= byte ptr -14h
.text:00401000 var_10= dword ptr -10h
.text:00401000
.text:00401000 push ebx
.text:00401001 sub esp, 38h
.text:00401004 mov eax, ds:off_417D40
.text:00401009 test eax, eax
.text:0040100B jz short loc_401029

We already know the information at the start, thanks to our static analysis.
We can see that this function is “near” the start function, indicating that it must be one of the first called/executed functions.

The “lpTopLevelExceptionFilter” is something to note as it is an anti-reversing technique employed by the Malware author. We will cover this in a moment.
After that we see variables being created but with no values.

Next, we see the “push ebx” which will push ebx onto the stack but I can’t see what ebx contains.
Further down we see “eax, ds:off_417D40” ( which stores the memory address at the data segment of off_417D40 into eax).
test eax, eax will then set the zero flag to 1, so that the jz short loc_401029 will be true, if the zero flag is set to 0 then it will jump to location 0040100D.

Now, the off_417D40 is the location of “tls_callback” which is used as an ant-debugging technique, (https://isc.sans.edu/diary/How+Malware+Defends+Itself+Using+TLS+Callback+Functions/6655)
(Note- I am hoping to demonstrate these techniques when I go through the debugging process of this binary)

If we skip past these, we arrive at the following function: sub_40C350-

.text:0040C350 sub_40C350 proc near
.text:0040C350 pushf
.text:0040C351 pushf
.text:0040C352 pop eax
.text:0040C353 mov edx, eax
.text:0040C355 xor eax, 200000h
.text:0040C35A push eax
.text:0040C35B popf
.text:0040C35C pushf
.text:0040C35D pop eax
.text:0040C35E popf
.text:0040C35F xor eax, edx
.text:0040C361 test eax, 200000h
.text:0040C366 jz locret_40C411

Now in the above, I’ve highlighted xor, a bitwirse operation which will do the following — eax = eax ^200000h (at the moment I can’t tell what 200000h signifies) and then it will clear eax.

Now, I’m not too sure what the binary is doing at the start here but if we look further down we see it is getting the cpuid and then testing it against 1 (and then 2,3,4 which you can’t see as I’ve not added it here :) )

It’s trying to compare the result of the cpuid dh (dh being the higher 8 bits of the ax register, which is the lower 16 bits of eax).
Also, after reading through https://c9x.me/x86/html/file_module_x86_id_45.html to get more information on the above, I have a feeling that the xor eax, 2000000h is trying to find out the cpuid.
After the binary has found the “cpuid” it’s looking for, it then returns.

One thing I noted, was before the “rep retn”, we see pop ebx, which means the value at the top of the stack is popped to ebx, the above pop won’t happen if the very first “if” is not true (test exa, 2000000h”).
So I’ll rename this function to “get_cpuid”.

The next set of instructions look to be setting the variables that have been declared above and then it calls “getmainargs” (https://docs.microsoft.com/en-us/cpp/c-runtime-library/getmainargs-wgetmainargs?view=msvc-160) I noticed the return value for “getmainargs” — “0 if successful; a negative value if unsuccessful.”
Assuming that the return value is stored in “dword_41EA7C”, then copied into “eax”.
It will do “test eax,eax” to see if the zflag is set or not.

If it is calling “getmainargs”, that indicates that the binary is being fed arguments. Also if the zflag is not set, then it does the following:

We see ebx being utilized here, also. So I feel that this process is to set the correct environment variables for the target machine.

End

This is only the end for the starting analysis of this binary, going through it instruction by instruction and then writing about it will take a long time.
So in the next write-up, I’m only going to write up about what we saw during our dynamic analysis.

Comments

Popular posts from this blog

Malware Analysis: Dissecting a Golang Botnet - Part 1

Introduction In this post, I walk through the process of analyzing a Golang-based botnet sample — specifically a variant of FritzFrog , a peer-to-peer (P2P) botnet known for brute-forcing SSH servers and spreading laterally across networks. The goal here is to share my steps, tools, and insights while preparing for a cybersecurity analyst role.  🐸 1. Downloading the Malware Sample I began by grabbing the malware sample from Da2dalus’ excellent GitHub repository of real-world malware: URL: FritzFrog Sample on GitHub To fetch the raw binary into my WSL environment, I used: wget -O botnet_malware_IM https://github.com/Da2dalus/The-MALWARE-Repo/raw/refs/heads/master/Botnets/FritzFrog/001eb377f0452060012124cb214f658754c7488ccb82e23ec56b2f45a636c859 📤 2. Transferring the Malware to the Flare VM (Windows) My analysis environment was running inside a Windows VM using FLARE VM . Since the malware was downloaded via WSL, I needed a way to securely transfer it to the Windows VM. First, ...

Building my own write blocker

  Spoiler — It’s cheaper than buying one I was looking to buy a write blocker to do data recovery/forensics tasks but I quickly noticed that I was window shopping write blockers due to their cost. Some starting at £300, others that cost less were no longer being built or sold, maybe you could find a 2nd hand one with or without the wires. Most of these write blockers were industry standard, used by law enforcement but was it necessary for me to buy such an expensive write blocker….or is it possible to build my own….. So th e  research began, reading through articles, publications, and so on, and with the information gained, I felt that I could build my own write blocker. So what do I need: A Raspberry Pi A Linux distro. HDD/SSD to test the write blocker And to put the information I gained into practice Building the write blocker So, I brought a Raspberry Pi 4 Model B that came with a power supply, HDMI cables, 32GB SD card, a case, and some extras. ( https://www.okdo.com/c/pi-...

Notes from a Linux command line course

 Recently I took a course on Linux command line and shell scripting, below are the notes I took which I decided to write into a blog to refer to for future reference (there's no way I could remember all of this in a single sitting) 1. Kernel vs Shell OS has 3 layers: Application layer - User apps, Daemons Shell - Command line interface. Kernel - Hardware management, memory management, I/O Handler, CPU, process management. Closest layer to the hardware The kernel controls and mediates access to hardware, for example, it schedules and allocates system resources like memory, CPU, disk etc. The shell works as an interface to access the services provided by the OS. We can further breakdown the layers into the following: User space - If you run a for loop etc, you are in user space. But when you want to perform an operation such as, write to the disk, for example, save a file, then it needs to talk to the kernel space. As the application can't directly talk to the hardware. Kernel sp...