PowerLoaderV2 Full Code Analysis | Execute the temp malware file[Part 4].

Mahmoud NourEldin
9 min readJan 16, 2023

--

We stopped in this subroutine let’s analyze it:

But We Will analyze it using Ghidra only let’s go:

In the figure below: MemSpace will be zeros by using memset API [ we discussed it in Part 3 ]. Then the malware checked for the file name it contains “.exe” by using StrStrIA API.

PCSTR StrStrIA(
[in] PCSTR pszFirst,
[in] PCSTR pszSrch
);
//which will be
PCSTR StrStrIA( "C:\\PowerLoaderV2.bin",".exe");
// So In my case it will be NULL.

So here in x64 before calling the API:

As you can see in the stack the 2 arguments of the StrStrIA API.

Let’s call the API by step over [F8]:

Yes, it’s 0 because .exe doesn’t include let’s see what happens:

NOTE: This is a big condition, The 2nd condition we will analyze after all of that so be open eyes.

This code will execute and if the filename doesn’t include .exe:

it will call GET_CSIDL_COMMON_APPDATA(), and that’s what I called let’s see what includes:

It calls SHGetFolderPathA API with 2nd argument 0x23 and based on MDSN it gets The path of the folder identified by CSIDL value.

SHFOLDERAPI SHGetFolderPathA(
[in] HWND hwnd,
[in] int csidl,
[in] HANDLE hToken,
[in] DWORD dwFlags,
[out] LPSTR pszPath
);

And click here to find these values but in our case, it contain a number, let’s search on Google CSIDL numeric values:

Source: tarma.com

So 0x23 value is CSIDL_COMMON_APPDATA which contains application data for all users and the path will be:

Here the Malware passes a variable to EAX before calling the subroutine which contains SHGetFolderPathA API and let’s step over to see the value in memory:

As you can see it’s C:\ProgramData, so Ghidra here doesn’t include this return value to a variable.

Here IDA explained enough, That’s Why I prefer Disassembling not Decompiling.

Let’s continue:

The malware now has the C:\ProgramData path, let’s see what can do

It calls GetTempFileNameA API which Creates a name for a temporary file. If a unique file name is generated, an empty file is created and the handle to it is released; otherwise, only a file name is generated[ MDSN]:

UINT GetTempFileNameA(
[in] LPCSTR lpPathName,
[in] LPCSTR lpPrefixString,
[in] UINT uUnique,
[out] LPSTR lpTempFileName
);
//which in our case will be
UINT GetTempFileNameA("C:\\ProgramData",0,GetTickCount(),OutPutFileName);

So The Malware generates a temp name for a file with GetTickCount API so the OutPutFileName will be C:\\ProgramData\\45632.tmp [ 45632 random ].

So Follow in memory the 4th argument to see the final result and the 3rd argument is 021F5766 [35608422]which is got from GetTickGount API.

So the GetTempFileNameA API generates a random number from 0 to 35608422 [ I think it ]. The final file in my case is:

“C:\\ProgramData\\5766.tmp”

So it’s our second IOC and we now understood everything for that random file, let’s continue:

Now, it calls PathRemoveExtensionA API from this temp file and then calls PathAddExtentionA which the result transforming from

“C:\\ProgramData\\5766.tmp” -> “C:\\ProgramData\\5766.” -> “C:\\ProgramData\\5766.exe”

Yes, It’s intelligent Malware let’s see those results from x64 Debugger:

Here pass the temp file and after stepping over The return value is 0 because if you went to MDSN, it will give you:

Note This function is deprecated. We recommend the use of the PathCchRemoveExtension in its place.

So, Let’s continue

If you noticed it removed .tmp from the temp file and in memory it removes “.” and placed it with 00 which is the end of the string [filename].

So, Yes it’s working because PathRemoveExtensionA API returns none hhhh. Don’t be confused about my mistake and I didn’t delete my mistake to learn you read the return value from the MDSN.

So it just searches for the last “.” and replaces it with “00”.

Let’s run the 2nd API PathAddExtentionA:

As you can see in the dump it adds .exe which that means the API searches for the first “00” and add 2E which is “.” and then exe, If you need details just step into the API and see what can do.

Let’s Continue:

Here it calls CrtFile_write2it which I called, let’s see it

It calls CreateFileA API with names that exist in EAX and we discussed in Part 3 How this API works so I’ll write C++ now without details:

The value in EAX is the Full Path of the Malware and dwDesiredAccess =1 This confused me then OPEN_EXISTING if the file or device, only if it exists.

If the specified file or device does not exist, the function fails and the last-error code is set to ERROR_FILE_NOT_FOUND (2).[MDSN]

HANDLE CreateFileA("$MalwarePath",1,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,0,OPEN_EXISTING);

So It opens the file if exists, if not returns an error.

In our case, it gave us the handle for the file $MalwarePath, and the other condition will return 0.

Let’s see Fun_00402970() [ Which we will get into if the malware path exists].

Let’s analyze faster now:

The Malware GetFileSize then calls FUN_00402390 which I renamed to HeapAllocation because it Calls GetProcessHeap, HeapAlloc which allocates a space in the current process for a reason, let’s see why.

This is our function, here The Malware Getting the size of the malware running, then allocating space in the process heap, then checking if success, then SetFilePointer to a file which is $MalwarePath, then ReadFile and stores the $MalwarePath file data into lpBuffer.

So here the buffer contains the Malware EXE [ it copies it self ].

Let’s see what’s next and renamed this function ReadFrom File:

So we backed again:

This function Creates the $MalwarePath [ Which you run it ] if not exist, if exist read the data from it.

Let’s Back again:

Let’s rename CrtFile_write2it to CrtMalwareFile_readFromIt because we analyze it and that’s its original behavior name.

Let’s analyze the last function in that condition Fun_00402870:

Let’s see What this file:

Aaaah, It’s the temp file [ C:\\ProgramData\\5766.exe ] if you remember, but different name because it’s another process and every process it will change [ That’s why it gives GetTickCount randomly ].

So it creates it with this:

HANDLE CreateFileA("C:\\ProgramData\\5766.exe",001F01FF,FILE_SHARE_READ,CREATE_ALWAYS);

And after executing this:

So let’s continue:

Then called write2file which we analyzed it in Part 3 takes a buffer and writes it to the specific file in our case the buffer is the malware data[malare executable data] and the file is AA.exe.

As you can see the file hashes are the same[ So The function copies the buffer from the malware to a ProgramData folder with EXE Extention.

let’s continue:

I called it CrtFile_Write2it based on its behavior.

So finally we analyzed it, Then FileName will be C:\\ProgramData\\AA.exe

NOTE: Now we will execute the 2nd big condition which it has EXE in the path or not in the first article, all we analyzed is just copying the executable code from the malware to a temporary file :).

So Let’s See What happens if the file contains EXE [and also continued if it creates the same temporary executable malware file ]and in the figure above local_3c will contain a handle for GetForegroundWindow API which Retrieves a handle to the foreground window (the window with which the user is currently working).[MDSN]

iVar3 will contain the return value of ShellExecuteExA API and pass MemSpace as an argument that has zeros values [ we analyzed above ].

MemSpace is a SHELLEXECUTEINFOA structure that contains this information:

typedef struct _SHELLEXECUTEINFOA {
DWORD cbSize;
ULONG fMask;
HWND hwnd;
LPCSTR lpVerb;
LPCSTR lpFile;
LPCSTR lpParameters;
LPCSTR lpDirectory;
int nShow;
HINSTANCE hInstApp;
void *lpIDList;
LPCSTR lpClass;
HKEY hkeyClass;
DWORD dwHotKey;
union {
HANDLE hIcon;
HANDLE hMonitor;
} DUMMYUNIONNAME;
HANDLE hProcess;
} SHELLEXECUTEINFOA, *LPSHELLEXECUTEINFOA;

The IDA here is better than Ghidra, that’s why I love IDA.

runas means to run the malware as an administrator but it will ask permission.

So the malware will be executed under the debugger if not it will give error to the log file:

“aRestartModuleShellExec(): ShellExecuteEx error: %x\n”

So we analyzed this Log2File function which will write this error to the %temp%/logs123.txt.

Then sleep for 3 seconds, then execute, then log2file, then sleep for 3 seconds, then execute.[ infinite loop ].

So now we understood this string will exist in the log file if the malware can’t execute itself in the machine by ShellExecuteExA API.

So all of this article is about it, let’s renamed it to CrtTmpFileMalware_ShellExe

Or any name you want just for remembering.

So Malware For this function what can do?

If the malware is not executable, create a temp malware file in the ProgramData folder then execute the malware in an infinite fault loop by writing a fault message to the log file.

To Be Continued … يتبع

--

--

Mahmoud NourEldin
Mahmoud NourEldin

Written by Mahmoud NourEldin

Threat Researcher and Malware Analyst.

No responses yet