Esempio n. 1
0
def memToLvl(address, levelId = None):
    refTableAddr = idc.LocByName("levelReferenceTable")
    if refTableAddr == BADADDR:
        print("Can't get level reference table address. Make sure its name is levelReferenceTable.")
        return
    
    if levelId == None:
        endTableAddr = idc.LocByName("levelEndTable")
        if endTableAddr == BADADDR:
            print("Can't get level end table address. Make sure its name is levelEndTable.")
            return

        lvl0StartAddr = idc.Dword(refTableAddr)
        lvl1StartAddr = idc.Dword(refTableAddr + 4)

        lvl0EndAddr = idc.Dword(endTableAddr) 
        lvl1EndAddr = idc.Dword(endTableAddr + 4)

        if address >= lvl0StartAddr and address <= lvl0EndAddr:
            fileRelativeAddr = address - lvl0StartAddr 
            idc.Message("Fix.lvl relative address: 0x" + format(fileRelativeAddr, '02X') + "\n")
            return

        if address >= lvl1StartAddr and address <= lvl1EndAddr:
            fileRelativeAddr = address - lvl1StartAddr 
            idc.Message("Actual level relative address: 0x" + format(fileRelativeAddr, '02X') + "\n")
            return

        idc.Message("ERROR: This address does not belong to any level file.")
    else:
        lvlStartAddr = idc.Dword(refTableAddr + levelId * 4)
        fileRelativeAddr = address - lvlStartAddr

        idc.Message("Address relative to file: 0x" + format(fileRelativeAddr, '02X') + "\n") 
Esempio n. 2
0
 def toggle_auto_rebase_push(self, *args):
     if self.repo_manager.repo_auto_sync:
         self.repo_manager.repo_auto_sync = False
         idc.Message('Auto rebase/push disabled')
     else:
         self.repo_manager.repo_auto_sync = True
         idc.Message('Auto rebase/push enabled')
Esempio n. 3
0
 def _do_run(self):
     try:
         super(BapIda, self).run()
         BapIda.instances.append(self)
         idaapi.register_timer(self.poll_interval_ms, self.update)
         idc.SetStatus(idc.IDA_STATUS_THINKING)
         self.run_handlers('instance_created')
         idc.Message("BAP> created new instance with PID {0}\n".format(
             self.proc.pid))
     except:  # pylint: disable=bare-except
         idc.Message("BAP> failed to create instance\nError: {0}\n".format(
             str(sys.exc_info()[1])))
         traceback.print_exc()
Esempio n. 4
0
    def __init__(self, symbols=True):
        try:
            check_and_configure_bap()
        except:
            idc.Message('BAP> configuration failed\n{0}\n'.format(
                str(sys.exc_info())))
            traceback.print_exc()
            raise BapIdaError()
        bap = config.get('bap_executable_path')
        if bap is None or not os.access(bap, os.X_OK):
            idc.Warning('''
            The bap application is either not found or is not an executable.
            Please install bap or, if it is installed, provide a path to it.
            Installation instructions are available at: http://bap.ece.cmu.edu.
            ''')
            raise BapNotFound()
        binary = idaapi.get_input_file_path()
        super(BapIda, self).__init__(bap, binary)
        # if you run IDA inside IDA you will crash IDA
        self.args.append('--no-ida')
        self._on_finish = []
        self._on_cancel = []
        self._on_failed = []
        if symbols:
            self._setup_symbols()

        headers = config.is_set('ida_api.enabled')

        if headers:
            self._setup_headers(bap)
Esempio n. 5
0
def ida_main():
    import idc

    filepath = idc.AskFile(0, "*.map", "Load a Dolphin emulator symbol map")
    if filepath is None:
        return
    symbol_map = load_dolphin_map(filepath)

    for symbol in symbol_map:
        addr = int(symbol.vaddr, 16)
        size = int(symbol.size, 16)
        idc.MakeUnknown(addr, size, 0)
        if symbol.section in [".init", ".text"]:
            idc.MakeCode(addr)
            success = idc.MakeFunction(
                addr, idc.BADADDR if not size else (addr + size))
        else:
            success = idc.MakeData(addr, idc.FF_BYTE, size, 0)

        if not success:
            idc.Message("Can't apply properties for symbol:"
                        " {0.vaddr} - {0.name}\n".format(symbol))

        flags = idc.SN_NOCHECK | idc.SN_PUBLIC
        if symbol.name.startswith("zz_"):
            flags |= idc.SN_AUTO | idc.SN_WEAK
        else:
            flags |= idc.SN_NON_AUTO
        idc.MakeNameEx(addr, symbol.name, flags)
Esempio n. 6
0
    def _launch(self, debug):
        start = time.time()
        idc.Message('Launching %s/%s... ' %
                    (self.packageName, self.launchActivity))

        args = [
            'shell', 'am', 'start', '-n',
            self.packageName + '/' + self.launchActivity, '-W'
        ]
        if debug:
            args.append("-D")

        proc = self.adb.call(args,
                             stderr=subprocess.PIPE,
                             async=True,
                             preexec_fn=utils.androidServerPreExec)

        def watchdog():
            time.sleep(15)
            if proc.poll() is None:  # still running
                proc.terminate()

        (threading.Thread(target=watchdog)).start()

        for _ in range(50):
            pid, _ = self._getPid(with_service=False)
            if pid is not None:
                break
            time.sleep(0.2)
        print "Done in %s seconds" % (time.time() - start)
Esempio n. 7
0
    def emit(self, record):
        """Emit a log record into IDA's output window.

        Args:
            record (LogRecord): a logging.LogRecord instance
        """
        idc.Message("%s\n" % (super(IdaLogHandler, self).format(record)))
Esempio n. 8
0
 def export_single_cache(self, *args):
     logger.info("Exporting database using one core")
     if not os.path.isdir("database"):
         os.mkdir("database")
     exporter = ya.MakeFlatBufferExporter()
     ya.MakeModel(self.hash_provider).accept(exporter)
     with open("database/database.yadb", "wb") as fh:
         fh.write(exporter.GetBuffer())
     idc.Message("Export complete.")
Esempio n. 9
0
    def install_callback(cls, callback_fn):
        """
        Install callback to be run when the user calls for BAP execution.

        Callback must take a dict and must return nothing.

        Dict is guaranteed to get the following keys:
            'ea': The value of EA at point where user propagated taint from.
        """
        idc.Message('a callback is installed\n')
        cls._callbacks.append(callback_fn)
Esempio n. 10
0
 def update(self):
     if all(bap.finished() for bap in BapIda.instances):
         idc.SetStatus(idc.IDA_STATUS_READY)
     if self.finished():
         if self.proc.returncode == 0:
             self.run_handlers('instance_finished')
             self.close()
             idc.Message("BAP> finished " + self.action + '\n')
         elif self.proc.returncode > 0:
             self.run_handlers('instance_failed')
             self.close()
             idc.Message("BAP> an error has occured while {0}\n".format(
                 self.action))
         else:
             if not self.closed:
                 self.run_handlers('instance_canceled')
             idc.Message("BAP> was killed by signal {0}\n".format(
                 -self.proc.returncode))
         return -1
     else:
         self.run_handlers('instance_updated')
         return self.poll_interval_ms
Esempio n. 11
0
 def run(self):
     "run BAP instance"
     if len(BapIda.instances) > 0:
         answer = idaapi.askyn_c(
             idaapi.ASKBTN_YES,
             "Previous instances of BAP didn't finish yet.\
             Do you really want to start a new one?".format(
                 len(BapIda.instances)))
         if answer == idaapi.ASKBTN_YES:
             self._do_run()
     else:
         self._do_run()
     idc.Message("BAP> total number of running instances: {0}\n".format(
         len(BapIda.instances)))
Esempio n. 12
0
def print_stats(bb_coverage):
    total_bbs = bb_coverage['stats']['total_basic_blocks']
    covered_bbs = bb_coverage['stats']['covered_basic_blocks']

    # Calculate the coverage percentage to avoid divide-by-zero
    if total_bbs:
        percent_str = '{:.1%}'.format(covered_bbs / total_bbs)
    else:
        percent_str = '-%'

    idc.Message(
        COVERAGE_MESSAGE.format(num_bbs=total_bbs,
                                num_covered_bbs=covered_bbs,
                                percent=percent_str))
    def init(self):
        architecture = utils.getIdaArchitecture()
        if architecture != "arm":
            print "%s unsupported architecture: %s" % (self.wanted_name,
                                                       architecture)
            return idaapi.PLUGIN_SKIP

        idc.Message("Initializing %s\n" % self.wanted_name)

        from aaf import adb
        wrapper = adb.AdbWrapper(ADB_PATH)

        from aaf import AndroidAttacher
        utilsJar = os.path.join(get_plugin_home(), "aaf", "utils.jar")
        config_file = os.path.splitext(idc.GetIdbPath())[0] + ".aaf.conf"
        self.androidAttacher = AndroidAttacher(wrapper, utilsJar, config_file)
        return idaapi.PLUGIN_KEEP
Esempio n. 14
0
 def run(self, arg):
     comms = {}
     for addr in ida.addresses():
         comm = idaapi.get_cmt(addr, 0)
         if comm:
             try:
                 parsed = bap_comment.parse(comm)
                 if parsed:
                     for (name, data) in parsed.items():
                         comms[(addr, name)] = data
             except:
                 idc.Message("BAP> failed to parse string {0}\n{1}".format(
                     comm, str(sys.exc_info()[1])))
     comms = [(name, addr, data) for ((addr, name), data) in comms.items()]
     attrs = Attributes(comms)
     choice = attrs.Show(modal=True)
     if choice >= 0:
         idc.Jump(comms[choice][1])
Esempio n. 15
0
def ReadString(ea):
    """
    Interprets ea as either an address or an ordinal and loads the string it points to accordingly.
    :param ea: address or ordinal of the string to be read
    :return: a string if the address or ordinal was valid
    """

    # Check if the address is within the module bounds.
    if ea == 0:
        return ""
    elif ea > g_BaseAddress:
        # The string is located in the module, read a null terminated string.
        return idc.GetString(ea)
    else:
        # The string is located in the h2alang.dll module.
        string = ctypes.create_string_buffer(500)
        if g_user32Dll.LoadStringA(g_h2langDll._handle, ea, string, 500) is 0:
            # Failed to load the string from the dll.
            idc.Message("Failed to load string %d from h2lang module!" % ea)

        # Return the string buffer.
        return string.value
Esempio n. 16
0
    def run_handlers(self, event):
        assert event in self.observers
        handlers = []
        instance_handlers = {
            'instance_canceled': self._on_cancel,
            'instance_failed': self._on_failed,
            'instance_finished': self._on_finish,
        }

        handlers += self.observers[event]
        handlers += instance_handlers.get(event, [])

        failures = 0
        for handler in handlers:
            try:
                handler(self)
            except:  # pylint: disable=bare-except
                failures += 1
                idc.Message("BAP> {0} failed because {1}\n".format(
                    self.action, str(sys.exc_info()[1])))
                traceback.print_exc()
        if failures != 0:
            idc.Warning("Some BAP handlers failed")
def main():
    #print('INF_VERSION:  %s' % (str(idc.GetLongPrm(idc.INF_VERSION))))
    #print('INF_PROCNAME: %s' % (str(idc.GetLongPrm(idc.INF_PROCNAME))))
    #print('INF_COMPILER: %s' % (str(idc.GetLongPrm(idc.INF_COMPILER))))
    #print('INF_FILETYPE: %s' % (str(idc.GetLongPrm(idc.INF_FILETYPE))))

    processor = str(idc.GetLongPrm(idc.INF_PROCNAME))

    is_x86 = processor == 'metapc'
    is_ARM = processor == 'ARM'

    if not is_x86:
        idc.Message('*** Sorry, currently only supported x86.\n')
        return

    def_struct()
    load_metadata()

    #return

    code_reg, meta_reg = analyze_reg()

    if code_reg != idc.BADADDR:
        analyze_code_reg(code_reg)

    if meta_reg != idc.BADADDR:
        analyze_meta_reg(meta_reg, code_reg)

    init_array = analyze_init_array()
    analyze_invoke_unityengine()
    analyze_invoke_library()

    print('%X: INIT_IL2CPP' % (idc.LocByName('INIT_IL2CPP')))
    print('%X: %s' % (code_reg, idc.Name(code_reg)))
    print('%X: %s' % (meta_reg, idc.Name(meta_reg)))
    print('%X: .init_array' % (init_array))
Esempio n. 18
0
def log(string, *argv):
    '''idc.Message(formatstring, ...)'''
    return idc.Message('>' + string % argv + '\n')
Esempio n. 19
0
            idc.Message('as non-root... ')
            androidServerArgs = ['shell', 'run-as', pkg, androidServerPath]
            androidServerArgs.extend(args)
            (androidServerProc, port, androidServerRunAsOut) = runAndroidServer(androidServerArgs)
    
        if not androidServerProc:
            idc.Message('in pkg dir... ')
            pkgAndroidServerPath = '/data/data/' + pkg + '/files/android_server'
            self.adb.call(['shell', 'run-as', pkg, 'cp', androidServerPath, pkgAndroidServerPath])
            self.adb.call(['shell', 'run-as', pkg, 'chmod', '755', pkgAndroidServerPath])
            androidServerArgs = ['shell', 'run-as', pkg, pkgAndroidServerPath] + args
            (androidServerProc, port, androidServerPkgRunAsOut) = runAndroidServer(androidServerArgs)
        '''

        if not androidServerProc:
            idc.Message('as root... ')
            (androidServerProc, port, androidServerSuOut) = runAndroidServer([
                'shell', 'su', '-c',
                '"' + " ".join([androidServerPath] + args) + '"'
            ])
        '''
        if not androidServerProc:
            idc.Message('in pkg dir... ')
            (androidServerProc, port, androidServerPkgSuOut) = runAndroidServer(['shell', 'su', '-c', '"' + " ".join([pkgAndroidServerPath] + args) + '"'])
        '''

        if not androidServerProc:
            '''
            print ''
            print '"run-as" output:'
            print ' ' + '\n '.join([s for s in androidServerRunAsOut if s]).replace('\0', '')
Esempio n. 20
0
class AndroidAttacher(object):
    def __init__(self, wrapper, utilsJar, config_file):
        self.packageName = None
        self.launchActivity = None
        self.android_server = None
        self.device = None
        self.adb = wrapper
        self.utilsJar = utilsJar
        self.config_file = config_file
        if hasattr(idc, "idadir"):
            # ida 7.0
            self.bindir = os.path.abspath(idc.idadir() + "/dbgsrv")
        else:
            import idaapi
            self.bindir = os.path.abspath(idaapi.get_idcpath() + "/../dbgsrv")

    def load_config(self):
        try:
            with open(self.config_file, "r") as f:
                return json.load(f, encoding="UTF-8")
        except:
            return {}

    def save_config(self, obj):
        try:
            with open(self.config_file, "w") as f:
                json.dump(obj, f, encoding="UTF-8", ensure_ascii=False)
        except:
            pass

    @fn_timer
    def _chooseDevice(self):
        self.device = self.adb.chooseDevice(self.device)
        print 'Using device %s' % self.device

    @fn_timer
    def _getPid(self):
        ps = self.adb.call(['shell', 'ps']).splitlines()
        for x in ps:
            xs = x.split()
            if self.packageName in xs and ('S' in xs or 'T' in xs):
                g = (col for col in xs if col.isdigit())
                return int(next(g))

    @fn_timer
    def _launch(self, debug):
        start = time.time()
        idc.Message('Launching %s/%s... ' % (self.packageName, self.launchActivity))

        args = ['shell', 'am', 'start', '-n', self.packageName + '/' + self.launchActivity, '-W']
        if debug:
            args.append("-D")

        proc = self.adb.call(args, stderr=subprocess.PIPE, async=True, preexec_fn=utils.androidServerPreExec)

        def watchdog():
            time.sleep(15)
            if proc.poll() is None:  # still running
                proc.terminate()

        (threading.Thread(target=watchdog)).start()

        for _ in range(50):
            time.sleep(0.2)
            if self._getPid():
                break
        print "Done in %s seconds" % (time.time() - start)

    @fn_timer
    def _attach(self, debug):
        pid = self._getPid()
        if not pid:
            self._launch(debug)

            for _ in range(10):
                pid = self._getPid()
                if pid:
                    break
                time.sleep(0.5)

        if not pid:
            raise StandardError("Error attach %s/%s." % (self.packageName, self.launchActivity))
        self.attach_app(pid)

    @fn_timer
    def attach_app(self, pid):
        idc.LoadDebugger("armlinux", 1)
        idc.SetRemoteDebugger("localhost", "", self.port)
        status = idc.AttachProcess(pid, -1)
        if status == 1:
            print 'Attaching to pid %s... Done' % pid
        else:
            print 'Attaching to pid %s... Failed: %s' % (pid, status)

    def _chooseLaunchActivity(self, packageName):
        '''
    packageApk = self.device.getApkPath(packageName)
    if not packageApk:
      raise StandardError("Error find package apk: %s." % packageName)
    '''

        aaf_utils = "/data/local/tmp/aaf_utils.jar"
        # print "Pushing utils.jar to device: %s" % aaf_utils
        self.adb.push(self.utilsJar, aaf_utils)
        out = self.adb.call(['shell', 'su', '-c',
                             '"dalvikvm -cp ' + aaf_utils + ' com.android.internal.util.WithFramework com.fuzhu8.aaf.GetMainActivity ' + packageName + '"'])
        resp = json.loads(out)
        if resp["code"] != 0:
            raise StandardError(resp["msg"])
        main = utils.decode_list(resp["main"])
        if len(main) == 1:
            return main[0]
        activities = utils.decode_list(resp["activities"])
        if len(activities) == 1:
            return activities[0]
        return utils.ChooserForm("Choose activity", activities).choose()

    @fn_timer
    def _startAndroidServer(self, skipShell=False, redirectOut=False):
        global androidServerSuOut
        global port

        ida_port = '-p' + str(self.android_server_port)
        ps = self.adb.call(['shell', 'ps']).splitlines()
        for proc in [x.split() for x in ps if 'android_server' in x]:
            pid = next((col for col in proc if col.isdigit()))
            cmdline = self.adb.call(['shell', 'cat', '/proc/' + pid + '/cmdline']).split('\0')
            if ida_port not in cmdline:
                continue
            self.adb.call(['shell', 'su', '-c', '"kill -9 ' + pid + '"'])

        localServerPath = os.path.join(self.bindir, 'android_server')
        androidServerPath = '/data/local/tmp/android_server'
        remote = self.adb.call(["shell", "md5", androidServerPath]).split()[0]
        md5 = hashlib.md5()
        with open(localServerPath, "r") as f:
            while True:
                strRead = f.read(1024)
                if not strRead:
                    break
                md5.update(strRead)

        if md5.hexdigest() != remote:
            print "Pushing android_server to device: %s" % androidServerPath
            self.adb.push(localServerPath, androidServerPath)
            self.adb.call(['shell', 'chmod', '755', androidServerPath])

        args = [ida_port]

        @fn_timer
        def runAndroidServer(args):  # returns (proc, port, stdout)
            # print "runAndroidServer:", args
            proc = self.adb.call(args, stderr=subprocess.PIPE, async=True, preexec_fn=utils.androidServerPreExec)
            need_watchdog = True

            def watchdog():
                time.sleep(180)
                if need_watchdog and proc.poll() is None:  # still running
                    proc.terminate()

            (threading.Thread(target=watchdog)).start()

            # we have to find the port used by android_server from stdout
            # while this complicates things a little, it allows us to
            # have multiple android_servers running

            # Listening on port #23946...
            # Listening on 0.0.0.0:23946...
            out = []
            line = ' '
            while line:
                try:
                    line = proc.stdout.readline()
                    # words = line.split()
                    # print "line:", line, "words:", words
                    out.append(line.rstrip())
                    if 'android_server terminated by' in line:
                        break
                    if 'Listening' not in line:
                        continue

                    if '#' in line:
                        start_index = line.index("#")
                    elif ':' in line:
                        start_index = line.index(":")
                    else:
                        print "parse line failed: ", line
                        continue
                    end_index = line.index("...")
                    port = line[start_index + 1: end_index]

                    if not port.isdigit():
                        print "parse failed: port=", port, ", line=", line
                        continue
                    need_watchdog = False
                    return (proc, port, out)
                except BaseException, e:
                    print e
            # not found, error?
            need_watchdog = False
            return (None, None, out)

        # can we run as root?
        androidServerProc = None

        '''
        if not androidServerProc:
            idc.Message('as non-root... ')
            androidServerArgs = ['shell', 'run-as', pkg, androidServerPath]
            androidServerArgs.extend(args)
            (androidServerProc, port, androidServerRunAsOut) = runAndroidServer(androidServerArgs)
    
        if not androidServerProc:
            idc.Message('in pkg dir... ')
            pkgAndroidServerPath = '/data/data/' + pkg + '/files/android_server'
            self.adb.call(['shell', 'run-as', pkg, 'cp', androidServerPath, pkgAndroidServerPath])
            self.adb.call(['shell', 'run-as', pkg, 'chmod', '755', pkgAndroidServerPath])
            androidServerArgs = ['shell', 'run-as', pkg, pkgAndroidServerPath] + args
            (androidServerProc, port, androidServerPkgRunAsOut) = runAndroidServer(androidServerArgs)
        '''

        if not androidServerProc:
            idc.Message('as root... ')
            (androidServerProc, port, androidServerSuOut) = runAndroidServer(
                ['shell', 'su', '-c', '"' + " ".join([androidServerPath] + args) + '"'])

        '''
        if not androidServerProc:
            idc.Message('in pkg dir... ')
            (androidServerProc, port, androidServerPkgSuOut) = runAndroidServer(['shell', 'su', '-c', '"' + " ".join([pkgAndroidServerPath] + args) + '"'])
        '''

        if not androidServerProc:
            '''
            print ''
            print '"run-as" output:'
            print ' ' + '\n '.join([s for s in androidServerRunAsOut if s]).replace('\0', '')
            print '"run-as pkg" output:'
            print ' ' + '\n '.join([s for s in androidServerPkgRunAsOut if s]).replace('\0', '')
            '''
            print '"su -c" output:'
            print ' ' + '\n '.join([s for s in androidServerSuOut if s]).replace('\0', '')
            '''
            print '"su -c pkg" output:'
            print ' ' + '\n '.join([s for s in androidServerPkgSuOut if s]).replace('\0', '')
            if any('not executable: magic' in s for s in (androidServerRunAsOut + androidServerPkgRunAsOut + androidServerSuOut + androidServerPkgSuOut)):
                print '\n********'
                print '* Your device platform is not supported by this android_server'
                print '********\n'
            '''
            raise StandardError('failed to run android_server')

        self.port = int(port)
        self.android_server = androidServerProc

        # forward the port that android_server gave us
        self.adb.forward('tcp:' + port, 'tcp:' + port)
        print 'Done'
Esempio n. 21
0
import os
import sys
import shutil
from glob import glob

try:
    import epydoc.apidoc
    import epydoc.cli
except ImportError as e:
    import idc
    import traceback
    idc.Message("Couldn't import module %s\n" % traceback.format_exc())
    idc.Exit(-1)

# --------------------------------------------------------------------------
DOC_DIR = 'hr-html'


# --------------------------------------------------------------------------
def log(msg):
    #print msg
    pass


# --------------------------------------------------------------------------
def add_footer(lines):
    S1 = 'Generated by Epydoc'
    S2 = '</table>'
    p = lines.find(S1)

    if p == -1:
Esempio n. 22
0
 def _check_input_file(self):
     if (self.machine_type == IMAGE_FILE_MACHINE_IA64):
         return True
     else:
         idc.Message("File format is not supported")
         return False
Esempio n. 23
0
        for ea, name in idautils.Names():
            flag = idc.GetFlags(ea)
            if not idc.hasUserName(flag):
                continue
            seg_ea = idc.SegStart(ea)
            seg_name = idc.SegName(ea)
            if seg_name not in self.sections:
                continue
            sym_type = 'function' if idc.isCode(flag) else 'object'
            self.symbols[name] = (seg_name, ea - seg_ea, sym_type)

    def run(self):
        self.load_symbols_from_ida()
        err, err_msg = self.objcopy()
        return err, err_msg


if is_ida:
    inp_file = idc.GetInputFilePath()
    if not os.path.isfile(inp_file):
        inp_file = idc.AskFile(0, '', 'Input ELF file')
    out_file = idc.AskFile(1, '', 'Output file')
    a = AddSym(inp_file, out_file)
    err, err_msg = a.run()
    if err != 0:
        idc.Warning(err_msg)
        if out_file != inp_file:
            os.remove(out_file)
    else:
        idc.Message('Saved to {}\n'.format(out_file))
Esempio n. 24
0
# This script adds a function - memToLvl - which allows you to convert memory addresses to file addresses for LVL files.
# You need to have my IDA database for this script to work.

import idc

idc.Message("Initializing Rayman 3 extension for IDA!\n")

def memToLvl(address, levelId = None):
    refTableAddr = idc.LocByName("levelReferenceTable")
    if refTableAddr == BADADDR:
        print("Can't get level reference table address. Make sure its name is levelReferenceTable.")
        return
    
    if levelId == None:
        endTableAddr = idc.LocByName("levelEndTable")
        if endTableAddr == BADADDR:
            print("Can't get level end table address. Make sure its name is levelEndTable.")
            return

        lvl0StartAddr = idc.Dword(refTableAddr)
        lvl1StartAddr = idc.Dword(refTableAddr + 4)

        lvl0EndAddr = idc.Dword(endTableAddr) 
        lvl1EndAddr = idc.Dword(endTableAddr + 4)

        if address >= lvl0StartAddr and address <= lvl0EndAddr:
            fileRelativeAddr = address - lvl0StartAddr 
            idc.Message("Fix.lvl relative address: 0x" + format(fileRelativeAddr, '02X') + "\n")
            return

        if address >= lvl1StartAddr and address <= lvl1EndAddr: