“As a matter of fact, yeah, they were foolproof. The problem is that you don’t have to protect yourself against fools. You have to protect yourself against people like me”Jeffery Deaver

Table Of Contents

0x1. Memory Forensics
    1.1 base of memory forensics
    1.2 Acquisition Process
    1.3 Volatile Memory
    1.4 Address Space
    1.5 Virtual Memory
    1.6 Paging
0x2. Rekall Memory Forensics
    2.1 Rekall structure
    2.2 Profile Mechanism
    2.3 Auto Profile Selection
0x3 Memory Dump with Rekall
    3.1 DLL
    3.2 PID Scanner malicious DLL 
0x4. Manual Mem File Analysis With Rekall
    4.1 Process Injection Detector Script

Greetings to the best hackers in the world. Today I am going to illustrate a framework called Rekall memory analysis

Memory Forensics

Today, I will explain you what memory Forensics is… Now this area is referred to as memory analysis. In this area, it is important to do your analysis of volatile data in a computer’s memory dump. Security Professionals are able to conduct such memory dump to investigate malware or other being injected process. We will be able to investigate and doing our forensics to catch malicious behaviours that do not leave easily detectable tracks on hard drive.

Acquisition Process

When we hear this term, we should consider this as the process of copying the contents of volatile memory(RAM). In order to have a good understanding of the process its important to learn some memory management principles and disiciplines. In this blogpost, we will be going to extract and dump our memory to get more familiar with the process. We will also learn a bit about live memory analysis on Windows OS. Memory live analysis has its advantages to dig deeper into memory dump. Now before diving into Rekall Project let me explain a bit more about acquisition Process.

Volatile Memory

We know that this definition has to do with Random Access Memory(RAM), which stores the code and data that the process actively access and stores. However, we ought to know that processes have not direct access to physical memory. This is because process can easily harm the operating system. RAM is defined as volatile memory because when you powered your computer on, it requires power for the data to remain accessible and when you powered your computer off, being stored will be permanently deleted. Ram can be attacked by Cold boot attack for more information you can get more from this source: Cold-Boot-Attack

Address Space

As I explained earlier that RAM is an array of memory cells without this powerful hardware component, we should not be able to work with computers. Ram has memory cells, each with its own physical memory used to access that cell. For the CPU to execute instructions and have access data stored in main memory, it must specify a unique address for that data. We also already know that process has not direct access to physical memory because it can be harmful the operating system and even cause the crash completely which can be irritating. Each process its own isolated address space, which is the predicatable because it solves the problem of security and isolation of processes from each other to OS. To have better understanding of address space, let me overview a bit about virtual memory. You can get more information from this source: Address-Space

Virtual Memory

I am not going to illustrate the usage of Virtual memory, but let me explain a bit about its skeleton. Virtual memory is a storage scheme that provides user an illusion of having a very big main memory. Which means that, the abstraction is designed to seperate the logical memory that processes work with from physical memory. I would like to say thet Virtual memory has a good usage by the OS because each process has its own virtual address space however, we ought not to forget that the size of that space is depending on the hardware architecture. You can get more information from this source: Virtual-Memory


This one will be the last one of acquisition. As a short explanation shall be that the entire process address space is divided into blocks of fixed size. Paging provides the ability to virtualize the linear address space. It creates an execution environment in which a large linear address space is simulated. We should not forget that the Memory Manager is responsible for unloading and also freeing physical memory. The Memory Manager is important because it also translates virtual addresses into physical address with the help of hardware. You can get more information from this source: Memory-Paging

–> I am ready to get started with Rekall Framework We will firstly look at the source code and understanding what it does while perfoming memory analysis. Lets kick off.

Rekall Memory Forensics

Now that we have understanding about Live memory forensics lets now talk about advanced memory forensics tool called Rekall.Rekall is a forensics Framework is a collection of memory to analyze memory dump. Rekall is written in Python and Its a fork of Volatility.

Discover Rekall

As we are dealing with memory forensics it also important to meet rekall structure and plugins. We need to understand the functionality. Rekall is written in Python thus that means that we are able to read easily the source code. For now you can use Rekall-Github but I should not recommend it. Morevover, you will be facing issues due to the python version. For this purpose, I will be going to use docker its more flexible and more handy.

As I mentioned earlier, when you git your repo to you /opt which is recommended. We are now analyzing the structre of this Framework.

Go to /memory-forensics/rekall/rekall-core/rekall and use ls -a command to see what kind of pluging are written in this framework.

I am not going to analyze all files however, we will analyze rekall.py, and lets understand this advanced memory forensics Framework.

darkghost@malware:~/memory-forensics/rekall/rekall-core/rekall$ ls -al

total 428
drwxr-xr-x  4 root root  4096 Sep 22 02:38 .
drwxr-xr-x  4 root root  4096 Sep 22 02:38 ..
-rwxr-xr-x  1 root root 25287 Sep 22 02:38 addrspace.py
-rw-r--r--  1 root root  5118 Sep 22 02:38 addrspace_test.py
-rw-r--r--  1 root root  2477 Sep 22 02:38 algo.py
-rwxr-xr-x  1 root root 18477 Sep 22 02:38 args.py
-rw-r--r--  1 root root 11875 Sep 22 02:38 cache.py
-rw-r--r--  1 root root  1157 Sep 22 02:38 compatibility.py
-rwxr-xr-x  1 root root  9246 Sep 22 02:38 config.py
-rw-r--r--  1 root root  4381 Sep 22 02:38 constants.py
-rw-r--r--  1 root root   136 Sep 22 02:38 __init__.py
-rw-r--r--  1 root root  1420 Sep 22 02:38 interactive.py
-rw-r--r--  1 root root 21946 Sep 22 02:38 io_manager.py
-rw-r--r--  1 root root  2575 Sep 22 02:38 io_manager_test.py
-rwxr-xr-x  1 root root  9768 Sep 22 02:38 ipython_support.py
-rw-r--r--  1 root root  1698 Sep 22 02:38 kb.py
-rw-r--r--  1 root root 89894 Sep 22 02:38 obj.py
-rw-r--r--  1 root root  7247 Sep 22 02:38 obj_test.py
-rw-r--r--  1 root root 35722 Sep 22 02:38 plugin.py
drwxr-xr-x 13 root root  4096 Sep 22 02:38 plugins
-rw-r--r--  1 root root  3393 Sep 22 02:38 quotas.py
-rwxr-xr-x  1 root root  3579 Sep 22 02:38 rekal.py
-rw-r--r--  1 root root  2878 Sep 22 02:38 resources.py
-rw-r--r--  1 root root 23653 Sep 22 02:38 scan.py
-rw-r--r--  1 root root 47273 Sep 22 02:38 session.py
-rw-r--r--  1 root root  1767 Sep 22 02:38 session_test.py
-rw-r--r--  1 root root 14844 Sep 22 02:38 testlib.py
-rw-r--r--  1 root root   196 Sep 22 02:38 tests.py
-rw-r--r--  1 root root  2990 Sep 22 02:38 threadpool.py
-rw-r--r--  1 root root 12369 Sep 22 02:38 type_generator.py
drwxr-xr-x  2 root root  4096 Sep 22 02:38 ui
-rw-r--r--  1 root root  3377 Sep 22 02:38 _version.py

At this point, we will use rekali.py to have better understanding of this code.

import logging
import pdb
import sys

import rekall
from rekall import args
from rekall import config
from rekall import constants
from rekall import plugin
from rekall import session
from rekall import quotas

from pkg_resources import iter_entry_points
for entry_point in iter_entry_points(group='rekall.plugins', name=None):

# Load all the plugins.
from rekall import plugins  # pylint: disable=unused-import

    "--version", default=False, type="Boolean",
    help="Prints the Rekall version and exits.")

    name = "run"

    def args(cls, parser):
        super(Run, cls).args(parser)
        parser.add_argument("script", default="print 'hello!'",
                            help="The script to evaluate")

        parser.add_argument("--run", default=None,
                            help="A file name to run.")

    def __init__(self, script, run=None, **kwargs):
        super(Run, self).__init__(**kwargs)
        if run is not None:
            script = open(run).read()

        exec(script, self.session.locals)

def main(argv=None):
    # New user interactive session (with extra bells and whistles).
    user_session = session.InteractiveSession()

if __name__ == '__main__':

Well, we are interested in this part and lets view the source understandably.

def main(argv=None):
    # New user interactive session (with extra bells and whistles).
    user_session = session.InteractiveSession()

    # Alow all special plugins to run.
    user_session.privileged = True

    def global_arg_cb(global_flags, _):
        if global_flags.version:
            print("This is Rekall Version %s (%s)" % (
                constants.VERSION, constants.CODENAME))


    with user_session.GetRenderer().start():
        plugin_cls, flags = args.parse_args(
            argv=argv, global_arg_cb=global_arg_cb,

We are seeing that the user_session is interacting with session.py. I am going to analyze a bit about ````session.py```

from rekall.ui import renderer
from rekall_lib import registry
from rekall_lib import utils

    "--repository_path", default=[], type="ArrayStringParser",
    help="Path to search for profiles. This can take "
    "any form supported by the IO Manager (e.g. zip files, "
    "directories, URLs etc)")

config.DeclareOption("-f", "--filename",
                     help="The raw image to load.")

    "--performance", default="normal", type="Choices",
    choices=["normal", "fast", "thorough"],
    help="Tune Rekall's choice of algorithms, depending on performance "

LIVE_MODES = ["API", "Memory"]

We are checking session.py, and immediately DeclareOption is being popped up. The session is quite simple it supports .zip, url, directory which is awesome. My memory dump is ready to be thrown in this framework. Rekall allows us to use config.DeclareOption("-f", "--filename",help="The raw image to load.") like Volatility Framework however, Volatility does not allow me to use .mem I mean it does not dump the memory. Overall i do like Volatility. It is quite simple to read and understand about this Framework as well. You can get more information from Rekall-Github to have better understanding.

Most importantly, let me explain a bit about scanning memory files. I am going to show you the source code of scan.py so that i can explain the code respectively

from rekall import addrspace
from rekall import constants
from rekall_lib import registry
from rekall_lib import utils

class ScannerCheck(with_metaclass(registry.MetaclassRegistry, object)):
    """A scanner check is a special class which is invoked on an AS to check
    for a specific condition.

    The main method is def check(self, buffer_as, offset):
    This will return True if the condition is true or False otherwise.

    This class is the base class for all checks.
    __abstract = True

    def __init__(self, profile=None, address_space=None, session=None,
        # The profile that this scanner check should use.
        self.profile = profile
        self.address_space = address_space
        self.session = session


First of all, ı will not cover about profile yet because that will be my next topic that i want to cover. Lets overview this source and look at the code step by step. Its important that you ought to understand the structure of this code for being able to write your own code. As you can see we have profile, session, adress Of course, we need to specify our profile such that it will recognize windows machine and to be run properly. Address space, shall be important because, when we talk about address spacing we should consider that there are few different categories of address spacing but let me cover about address space stack. The main concept is about rekall but let me give a short demonstration about volatility plugins how it looks like.

As an example, we are considering Windows System crash dump with the architecture x64

Plugins // this reads the virtual address, which is requested by OS

After this process, it will go to AMD64PagedMemory

AMD64PagedMemory // this translates to physical memory address 

after this process, it will go to WindowsCrashDumpSpace 

WindowsCrashDumpSpace // this translates to file offset decompress (if it necessary)

after the last process, it will go to FileAddressSpace

FileAddressSpace // this will seek and read from file offset 

In this script I just wanted to illustrate what address space was and what it done. Let move to our main topic Rekall. If you have understood this topic lets get started with profile mechanis

Profile Mechanism

AS I mentioned before that profile mechanism is the most important part of Rekall. In order to work with Memory forensics you have to be dealing with OS(operating system), thus its necessary to specify your operating sytstem,being able to dump your memory to be analyzed it will be important. Plugins are requesting virtual address from that dump. Rekall allows us to work with different operating system and processors which is of course predicatable. Now that we already know why we using such profile mechanisms. Lets get started with using our memory dump. You can get your own memory through virtual or your main OS.

** I should say that, when i was trying to capture my own volatile memory i got a blue screen with windows error. You should be alerted. It can have to with your current CPU.**

from rekall import plugin
from rekall.plugins.windows import common

class LoadWindowsProfile(common.AbstractWindowsCommandPlugin):

    name = "load_profile"

            profile_name = module.detect_profile_name()
            if not profile_name:
                raise plugin.PluginError(
                    "Unable to determine GUID for module %s." %
            profile_name = "%s/GUID/%s" % (self.module_name, self.guid)

        profile = self.session.LoadProfile(profile_name)
        if profile == None:
            # Try to build it from the symbol serv
            profile = module.build_local_profile(profile_name, force=True)
            if profile == None:
                raise plugin.PluginError(
                    "Unable to fetch or build %s" % profile_name)

        if profile:
            module.profile = profile

        return []

I would like to explain by this code that profile is important because, you might be able to get a lot information from this memory. It does not matter what you are using it can be Volatility or Rekall. You need to specify your own operating system. Whether you not do than it will not resolve your problem anc will have been an issue by investigating a memory.Lets focus on GUID As you can see that it is trying to detect GUID this term has a functionality such that it identifies an object such as COM interface, or a COM class object, or a manager entry point.

struct GUID{

unsigned long data1;
unsigned short data2;
unsigned short data3;
unsigned char data4[16];

Which data is declared in this struct. We need to know that a GUID is a 128-bit value consisting of one group 16 hexedecimal digits. this code is important module = self.session.address_resolver.GetModuleByName( self.module_name)

1.module is declared to self session address because we need to know the exact GUID

  1. if not module, then it will be redirected to error regarding collecting GUID address

Linux resolver

from builtins import str
__author__ = "Michael Cohen <scudette@gmail.com>"
from rekall import obj
from rekall.plugins.common import address_resolver
from rekall.plugins.linux import common

class LinuxAddressResolver(address_resolver.AddressResolverMixin,
    """A Linux specific address resolver plugin."""

    def _EnsureInitialized(self):
        if self._initialized:

        # Insert a psuedo module for the kernel

        # Add LKMs.
        for kmod in self.session.plugins.lsmod().get_module_list():
            self.AddModule(LKMModule(kmod, session=self.session))

        task = self.session.GetParameter("process_context")

        for vma in task.mm.mmap.walk_list("vm_next"):
            start = vma.vm_start
            end = vma.vm_end
                name="map_%#x" % start,
                start=start, end=end, session=self.session))

        self._initialized = True

This plugin is written for Linux OS and as you can understand from this source code that it looking for any kernel address of your ELF file to be recognized.

Winndows resolver

class WinAPIAddressResponse(address_resolver.AddressResolverMixin,
    """Address resolver for windows API access."""

            process_context = self.session.GetParameter("process_context")
            if process_context != None:
                # Now use the vad.
                for vad in self.session.plugins.vad().merge_ranges(
                    self.AddModule(LiveModule(vad=vad, session=self.session))

            self._initialized = True

Here is the source/plugin for Windows OS. You can check it out. Here you can get more information about this plugin:


Everthing is abstracted and well explained. You can get also help from the internet. the purpose of this blog is telling you that Rekall has a lot cons.If you get any doubts, you can always ask us for any problem which you are facing with. Before analyzing a dump memory let me also explain about auto profile selection I always recommned to forensics (investigators) please do not forget to practice and enhance your skills. Create your own memory dump file and look for any suspicious DLL and process injection. It will be awesome to create your own detection system. I hope that everything was clear and when you may not be able to read the source code well, please then check on internet or ask us.

# Profile Auto Selection

Lets remind us what profile was? Profile is where you place your operating system, architecture, version to give the information to the framework to analyze the your memory dump file. Now the most significant difference from volatility from the profile plugin, is that in rekall, the profile is in JSON format which makes us easily readable. For instance, Volatility represents a specific class defined within code based. Where Rekall represents such information in JSON format.

Rekall has another cons, such as it can be hosted in public repository because those files are just data. Rekall will simply download necessary profile from the repository when you need it or required. Now when you do own deep research it seems that Rekall has a lot of capabilities. Lets see what Rekall has for us.

class PEImageFileDetector(DetectionMethod):

    name = "pe"
    order = 50

    def __init__(self, **kwargs):
        super(PEImageFileDetector, self).__init__(**kwargs)
        self.pe_profile = self.session.LoadProfile("pe")

    def Offsets(self):
        # We only care about the first offset in the file.
        return [0]

    def DetectFromHit(self, hit, _, address_space):
        # If the file is a PE file, we simply return the PE address space.
        if self.pe_profile._IMAGE_DOS_HEADER(vm=address_space).NTHeader:
            pe_as = pe_vtypes.PEFileAddressSpace(
                base=address_space, profile=self.pe_profile)

            self.session.kernel_address_space = pe_as
            self.session.SetCache("default_image_base", pe_as.image_base)

            machine_type = pe_as.nt_header.FileHeader.Machine
            if machine_type == "IMAGE_FILE_MACHINE_AMD64":
                self.pe_profile.set_metadata("arch", "AMD64")
                self.pe_profile.set_metadata("arch", "I386")

            return self.pe_profile

Firstly, we should understand that PE header string has been controlled by this plugin. If the PE is recognized by plugin then it will continue the process.

if self.pe_profile._IMAGE_DOS_HEADER(vm=address_space).NTHeader:
            pe_as = pe_vtypes.PEFileAddressSpace(base=address_space, profile=self.pe_profile)
		` `


In order to understand this process address space should be reminded.

Address Space

I am not going to fully explain about this term, but let me explain briefly. When this plugin recognizes the PE file, then it will redirect to address space of PE which will be accessed to data in RAM. It handles virtual-to-physical-address translation when necessary, and transparently for difference in memory dump file formats.

You can check get more information Guess-Profile

Now view the source of DLLKernelImageDetector

class WindowsKernelImageDetector(WindowsRSDSDetector):
    name = "windows_kernel_file"
    order = 50

    def Offsets(self):
        return [0]

    KERNEL_PATHS = [r"C:\Windows\SysNative\ntoskrnl.exe",

    def DetectFromHit(self, hit, _, address_space):
        for potential_path in self.KERNEL_PATHS:
            # Try to make the kernel image into the address_space.
            image_offset = address_space.get_mapped_offset(potential_path, 0)

            if image_offset is not None:
                file_as = addrspace.RunBasedAddressSpace(
                    base=address_space, session=self.session)
                file_as.add_run(0, image_offset, 2**63)

                pe_file_as = pe_vtypes.PEFileAddressSpace(
                    base=file_as, session=self.session)

                pe_helper = pe_vtypes.PE(

                rsds = pe_helper.RSDS
                    "Found RSDS in kernel image: %s (%s)",
                    rsds.GUID_AGE, rsds.Filename)
                result = self._test_rsds(rsds)
                if result:
                    return result

Memory Dump With Rekall

Yes, we are now able to inject a code to our process, and we will understand how Rekall powerful it is. Lets get started to download Rekall with Docker. I do not recommned you to download Rekall to clone into /opt because you will be facing with python errors. To start off, you should consider to download docker to your machine or you can just login remotely. You can get more information from Rekall-Docker. You just pull yoır docker image and let run it.

PS C:\WINDOWS\system32> docker images
REPOSITORY               TAG       IMAGE ID       CREATED         SIZE
docker101tutorial        latest    6151c6cdd116   8 days ago      28.9MB
qilingframework/qiling   latest    620bc4d94151   2 weeks ago     389MB
alpine/git               latest    692618a0d74d   4 weeks ago     43.4MB
remnux/rekall            latest    0d2ed24e9d2a   11 months ago   925MB
PS C:\WINDOWS\system32>

As you can see Rekall has been installed. We do not forget to use ftk imager to capture your volatile memory because we are going to be able to inject the process and dump it in Rekall.

Well, i will use windows 10 machine and we should understand scan.py once again.

'_EPROCESS' : [None, {
        # Some standard fields for windows processes.
        'name': lambda x: x.ImageFileName,
        'pid': lambda x: x.UniqueProcessId,
        'dtb': lambda x: x.Pcb.DirectoryTableBase.v(),

        'CreateTime' : [None, ['WinFileTime', {}]],
        'ExitTime' : [None, ['WinFileTime', {}]],
        'InheritedFromUniqueProcessId' : [None, ['unsigned int']],
        'ImageFileName' : [None, ['String', dict(length=16)]],
        'UniqueProcessId' : [None, ['unsigned int']],
        'Session': [None, ["Pointer", dict(target="_MM_SESSION_SPACE")]],=-
        'Token': [None, ["_EX_FAST_REF", dict(target="_TOKEN")]],

We have Session which we talked before. UniqueProcessId, which will be important, because we will be deailng with process ID as well as ImageFileName. PID, is defined as process ID for instance, if you want to inject notepad.exe that you can use process ID of notepad. Before diving into Rekall’s memory forensics let me cover about DLL. We are going to inject DLL and process to demonstrate how it looks like, but before it is important to have a knowledge about DLL.

A DLL is available as a file on Windows with the .dll extension. Without DLL it is impossible to run an .EXE. A DLL file also uses the PE file format to describe its structure and content. Windows uses DLL file because it holds executable code and instructions. Its important to note that, if you double click an EXE file, it launches as a process.

DLLfunction(x,y) // dll

 x = y + z;
 return x;

// program 1
int main() 
	numeric = DLLfunction(4,6);

// program 2

int main() 
	numeric = DLLfunction(4,6);
	printf("Value: %d",numeric);

As you can DLLfunction has two helpers to be run properly. We already know what Import table is, if you could not remember please check above for more information. A DLL is loaded into memory. We also already know that an executable file depends on DLL for their APIs thus its important to note that Windows loader loads an executable PE file, which means that all DLLs dependencies into memory first.

Now lets get started to discover Rekall Framework

Memory dump

Being able to run rekall, i had already mentioned about docker which should be installed. You will be facing some issues if you try to run rekall from github repositories, there will be dependencies errors.

C:\WINDOWS\system32> docker pull remnux/rekall
Using default tag: latest
latest: Pulling from remnux/rekall
7b1a6ab2e44d: Pull complete
958b3bb1d32e: Pull complete
ba8b47b35067: Pull complete
73d2e657e820: Pull complete
4f4fb700ef54: Pull complete
Digest: sha256:301664d32ebee20c8653ea137e414f938e6b717e1eebcf62cb8e690433cee627
Status: Downloaded newer image for remnux/rekall:latest

As you can see, I pulled remnux/rekall from docker.io. The next step is:

C:\WINDOWS\system32> docker images
REPOSITORY               TAG       IMAGE ID       CREATED         SIZE
docker/getting-started   latest    cb90f98fd791   5 months ago    28.8MB
remnux/rekall            latest    0d2ed24e9d2a   11 months ago   925MB

To see of the repository is being placed. The next is:

C:\WINDOWS\system32>docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED         STATUS         PORTS                NAMES
b843c6cafa1e   docker/getting-started   "/docker-entrypoint.…"   7 minutes ago   Up 7 minutes>80/tcp   cranky_black

To see the process of this container. Now it is to use this command:

C:\WINDOWS\system32> docker exec -it b7c98db01e8c  bash
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

Just specify your docker container and use: docker exec -it b7c98db01e8c bash

If everything is OK! lets try to use rekall -h command

nonroot@b7c98db01e8c:~/files$ rekall -h
Webconsole disabled: cannot import name 'webconsole_plugin' from partially initialized module 'rekall.plugins.tools' (most likely due to a circular import) (/usr/local/lib/python3.8/dist-packages/rekall/plugins/tools/__init__.py)
usage: rekall [-p PROFILE] [-v] [-q] [--debug] [--output_style {concise,full}] [--logging_level {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [--log_domain [{PageTranslation} [{PageTranslation} ...]]] [--pager PAGER]
              [--paging_limit PAGING_LIMIT] [--colors {auto,yes,no}] [-F FORMAT] [--plugin [PLUGIN [PLUGIN ...]]] [-h] [--cache CACHE] [--cache_expiry_time CACHE_EXPIRY_TIME]
              [--repository_path [REPOSITORY_PATH [REPOSITORY_PATH ...]]] [-f FILENAME] [--buffer_size BUFFER_SIZE] [--output OUTPUT] [--max_collector_cost MAX_COLLECTOR_COST] [--home HOME]
              [--logging_format LOGGING_FORMAT] [--performance {normal,fast,thorough}] [--live LIVE] [--cpu_quota CPU_QUOTA] [--load_quota LOAD_QUOTA] [--dtb DTB] [--kernel_slide KERNEL_SLIDE] [-o FILE_OFFSET]
              [--ept EPT [EPT ...]] [--timezone TIMEZONE] [--cache_dir CACHE_DIR]
              [--highlighting_style {default,emacs,friendly,colorful,autumn,murphy,manni,material,monokai,perldoc,pastie,borland,trac,native,fruity,bw,vim,vs,tango,rrt,xcode,igor,paraiso-light,paraiso-dark,lovelace,algol,algol_nu,arduino,rainbow_dash,abap,solarized-dark,solarized-light,sas,stata,stata-light,stata-dark,inkpot,zenburn,gruvbox-dark,gruvbox-light}]
              [--name_resolution_strategies [{Module,Symbol,Export} [{Module,Symbol,Export} ...]]] [--autodetect_build_local_tracked [AUTODETECT_BUILD_LOCAL_TRACKED [AUTODETECT_BUILD_LOCAL_TRACKED ...]]]
              [--pagefile [PAGEFILE [PAGEFILE ...]]]
              [--autodetect {nt_index,pe,rsds,windows_kernel_file,linux_index,linux,osx,ntfs,tsk} [{nt_index,pe,rsds,windows_kernel_file,linux_index,linux,osx,ntfs,tsk} ...]]
              [--autodetect_threshold AUTODETECT_THRESHOLD] [--autodetect_build_local {full,basic,none}] [--autodetect_scan_length AUTODETECT_SCAN_LENGTH] [--agent_configuration AGENT_CONFIGURATION]
              [--version] [-]

So this means that everything is OK!

Being able to demonstrate rekall I am going go inject inject.dll to notepad to illustrate it properly

 Directory of C:\Users\Malwa\Desktop\Malware Dev\DLL\DLLinject\x64\Debug

09/29/2022  12:47 PM    <DIR>          .
09/29/2022  12:47 PM    <DIR>          ..
09/29/2022  12:48 PM            64,000 Rekall-DLL.exe
09/29/2022  12:48 PM         1,355,776 Rekall-DLL.pdb
               2 File(s)      1,419,776 bytes
               2 Dir(s)  133,399,515,136 bytes free

C:\Users\Malwa\Desktop\Malware Dev\DLL\DLLinject\x64\Debug>Rekall-DLL.exe 19608
Injecting DLL to PID: 19608

You should look at the process hacker or task manager to identify the PID. In my case, it was 19608 Now, we are going to be able to dump our volatile memory to be analyzed with Rekall Framework.

I am also going to disassamble this code with IDA to look at the process

lea     rax, [rsp+5C8h+ProcessInformation]
mov     [rsp+5C8h+lpProcessInformation], rax ; lpProcessInformation
lea     rax, [rsp+5C8h+StartupInfo]
mov     [rsp+5C8h+lpStartupInfo], rax ; lpStartupInfo
mov     [rsp+5C8h+lpCurrentDirectory], 0 ; lpCurrentDirectory
mov     [rsp+5C8h+lpEnvironment], 0 ; lpEnvironment
mov     [rsp+5C8h+dwCreationFlags], 1000044h ; dwCreationFlags
mov     [rsp+5C8h+bInheritHandles], 1 ; bInheritHandles
xor     r9d, r9d        ; lpThreadAttributes
xor     r8d, r8d        ; lpProcessAttributes
lea     rdx, CommandLine ; "rundll32.exe"
xor     ecx, ecx        ; lpApplicationName
call    cs:CreateProcessA
mov     [rsp+5C8h+var_578], eax
cmp     [rsp+5C8h+var_578], 0
jnz     short loc_18000114C

lea     r8, [rbp+1C0h+dllPath] ; lpBuffer
mov     rdx, [rbp+1C0h+remoteBuffer] ; lpBaseAddress
mov     rcx, [rbp+1C0h+processHandle] ; hProcess
call    cs:__imp_WriteProcessMemory
lea     rcx, ModuleName ; "Kernel32"
call    cs:__imp_GetModuleHandleW
lea     rdx, ProcName   ; "LoadLibraryW"
mov     rcx, rax        ; hModule
call    cs:__imp_GetProcAddress
mov     [rbp+1C0h+threatStartRoutineAddress], rax
mov     [rsp+200h+lpThreadId], 0 ; lpThreadId
mov     [rsp+200h+dwCreationFlags], 0 ; dwCreationFlags
mov     rax, [rbp+1C0h+remoteBuffer]
mov     qword ptr [rsp+200h+flProtect], rax ; lpParameter
mov     r9, [rbp+1C0h+threatStartRoutineAddress] ; lpStartAddress
xor     r8d, r8d        ; dwStackSize
xor     edx, edx        ; lpThreadAttributes
mov     rcx, [rbp+1C0h+processHandle] ; hProcess
call    cs:__imp_CreateRemoteThread
mov     rcx, [rbp+1C0h+processHandle] ; hObject
call    cs:__imp_CloseHandle

Let me explain a bit about this piece of code.

WriteProcessMemory With the WriteProcessMemory function, we write the path of our dll file to the virtual address of the previously designed process. VirtualAllocEx With the VirtualAllocEx function, we allocate space before we can write the path of our dll file to the virtual address space of the target process. GetProcAddress With the GetProcAddress function, we get the address on the memory of the LoadLibraryW function, which we will use to load our dll file to the target process. The LoadLibraryW function is a function of the kernel32.dll library.

Awesome. Now we are going to analyze with Rekall. First of all, you should have already dumped your volatile memory to your main OS or virtual machine to make it more easier.

  1. be sure that your docker is running
  2. when you dumped your file to the right directory
  3. use this command docker exec -it rekallcontainer bash
  4. Use this command docker cp inject.mem rekallcontainer:/
  5. after entering to your docker, you should use cd ../../../../
  6. use mv command to /home/nonroot/files

Of course, we already know that PID of notepad 19608 lets analyze that

[1] suspicious.mem 08:00:30> ldrmodules(19608)
       base      in_load in_init in_mem mapped
  -------------- ------- ------- ------ ------
0xb70d37594180 Notepad.exe 19608
  0x7ffafdc20000 True    True    True   C:\Windows\System32\propsys.dll
  0x7ffaee110000 True    True    True   C:\Windows\System32\winspool.drv
  0x7ffadce60000 True    True    True   C:\Windows\System32\Windows.UI.Xaml.Controls.dll
  0x7ffad4f70000 True    True    True   C:\Program Files\WindowsApps\microsoft.vclibs.140.00.uwpdesktop_14.0.30704.0_x64__8wekyb3d8bbwe\vcruntime140_1.dll
  0x7ffa91690000 True    True    True   C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2208.25.0_x64__8wekyb3d8bbwe\Notepad\NotepadXamlUI.dll
  0x7ff615230000 True    False   True   C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2208.25.0_x64__8wekyb3d8bbwe\Notepad\Notepad.exe
  0x7ffa60750000 True    True    True   C:\Program Files\WindowsApps\microsoft.ui.xaml.2.8_8.2208.12001.0_x64__8wekyb3d8bbwe\Microsoft.UI.Xaml.dll
  0x7ffaa2400000 True    True    True   C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2208.25.0_x64__8wekyb3d8bbwe\msptls.dll
  0x7ffa91910000 True    True    True   C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2208.25.0_x64__8wekyb3d8bbwe\riched20.dll
  0x7ffa99e70000 True    True    True   C:\Windows\System32\efswrt.dll
  0x7ffac2750000 True    True    True   C:\Program Files\WindowsApps\microsoft.vclibs.140.00.uwpdesktop_14.0.30704.0_x64__8wekyb3d8bbwe\vcruntime140.dll
  0x7ffac26c0000 True    True    True   C:\Program Files\WindowsApps\microsoft.vclibs.140.00.uwpdesktop_14.0.30704.0_x64__8wekyb3d8bbwe\msvcp140.dll
  0x7ffad79e0000 True    True    True   C:\Program Files\WindowsApps\microsoft.vclibs.140.00_14.0.30704.0_x64__8wekyb3d8bbwe\vcruntime140_1_app.dll
  0x7ffad7930000 True    True    True   C:\Program Files\WindowsApps\microsoft.vclibs.140.00_14.0.30704.0_x64__8wekyb3d8bbwe\msvcp140_app.dll
  0x7ffad53a0000 True    True    True   C:\Windows\System32\msftedit.dll
  0x7ffad5370000 True    True    True   C:\Windows\System32\globinputhost.dll
  0x7ffad69f0000 True    True    True   C:\Windows\System32\UIAutomationCore.dll
  0x7ffad79c0000 True    True    True   C:\Program Files\WindowsApps\microsoft.vclibs.140.00_14.0.30704.0_x64__8wekyb3d8bbwe\vcruntime140_app.dll
  0x7ffadc0b0000 True    True    True   C:\Windows\System32\DataExchange.dll
  0x7ffad9390000 True    True    True   C:\Windows\System32\Windows.UI.Core.TextInput.dll
  0x7ffadc2c0000 True    True    True   C:\Windows\System32\threadpoolwinrt.dll

When we use ldrmodules(19608), You will see this output.It is also important to check vad

What is VAD?

VAD is a tree structure and like any tree structure it has a root (which is called Vadroot) and nodes/leafs (Vadnodes) that contains all the information related to memory ranges reserved for a specific process by the memory manager

source: VAD

We should consider where it has permissions. Let me cover about the permissions a bit.

PAGE_EXECUTE: Memory can be executed but cannot be written to
PAGE_EXECUTE_READ: Memory can be executed or read but cannot be written to
PAGE_EXECUTE_READWRITE: Memory can be executed, read and write.
PAGE_NOACCESS: No access to this memory region
PAGE_READONLY: Only read access to the memory
PAGE_READWRITE: Read, Write access to the memory but no execution.

These permissions give us an indication of the type of access. Lets analyze that with vad()

0xb70d3aa9a6c0   2 0x7ffaee110000 0x7ffaee1aafff      4 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\winspool.drv
0xb70d3aa7bb80   8 0x7ffaee1b0000 0x7ffaee218fff      4 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\oleacc.dll
0xb70d3aa9b160   7 0x7ffaee220000 0x7ffaee4c4fff      8 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.22000.120_none_9d947278b86cc467\comctl32.dll
0xb70d3aa9f260   8 0x7ffaeecd0000 0x7ffaeecd5fff      3 Mapped  Exe    EXECUTE_WRITECOPY    C:\Users\Malwa\Desktop\Malwation\Rekall\dark.dll
0xb70d3aa9ba20   6 0x7ffaf0750000 0x7ffaf0850fff      6 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\MrmCoreR.dll
0xb70d3aa9e360   7 0x7ffaf3cc0000 0x7ffaf55bffff    157 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\DriverStore\FileRepository\u0357176.inf_amd64_828ff99cacd4aa89\B356563\atidxx64.dll
0xb70d3aa9b840   5 0x7ffaf68b0000 0x7ffaf68edfff      3 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\Windows.StateRepositoryClient.dll
0xb70d3aaa0de0   8 0x7ffaf71b0000 0x7ffaf71dcfff      4 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\D3DSCache.dll
0xb70d3aaa00c0   7 0x7ffaf7880000 0x7ffaf78aefff      4 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\amdihk64.dll
0xb70d3aa9eb80   6 0x7ffaf7930000 0x7ffaf7967fff      3 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\DriverStore\FileRepository\u0357176.inf_amd64_828ff99cacd4aa89\B356563\atiuxp64.dll
0xb70d3aa9ef40   7 0x7ffaf7a00000 0x7ffaf7bdafff     16 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\DriverStore\FileRepository\u0357176.inf_amd64_828ff99cacd4aa89\B356563\aticfx64.dll
0xb70d3aa9ce20   4 0x7ffaf8120000 0x7ffaf8935fff     18 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\OneCoreUAPCommonProxyStub.dll
0xb70d3aa9c420   6 0x7ffaf8c60000 0x7ffaf8ec5fff      7 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\twinapi.appcore.dll
0xb70d3aa9c600   5 0x7ffaf9650000 0x7ffaf966afff      3 Mapped  Exe    EXECUTE_WRITECOPY    C:\Windows\System32\Windows.StateRepositoryCore.dll

hmm…. EXECUTE_WRITECOPY seems interesting. APT would use hidden directory of course however, ı just want to demonstrate what kind of capabilities it has.

Enables execute, read-only, or copy-on-write access to a mapped view of a file mapping object. An attempt to write to a committed copy-on-write page results in a private copy of the page being made for the process. The private page is marked as PAGE_EXECUTE_READWRITE, and the change is written to the new page.

source : Microsoft

We can also use pslist() command to specify only the process

0xb70d3a9240c0 msedgewebview2       16344  17700            9            -          1 False  2022-10-01 09:02:35Z     -
0xb70d2cb04080 SystemSettings       16348   1344           14            -          1 False  2022-10-01 09:00:55Z     -
0xb70d32d570c0 firefox.exe          16428   2756            5            -          1 False  2022-10-01 09:19:08Z     -
0xb70d39b25080 vcpkgsrv.exe         16568  19320           10            -          1 True   2022-10-01 09:23:15Z     -
0xb70d31f230c0 conhost.exe          16680  16692            2            -          1 False  2022-10-01 09:01:00Z     -
0xb70d2bc70080 wsl.exe              16692  11088            2            -          1 False  2022-10-01 09:01:00Z     -
0xb70d32d92180 Telegram.exe         16768   4828           45            -          1 False  2022-10-01 09:05:16Z     -
0xb70d2e4bf180 FluentTerminal       16792   1344           39            -          1 False  2022-10-01 09:01:27Z     -
0xb70d31cd1180 dllhost.exe          16808   1344            4            -          1 False  2022-10-01 09:14:05Z     -
0xb70d2cf460c0 svchost.exe          16844   1124           11            -          0 False  2022-10-01 09:00:56Z     -
0xb70d318c10c0 dllhost.exe          16868   1344           16            -          1 False  2022-10-01 09:00:56Z     -
0xb70d3a7680c0 vmware-unity-h       17212   6072            3            -          1 True   2022-10-01 09:16:24Z     -
0xb70d31a0e080 docker.exe           17256  11088           16            -          1 False  2022-10-01 09:01:00Z     -
0xb70d2ad0a0c0 wslhost.exe          17332   5240            1            -          1 False  2022-10-01 09:00:57Z     -
0xb70d32e890c0 conhost.exe          17512  13856            4            -          1 False  2022-10-01 09:01:29Z     -
0xb70d32658080 wslhost.exe          17580   1424            1            -          1 False  2022-10-01 09:01:02Z     -
0xb70d3265b080 wslhost.exe          17588   4252            1            -          1 False  2022-10-01 09:01:02Z     -
0xb70d3265c080 wslhost.exe          17596  12908            1            -          1 False  2022-10-01 09:01:02Z     -
0xb70d3a9350c0 firefox.exe          17624   2756           33            -          1 False  2022-10-01 09:19:08Z     -
0xb70d3265f080 conhost.exe          17660  17580            3            -          1 False  2022-10-01 09:01:02Z     -
0xb70d32662080 conhost.exe          17680  17588            3            -          1 False  2022-10-01 09:01:02Z     -
0xb70d3a44b180 msedgewebview2       17700  15788           30            -          1 False  2022-10-01 09:02:35Z     -
0xb70d3265e080 conhost.exe          17704  17596            3            -          1 False  2022-10-01 09:01:02Z     -
0xb70d32d17100 MoNotification       18120   2272            4            -          1 False  2022-10-01 09:01:46Z     -
0xb70d2d6f1180 firefox.exe          18536   2756           27            -          1 False  2022-10-01 09:19:08Z     -
0xb70d396da0c0 ServiceHub.Hos       18600  15520           13            -          1 False  2022-10-01 09:22:24Z     -
0xb70d377e5080 vcpkgsrv.exe         18664   3572            7            -          1 True   2022-10-01 09:22:21Z     -
0xb70d3a8020c0 ServiceHub.Thr       18992    664           26            -          1 False  2022-10-01 09:23:11Z     -
0xb70d1dc32080 vcpkgsrv.exe         19080  19320           10            -          1 True   2022-10-01 09:23:15Z     -
0xb70d39b9e080 vshost.exe           19320  15208            1            -          1 False  2022-10-01 09:23:15Z     -
0xb70d2b5af180 dllhost.exe          19512   1344            6            -          1 False  2022-10-01 09:28:08Z     -
0xb70d37594180 Notepad.exe          19608   4828           19            -          1 False  2022-10-01 09:27:01Z     -
0xb70d378dd180 firefox.exe          20032   2756           12            -          1 False  2022-10-01 09:24:09Z     -
0xb70d3a76e180 MSBuild.exe          20568  15208            8            -          1 False  2022-10-01 09:26:23Z     -
0xb70d39e9b0c0 vcpkgsrv.exe         20608  19320            9            -          1 True   2022-10-01 09:23:35Z     -
0xb70d39ae80c0 ServiceHub.Hos       20812    664           22            -          1 False  2022-10-01 09:23:36Z     -
0xb70d3a6ae180 ServiceHub.Tes       21196    664           14            -          1 False  2022-10-01 09:23:39Z     -
0xb70d3acbd0c0 audiodg.exe          21660   4120            6            -          0 False  2022-10-01 09:26:26Z     -
0xb70d2af4d080 WinRAR.exe           22796   6608            9            -          1 False  2022-10-01 09:28:09Z     -
0xb70d2b180180 wsl.exe              23084  12072            0            -          0 False  2022-10-01 09:28:49Z     2022-10-01 09:28:49Z
0xb70d39b680c0 firefox.exe          24048   2756           12            -          1 False  2022-10-01 09:24:19Z     -
0xb70d32cbd180 conhost.exe          24476  20568            2            -          1 False  2022-10-01 09:26:23Z     -
Out<06:49:07> Plugin: pslist (WinPsList)

After this we can use regex method to find our malicios exe file.

[1] suspicious.mem 06:49:39> pslist(proc_regex="notepad")
  _EPROCESS            name          pid   ppid  thread_count handle_count session_id wow64    process_create_time       process_exit_time
-------------- -------------------- ----- ------ ------------ ------------ ---------- ------ ------------------------ ------------------------
0xb70d37594180 Notepad.exe          19608   4828           19            -          1 False  2022-10-01 09:27:01Z     -

Use this command: pslist(proc_regex="notepad") to filter malicious .exe

We can also dump DLL files with dlldump(proc_regex = "notepad")

0xb70d37594180 Notepad.exe 19608 0x7ffafbcc0000 CoreUIComponents.dll module.19608.3a0394180.7ffafbcc0000.CoreUIComponents.dll
0xb70d37594180 Notepad.exe 19608 0x7ffa99e70000 efswrt.dll           module.19608.3a0394180.7ffa99e70000.efswrt.dll
0xb70d37594180 Notepad.exe 19608 0x7ffaee1b0000 oleacc.dll           module.19608.3a0394180.7ffaee1b0000.oleacc.dll
0xb70d37594180 Notepad.exe 19608 0x7ffaea090000 Windows.ApplicationM module.19608.3a0394180.7ffaea090000.Windows.ApplicationModel.dll
0xb70d37594180 Notepad.exe 19608 0x7ffaddf40000 directmanipulation.d module.19608.3a0394180.7ffaddf40000.directmanipulation.dll
0xb70d37594180 Notepad.exe 19608 0x7ffaf9ab0000 windowscodecs.dll    module.19608.3a0394180.7ffaf9ab0000.windowscodecs.dll
0xb70d37594180 Notepad.exe 19608 0x7ffaf9710000 wuceffects.dll       module.19608.3a0394180.7ffaf9710000.wuceffects.dll
0xb70d37594180 Notepad.exe 19608 0x7ffb01020000 bcrypt.dll           module.19608.3a0394180.7ffb01020000.bcrypt.dll
0xb70d37594180 Notepad.exe 19608 0x7ffae0030000 twinapi.dll          module.19608.3a0394180.7ffae0030000.twinapi.dll
0xb70d37594180 Notepad.exe 19608 0x7ffaeecd0000 dark.dll             module.19608.3a0394180.7ffaeecd0000.dark.dll     <---------
0xb70d37594180 Notepad.exe 19608 0x7ffaea2c0000 daxexec.dll          module.19608.3a0394180.7ffaea2c0000.daxexec.dll
0xb70d37594180 Notepad.exe 19608 0x7ffaeb3f0000 container.dll        module.19608.3a0394180.7ffaeb3f0000.container.dll

We can also use threads() to specify win32_start_symb

0xb70d2c672080  19608  23536 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ff615275e28 notepad+0x45e28
0xb70d2ea50080  19608  11052 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb04176a00 ntdll!TppWorkerThread
0xb70d37ded080  19608  23532 0xe687b90ab870 0xe687b90ab870                 Notepad.exe      0x7ffaf077fff0 mrmcorer!GetStringValueForManifestField+0x69e00xb70d2d671080  19608  10404 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb04176a00 ntdll!TppWorkerThread
0xb70d2b0c1080  19608  16860 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb0216f760 combase!CoTaskMemRealloc+0x870
0xb70d2acaf080  19608  17924 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb04176a00 ntdll!TppWorkerThread
0xb70d2af3c080  19608   7376 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb02451160 shcore!SHQueryValueExW+0x970
0xb70d20f1b080  19608   1804 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffadf1b9e70 windows!DllCanUnloadNow+0x2f70
0xb70d2ded0080  19608   7656 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffaf4711344 atidxx64!AmdLiquidVrD3D11WrapDeviceContext+0xa9014
0xb70d393e3080  19608  11704 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb0216f760 combase!CoTaskMemRealloc+0x870
0xb70d31620080  19608   6020 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffaddf55410 directmanipulation+0x15410
0xb70d390c3080  19608  12484 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb04176a00 ntdll!TppWorkerThread
0xb70d2d9e0080  19608  10476 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffaf4711344 atidxx64!AmdLiquidVrD3D11WrapDeviceContext+0xa9014
0xb70d2e45f080  19608  13692 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffaf78844b0 amdihk64!Terminate+0x1520
0xb70d39087080  19608  21156 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffaf7885760 amdihk64!Terminate+0x27d0
0xb70d39176080  19608   4040 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb02451160 shcore!SHQueryValueExW+0x970
0xb70d324cd080  19608  16368 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb02451160 shcore!SHQueryValueExW+0x970
0xb70d39070080  19608  21776 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb02451160 shcore!SHQueryValueExW+0x970
0xb70d2aa84080  19608  23156 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb02451160 shcore!SHQueryValueExW+0x970
0xb70d393cd080  19608  15556 0x7ffb04164830 ntdll!RtlUserThreadStart       Notepad.exe      0x7ffb02451160 shcore!SHQueryValueExW+0x970

As you see can it will be very useful to use regex_proc So far, we were talking about useful commands in Rekall terminal. Now let me write a simple how we can detect Notepadwith Rekall plugins.

Process Injection Detector Script

In order to write a correct script, we should be able to use Rekall’s plugins. Before diving into our script let me explain about this piece of code below:

yield dict(_ETHREAD=thread,

First of all, we are going to be able to use pid and win32_start_symb to analyze our malicious process.

Here is the code. Do not worry I will explain my code step by step.

Automated Python script for Rekall

You can check my script: DLLProcessDetector.py

# Telegram : @Black_Mamba010
# Twitter :  @DarkGhost
# Instagram: @d4rkc0d3r
dll_inject = []

def process():
    procs = session.plugins.pslist()
    for eprocess in procs.filter_processes():
        if(eprocess.name == "lsass.exe"):
        if(eprocess.name == "Notepad.exe"):

def vad(sample):
    a = True
    b = False
    vad_list = session.plugins.vad().collect_vadroot(sample.RealVadRoot, sample)
    if(len(vad_list) < 0):
        return b
    for s in vad_list:
        if(s['type'] == "Mapped" and s['protect'] == "EXECUTE_WRITECOPY" and s['filename'] != None):
            return a

def thread(pid):
     t = session.plugins.threads(pid)
     for k in t:
       if("kernel32!LoadLibraryW" in str(k["win32_start_symb"])):
        if(len(dll_inject) > 0):
            for pid in dll_inject:
             print("Notepad has been infected  (PID: %d) " % (pid))
            print("Notepad has not been infected")
     except Exception as p:

if __name__ == "__main__":

def process()

First of all, as we seen earlier that we need to dump process list because we already knew that we put our malicious DLL to Notepad.exe but we have a problem. We know that the target is Notepad but as you can see in my code,if lsass in the process, please continue because it gives us some issues on Windows 11. Lsass, Local Security Authority Server Service (LSASS) is a process in Microsoft Windows operating systems that is responsible for enforcing the security policy.

if Notepad in the process then, send it to vad (virtual address Descriptor).

def vad()

Virtual address descriptor, this will be useful because it will give us the information about;

DLL files, memory protection, type, and more… so we parsed Notepad to vad. You can also check it via Rekall framework simultaneously. If the given statements is true then, we will get True from that function. This means we can get the UniqueProcessId from that process.

def thread()

kernel32!LoadLibraryW, Loads the specified module into the address space of the calling process. The specified module may cause other modules to be loaded. It will be very handy, if we can identify that this process uses kernel32.dll after being executed. If that is correct, and we are able to catch kernel32.dll then it will be placed in our dll_inject we are appending.

Lastly, we will print the result.

Output of my script

[1] suspicious.mem 06:47:54> run -i DLLProcessDetect.py

Notepad has been infected  (PID: 19608) 


If you did like this memory Forensics with Rekall blog-post, please then not forget to share and like this blog. More awesome reverse and malware blogs will be appeared in this blog-site. If you unable to understand this concept, feel free to ask us for help.

Thank you for reading this blog.

Ahmet Göker