-
-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add feature dump memory of application
- Loading branch information
Showing
5 changed files
with
254 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import os | ||
import logging | ||
|
||
# Reading bytes from session and saving it to a file | ||
|
||
def dump_to_file(agent,base,size,error,directory): | ||
try: | ||
filename = str(base)+'_dump.data' | ||
dump = agent.read_memory(base, size) | ||
f = open(os.path.join(directory,filename), 'wb') | ||
f.write(dump) | ||
f.close() | ||
return error | ||
except Exception as e: | ||
logging.debug("[!]"+str(e)) | ||
print("Oops, memory access violation!") | ||
return error | ||
|
||
#Read bytes that are bigger than the max_size value, split them into chunks and save them to a file | ||
|
||
def splitter(agent,base,size,max_size,error,directory): | ||
times = size/max_size | ||
diff = size % max_size | ||
if diff is 0: | ||
logging.debug("Number of chunks:"+str(times+1)) | ||
else: | ||
logging.debug("Number of chunks:"+str(times)) | ||
global cur_base | ||
cur_base = int(base,0) | ||
|
||
for time in range(int(times)): | ||
logging.debug("Save bytes: "+str(cur_base)+" till "+str(cur_base+max_size)) | ||
dump_to_file(agent, cur_base, max_size, error, directory) | ||
cur_base = cur_base + max_size | ||
|
||
if diff is not 0: | ||
logging.debug("Save bytes: "+str(hex(cur_base))+" till "+str(hex(cur_base+diff))) | ||
dump_to_file(agent, cur_base, diff, error, directory) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
import textwrap | ||
import frida | ||
import os | ||
import sys | ||
import frida.core | ||
import dumper | ||
import utils | ||
import argparse | ||
import logging | ||
|
||
logo = """ | ||
______ _ _ | ||
| ___| (_) | | | ||
| |_ _ __ _ __| |_ _ _ __ ___ _ __ | ||
| _| '__| |/ _` | | | | '_ ` _ \| '_ \\ | ||
| | | | | | (_| | |_| | | | | | | |_) | | ||
\_| |_| |_|\__,_|\__,_|_| |_| |_| .__/ | ||
| | | ||
|_| | ||
""" | ||
|
||
|
||
# Main Menu | ||
def MENU(): | ||
parser = argparse.ArgumentParser( | ||
prog='dump-memory', | ||
formatter_class=argparse.RawDescriptionHelpFormatter, | ||
description=textwrap.dedent("")) | ||
|
||
# parser.add_argument('process', | ||
# help='the process that you will be injecting to') | ||
parser.add_argument('-o', '--out', type=str, metavar="dir", | ||
help='provide full output directory path. (def: \'memory-dump\')') | ||
parser.add_argument('-U', '--usb', action='store_true', | ||
help='device connected over usb') | ||
parser.add_argument('-v', '--verbose', action='store_true', | ||
help='verbose') | ||
parser.add_argument('-r', '--read-only', action='store_true', | ||
help="dump read-only parts of memory. More data, more errors") | ||
parser.add_argument('-s', '--strings', action='store_true', | ||
help='run strings on all dump files. Saved in output dir.') | ||
parser.add_argument('--max-size', type=int, metavar="bytes", | ||
help='maximum size of dump file in bytes (def: 20971520)') | ||
args = parser.parse_args() | ||
return args | ||
|
||
|
||
#print(logo) | ||
|
||
arguments = MENU() | ||
|
||
# Define Configurations | ||
APP_NAME = arguments.process | ||
DIRECTORY = "" | ||
USB = arguments.usb | ||
DEBUG_LEVEL = logging.INFO | ||
STRINGS = arguments.strings | ||
MAX_SIZE = 20971520 | ||
PERMS = 'rw-' | ||
|
||
if arguments.read_only: | ||
PERMS = 'r--' | ||
|
||
if arguments.verbose: | ||
DEBUG_LEVEL = logging.DEBUG | ||
logging.basicConfig(format='%(levelname)s:%(message)s', level=DEBUG_LEVEL) | ||
|
||
|
||
# Start a new Session | ||
session = None | ||
try: | ||
if USB: | ||
session = frida.get_usb_device().attach(APP_NAME) | ||
else: | ||
session = frida.attach(APP_NAME) | ||
except Exception as e: | ||
print("Can't connect to App. Have you connected the device?") | ||
logging.debug(str(e)) | ||
sys.exit() | ||
|
||
|
||
# Selecting Output directory | ||
if arguments.out is not None: | ||
DIRECTORY = arguments.out | ||
if os.path.isdir(DIRECTORY): | ||
print("Output directory is set to: " + DIRECTORY) | ||
else: | ||
print("The selected output directory does not exist!") | ||
sys.exit(1) | ||
|
||
else: | ||
print("Current Directory: " + str(os.getcwd())) | ||
DIRECTORY = os.path.join(os.getcwd(), "memory-dump") | ||
print("Output directory is set to: " + DIRECTORY) | ||
if not os.path.exists(DIRECTORY): | ||
print("Creating directory...") | ||
os.makedirs(DIRECTORY) | ||
|
||
mem_access_viol = "" | ||
|
||
print("Starting Memory dump...") | ||
|
||
script = session.create_script( | ||
"""'use strict'; | ||
rpc.exports = { | ||
enumerateRanges: function (prot) { | ||
return Process.enumerateRangesSync(prot); | ||
}, | ||
readMemory: function (address, size) { | ||
return Memory.readByteArray(ptr(address), size); | ||
} | ||
}; | ||
""") | ||
script.on("message", utils.on_message) | ||
script.load() | ||
|
||
agent = script.exports | ||
ranges = agent.enumerate_ranges(PERMS) | ||
|
||
if arguments.max_size is not None: | ||
MAX_SIZE = arguments.max_size | ||
|
||
i = 0 | ||
l = len(ranges) | ||
|
||
# Performing the memory dump | ||
for range in ranges: | ||
base = range["base"] | ||
size = range["size"] | ||
|
||
logging.debug("Base Address: " + str(base)) | ||
logging.debug("") | ||
logging.debug("Size: " + str(size)) | ||
|
||
|
||
if size > MAX_SIZE: | ||
logging.debug("Too big, splitting the dump into chunks") | ||
mem_access_viol = dumper.splitter( | ||
agent, base, size, MAX_SIZE, mem_access_viol, DIRECTORY) | ||
continue | ||
mem_access_viol = dumper.dump_to_file( | ||
agent, base, size, mem_access_viol, DIRECTORY) | ||
i += 1 | ||
utils.printProgress(i, l, prefix='Progress:', suffix='Complete', bar=50) | ||
print("") | ||
|
||
# Run Strings if selected | ||
|
||
if STRINGS: | ||
files = os.listdir(DIRECTORY) | ||
i = 0 | ||
l = len(files) | ||
print("Running strings on all files:") | ||
for f1 in files: | ||
utils.strings(f1, DIRECTORY) | ||
i += 1 | ||
utils.printProgress(i, l, prefix='Progress:', suffix='Complete', bar=50) | ||
print("Finished!") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import sys | ||
import string | ||
import logging | ||
import os | ||
import re | ||
from io import open | ||
|
||
# Progress bar function | ||
def printProgress (times, total, prefix ='', suffix ='', decimals = 2, bar = 100): | ||
filled = int(round(bar * times / float(total))) | ||
percents = round(100.00 * (times / float(total)), decimals) | ||
bar = '#' * filled + '-' * (bar - filled) | ||
sys.stdout.write('%s [%s] %s%s %s\r' % (prefix, bar, percents, '%', suffix)), | ||
sys.stdout.flush() | ||
if times == total: | ||
print("\n") | ||
|
||
|
||
# A very basic implementations of Strings | ||
def strings(filename, directory, min=4): | ||
strings_file = os.path.join(directory, "strings.txt") | ||
path = os.path.join(directory, filename) | ||
with open(path, encoding='Latin-1') as infile: | ||
str_list = re.findall("[\x20-\x7E]+\x00", infile.read()) | ||
with open(strings_file, "a") as st: | ||
for string in str_list: | ||
if len(string) > min: | ||
logging.debug(string) | ||
st.write(string + "\n") | ||
|
||
# Method to receive messages from Javascript API calls | ||
def on_message(message, data): | ||
print("[on_message] message:", message, "data:", data) |