Part 2

To check the first part please go to https://ret.re/malware/reverse/engineering/2019/07/02/malware-analysis-rig-ek.html .

Progress

I though that the crash could be some problem on debugger. So I cleared the breakpoints and just added after the mov’s into the allocated space and let it run. It’s a slow process because of our execute break point on ALL memory segment.

After a while BAM! breakpoint hit:

progress.png

So, it’s time to renable all breakpoints and continue to run!

We are now in an interesting function. It’s a function that uses a suspect calls and seems to decode the previous tor onion domains.

decodingstuff.png

Let’s insert breakpoints on those functions.

  • GetLongPathNameW
  • WritePrivateProfileStructA
  • ExpandEnvironmentStringsW

Let’s now focus on LocalAlloc and monitor the allocated space.

My case is 0x022B6020 and has the same size has previous LocalAlloc. Maybe some data exchange will happen here. Create a breakepoint on execute and a access breakpoint on the first allocated memory (0x0211A000)

Now we are going to move the first allocated memory into cl register (byte by byte) as shown:

memcpy.png

We let it copy and then another crash!

So it seems our breakpoints on the allocated memory is somehow delay the instructions so we can disable it and execute until return! Interesting is that the functions WritePrivateProfileStructA, ExpandEnvironmentStringsW and GetLongPathNameW wasn’t called.

The first and second memory segments looks like this:

firstalloc.png

secondalloc.png

At this time we want to move further. So hit the run again and we can see kernel32.dll is being loaded dynamically. We don’t have to bother about this now because we inserted breakpoints on important Windows APIs (like VirtualProtect). After this being loaded VirtualProtect is called.

The function changes permissions on memory of calling process. On stack we can see the following data being pushed as arguments:

firstvirtualprotect.png

BOOL VirtualProtect(
  LPVOID lpAddress, //base address
  SIZE_T dwSize, //size of allocated memory to be changed
  DWORD  flNewProtect, //protection defined (read/write/execute/...)
  PDWORD lpflOldProtect //this points the the thread stack 
);

The base address belongs to the second alloc. As we can see on memory dump, it has just, what lookslike for us, junk. But the newprotect dword is 0x40 which is defined as PAGE_EXECUTE_READWRITE. So, the malware is changing the permissions to be able to execute on this memory segment.

This said we can change the breakpoint on 0x020D9000 to be just READ and 0x02173000 to be execute.

Before VirtualAlloc execute the segments looks like this:

beforevirtualprotect.png

We execute until return and we can see the protections changed on 0x02173000

aftervirtualprotect.png

Right after virtualprotect we can see a lot of mov instructions:

movsbeforejumpbegin.png

movsbeforejumpend.png

Viewing this on C-style it’s something like this:

  //... the other locals above.
  local_148 = 0x34eba593;
  local_58 = 0x738a618c;
  FUN_00401912();
  DAT_004c6c74 = (code *)FUN_00401a13();
  (*DAT_004c6c74)(); //jump to this location, probably the first stage?
  return;

We add a breakpoint right the call FUN_00401912().

void FUN_00401912(void)

{
  int iVar1;
  uint uVar2;
  uint uVar3;
  _OSVERSIONINFOEXA local_a0;
  
  iVar1 = DAT_004c6c74;
  uVar2 = uBytes_004caffc / 8;
  uVar3 = 0;
  if (uVar2 != 0) {
    do {
      if (uBytes_004caffc == 0x115d) {
        VerifyVersionInfoA((LPOSVERSIONINFOEXA)&local_a0,0,0.00000000);
      }
      FUN_0040166e((uint *)(uVar3 * 8 + iVar1));
      uVar3 = uVar3 + 1;
    } while (uVar3 < uVar2);
  }
  return;
}

If you move forward you see that probably you won’t hit the VerifyVersionInfoA. You keep hit run until a new, the third, allocation is invoked. This case VirtualAlloc. On this run the memory is 0x02200000. We monitor this segment and insert a access breakpoint. When you start stepinto you can see the MZ starting to be written:

injectionPEonmem.png

Note the registers (at interation 3):

srcdstpeinject.png

mov dl,byte ptr ds:[ecx] ; ecx points to source
mov byte ptr ds:[eax],dl ; eax points to destination
inc eax ; (src)++
inc ecx ; (dst)++
dec edi ; VS compiler being stupid?

The memory dump on [ecx]:

srcdumpPE.png

We can see it’s a PE file. The DOS header, the segment table, etc.

What is more interesting is that this instructions are being executed in 0x02173000. This is our shell code, in 2nd alloc being executed, copying a PE file in memory (from the same segment) to another third allocation.

We can now extract this. Since it begin in 0x21773D3 and ends in 0x21DAFF9 so it has 408 614 bytes.

endofpefile.png

It’s probable not be alligned so we can use HxD to adjust the MZ magic number to offset 0. It’s ok to have a larger PE than normal. What is most important is the first part.

hxdview.png

If we scroll down we can see the absence of a large null bytes sequence on the PE. This means the PE is unmamped, so is in disk format ready to be loaded.

When I try to open on PE Bear this message appears:

pebearcannotload.png

If you let the copy continue you notice that the null bytes are being copied OK. Maybe it’s full of junk and the copy task cleans it up (to avoid being reversed eng).

probpealligned.png