Tuesday, February 17, 2026

LAB 5: Inter Process Communication – Shared Memory

Inter-Process Communication (IPCs)

            In every modern operating system, multiple programs run at the same time. Each of these programs have their own executing instances (think of them as an active unit of work which needs resources like CPU time, memory, files), which we call processes.

            By default, every process is independent (think of them as islands).  This simply means that they are isolated from one another and think that they are the sole process in the system. This is a direct result of the Memory Management Unit (MMU). The MMU is a computer hardware part that translates virtual memory addresses into physical addresses, as well as manages cache and enforces memory protection.  

            In order to keep up with the next parts of the lab, we will also need to explain what virtual memory, virtual memory address, and physical memory are.

            The “physical memory” is just the physical RAM of the computer, which is accessible for fast and precise data transfers or calculations within a system. 

            The virtual memory is simply a method that “extends” the RAM, meaning that it enables the system to compensate for physical memory shortages by temporarily transferring data from the RAM to the Disk storage.

            The virtual address is just a simple compartment of the whole virtual memory, as can be seen in the picture below.

As mentioned, all of this process is possible because of the MMU, which translates the virtual memory addresses into physical addresses with efficiency.

However, sometimes we also need these processes to communicate with each other. The processes that affect or are affected by one another are simply called Cooperating Processes.

Cooperating Processes are made possible by the Inter-Process Communication (IPC). IPC refers to the set of techniques that allows these processes to talk and share data with each other while theyre operating, so complex software can be run efficiently (a good example would be a shared database). We have a lot of IPC mechanisms, such as Named and Anonymous Pipes, mailslots, sockets, and even clipboards. However, in this lab, we will be focusing on a specific IPC named Shared Memory.  


Shared memory

            Among the various methods of IPCs, shared memory is one of the most efficient mechanisms, especially when it comes to performance-critical applications; think of it as the Ferrari of IPCs.

            Shared Memory, as a concept, is the memory region that can be accessed simultaneously by multiple processes. In an OS, each process has its own virtual address space. Shared memory then proceeds to create a shared region of memory that is accessible by multiple processes at the same time. This shared region is then mapped into the virtual address space of each of the processes, allowing them to read and write to the same physical memory location, as can be seen in the picture below.



            To fully grasp the concept of how shared memory initializes itself, we looked at the article below:

(https://www.geeksforgeeks.org/computer-organization-architecture/what-is-a-shared-memory/),  

Let's say we have two processes that want to communicate with each other, we'll call them P1 and P2. Let's also say that P1 has an address space which we’ll call A1, and P2 has an address space which we’ll call A2. In order for the shared memory to start, P1 will first take up some address space as a shared memory space, which we’ll also call S1. After P1 takes S1, it will then write into it the data that it wants to share. P2 will simply read from the shared data found in S1. Additionally, P1 can also give write rights to P2, as can be seen in the picture below:



An interesting fact about the shared memory is that only the creator process has the right to destroy the shared memory, which in our case means that only P1 can end the whole process.

While the concept of shared memory is easy, the process of how it actually works is a bit more challenging. For this part, we continued with another Geeks for Geeks article (https://www.geeksforgeeks.org/operating-systems/ipc-shared-memory/). From here, we understood the basic outline of how the shared memory operates:

Creation of Shared Memory Segment: The parent creates a shared memory segment. This can be done using system calls like shmget(), usually mostly done in Unix-like systems. This segment is then assigned the unique identifier (shmid).

Attaching to the Shared Memory Segment: The processes that need to access the shared memory attach themselves to this segment using shmat() system call. Once attached, the processes can directly read from and write to the shared memory, according to the privileges.

Synchronization: Since multiple processes can access the shared memory at the same time, synchronization between them is a must. This is done through synchronization mechanisms like semaphores. To put it simply, Semaphores are another IPC that are often used ensure data consistency.

Detaching and Deleting the Segment: When a process no longer needs access to the shared memory, it can detach from it using the shmdt() system call. Additionally, the parent process can also remove the shared memory by using the shmctl() system call.


Advantages

            The main benefit of Shared Memory is speed. Since this IPC processes directly read and write to the shared memory location.

            Additionally, it is highly efficient, since it eliminates the overhead associated with the message passing where data has to be copied from one process to another. This then also means that it can be particularly useful for transferring large amounts of data between the processes.


Disadvantages

            The main downside of shared memory is the complex synchronization. It requires explicit synchronizations to prevent race conditions (which make the code complex and error-prone). Additionally, it can sometimes be a tedious process since it requires manual cleanup by manually detaching and removing the segments.

            The manual cleanup can also lead to security risks, where unauthorized processes may access or modify data.


Security Exploitation cases

            Throughout history, there have been many cases where the Shared Memory IPC has been exploited by malware. Malware uses this IPC as a technique to split its functionality across multiple processes without writing data to the disk (which helps it evade antivirus file scans), or even generate network traffic (which helps it evade firewalls). This technique is called Shared Memory Injection.

The two main instances we have of shared memory injections are the SquidLoader and the RotaJakiro malware.

            SquidLoader is a very recent and relevant example that gained influence in late 2024. This specific malware used shared memory to create a complex graph of shared memory segments, in which it broke its encrypted payload into parts. This then would mean that analysis was made really hard since the full malicious code didn’t exist in one place until the exact moment of execution.

            RotaJakiro, on the other hand,d is classified as a Linux backdoor. Through the shmget() system call, it checked if other instances of the malware were already running as well as shared the PIDs between its various forked processes. This then allowed the malware's different parts to coordinate without sending any signals that could possibly be detected by the Endpoint Detection and Response tools.


Conclusion

            In conclusion, Shared Memory serves as a vital, high-performance Inter-Process Communication (IPC) mechanism that bridges the gap between isolated processes managed by the Memory Management Unit (MMU). By mapping a single physical memory region into the virtual address spaces of multiple distinct processes, it eliminates the overhead of data copying to achieve superior speed, effectively acting as the "Ferrari" of IPCs.  However, this efficiency necessitates rigorous implementation, requiring developers to manage manual memory lifecycles and enforce synchronization via semaphores to prevent race conditions. Ultimately, while shared memory is indispensable for performance-critical applications, it introduces a significant attack surface; as evidenced by malware like SquidLoader and RotaJakiro, the very features that facilitate direct access can be weaponized for stealthy injections and evasion, highlighting the critical trade-off between operational speed and system security.




Monday, February 9, 2026

LAB 4: Dynamic Malware Analysis (cookieloader.exe)

   Dynamic Malware Analysis is a technique that involves executing suspicious files within a secure sandbox environment, so that we can see their behaviour in real-time without risking our systems. By doing so, we can identify malicious actions and analyze how sophisticated, packed, or obfuscated the malware actually is. In our case, we are going to analyse a malware called cookieloader.exe. 

For this analysis were going to be using these tools: 

  • PE Bear
  • Pe Studio
  • DiE (Detect it Easy)
  • Capa
  • Floss
  • Procmon
  • CyberChef
  • RemNux
  • Wireshark


The whole lab will go through these main steps: 

PE File Triage

Capability Identification

String Analysis

Dynamic Analysis

Conclusions



1. PE File Triage

Before starting with the dynamic analysis, it is important to conduct static analysis so that we can find as much info before starting the malware. By doing so, we can find valuable code/data/behavior that may give us hints so we can proceed easier in the longrun. 

For this part, we will be using PE-bear, PEStudio, DiE, CAPA and FLOSS as our main tools. For further analysis of each specific finding and its meaning, please check the previous Static Analysis Lab, where each of them is explained in detail (https://art-krasniqi.blogspot.com/2026/02/lab-2-static-malware-analysis.html)

SHA 256 Hash

Machine Architecture => AMD64 (K8, 64 bit)

DLL Characteristics 

Subsystem => Windows Console (CLI)



Time when created

TLS => No TLS found

Sections and permissions (and their raw vs virtual size)


.text -rx (5120 bytes raw - 4732 bytes virtual)

.rdata -r (8704 bytes raw - 8214 bytes virtual)

.data -rw (512 bytes raw - 1664 bytes virtual)

.pdata -r (512 bytes raw - 420 bytes virtual) 

.rsrc -r (512 bytes raw - 480 bytes virtual)

.reloc -r (512 bytes raw - 60 bytes virtual)



Overlay => No overlay present, found by comparing raw and virtual size in PEBear, as can be
seen above

Flagged APIs found using PEstudio


Previously, we had a lab where we had to create a persistence script, where we used
RegCreateKeyExW and RegSetValueExW as our main APIs. This is a dead giveaway
that the malware might be a CNO (Computer Network Operations)

DLLs found using PEStudio


The DLL's seem normal

Entropy and packed percentage using DiE


As can be seen from the picture from DiE, since the level of entropy is 6 or below 6 at all
times, we can conclude that the malware does not have high entropy. Additionally, we can
also confirm with almost 60% guarantee that it is not packed.


2. Capability Identification


From what we have seen so far from both CAPA and the imported APIs from PEstudio, we most likely are dealing with a Persistence malware which is run via registry keys. We have 2 matches in CAPA that support our theory.

3. String Analysis



Using FLOSS, we were also able to extract these findings: 


From this image, we can see that the user called Sentry was defined as the user who created the malware. We already knew this before getting the strings, since the malware sample was given 
to us to analyze by our professor, who works with the team at Sentry. This was nice to confirm via FLOSS.


Here we can also see most of the APIs and DLLs which we previously identified using other tools.



An important find we got from using FLOSS was also the UTF-16LE. From this article (https://mike-diaz006.medium.com/what-i-learned-at-work-this-week-utf-16-le-with-bom-17f56e727abe) we found out that UTF means Unicode Transformat Format. IT uses 16 bits in order to encode, and LE (which stands for little-endian) tells the computer that the least-significant byte of the word is at the smallest address, which then tells the computer how to read and decode the text. This will become useful later during the dynamic analysis, especially when using CyberShef, since it is an encoding standard. 

Additionally, from the strings, we also figured out that the malware has little to no obfuscation going on since we can read most of the important information through strings.

As we said before, from these findings, our initial thought is that we are dealing with a persistent malware that saves itself in reg keys, which then activate straight away when turning on Windows. This indicates that the malware is a CNO. We can only confirm this with low to medium confidence so far, which means that we also have to conduct a dynamic analysis. 

4. Dynamic Analysis

To begin the dynamic analysis, we first installed the malcode analyst pack from this link

(https://sandsprite.com/tools.php?id=12). After downloading the files, we then transported

the files and installed them on the VM via .iso image files. Once the setup was completed,

we first opened Internet Explorer to see if the INetSim is still working so that the malware

can get false-positives that the device i connected to a local network, to see what it's

trying to do. Additionally, we also opened 2 other tools called Process Monitor and

Wireshark, which we got from the malcode analyst pack.


Process Monitor will be the main tool we use in this lab to see what the malware does.
ProcMon is an advanced real-time monitoring tool that captures file systems, registries, and
process/thread activity. Think of ProcMon as an upgraded Task Manager from Windows.
In our case, since we already suspect that our malware is of the persistence type and its
starting processes, we need to find an operation that contains Process Start as a value.
To do so, we simply run the virus and select the filters we just mentioned in Procmon,
as can be seen in the picture below.


After doing so, we get a bunch of results, from which we can see our main The

Cookieloader.exe file that we just ran. The next step is to find if the main process (a.k.a. the

parent process) has any “child processes” (child processes are just a way of calling the processes

that are activated by the parent process, which either serve as a decoy or do the actual damage).

To do so, we need to filter by the ID of the parent process, which in our case is 8496. 



Right after adding the second filter shown above, we can clearly see that we have two

sub-processes happening, one called conhost.exe and the other called powershell.exe. To

 understand what they do, we need to go into their properties.



First, we went into the properties of the Conhost.exe. From what we saw while googling,

especially from the command line, we figured out that this child process simply acts as a

decoy and is nothing to fear.


However, when we moved onto the powershell.exe child process, we saw something highly

suspicious. The command line, matched the defuscated string that we saw while using floss,

and since we saw -EncodedCommand we wanted to look further into it. 


In order to advance with our analysis, we decided to use CyberShef as a tool. CyberShef is a

web app for encryption, encoding, compression, and data analysis. Since we did not want to

allow drag and drop, or clipboard compatibility from our VM to our main device, we decided

to install CyberShef into our VM, using the same .ISO method we always do. After doing so,

we copied the command line from powershell.exe and input it into CyberShef. At first, we

had no clue what type of recipe to use. Everything changed when we saw the two “==” signs

at the end of the command line. After looking at this Stack Overflow post (https://stackoverfl

ow.com/questions/6916805/why-does-a-base64-encoded-string-have-an-sign-at-the-end)we decided to add From Base64 to our recipe.



While we saw some improvements from the initial command line, we still couldn't understand a

thing. This was the moment when we remembered the results we got from floss, where we

understood that it also uses UTF-16LE as an encoding method. After we added this encoding

standard to the recipe of cybershef, we finally got some readable code as the output.


This is the whole code we extracted

  

The code was interesting to look at, but the main part we focused on was the first line, from

which we can tell that the malware is listening on port 666. Another interesting part we found

was that when loading the virus, the Cookie loader terminal stays open and says this.



After a simple Google search, we found this link (https://www.geeksforgeeks.org/computer

-networks/difference-between-bind-shell-and-reverse-shell/) and concluded that since the

malware launches a Bind Shell, it means the attacker always connects to the victim. In

simple terms, it means that the attacker runs a command on the target that “binds” a

command shell to a specific TCP/UDP port (as was 666 in our case). Then the victim

machine acts as a listener, waiting for anyone to connect to that port. The attacker then

connects directly to the victim’s IP address on that port, giving him a full CLI prompt and

allowing him to run commands with the privileges of the compromised service/user. 

Additionally, since a Bind Shell is considered a Command and Control (C2) mechanism

,a key defining element of all CNOs, this serves as another high-confidence indicator

that the malware is a CNO.

However, just knowing what the malware does is not enough; we also need to know what to

do to read the “infected” TCP port. Just like before, we found another

Geeksforgeeks link (https://www.geeksforgeeks.org/computer-networks/introduction-to-

netcat/), which equipped us with NetCat (a utility tool that uses TCP and UDP connections

to read and write in a network). This website suggested that we should run it in a Linux

environment through these commands:

So we did as mentioned in RemNux:

By doing so we move on to the last step of the dynamic analysis, using Wireshark.

Wireshark is a network protocol analyzer used to capture and analyze network traffic in real

time. In our case, we specifically used Wireshark to track the network traffic in port 666, which

we did through this command. 


Combining it with the NetCat tool we used earlier, we got 7 new packets when using the tcp

port filter. As we can see, the TCP three-way handshake and a complete TCP lifecycle have

been completed. We can see this by looking at the [SYN], [SYN,ACK], [ACK],[FIN,ACK],

[ACK] packets in the picture below.



Additionally, the result of the terminal also changed, which was interesting.




Conclusion



The main evidence that supports the CNO claim is the APIs used, the persistence

via registry keys double-match by CAPA, the ProcMon startup analysis, as well as

The presence of a C2 (Bind Shell).

Additionally, in the great words of our professor, "You can tell just as much about malware

from what it doesn't do as you can from what it does". This means that since we can not

find any proof of profiteering (CNP), or any proof of immediate damage and escape (CNA)

, we have a better likelihood of it being a CNO.

To conclude, based on the results we got from both the static and dynamic analysis, we can

Classify the Cookieloader malware as a CNO (Computer Network Operation) with High

confidence.




LAB 10: APK Security Scanner - Multi-Agent Static Analysis pt.2

Taking Android Apps Apart: Building an AI-Powered Security Scanner Part 2: The Analysis, Execution and Findings In Part 1 we defined our obj...