/Universal-Pointer-Searcher-Engine

An efficient C++ command line tool for performing highly configurable and parallelized pointer searches

OtherNOASSERTION

Universal Pointer Searcher

This is a severely reworked C++ command line version of the Universal Pointer Searcher which offers you a very flexible way of performing pointer searches which furthermore supports finding pointers on memory dumps of any system/console out there (and not just one specific system like all other pointer searchers I have seen).

Requirements

Windows

This application may require you to install the Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017, 2019 and 2022 from here:

>dumpbin /dependents UniversalPointerSearcher.exe
Microsoft (R) COFF/PE Dumper Version 14.28.29336.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file UniversalPointerSearcher.exe

File Type: EXECUTABLE IMAGE

  Image has the following dependencies:

    KERNEL32.dll
    USER32.dll
    bcrypt.dll
    WLDAP32.dll
    ADVAPI32.dll
    CRYPT32.dll
    WS2_32.dll
    WTSAPI32.dll
    KERNEL32.dll
    USER32.dll
    KERNEL32.dll
    USER32.dll

Linux

The application may require you to install Intel TBB via e.g. sudo apt install libtbb-dev. The application has the following dependencies:

$ ldd UniversalPointerSearcher.elf
    linux-vdso.so.1 (0x00007ffe2db9a000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f7c34edf000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f7c34ebc000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f7c34cdb000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f7c34b8c000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f7c34b71000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7c3497f000)
    libtbb.so.2 => /usr/lib/x86_64-linux-gnu/libtbb.so.2 (0x00007f7c34937000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f7c365f6000)

macOS

Fair warning: The macOS build is currently not optimal due to missing C++17 parallel algorithms in AppleClang 14 on my macOS development machine (since the Macbook is from 2015 it no longer receives the latest updates). This means that certain operations by the pointer searcher will remain single-threaded and therefore will be slower than on other operating systems.

% oTool -L UniversalPointerSearcher.macho
UniversalPointerSearcher.macho:
        /System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration (compatibility version 1.0.0, current version 1163.100.19)
        /System/Library/Frameworks/Security.framework/Versions/A/Security (compatibility version 1.0.0, current version 60158.100.133)
        /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1858.112.0)
        /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1300.23.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.100.3)

Files

The release contains the README.md, the LICENSE, the compiled UniversalPointerSearcher.exe (Windows version), the DLLs for the Windows version (if any), the UniversalpointerSearcher.macho (MacOS X version) and the compiled UniversalPointerSearcher.elf (Linux version).

Usage

This is a command line application. You have to pass the respective information such as source memory dump file path and starting address to the application via your system's command line (e.g. cmd.exe). Alternatively, there are more optional options to configure the pointer searcher. You can list them by passing the --help flag:

>UniversalPointerSearcher.exe --help
[2023-09-06 20:09:35.276] [42640] [info] Windows C++ Universal Pointer Searcher Engine v3.91
Release Build
Copyright (C) 2018 - 2024 BullyWiiPlaza Productions
[2023-09-06 20:09:35.277] [42640] [info] Command line arguments:
[2023-09-06 20:09:35.277] [42640] [info] [0]: UniversalPointerSearcher.exe
[2023-09-06 20:09:35.277] [42640] [info] [1]: --help
[2023-09-06 20:09:35.277] [42640] [info] Parsing command line arguments...
Usage: UniversalPointerSearcher.exe [OPTIONS]

Options:
  -h,--help                   Print this help message and exit
  --verbose                   Whether to perform verbose logging of the pointer searcher output
  --working-directory TEXT    The directory to use as a relative base for resolving file paths
  --initial-file-path TEXT ...
                              The file path to a memory snapshot file to add to the initial input or a folder to parse
  --input-memory-pointers-file-path TEXT
                              The file path memory pointers will be loaded and validated from on all added memory snapshots
  --store-memory-pointers-file-path TEXT
                              The file path to store all memory pointer results to
  --file-extensions TEXT ...  The file extension(s) of the memory snapshot file(s) to add from a folder (requires file names representing the hexadecimal starting address of the memory snapshot file respectively)
  --initial-starting-address TEXT ...
                              The starting address of each memory snapshot file
  --target-address TEXT ...   The target address of the memory snapshot(s)
  --endian TEXT               All memory snapshot file's endian (= byte order)
  --address-size UINT         Every memory snapshot file's address size (in bytes)
  --pointer-address-range TEXT ...
                              The memory snapshot's pointer address range (useful for speeding up slow pointer map parsing). Each range consists of a positive numeric start value, a comma and a positive numeric end value (inclusive).
  --comparison-file-path TEXT ...
                              The file path to a memory snapshot file to add as comparison or a folder to parse
  --comparison-starting-address TEXT ...
                              The starting address of each comparison memory snapshot file
  --scan-deeper-by INT        Specifies how many additional levels of depth the pointer searcher should add to the provided memory pointers, by default 0 (requires an input memory pointers file path).
  --target-pointer-maps TEXT ...
                              The pointer maps to target for writing/reading, must be either "initial" or "comparison"followed by the comparison group number (which starts at 1). You may not skip numbers or provide them in a different order for correct behavior.
  --write-pointer-maps-file-paths TEXT ...
                              The file paths to write the generated pointer maps to
  --compress-pointer-maps BOOLEAN ...
                              Whether to compress the respective written pointer map (default = true)
  --pointer-map-compression-levels INT:INT in [0 - 9] ...
                              The compression levels for generating the pointer maps
  --read-pointer-maps-file-paths TEXT ...
                              The file paths to read the pointer maps from
  --pointer-offset-range TEXT The pointer offset range to use for the pointer search. Each range consists of a potentially negative start value, a comma and a potentially negative end value (inclusive)
  --exclude-cycles BOOLEAN    Whether cycles are excluded in the resulting memory pointers list (reduces redundant results)
  --pointer-depth-range TEXT  The pointer depth range for the pointer search (may yield a lot more results). Each range consists of a positive start value, a comma and a positive end value (inclusive)
  --maximum-pointer-count INT The pointer count where the pointer searcher will stop searching for more
  --last-pointer-offsets TEXT The enforced last pointer offsets of all memory pointers for the pointer search
  --pointer-sorting-type Memory pointer sorting type, one of: (no sorting = 0) | (by address = 1) | (by absolute offset sum and by address = 2) | (by offset count, by absolute offset sum and by address = 3):{0,1,2,3}
                              The memory pointer sorting type to use
  --maximum-pointers-printed-count UINT
                              The maximum amount of pointers printed by the pointer searcher (useful for performance reasons)
  --print-visited-addresses   Whether to print the visited addresses for each discovered memory pointer
  --disable-printing-memory-pointers-to-console
                              Whether to disable printing memory pointers to the console (useful when writing the pointers to an output file)
  --print-module-file-names   Whether the base addresses of memory pointers will be expressed with the module file's file name
  --maximum-memory-utilization-fraction FLOAT:FLOAT in [0 - 1]
                              Whether to stop collecting memory pointers when the RAM is full at least the provided percentage to avoid out of memory crashes
  --target-system TEXT        The system to target, one of "Game Boy", "Game Boy Advance", "Game Boy Color", "Microsoft Windows x64", "Microsoft Windows x86", "NES", "Nintendo 3DS", "Nintendo 64", "Nintendo DS", "Nintendo GameCube", "Nintendo Switch", "Nintendo Wii", "Nintendo Wii U", "Playstation 1", "Playstation 2", "Playstation 3", "Playstation 4", "Playstation 5", "Playstation Portable", "Playstation Vita", "SNES", "Sega CD", "Sega Dreamcast", "Sega Saturn", "Triforce", "Xbox", "Xbox 360", "Xbox One" or "Xbox Series". Simply just a convenience flag for setting the address size and byte order. Therefore, if you try to target a system not listed here, it does NOT mean that it's unsupported, you will have to specify the address size and byte order manually.
  --print-target-system-configurations BOOLEAN
                              Whether to print the configurations of recognized target systems

If you do not pass certain command line options, meaningful defaults will be chosen for you automatically which may or may not be what you wanted.

Command line parsing works via CLI11 so you may want to consult the documentation here if you have any questions on how to pass certain information to the application.

Some pointer searcher demonstration runs can be seen here or for learning in the section below.

Note:

Some of the command line switches may be renamed or changed since the creation of the video so always consult the --help documentation when in doubt.

Examples

The following command line options can be used to perform different use cases. On Windows, you need to type UniversalPointerSearcher.exe followed by the command line flags. On Linux you need to type ./UniversalPointerSearcher instead.

  • Performing a pointer search using 1 initial memory dump and 3 comparison memory dumps:

    --working-directory D:\Cpp\PointerSearcher\test_memory_dumps\mario_kart_8 --initial-file-path 39CEB148.bin --initial-starting-address 0x30000000 --address-size 4 --comparison-file-path 39CF14D8.bin %% 39CF14D8.bin %% 39CF14D8.bin --comparison-starting-address 0x30000000 %% 0x30000000 %% 0x30000000 --endian big --target-address 0x39CEB148 0x39CF14D8 0x39CF14D8 0x39CF14D8
    

    Note that the %% signs separate the memory snapshot file groups respectively. If you don't use them, the pointer searcher will assume you mean 1 memory snapshot with 3 memory snapshot files which would probably yield an error.

  • Validating existing pointers against an initial memory dump and a comparison memory dump, also find pointers with (an) additional depth level(s) and write them to a file:

    --working-directory D:\Cpp\PointerSearcher\test_memory_dumps\mario_kart_8 --input-memory-pointers-file-path MemoryPointers.txt --initial-file-path 39CF14D8.bin --comparison-file-path 39CF14D8.bin --comparison-starting-address 0x30000000 --target-address 0x39CF14D8 0x39CF14D8 --initial-starting-address 0x30000000 --address-size 4 --endian big --scan-deeper-by 2 --store-memory-pointers-file-path MemoryPointersUpdated.txt
    

    Note that the MemoryPointers.txt is a text file containing memory pointers, one per line. An example of such a text file would look like the following:

    [0x86409AFC] + 0x12E4
    [0x80409AFC] + 0x14
    [[0x86409AFC] + 0x14] + 0x10
    

    You can always output all memory pointers found by the pointer searcher into a text file by using the --store-memory-pointers-file-path command line option. The file can then be re-used as input for deeper pointer depth scans via --scan-deeper-by.

  • Performing a pointer search by parsing an entire folder:

    --working-directory D:\Cpp\PointerSearcher\test_memory_dumps\smash_switch_2 -initial-file-path Dump1 --file-extensions bin --target-address 0x5FDF030420 --address-size 8 --endian little
    

    The preconditions for this to work are that all memory snapshot files/modules have to be named by the module name (optional), an underscore (_) and the starting address of that memory snapshot. For example: Heap0000_5F3E000000.bin or 5F3E000000.bin. If you want to specify a different file extension, you may use the respective command line option to do so.

  • Performing a pointer search with multiple memory snapshot files:

    --working-directory D:\Cpp\PointerSearcher\test_memory_dumps\super_mario_galaxy_2 --initial-file-path SB4E01_DUMP80.bin SB4E01_DUMP90.bin --initial-starting-address 0x80000000 0x90000000 --address-size 4 --target-address 0x81458EEC 0x81458EEC --comparison-file-path SB4E01_DUMP80.bin SB4E01_DUMP90.bin --comparison-starting-address 0x80000000 0x90000000 --endian big --pointer-offset-range 0x0,0x400 --pointer-depth-range 1,3 --maximum-pointers-printed-count 1000
    
  • Writing (compressed) pointer maps:

    --working-directory D:\Cpp\PointerSearcher\test_memory_dumps\super_mario_galaxy_2 --initial-file-path SB4E01_DUMP80.bin SB4E01_DUMP90.bin --initial-starting-address 0x80000000 0x90000000 --address-size 4 --target-address 0x81458EEC --endian big --write-pointer-maps-file-paths PointerMap.bin
    
  • Reading/Using (compressed) pointer maps for a pointer search:

    --working-directory D:\Cpp\PointerSearcher\test_memory_dumps\super_mario_galaxy_2 --address-size 4 --target-address 0x81458EEC --read-pointer-maps-file-paths PointerMap.bin
    

Saving/Re-running Searches

Keep in mind that you can write batch/shell scripts in order to save your command line command for re-use later. More information can be found here.

Glossary

For your better understanding of how this tool operates/is meant to be used, here are a few important terms.

  • Memory pointer

    A memory pointer consists of a base address and a variable number of offsets. An example for a memory pointer may be: [[[0x86409AFC] + 0x12E4] + 0x199C] + 0x1A30

    Here, the base address is 0x86409AFC and the offsets are 0x12E4, 0x199C and 0x1A30.

    If you want to follow a memory pointer manually, you need to look up the base address in the memory, take the value stored there, add the 1st offset to that value, look up the value stored at the result, add the 2nd offset, look up the value stored at that result and so on until all offsets have been processed. The final result will then be the destination address. Hopefully, you landed at the right address. Since following pointers manually is tedious, this application offers ways of doing this automatically via its validation mode.

  • Memory dump

    This is a file representing a direct copy of the RAM from a starting address to an end address. Typically it covers the whole memory range or a more relevant fraction of it.

  • Pointer search

    This is the act of finding potentially viable memory pointers based on provided memory dumps.

  • Pointer validation

    In this step, all existing memory pointers are checked against all provided comparison memory snapshots. This means that the pointers will be followed on each comparison memory snapshot and if they do not reach the given target address, the respective pointer will be excluded from the final results.

  • Address

    In computing, an address is an absolute (hexadecimal) number which uniquely specifies a location in memory.

  • Offset

    This is a (hexadecimal) number which is kind of a relative address. It can be added to an address to get somewhere else in memory. Furthermore, offsets in e.g. memory dumps start at 0 but the address at that location may not be 0 (see starting address).

  • Starting address

    This is the address where you started dumping the memory from.

  • Target address

    This is the address you're trying to reach in the pointer search. The amount of provided target addresses must be 1 for each memory snapshot.

  • Memory snapshot file

    This is a memory dump which has a starting address (and a certain length). The end address is of course given by starting address + length.

  • Pointer address range

    This is a range consisting of a starting and an end address. By specifying a range, you can exclude collecting address value pairs outside of that particular range.

  • Memory snapshot

    This is a collection of multiple memory snapshot files which form a complete memory snapshot. On some systems there are different memory regions which have to be dumped specifically, e.g. MEM80 and MEM90 on the Nintendo Wii. On other systems, there may only be 1 contiguous memory region to be dumped, hence the memory snapshot is the same as that file.

    Consequently, memory snapshot can only have 1 target address when performing a pointer search.

  • Endian

    This is the byte order of all memory snapshot files. The endian is fixed and given by the operating system you dumped the memory from. It can either be little or big endian.

  • Address size

    Similar to the endian, the address size is fixed on the system you're dumping memory from. On 32-bit systems the address size is 32-bit, on 64-bit systems the address size is 64-bit and so on. When passing a value for the address size, the value has to be 1 (= 8 bit), 2 (= 16 bit), 4 (= 32 bit) or 8 (= 64 bit). Any other values are invalid.

  • Pointer map

    This is a file containing the address value pairs retrieved from a memory snapshot which have been determined to be viable for a pointer search.

  • Compressed pointer map

    Simply a pointer map which has furthermore been compressed with a compression algorithm to save disc space.

  • Pointer depth range

    This is the range of depth levels to search pointers at which is equivalent to the amount of offsets the resulting memory pointers will have. A pointer depth of 3 will e.g. yield a memory pointer with 3 offsets.

    Note: Using a depth of e.g. 5 or higher could make your RAM usage "explode" due to many pointers being added to the list so be careful when you modify this setting.

  • Pointer offset range

    This is the range of pointer offsets to consider valid. Any offset which happens to be outside of that range will cause the pointer result to be removed from the list of viable memory pointers. It is a good idea to keep the offset range reasonable low to avoid nonsensical pointers with huge offsets to be outputted.

  • Visited addresses

    The visited addresses are the addresses which are visited when following a memory pointer. It is a chain of addresses and the amount of addresses is equal to the base address + the amount of pointer offsets. When excluding cycles, duplicated addresses in the visited addresses chain will cause the respective memory pointer to be excluded.

Anti Virus Problems

If your anti virus marks the pointer searcher as a virus, it's a false positive. The program is protected for security reasons and might cause some anti virus vendors to get worried due to the added protection like packing. There is absolutely no malicious code.

Bug Reports/Feature Requests

If you find a definite bug or a lacking feature, please create a detailed GitHub issue (e.g. with all input and output data as well as error messages if applicable) and I will try to help you out.

Performance Tips

The more pointer depth you are asking for and the more viable pointers are found for the pointer search, the slower it will take. You can try the following measures to improve the performance:

  • Reduce the (upper) pointer depth
  • Reduce the pointer offset range size

The pointer searches with many small memory dump files being added as a unit (memory snapshots) could be sped up as well at the pointer map parsing stage by generating a pointer map. Using compression slows the loading down a bit due to decompression but it will save a lot of disk space.

Contributing

If you appreciate this tool, feel free to donate any amount of money to me on PayPal to support further development and updates.