Nightbringer21 / fridump

A universal memory dumper using Frida
753 stars 139 forks source link

Error to Enumerate Memory Ranges #12

Closed georgepetz closed 6 years ago

georgepetz commented 6 years ago

Hi, I tried to make memory dump from my iPhone and the follow message was showed: Current Directory: c:\fridump Output directory is set to: c:\fridump\dump Starting Memory dump... Traceback (most recent call last): File "fridump.py", line 101, in Memories = session.enumerate_ranges(PERMS) AttributeError: 'Session' object has no attribute 'enumerate_ranges'

It's sounds like a problem with frida, but I couldn't solve that by myself.

The version of frida and frida-server is 12.0.3

Nightbringer21 commented 6 years ago

Hi georgepetz,

This appears to be an issue introduced today due to some changes implemented on Frida 12. (https://www.frida.re/news/2018/07/12/frida-12-0-released/)

Unfortunately I am not able to make the appropriate changes for a couple of days, so I would suggest downgrading to Frida version 11 for the moment.

I will try to debug the issue soon and update accordingly. Sorry for the inconvenience.

georgepetz commented 6 years ago

Hi Night

I talked with André (developer of Frida) and he helped me with some adjustments on fridump.

If I obtain success on the implementation, I will forward the code for your revision and, if you like, you can pull the code!

Thanks for replay, I consider fridump one of the best tool to memory dump!

Regards, George.

On Thu, Jul 12, 2018, 21:07 Nightbringer21 notifications@github.com wrote:

Hi georgepetz,

This appears to be an issue introduced today due to some changes implemented on Frida 12. ( https://www.frida.re/news/2018/07/12/frida-12-0-released/)

Unfortunately I am not able to make the appropriate changes for a couple of days, so I would suggest downgrading to Frida version 11 for the moment.

I will try to debug the issue soon and update accordingly. Sorry for the inconvenience.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Nightbringer21/fridump/issues/12#issuecomment-404687275, or mute the thread https://github.com/notifications/unsubscribe-auth/ATTkIwA5N7PXHEO_Wc1zrKqmMl036bXmks5uF-TSgaJpZM4VNDae .

georgepetz commented 6 years ago

HI Night,

I was able to finish the code adjustments for integration with the new version of Frida (12) and python 3.

I am not familiar with git, however follow the classes modified by me.

I'm not sure if the mode that I handle with encode on "utils.py" (line 25) is correctly, but I tested sometimes and didn't give me an error.

I hope this is help the community!

Regards, George Petz.

On Thu, Jul 12, 2018 at 9:14 PM George Petz petz.george@gmail.com wrote:

Hi Night

I talked with André (developer of Frida) and he helped me with some adjustments on fridump.

If I obtain success on the implementation, I will forward the code for your revision and, if you like, you can pull the code!

Thanks for replay, I consider fridump one of the best tool to memory dump!

Regards, George.

On Thu, Jul 12, 2018, 21:07 Nightbringer21 notifications@github.com wrote:

Hi georgepetz,

This appears to be an issue introduced today due to some changes implemented on Frida 12. ( https://www.frida.re/news/2018/07/12/frida-12-0-released/)

Unfortunately I am not able to make the appropriate changes for a couple of days, so I would suggest downgrading to Frida version 11 for the moment.

I will try to debug the issue soon and update accordingly. Sorry for the inconvenience.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Nightbringer21/fridump/issues/12#issuecomment-404687275, or mute the thread https://github.com/notifications/unsubscribe-auth/ATTkIwA5N7PXHEO_Wc1zrKqmMl036bXmks5uF-TSgaJpZM4VNDae .

import sys import string import logging import os import re

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: strlist = re.findall("[A-Za-z0-9/-:;.,$%'!()[]<> #]+", 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")

Normalize thw namo of application works better on frida

def normalize_app_name(appName: str): try: appName = int(appName) except ValueError: pass return appName

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(times):
            # logging.debug("Save bytes: "+str(cur_base)+" till "+str(hex(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)

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='fridump', 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, help='provide full output directory path. (def: \'dump\')',
                    metavar="dir")
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, help='maximum size of dump file in bytes (def: 20971520)',
                    metavar="bytes")
args = parser.parse_args()
return args

print(logo)

arguments = MENU()

Define Configurations

APP_NAME = utils.normalize_app_name(appName=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(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(), "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...")

def on_message(message, data): print("[on_message] message:", message, "data:", data)

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", 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: logging.debug("Base Address: " + str(range["base"])) logging.debug("") logging.debug("Size: " + str(range["size"])) if range["size"] > MAX_SIZE: logging.debug("Too big, splitting the dump into chunks") mem_access_viol = dumper.splitter( agent, range["base"], range["size"], MAX_SIZE, mem_access_viol, DIRECTORY) continue mem_access_viol = dumper.dump_to_file( agent, range["base"], range["size"], mem_access_viol, DIRECTORY) i += 1 utils.printProgress(i, l, prefix='Progress:', suffix='Complete', bar=50)

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!")

raw_input('Press Enter to exit...')

AlexKoshulyan commented 6 years ago

Thanks, the fixe attached into the comment helped me!

decidedlygray commented 6 years ago

Until a PR for the above is submitted, to just install an older version of frida:

pip uninstall frida
pip install -Iv frida==11.0.10
bihihinok commented 6 years ago

Yup, this worked for me too .

Thanks @georgepetz

moorer2k commented 6 years ago

Modifications worked for me also @georgepetz. Thanks.

Nightbringer21 commented 6 years ago

I have just pushed the changes to the repository. @georgepetz thank you very much for the contribution.

I will close the issue, but if any further updates are required or something is not working as expected, feel free to reopen it.