#
# IMPORTANT NOTE
#
# The python scripts (startup.py, api_*.py) will only be used if "idaapi.enable_extlang_python(1)"
# has been called to enable python as an external language in IDA Pro
#

# // This file contains bochs startup and exit procedures bochs_startup() and bochs_exit()
# // The former is called when the process starts
# // The latter is called when the process is about to exit
# // Both functions cause IDA debugger to suspend if they return a non zero value
#
# // This section declares which DLLs will be available:
# // * Use the "stub" to mark a dll for stubbing
#
# // * Use the "load" to mark a dll to be loaded as is
# // The "load" keyword has an additional attributes called "R0UserEntry"
# // This attribute is used to designate an exported function that will be called from ring0
# // Such a mechanism is useful to extend bochsys kernel or even replace it after it is loaded
# // One simple application is to modify the IDT and add R3 callable interrupts into your kernel
#
# // Only lines containing three forward slashes ("/") are processed:

#/// stub ntdll.dll
#/// stub kernel32.dll
#/// stub user32.dll
#/// stub shell32.dll
#/// stub shlwapi.dll
#/// stub urlmon.dll
#/// stub advapi32.dll
#/// stub mswsock.dll
#/// stub wininet.dll
#/// stub msvcrt.dll
#/// stub gdi32.dll
#/// stub ole32.dll
#/// stub wsock32.dll

#// Define our own environment variables.
#// (add triple slashes to enable)
#// env path=c:\games\bin;d:\bin\asdf\
#// env userprofile=c:\games\
#
#// Define your dependency mappings
#// (add triple slashes to enable the following lines)
#// map /home/guest/sys_dlls/user32.dll=d:\winnt\system32\user32.dll
#// map /home/guest/sys_dlls/shell32.dll=d:\winnt\system32\shell32.dll
#// map /home/guest/sys_dlls/kernel32.dll=d:\winnt\system32\kernel32.dll
#// map /home/guest/sys_dlls/shlwapi.dll=d:\winnt\system32\shlwapi.dll
#// map /home/guest/sys_dlls/urlmon.dll=d:\winnt\system32\urlmon.dll
#// map /home/guest/sys_dlls/mswsock.dll=d:\winnt\system32\mswsock.dll
#// map /home/guest/sys_dlls/wininet.dll=d:\winnt\system32\wininet.dll
#// map /home/guest/sys_dlls/msvcrt.dll=d:\winnt\system32\msvcrt.dll
#// map /home/guest/sys_dlls/gdi32.dll=d:\winnt\system32\gdi32.dll
#// map /home/guest/sys_dlls/ntdll.dll=d:\winnt\system32\ntdll.dll
#// map /home/guest/sys_dlls/advapi32.dll=d:\winnt\system32\advapi32.dll
#
#// Define additional DLL path
#// (you need to add proper terminating slashes)
#// (add triple slashes to enable the following lines)
#// path /home/guest/sys_dlls/=c:\winnt\system32\
#
#// Bochs debugger plugin also allows you to specify the DLL path through the environment variable IDABXPATHMAP
#// (It is possible to specify more than one key/value pair by separating them with a semi-colon)
#// For example:
#//    $ export IDABXPATHMAP="/home/guest/sys_dlls/=c:/winnt/system32/;/home/user2/other_dlls/=c:/program files/common files/3rd party/"
#// Similarly, one can specify the environment variables through the environment variable IDABXENVMAP
#// (it is possible to specify more than one key/value pair by separating them with a "++")
#// For example:
#//    $ export IDABXENVMAP="TMP=c:/Users/Guest/Temp++SystemDrive=C:++windir=c:/windows/"
#//
#// Please note that the forward slashes "/" in the value part of the key/value pair will always be replaced with a backslash

#//
#// For loading drivers, you may uncomment the following stub definition(s):
#//
#// stub ntoskrnl.exe

#// for example, to load a dll as is: load mydll.dll
#// for example, to load a dll as is and specify a user R0 entry: load mydll.dll R0UserEntry=MyExportedFunc

#//--------------------------------------------------------------------------
#// IDC scripts that will be available during the debugging session

#// MS Windows related functions
#// ------------------------------
#// BochsVirtXXXX functions allocate/free virtual memory in the emulated session.
#// The "size" parameter is always rounded to a page.
#//

#//
#// Allocate virtual memory
#// This function emulates the VirtualAlloc function from MS Windows
#//      addr - the preferred address for the allocation. Zero means no preference
#//      size - size of the block to allocate
#//      writable - should be allocated memory be wrtiable?
#//                 Currently only read/write page protections are supported
#// Returns: the address of the allocated block or zero
#//
#// long BochsVirtAlloc(long addr, long size, bool writable);
#//

def BochsVirtAlloc(addr, size, writable):
    return Eval("BochsVirtAlloc(0x%X,0x%X, %d)"%(addr, size, writable))


#//
#// Change protection of memory page
#// This function emulates the VirtualProtect function from MS Windows
#//      addr - the desired address to change protection.
#//      size - size of the block
#//      attr - the new page attribute:
#//                 0 = Read only
#//                 1 = Read/Write
#// Returns: the old protection value or -1 on failure
#//
#// long BochsVirtProtect(long addr, long size, long attr);
#//
def BochsVirtProtect(addr, size, attr):
    return Eval("BochsVirtProtect(0x%X,0x%X, %d)"%(addr, size, writable))


#//
#// Free virtual memory
#// This function emulates the VirtualFree function from MS Windows
#//      addr - the address of previously allocated memory block
#//      size - the size of the block. If zero, then the entire block at addr
#//             will be freed.
#// Returns: success
#//
#// bool BochsVirtFree(long addr, long size);
#//
def BochsVirtFree(addr, size):
    return Eval("BochsVirtFree(0x%X,0x%X)"%(addr, size))

#//
#// Returns the base address of a given module name
#//      module_name - The name of the module.
#//                    The name can be full path or filename with extension, or simply filename without extension
#// Returns: zero if it fails
#//
#// long BochsGetModuleHandle(string module_name);
#//
def BochsGetModuleHandle(module_name):
    return Eval('BochsGetModuleHandle("%s")'%(module_name))

#//
#// Returns a procedure's address
#// This function calls the internal GetProcAddress to resolve function addresses.
#//      hmod      - the module handle
#//      procname  - name of the procedure inside the module
#// Returns: the zero if procedure not found, otherwise the address
#//
#// long BochsGetProcAddress(long hmod, string procname);
#//
def BochsGetProcAddress(hmod, procname):
    return Eval('BochsGetProcAddress(0x%X,"%s")'%(hmod, procname))

#//
#// Returns the module name given its base address
#//      module_handle: the base address of a given module
#// Returns: empty string if module was not found
#//
#// string BochsGetModuleFileName(long module_handle)
#//
def BochsGetModuleFileName(module_handle):
    return Eval("BochsGetModuleFileName(0x%X)"%(module_handle))

#//
#// Returns the command line value passed to the application
#//
#// string BochsGetCommandLine()
#//
def BochsGetModuleFileName():
    return Eval("BochsGetCommandLine()")

#//
#// Set last error code
#// This function emulates the SetLastError function from MS Windows.
#// It writes the specified code to TIB.
#//      error_code - new error code to set
#// Returns: success
#//
#// success BochsWin32SetLastError(long error_num);
#//
def BochsWin32SetLastError(error_num):
    return Eval("BochsWin32SetLastError(0x%X)"%(error_num))

#//
#// Other functions:
#// -------------------
#//

#//
#// Sends arbitrary commands to the internal debugger of BOCHS. The output is returned as a string.
#// This is useful for example to send some commands to BOCHS that are not exposed via the GUI of IDA.
#//      command: the command you want to send
#// Returns: output string or empty string if it failed
#//
#// string SendDbgCommand(string command)
#//
def SendDbgCommand(command):
    return Eval('SendDbgCommand("%s")'%(command))

#//
#// Retrieves the parameter value passed to an IDC script that is implementing a given API.
#// This same function can be implemented with this expression: #define BX_GETPARAM(n) Dword(esp+4*(n+1))
#//      arg_num: the argument number (starting by one)
#// Returns: the value or zero in case it fails
#//
#// string BochsGetParam(long arg_num)
#//

def BochsGetParam(num):
  return Eval("BochsGetParam(%d)"%num)

#//
#// Calls a function inside Bochs
#// This function can call functions inside Bochs. Very useful if you want to call
#// functions in the user's code. The arguments are pushed from right to left.
#//      func_ptr - The address of the function to be called
#//      argN - a set of dwords that contain the arguments.
#//             Arguments can be numbers or pointers
#// Returns: success
#//
#// long BochsCall(long func_ptr, arg1, arg2, ...);
#//

def BochsCall(func_ptr, *args):
  return Eval("BochsCall(0x%X, %s)"%(func_ptr, ", ".join(map(hex, args))) )

#//
#// These functions will return the total physical memory amount and the remaining free
#// memory in bytes.
#// Returns: memory size in bytes
#//
#// long BochsGetFreeMem()
#// long BochsGetMaxMem()
#//
def BochsGetFreeMem():
    return Eval("BochsGetFreeMem()")
def BochsGetMaxMem():
    return Eval("BochsGetMaxMem()")

def bochs_startup():
  Message("[Python] Bochs debugger has been initialized.\n")
  return 0

def bochs_exit():
  Message("[Python] Bochs debugger has been terminated.\n")
  return 0

def BochsPatchDbgDword(ea, dv):
  for i in range(4):
    PatchDbgByte(ea+i, dv & 0xFF)
    dv = dv >> 8
