Skip to main content

Minimal Python memory scraper with memory attributes support

Project description

Skrapa

Skrapa is a zero dependency and customizable Python library for scanning Windows and Linux process memory.

Contents

Installation

Installation can be done using pip:

$ pip install skrapa

You can also include YARA support by installing the yara variant:

$ pip install skrapa[yara]

Quickstart

Start scanning with a given process ID after installing the library:

python examples/scan_pid.py --pid 8320 --hex 0000488B0557F402004833C448894424 --protect PAGE_EXECUTE_READ --alloc-protect PAGE_EXECUTE_WRITECOPY --type MEM_IMAGE --state MEM_COMMIT

How it works

Skrapa differs slightly from the traditional sense of memory scanning in that it allows you to filter on specific memory attributes, which can greatly reduce the time it takes to scan process memory.

On the Windows and Linux platforms the memory regions assigned to a specific process each hold their own set of permissions. These permissions can basically be boiled down to the permissions we know and love: READ, WRITE, and EXECUTE. Within process memory these permissions can be combined as some process memory needs to be readable as well as executable when we want to execute code from this memory region.

The API was designed to be transparent so it doesn't matter if the script was written for Windows or Linux (with the single exception for a permission that is only available on Windows).

Warning to effectively scan the memory space on Windows or Linux you will need administrative privileges on the target system.

Usage

Scanning a PID

Let's try to scan for the hex pattern of 0000488B0557F402004833C448894424 on Windows. To speed up the scanning process we assume that the following memory permissions are set for the region that the pattern should exist in:

  • Protect: PAGE_EXECUTE_READ
  • Allocation Protect: PAGE_EXECUTE_WRITECOPY
  • Type: MEM_IMAGE
  • State: MEM_COMMIT

Any memory region that does not have these permissions set will be exempt from the matching process, increasing the speed of the scan. The boilerplate code for such a scan would look something like this:

from skrapa import AccessProtectionType, HexPattern, MemoryAttributes, scan_pid

mem_attributes = MemoryAttributes(
    protect=AccessProtectionType.PAGE_EXECUTE_READ,
    allocation_protect=AccessProtectionType.PAGE_EXECUTE_WRITECOPY,
    type=AllocationType.MEM_IMAGE,
    state=AllocationType.MEM_COMMIT,
)

for hit in scan_pid(pid=8320, patterns=HexPattern("0000488B0557F402004833C448894424"), attributes=mem_attributes):
    print(hit)

For each hit on the pattern we can look at the different attributes belonging to the process:

  • Process name: hit.process.name
  • Process path: hit.process.path
  • Process architecture: hit.process.architecture

Or for the associated memory region:

  • Memory region start: hit.region_start
  • Memory region size: hit.region_size
  • Memory region end: hit.region_start + hit.region_size
  • Address of the match: hit.address

We can read 128 bytes from the start of the pattern match because we might know there will be some interesting information after this pattern:

from skrapa import read_process_memory

match_content = read_process_memory(pid=8320, address=hit.address, size=128)

You can then do whatever post processing you want on these bytes.

Scan using YARA

Note: to use the YARA functionality of Skrapa, you'll need to have yara-python installed. You can install this manually or run pip install skrapa[yara].

We're continuing our search leveraging YARA to find a pattern in the process memory of notepad.exe. Using YARA rules with Skrapa is as easy as pointing to your YARA file containing the rule(s) you want to match within the process memory. The YARA rule we're using for this example is:

rule l33t_notepad_rule {
    strings:
        $ = {
            00 00 48 8B 05 57 F4 02
            00 48 33 C4 48 89 44 24
        }
    condition:
        any of them
}

We can use the YARA rule from above to find the pattern in the process memory:

from skrapa import AccessProtectionType, MemoryAttributes, scan_pid

try:
    import yara
except ImportError:
    logging.error("YARA Python module not found, install it with: pip install yara-python")
    exit(1)

mem_attributes = MemoryAttributes(
    protect=AccessProtectionType.PAGE_EXECUTE_READ,
    allocation_protect=AccessProtectionType.PAGE_EXECUTE_WRITECOPY,
    type=AllocationType.MEM_IMAGE,
    state=AllocationType.MEM_COMMIT,
)

patterns = yara.compile(
    source="rule l33t_notepad { strings: $ = {0000488B0557F402004833C448894424} condition: any of them }"
)

for hit in scan_pid(pid=8320, patterns=patterns, attributes=mem_attributes):
    print(hit)

The results of the above scan can be used in the exact same manner as the previous example shown. If you'd rather load in a YARA from a specified file you can switch the source= parameter of the yara.compile call with filepath=.

Page filters

Skrapa allows users to define more complex memory filtering conditions by making use of a callback function. The callback function can also be used to check the size of the memory region before trying to match the given pattern.

For this example we will define the following page_filter function that will first check if:

  • The given region is bigger than 0x300000 and smaller than 0x400000
  • The given region does not have the PAGE_NOACCESS protect attribute set
  • The given region has the PAGE_READWRITE protect attribute set

Note that we will not provide any of the memory attributes when using the above page_filter definition, instead we define every condition in the function:

from skrapa import AccessProtectionType, HexPattern, MemoryAttributes, scan_pid

def page_filter(pageinfo) -> bool:
    return (
        0x300000 > pageinfo.size <= 0x400000
        and pageinfo.attributes.protect.name != "PAGE_NOACCESS"
        and pageinfo.attributes.protect.name == "PAGE_READWRITE"
    )

mem_attributes = MemoryAttributes(protect=None, allocation_protect=None, type=None, state=None)

for hit in scan_pid(pid=8320, patterns=HexPattern("0000488B0557F402004833C448894424"), attributes=mem_attributes, page_filter=page_filter):
    print(hit)

We will now only receive hits if the page_filter conditions were met.

Check out the examples/ folder to quickly get started!

Features

  • Supports x86 and x64 Windows and Linux platforms;
  • Scan a single process by name or PID, or scan the entire memory space;
  • Support for YARA signatures;
  • Support for page filters for more complex conditions;

Project details


Release history Release notifications | RSS feed

This version

1.0

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

skrapa-1.0.tar.gz (26.4 kB view hashes)

Uploaded Source

Built Distribution

skrapa-1.0-py3-none-any.whl (23.5 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page