scanmem examples - scanmem/scanmem GitHub Wiki

Description of scanmem

man scanmem should be tried first to get a brief overview of what(and how) scanmem works.

Scanmems interactive mode

scanmem was intended to be used interactive therefore it behaves different than other programs. Which means you normally stay within scanmem to look for values or changing data types until you exit the program. There is a way to call scanmem using scripting but this will be explained further down.

You have to keep in mind that due to its access to various memory regions it is necessary to run scanmem using root privileges. Without this privileges scanmem can not access the memory. Usually you would use sudo scanmem to run it with root privileges. But scanmem does not know which process you want to examine at this moment! Type pid 1234(within scanmem) to tell the correct process id(1234 is just an example pid!).

You could also run scanmem right from the start with sudo scanmem 1234 (1234 is an example pid!).

If you dont know a pid yet you can search using ps aux in the console. There will be plenty pids shown, but you can narrow your search using grep: ps aux | grep firefox would narrow the search down to all firefox processes.

username 2759 6.1 4.3 9638284 715996 ? Sl 13:45 12:51 /usr/lib/firefox-esr/firefox-esr

In this case the process id would be 2759 for firefox. sudo scanmem 2759 would now run scanmem attached to process id 2759(firefox).

Commands in interactive mode of scanmem

option set runtime options of scanmem, see help option write change the value of a specific memory location dump dump a memory region to screen or a file show display information about scanmem. watch monitor the value of a memory location as it changes shell execute a shell command without leaving scanmem help access online documentation, use help command for specific help exit exit the program immediately update update match values without culling list " match a given string(watch the space after the quotation mark!!) - match values that have decreased at all or by some number + match values that have increased at all or by some number > match values that have increased or greater than some number < match values that have decreased or less than some number != match values that have changed or different from some number = match values that have not changed or equal to some number version print current version lregions list all known regions dregion delete a known region by region-id snapshot take a snapshot of the current process state pid print current pid, or attach to a new process reset forget all matches, and reinitialise regions delete delete known matches by match-id list list currently known matches set change known matches to specified value

The option commands..

  • option scan_data_type int data type set to integer of any width default
  • option scan_data_type number data type set to integer or float
  • option scan_data_type float data type set to float of any width
  • option scan_data_type int8 data type set to int8
  • option scan_data_type int16 data type set to int16
  • option scan_data_type int32 data type set to int32
  • option scan_data_type int64 data type set to int64
  • option scan_data_type float32 data type set to float32
  • option scan_data_type float64 data type set to float64
  • option scan_data_type bytearray data type set to bytearray
  • option scan_data_type string data type set to string

MOST OF TIME YOU MUST EXECUTE `reset' IMMEDIATELY AFTER CHANGING scan_data_type

  • option region_scan_level 1 scans heap, stack and executable only

  • option region_scan_level 2 heap, stack executable and bss only default

  • option region_scan_level 3 scans everything(e.g. other libs) (increases chances of crashing)

  • option dump_with_ascii 1 whether to print ascii characters with a memory dump (1=y/0=n)

  • option endianness 0 endianness of data(host endian) default

  • option endianness 1 endianness of data(little endian)

  • option endianness 2 endianness of data(big endian)

Obviously this was taken from the interactive help command but it may be better to read this way.

Accessing scanmem using scripting

We can use a script with the following line to set the data type to string and then search for the string Gandalf the grey, list all possible hits and exit the interactive mode. The $procid has to be replaced by the correct pid first!

sudo scanmem -p $procid -e -c 'option scan_data_type string;" Gandalf the grey;list;exit'

Another example while searching for an array of bytes(for a guy named Marcus) encoded in hex, the string is zero terminated and an exclamation mark follows for uniquifying.. Screen output piped to test.dat for further processing:

sudo scanmem -p $procid -e -c 'option scan_data_type bytearray;4D 61 72 63 75 73 00 21;list;exit'>test.dat

Even with proper command usage there may be the following error message: (Fixed since 20-nov-2020)

info: we currently have 1 matches.
info: match identified, use "set" to modify value.
info: enter "help" for other commands.
1> list
warn: handler__list(): couldn't get terminal size.
warn: get_pager(): couldn't get $PAGER, falling back to `more`
1> exit

But the contempt of test.dat is as desired so we can safely ignore those error message.

[ 0] 908f35, 8 + 441f35, misc, 4d 61 72 63 75 73 00 21, [bytearray]

But the given array of bytes 4D 61 72 63 75 73 00 21 has been changed by scanmems output to 4d 61 72 63 75 73 00 21. Precisely any letter changes to lower case(4D -> 4d). So we must convert the search pattern to lower cases directly before using grep . In this example the variable SEARCH_AOB (4D 61 72 63 75 73 00 21) is being used. (This line must be removed if scanmem returns upper case letters only in the future)

SEARCH_AOB="$(echo $SEARCH_AOB | tr '[A-Z]' '[a-z]')"

And the last line should then do the magic to store the address of the matching bytearray in base_hex:

base_hex=`cat test.dat | grep -m 1 "$SEARCH_AOB" | awk '{print $3}' | tr -d ','`

Explanation: cat prints the contempt of test.dat to standard output, grep then searches for the first appearance of SEARCH_AOB(4d 61 72 63 75 73 00 21), awk cuts anything except the third "colon" away and finally tr gets rid of the , so we get a clean address stored in base_hex(908f35).

Which still is unusable until we convert it from hex to decimal:

BASE_ADDRESS_HEX="0x$base_hex"
BASE_ADDRESS_DEC=$(printf "%d\n" $BASE_ADDRESS_HEX)

We could shorten the script commands further down but then only geeks would understand them..

I wanted to use the variable SEARCH_AOB(4d 61 72 63 75 73 00 21) in the script but unfortunately it turned out that the shell does not want it that way. While the following line DOES work as intended..

base_hex=`cat mm6.dat | grep -m 1 "$SEARCH_AOB" | awk '{print $3}' | tr -d ','`

none of them works due to encapsulation ':

sudo scanmem -p $procid -e -c 'option scan_data_type bytearray;$SEARCH_AOB;list;exit'>mm6.dat
sudo scanmem -p $procid -e -c 'option scan_data_type bytearray;$((SEARCH_AOB));list;exit'>mm6.dat
sudo scanmem -p $procid -e -c 'option scan_data_type bytearray;$[ SEARCH_AOB ];list;exit'>mm6.dat

So I have to enter the bytearry manually everytime it changes :tired_face: