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 defaultoption scan_data_type number
data type set to integer or floatoption scan_data_type float
data type set to float of any widthoption scan_data_type int8
data type set to int8option scan_data_type int16
data type set to int16option scan_data_type int32
data type set to int32option scan_data_type int64
data type set to int64option scan_data_type float32
data type set to float32option scan_data_type float64
data type set to float64option scan_data_type bytearray
data type set to bytearrayoption 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: