|
| 1 | +;;;; This file is to organize all the functions which access the memory mappings of the current process |
| 2 | + |
| 3 | +;; Make a standardized format to remember functions by: |
| 4 | +;; -- a range of addresses is called a region. e.g., (- 111222333 777888999) is a region |
| 5 | +;; -- search functions will return a list of addresses (1111 2222 3333 4444 5555 6666) |
| 6 | +;; -- get functions return region(s) |
| 7 | +;; -- snapshot macros return an address value pair |
| 8 | + |
| 9 | +;; [X] removed comparison and parsing function from get-memory-regions function |
| 10 | +;; [X] made a macro to specifically target the heap from a process |
| 11 | +;; [X] make a function to search memory regions for a specific value |
| 12 | +;; [ ] make a function to COMPLETELY stop multi-threaded processes |
| 13 | + |
| 14 | +;; -- Aside/Rants -- |
| 15 | + |
| 16 | +;; I was erroring because my guess is that I was reading too small of address ranges |
| 17 | +;; and when the REPL was trying to convert it to an unsigned bytes it was crashing. Why? great question. |
| 18 | +;; The fix was fixing the value of +CHAR+ from 4 bits to 8 bits. Which it what it was supposed to be but |
| 19 | +;; I can't understand how many bits are in a byte. |
| 20 | + |
| 21 | +;; -- Future -- |
| 22 | + |
| 23 | +;; Actually use this library on a simple program like an emulator |
| 24 | + |
| 25 | +;; Make a function to calculate the displacement of a certain address from the start of the program |
| 26 | +;; and save it to a file |
| 27 | +;; e.g., calculate the displacement for a health variable |
| 28 | + |
| 29 | +(in-package :cl-ptrace) |
| 30 | + |
| 31 | +;; We are counting in bits, not bytes |
| 32 | +(defconstant +CHAR+ (* 8 1)) ; 1 byte |
| 33 | +(defconstant +SHORT+ (* 8 2)) ; 2 bytes |
| 34 | +(defconstant +INTEGER+ (* 8 4)) ; 4 bytes |
| 35 | +(defconstant +LONG+ (* 8 8)) ; 8 bytes |
| 36 | + |
| 37 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 38 | +;; Snapshot Functions |
| 39 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 40 | + |
| 41 | +(defmacro heap-snapshot (&optional (pid *pid*) (read-size +CHAR+)) |
| 42 | + "This function is a short-hand to read and take the snapshot of the heap." |
| 43 | + `(let ((heap-range (get-heap-region ,pid))) |
| 44 | + (if (null heap-range) |
| 45 | + nil |
| 46 | + (collect-address-value-pairs heap-range ,read-size ,pid)))) |
| 47 | + |
| 48 | +(defmacro memory-snapshot (&optional (pid *pid*) (read-size +CHAR+)) |
| 49 | + "This function takes a list of address ranges and then calls collect-address-value-pairs on them." |
| 50 | + `(apply #'append (loop for region in (get-memory-regions ,pid) |
| 51 | + collect (collect-address-value-pairs region ,pid ,read-size)))) |
| 52 | + |
| 53 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 54 | +;; Get Functions |
| 55 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 56 | + |
| 57 | +(defmacro get-heap-region (&optional (pid *pid*)) |
| 58 | + "Parses the memory regions of the process and returns the memory region of the heap" |
| 59 | + `(car (get-memory-regions ,pid #'parse-memory-regions "(heap)"))) |
| 60 | + |
| 61 | +(defun get-memory-regions (&optional (pid *pid*) (parser #'parse-memory-regions) (match-query "([r\-][w\-][x\-]p)")) |
| 62 | + "Reads the /proc/id/maps file and returns all the memory addresses associated with the process" |
| 63 | + (with-open-file (stream (concatenate 'string "/proc/" (write-to-string pid) "/maps")) |
| 64 | + (loop for line = (read-line stream nil) |
| 65 | + while line |
| 66 | + if (cl-ppcre:scan match-query line) ; this is to make sure I'm reading the memory regions that are private and not shared |
| 67 | + collect (funcall parser line)))) |
| 68 | + |
| 69 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 70 | +;; Search Functions |
| 71 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 72 | + |
| 73 | +(defmacro search-all-regions (target-value &optional (pid *pid*) (read-size +CHAR+)) |
| 74 | + "This macro is a short-hands to search every memory region for the target-value" |
| 75 | + `(apply #'append (loop for range in (get-memory-regions ,pid) |
| 76 | + collect (search-region ,target-value range ,pid ,read-size)))) |
| 77 | + |
| 78 | +(defun search-region (target-value region &optional (pid *pid*) (read-size +CHAR+)) |
| 79 | + "This function searches for the target-value in a region of memory addresses and returns a list of addresses who's value matches the target-value." |
| 80 | + (loop for n from 0 to (/ (- (cadr region) (car region)) read-size) |
| 81 | + for mem-value = (peekdata (+ (car region) (* n read-size)) pid nil nil) |
| 82 | + if (= target-value mem-value) |
| 83 | + collect (+ (car region) (* n read-size)))) |
| 84 | + |
| 85 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 86 | +;; Miscellaneous Functions |
| 87 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 88 | + |
| 89 | +(defun collect-address-value-pairs (region &optional (pid *pid*) (read-size +CHAR+)) |
| 90 | + "This function searches each memory address and returns it and its corresponding value." |
| 91 | + (loop for n from 0 to (/ (- (cadr region) (car region)) read-size) |
| 92 | + collect (list (+ (car region) (* n read-size)) (peekdata (+ (car region) (* n read-size)) pid nil nil)))) |
| 93 | + |
| 94 | +(defmacro print-memory-regions (&optional (pid *pid*) (read-size +CHAR+)) |
| 95 | + "This function prints the number of addresses in each address range: [a, b]. Including a proper (- a b) form" |
| 96 | + `(let ((list-regions (get-memory-regions ,pid))) |
| 97 | + (format t "Read size: ~D bits~%" ,read-size) |
| 98 | + (loop for region in list-regions |
| 99 | + do (format t "(- ~D ~D) >> ~D Addrs~%" (car region) (cadr region) (/ (- (cadr region) (car region)) ,read-size))) |
| 100 | + t)) |
| 101 | + |
| 102 | +(defun num-addresses (&optional (pid *pid*) (read-size +CHAR+)) |
| 103 | + "Sums the amount of addresses used by the process" |
| 104 | + (let ((mappings (get-memory-regions pid))) |
| 105 | + (apply #'+ (loop for region in mappings |
| 106 | + collect (/ (- (cadr region) (car region)) read-size))))) |
| 107 | + |
| 108 | +(defun parse-memory-regions (string) |
| 109 | + "Function built to parse the /proc/id/maps file" |
| 110 | + (mapcar #'(lambda (x) (parse-integer x :radix 16)) (cl-ppcre:split "\-" (car (cl-ppcre:split "\\s+" string))))) |
0 commit comments