8000 lldbinit/lldbinit.py at master · evilpan/lldbinit · GitHub
[go: up one dir, main page]

Skip to content

Latest commit

 

History

History
4268 lines (3685 loc) · 138 KB

lldbinit.py

File metadata and controls

4268 lines (3685 loc) · 138 KB
'''
.____ .____ ________ __________.__ _______ ._____________
| | | | \______ \\______ \__|\ \ |__\__ ___/
| | | | | | \| | _/ |/ | \| | | |
| |___| |___ | ` \ | \ / | \ | | |
|_______ \_______ \/_______ /______ /__\____|__ /__| |____|
\/ \/ \/ \/ \/ LLDBINIT v2.0
A gdbinit clone for LLDB aka how to make LLDB a bit more useful and less crappy
(c) Deroko 2014, 2015, 2016
(c) fG! 2017-2019 - reverser@put.as - https://reverse.put.as
Available at https://github.com/gdbinit/lldbinit
No original license by Deroko so I guess this is do whatever you want with this
as long you keep original credits and sources references.
Original lldbinit code by Deroko @ https://github.com/deroko/lldbinit
gdbinit available @ https://github.com/gdbinit/Gdbinit
Huge thanks to Deroko for his original effort!
To list all implemented commands use 'lldbinitcmds' command.
How to install it:
------------------
$ cp lldbinit.py ~
$ echo "command script import ~/lldbinit.py" >>$HOME/.lldbinit
or
$ cp lldbinit.py /Library/Python/2.7/site-packages
$ echo "command script import lldbinit" >> $HOME/.lldbinit
or
just copy it somewhere and use "command script import path_to_script" when you want to load it.
TODO:
-----
- better ARM support and testing - this version is focused on x86/x64
- shortcut to dump memory to file
- check sbthread class: stepoveruntil for example
- help for aliases
- error checking on many return values for lldb objects (target, frame, thread, etc) - verify if frame value is valid on the beginning of each command?
- add source window?
- add threads window?
- remove that ugly stop information (deroko's trick doesn't seem to work anymore, lldb forces that over our captured input?)
- command to search for symbol and display image address (image lookup -s symbol -v) (address is the range)
- command to update breakpoints with new ASLR
- fix get_indirect_flow_target (we can get real load address of the modules - check the new disassembler code)
- solve addresses like lea rsi, [rip + 0x38cf] (lldb does solve some stuff that it has symbols for and adds the info as comment)
- some sort of colors theme support?
BUGS:
-----
LLDB design:
------------
lldb -> debugger -> target -> process -> thread -> frame(s)
-> thread -> frame(s)
'''
if __name__ == "__main__":
print("Run only as script from LLDB... Not as standalone program!")
try:
import lldb
except:
pass
import sys
import re
import os
import time
import struct
import argparse
import subprocess
import tempfile
try:
from keystone import *
CONFIG_KEYSTONE_AVAILABLE = 1
except:
CONFIG_KEYSTONE_AVAILABLE = 0
pass
VERSION = "2.0"
#
# User configurable options
#
CONFIG_ENABLE_COLOR = 1
CONFIG_DISPLAY_DISASSEMBLY_BYTES = 1
CONFIG_DISASSEMBLY_LINE_COUNT = 8
CONFIG_USE_CUSTOM_DISASSEMBLY_FORMAT = 1
CONFIG_DISPLAY_STACK_WINDOW = 0
CONFIG_DISPLAY_FLOW_WINDOW = 0
CONFIG_ENABLE_REGISTER_SHORTCUTS = 1
CONFIG_DISPLAY_DATA_WINDOW = 0
# setup the logging level, which is a bitmask of any of the following possible values (don't use spaces, doesn't seem to work)
#
# LOG_VERBOSE LOG_PROCESS LOG_THREAD LOG_EXCEPTIONS LOG_SHLIB LOG_MEMORY LOG_MEMORY_DATA_SHORT LOG_MEMORY_DATA_LONG LOG_MEMORY_PROTECTIONS LOG_BREAKPOINTS LOG_EVENTS LOG_WATCHPOINTS
# LOG_STEP LOG_TASK LOG_ALL LOG_DEFAULT LOG_NONE LOG_RNB_MINIMAL LOG_RNB_MEDIUM LOG_RNB_MAX LOG_RNB_COMM LOG_RNB_REMOTE LOG_RNB_EVENTS LOG_RNB_PROC LOG_RNB_PACKETS LOG_RNB_ALL LOG_RNB_DEFAULT
# LOG_DARWIN_LOG LOG_RNB_NONE
#
# to see log (at least in macOS)
# $ log stream --process debugserver --style compact
# (or whatever style you like)
CONFIG_LOG_LEVEL = "LOG_NONE"
# removes the offsets and modifies the module name position
# reference: https://lldb.llvm.org/formats.html
CUSTOM_DISASSEMBLY_FORMAT = "\"{${function.initial-function}{${function.name-without-args}} @ {${module.file.basename}}:\n}{${function.changed}\n{${function.name-without-args}} @ {${module.file.basename}}:\n}{${current-pc-arrow} }${addr-file-or-load}: \""
# default colors - modify as you wish
COLOR_REGVAL = "WHITE"
COLOR_REGNAME = "GREEN"
COLOR_CPUFLAGS = "RED"
COLOR_SEPARATOR = "BLUE"
COLOR_HIGHLIGHT_LINE = "RED"
COLOR_REGVAL_MODIFIED = "RED"
COLOR_SYMBOL_NAME = "BLUE"
COLOR_CURRENT_PC = "RED"
#
# Don't mess after here unless you know what you are doing!
#
COLORS = {
"BLACK": "\033[30m",
"RED": "\033[31m",
"GREEN": "\033[32m",
"YELLOW": "\033[33m",
"BLUE": "\033[34m",
"MAGENTA": "\033[35m",
"CYAN": "\033[36m",
"WHITE": "\033[37m",
"RESET": "\033[0m",
"BOLD": "\033[1m",
"UNDERLINE": "\033[4m"
}
DATA_WINDOW_ADDRESS = 0
old_x86 = { "eax": 0, "ecx": 0, "edx": 0, "ebx": 0, "esp": 0, "ebp": 0, "esi": 0, "edi": 0, "eip": 0, "eflags": 0,
"cs": 0, "ds": 0, "fs": 0, "gs": 0, "ss": 0, "es": 0, }
old_x64 = { "rax": 0, "rcx": 0, "rdx": 0, "rbx": 0, "rsp": 0, "rbp": 0, "rsi": 0, "rdi": 0, "rip": 0, "rflags": 0,
"cs": 0, "fs": 0, "gs": 0, "r8": 0, "r9": 0, "r10": 0, "r11": 0, "r12": 0,
"r13": 0, "r14": 0, "r15": 0 }
old_arm = { "r0": 0, "r1": 0, "r2": 0, "r3": 0, "r4": 0, "r5": 0, "r6": 0, "r7": 0, "r8": 0, "r9": 0, "r10": 0,
"r11": 0, "r12": 0, "sp": 0, "lr": 0, "pc": 0, "cpsr": 0 }
arm_type = "thumbv7-apple-ios"
GlobalListOutput = []
Int3Dictionary = {}
crack_cmds = []
crack_cmds_noret = []
All_Registers = [ "rip", "rax", "rbx", "rbp", "rsp", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "eip", "eax", "ebx", "ebp", "esp", "edi", "esi", "edx", "ecx" ]
def __lldb_init_module(debugger, internal_dict):
''' we can execute commands using debugger.HandleCommand which makes all output to default
lldb console. With GetCommandinterpreter().HandleCommand() we can consume all output
with SBCommandReturnObject and parse data before we send it to output (eg. modify it);
'''
# don't load if we are in Xcode since it is not compatible and will block Xcode
if os.getenv('PATH').startswith('/Applications/Xcode'):
return
'''
If I'm running from $HOME where .lldbinit is located, seems like lldb will load
.lldbinit 2 times, thus this dirty hack is here to prevent doulbe loading...
if somebody knows better way, would be great to know :)
'''
var = debugger.GetInternalVariableValue("stop-disassembly-count", debugger.GetInstanceName())
if var.IsValid():
var = var.GetStringAtIndex(0)
if var == "0":
return
res = lldb.SBCommandReturnObject()
ci = debugger.GetCommandInterpreter()
# settings
ci.HandleCommand("settings set target.x86-disassembly-flavor intel", res)
ci.HandleCommand("settings set prompt \"(lldbinit) \"", res)
#lldb.debugger.GetCommandInterpreter().HandleCommand("settings set prompt \"\033[01;31m(lldb) \033[0m\"", res);
ci.HandleCommand("settings set stop-disassembly-count 0", res)
# set the log level - must be done on startup?
ci.HandleCommand("settings set target.process.extra-startup-command QSetLogging:bitmask=" + CONFIG_LOG_LEVEL + ";", res)
if CONFIG_USE_CUSTOM_DISASSEMBLY_FORMAT == 1:
ci.HandleCommand("settings set disassembly-format " + CUSTOM_DISASSEMBLY_FORMAT, res)
# the hook that makes everything possible :-)
ci.HandleCommand("command script add -f lldbinit.HandleHookStopOnTarget HandleHookStopOnTarget", res)
ci.HandleCommand("command script add -f lldbinit.HandleHookStopOnTarget ctx", res)
ci.HandleCommand("command script add -f lldbinit.HandleHookStopOnTarget context", res)
# commands
ci.HandleCommand("command script add -f lldbinit.cmd_lldbinitcmds lldbinitcmds", res)
ci.HandleCommand("command script add -f lldbinit.cmd_IphoneConnect iphone", res)
#
# dump memory commands
#
ci.HandleCommand("command script add -f lldbinit.cmd_db db", res)
ci.HandleCommand("command script add -f lldbinit.cmd_dw dw", res)
ci.HandleCommand("command script add -f lldbinit.cmd_dd dd", res)
ci.HandleCommand("command script add -f lldbinit.cmd_dq dq", res)
ci.HandleCommand("command script add -f lldbinit.cmd_DumpInstructions u", res)
ci.HandleCommand("command script add -f lldbinit.cmd_findmem findmem", res)
#
# Settings related commands
#
ci.HandleCommand("command script add -f lldbinit.cmd_enable enable", res)
ci.HandleCommand("command script add -f lldbinit.cmd_disable disable", res)
ci.HandleCommand("command script add -f lldbinit.cmd_contextcodesize contextcodesize", res)
# a few settings aliases
ci.HandleCommand("command alias enablesolib enable solib", res)
ci.HandleCommand("command alias disablesolib disable solib", res)
ci.HandleCommand("command alias enableaslr enable aslr", res)
ci.HandleCommand("command alias disableaslr disable aslr", res)
#
# Breakpoint related commands
#
ci.HandleCommand("command script add -f lldbinit.cmd_bhb bhb", res)
ci.HandleCommand("command script add -f lldbinit.cmd_bht bht", res)
ci.HandleCommand("command script add -f lldbinit.cmd_bpt bpt", res)
ci.HandleCommand("command script add -f lldbinit.cmd_bpn bpn", res)
# disable a breakpoint or all
ci.HandleCommand("command script add -f lldbinit.cmd_bpd bpd", res)
ci.HandleCommand("command script add -f lldbinit.cmd_bpda bpda", res)
# clear a breakpoint or all
ci.HandleCommand("command script add -f lldbinit.cmd_bpc bpc", res)
ci.HandleCommand("command alias bpca breakpoint delete", res)
# enable a breakpoint or all
ci.HandleCommand("command script add -f lldbinit.cmd_bpe bpe", res)
ci.HandleCommand("command script add -f lldbinit.cmd_bpea bpea", res)
# commands to set temporary int3 patches and restore original bytes
ci.HandleCommand("command script add -f lldbinit.cmd_int3 int3", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rint3 rint3", res)
ci.HandleCommand("command script add -f lldbinit.cmd_listint3 listint3", res)
ci.HandleCommand("command script add -f lldbinit.cmd_nop nop", res)
ci.HandleCommand("command script add -f lldbinit.cmd_null null", res)
# change eflags commands
ci.HandleCommand("command script add -f lldbinit.cmd_cfa cfa", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfc cfc", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfd cfd", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfi cfi", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfo cfo", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfp cfp", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfs cfs", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cft cft", res)
ci.HandleCommand("command script add -f lldbinit.cmd_cfz cfz", res)
# skip/step current instruction commands
ci.HandleCommand("command script add -f lldbinit.cmd_skip skip", res)
ci.HandleCommand("command script add -f lldbinit.cmd_stepo stepo", res)
ci.HandleCommand("command script add -f lldbinit.cmd_si si", res)
# load breakpoints from file
ci.HandleCommand("command script add -f lldbinit.cmd_LoadBreakPoints lb", res)
ci.HandleCommand("command script add -f lldbinit.cmd_LoadBreakPointsRva lbrva", res)
# cracking friends
ci.HandleCommand("command script add -f lldbinit.cmd_crack crack", res)
ci.HandleCommand("command script add -f lldbinit.cmd_crackcmd crackcmd", res)
ci.HandleCommand("command script add -f lldbinit.cmd_crackcmd_noret crackcmd_noret", res)
# alias for existing breakpoint commands
# list all breakpoints
ci.HandleCommand("command alias bpl breakpoint list", res)
# alias "bp" command that exists in gdbinit - lldb also has alias for "b"
ci.HandleCommand("command alias bp _regexp-break", res)
# to set breakpoint commands - I hate typing too much
ci.HandleCommand("command alias bcmd breakpoint command add", res)
# launch process and stop at entrypoint (not exactly as gdb command that just inserts breakpoint)
# usually it will be inside dyld and not the target main()
ci.HandleCommand("command alias break_entrypoint process launch --stop-at-entry", res)
ci.HandleCommand("command script add -f lldbinit.cmd_show_loadcmds show_loadcmds", res)
ci.HandleCommand("command script add -f lldbinit.cmd_show_header show_header", res)
ci.HandleCommand("command script add -f lldbinit.cmd_tester tester", res)
ci.HandleCommand("command script add -f lldbinit.cmd_datawin datawin", res)
# shortcut command to modify registers content
if CONFIG_ENABLE_REGISTER_SHORTCUTS == 1:
# x64
ci.HandleCommand("command script add -f lldbinit.cmd_rip rip", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rax rax", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rbx rbx", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rbp rbp", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rsp rsp", res)
ci.HandleCommand("command script add 10BC8 -f lldbinit.cmd_rdi rdi", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rsi rsi", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rdx rdx", res)
ci.HandleCommand("command script add -f lldbinit.cmd_rcx rcx", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r8 r8", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r9 r9", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r10 r10", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r11 r11", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r12 r12", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r13 r13", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r14 r14", res)
ci.HandleCommand("command script add -f lldbinit.cmd_r15 r15", res)
# x86
ci.HandleCommand("command script add -f lldbinit.cmd_eip eip", res)
ci.HandleCommand("command script add -f lldbinit.cmd_eax eax", res)
ci.HandleCommand("command script add -f lldbinit.cmd_ebx ebx", res)
ci.HandleCommand("command script add -f lldbinit.cmd_ebp ebp", res)
ci.HandleCommand("command script add -f lldbinit.cmd_esp esp", res)
ci.HandleCommand("command script add -f lldbinit.cmd_edi edi", res)
ci.HandleCommand("command script add -f lldbinit.cmd_esi esi", res)
ci.HandleCommand("command script add -f lldbinit.cmd_edx edx", res)
ci.HandleCommand("command script add -f lldbinit.cmd_ecx ecx", res)
if CONFIG_KEYSTONE_AVAILABLE == 1:
ci.HandleCommand("command script add -f lldbinit.cmd_asm32 asm32", res)
ci.HandleCommand("command script add -f lldbinit.cmd_asm64 asm64", res)
ci.HandleCommand("command script add -f lldbinit.cmd_arm32 arm32", res)
ci.HandleCommand("command script add -f lldbinit.cmd_arm64 arm64", res)
ci.HandleCommand("command script add -f lldbinit.cmd_armthumb armthumb", res)
# add the hook - we don't need to wait for a target to be loaded
ci.HandleCommand("target stop-hook add -o \"HandleHookStopOnTarget\"", res)
ci.HandleCommand("command script add --function lldbinit.cmd_banner banner", res)
debugger.HandleCommand("banner")
return
def cmd_banner(debugger,command,result,dict):
print(COLORS["RED"] + "[+] Loaded lldbinit version: " + VERSION + COLORS["RESET"])
def cmd_lldbinitcmds(debugger, command, result, dict):
'''Display all available lldbinit commands.'''
help_table = [
[ "lldbinitcmds", "this command" ],
[ "enable", "configure lldb and lldbinit options" ],
[ "disable", "configure lldb and lldbinit options" ],
[ "contextcodesize", "set number of instruction lines in code window" ],
[ "b", "breakpoint address" ],
[ "bpt", "set a temporary software breakpoint" ],
[ "bhb", "set an hardware breakpoint" ],
[ "bpc", "clear breakpoint" ],
[ "bpca", "clear all breakpoints" ],
[ "bpd", "disable breakpoint" ],
[ "bpda", "disable all breakpoints" ],
[ "bpe", "enable a breakpoint" ],
[ "bpea", "enable all breakpoints" ],
[ "bcmd", "alias to breakpoint command add"],
[ "bpl", "list all breakpoints"],
[ "bpn", "temporarly breakpoint next instruction" ],
[ "break_entrypoint", "launch target and stop at entrypoint" ],
[ "skip", "skip current instruction" ],
[ "int3", "patch memory address with INT3" ],
[ "rint3", "restore original byte at address patched with INT3" ],
[ "listint3", "list all INT3 patched addresses" ],
[ "nop", "patch memory address with NOP" ],
[ "null", "patch memory address with NULL" ],
[ "stepo", "step over calls and loop instructions" ],
[ "lb", "load breakpoints from file and apply them (currently only func names are applied)" ],
[ "lbrva", "load breakpoints from file and apply to main executable, only RVA in this case" ],
[ "db/dw/dd/dq", "memory hex dump in different formats" ],
[ "findmem", "search memory" ],
[ "cfa/cfc/cfd/cfi/cfo/cfp/cfs/cft/cfz", "change CPU flags" ],
[ "u", "dump instructions" ],
[ "iphone", "connect to debugserver running on iPhone" ],
[ "ctx/context", "show current instruction pointer CPU context" ],
[ "show_loadcmds", "show otool output of Mach-O load commands" ],
[ "show_header", "show otool output of Mach-O header" ],
[ "enablesolib/disablesolib", "enable/disable the stop on library load events" ],
[ "enableaslr/disableaslr", "enable/disable process ASLR" ],
[ "crack", "return from current function" ],
[ "crackcmd", "set a breakpoint and return from that function" ],
[ "crackcmd_noret", "set a breakpoint and set a register value. doesn't return from function" ],
[ "datawin", "set start address to display on data window" ],
[ "rip/rax/rbx/etc", "shortcuts to modify x64 registers" ],
[ "eip/eax/ebx/etc", "shortcuts to modify x86 register" ],
[ "asm32/asm64", "x86/x64 assembler using keystone" ],
[ "arm32/arm64/armthumb", "ARM assembler using keystone" ]
]
print("lldbinit available commands:")
for row in help_table:
print(" {: <20} - {: <30}".format(*row))
print("\nUse \'cmdname help\' for extended command help.")
# placeholder to make tests
def cmd_tester(debugger, command, result, dict):
print("test")
#frame = get_frame()
# the SBValue to ReturnFromFrame must be eValueTypeRegister type
# if we do a lldb.SBValue() we can't set to that type
# so we need to make a copy
# can we use FindRegister() from frame?
#return_value = frame.reg["rax"]
#return_value.value = "1"
#thread.ReturnFromFrame(frame, return_value)
# -------------------------
# Settings related commands
# -------------------------
def cmd_enable(debugger, command, result, dict):
'''Enable certain lldb and lldbinit options. Use \'enable help\' for more information.'''
help = """
Enable certain lldb and lldbinit configuration options.
Syntax: enable <setting>
Available settings:
color: enable color mode.
solib: enable stop on library events trick.
aslr: enable process aslr.
stackwin: enable stack window in context display.
datawin: enable data window in context display, configure address with datawin.
flow: call targets and objective-c class/methods.
"""
global CONFIG_ENABLE_COLOR
global CONFIG_DISPLAY_STACK_WINDOW
global CONFIG_DISPLAY_FLOW_WINDOW
global CONFIG_DISPLAY_DATA_WINDOW
cmd = command.split()
if len(cmd) == 0:
print("[-] error: command requires arguments.")
print("")
print(help)
return
if cmd[0] == "color":
CONFIG_ENABLE_COLOR = 1
print("[+] Enabled color mode.")
elif cmd[0] == "solib":
debugger.HandleCommand("settings set target.process.stop-on-sharedlibrary-events true")
print("[+] Enabled stop on library events trick.")
elif cmd[0] == "aslr":
debugger.HandleCommand("settings set target.disable-aslr false")
print("[+] Enabled ASLR.")
elif cmd[0] == "stackwin":
CONFIG_DISPLAY_STACK_WINDOW = 1
print("[+] Enabled stack window in context display.")
elif cmd[0] == "flow":
CONFIG_DISPLAY_FLOW_WINDOW = 1
print("[+] Enabled indirect control flow window in context display.")
elif cmd[0] == "datawin":
CONFIG_DISPLAY_DATA_WINDOW = 1
print("[+] Enabled data window in context display. Configure address with \'datawin\' cmd.")
elif cmd[0] == "help":
print(help)
else:
print("[-] error: unrecognized command.")
print(help)
return
def cmd_disable(debugger, command, result, dict):
'''Disable certain lldb and lldbinit options. Use \'disable help\' for more information.'''
help = """
Disable certain lldb and lldbinit configuration options.
Syntax: disable <setting>
Available settings:
color: disable color mode.
solib: disable stop on library events trick.
aslr: disable process aslr.
stackwin: disable stack window in context display.
datawin: enable data window in context display.
flow: call targets and objective-c class/methods.
"""
global CONFIG_ENABLE_COLOR
global CONFIG_DISPLAY_STACK_WINDOW
global CONFIG_DISPLAY_FLOW_WINDOW
global CONFIG_DISPLAY_DATA_WINDOW
cmd = command.split()
if len(cmd) == 0:
print("[-] error: command requires arguments.")
print("")
print(help)
return
if cmd[0] == "color":
CONFIG_ENABLE_COLOR = 0
print("[+] Disabled color mode.")
elif cmd[0] == "solib":
debugger.HandleCommand("settings set target.process.stop-on-sharedlibrary-events false")
print("[+] Disabled stop on library events trick.")
elif cmd[0] == "aslr":
debugger.HandleCommand("settings set target.disable-aslr true")
print("[+] Disabled ASLR.")
elif cmd[0] == "stackwin":
CONFIG_DISPLAY_STACK_WINDOW = 0
print("[+] Disabled stack window in context display.")
elif cmd[0] == "flow":
CONFIG_DISPLAY_FLOW_WINDOW = 0
print("[+] Disabled indirect control flow window in context display.")
elif cmd[0] == "datawin":
CONFIG_DISPLAY_DATA_WINDOW = 0
print("[+] Disabled data window in context display.")
elif cmd[0] == "help":
print(help)
else:
print("[-] error: unrecognized command.")
print(help)
return
def cmd_contextcodesize(debugger, command, result, dict):
'''Set the number of disassembly lines in code window. Use \'contextcodesize help\' for more information.'''
help = """
Configures the number of disassembly lines displayed in code window.
Syntax: contextcodesize <line_count>
Note: expressions supported, do not use spaces between operators.
"""
global CONFIG_DISASSEMBLY_LINE_COUNT
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert the number of disassembly lines to display.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
print("\nCurrent configuration value is: {:d}".format(CONFIG_DISASSEMBLY_LINE_COUNT))
return
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value.")
print("")
print(help)
return
CONFIG_DISASSEMBLY_LINE_COUNT = value
return
# ---------------------------------
# Color and output related commands
# ---------------------------------
def color(x):
out_col = ""
if CONFIG_ENABLE_COLOR == 0:
output(out_col)
return
output(COLORS[x])
# append data to the output that we display at the end of the hook-stop
def output(x):
global GlobalListOutput
GlobalListOutput.append(x)
# ---------------------------
# Breakpoint related commands
# ---------------------------
# temporary software breakpoint
def cmd_bpt(debugger, command, result, dict):
'''Set a temporary software breakpoint. Use \'bpt help\' for more information.'''
help = """
Set a temporary software breakpoint.
Syntax: bpt <address>
Note: expressions supported, do not use spaces between operators.
"""
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert a breakpoint address.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
return
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value.")
print("")
print(help)
return
target = get_target()
breakpoint = target.BreakpointCreateByAddress(value)
breakpoint.SetOneShot(True)
breakpoint.SetThreadID(get_frame().GetThread().GetThreadID())
print("[+] Set temporary breakpoint at 0x{:x}".format(value))
# hardware breakpoint
def cmd_bhb(debugger, command, result, dict):
'''Set an hardware breakpoint'''
help = """
Set an hardware breakpoint.
Syntax: bhb <address>
Note: expressions supported, do not use spaces between operators.
"""
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert a breakpoint address.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
return
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value.")
print("")
print(help)
return
# the python API doesn't seem to support hardware breakpoints
# so we set it via command line interpreter
res = lldb.SBCommandReturnObject()
lldb.debugger.GetCommandInterpreter().HandleCommand("breakpoint set -H -a " + hex(value), res)
print("[+] Set hardware breakpoint at 0x{:x}".format(value))
return
# temporary hardware breakpoint
def cmd_bht(debugger, command, result, dict):
'''Set a temporary hardware breakpoint'''
print("[-] error: lldb has no x86/x64 temporary hardware breakpoints implementation.")
return
# clear breakpoint number
def cmd_bpc(debugger, command, result, dict):
'''Clear a breakpoint. Use \'bpc help\' for more information.'''
help = """
Clear a breakpoint.
Syntax: bpc <breakpoint_number>
Note: only breakpoint numbers are valid, not addresses. Use \'bpl\' to list breakpoints.
Note: expressions supported, do not use spaces between operators.
"""
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert a breakpoint number.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
return
# breakpoint disable only accepts breakpoint numbers not addresses
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value - only a breakpoint number is valid.")
print("")
print(help)
return
target = get_target()
for bpt in target.breakpoint_iter():
if bpt.id == value:
if target.BreakpointDelete(bpt.id) == False:
print("[-] error: failed to delete breakpoint #{:d}".format(value))
return
print("[+] Deleted breakpoint #{:d}".format(value))
return
print("[-] error: breakpoint #{:d} not found".format(value))
return
# disable breakpoint number
# XXX: we could support addresses, not sure it's worth the trouble
def cmd_bpd(debugger, command, result, dict):
'''Disable a breakpoint. Use \'bpd help\' for more information.'''
help = """
Disable a breakpoint.
Syntax: bpd <breakpoint_number>
Note: only breakpoint numbers are valid, not addresses. Use \'bpl\' to list breakpoints.
Note: expressions supported, do not use spaces between operators.
"""
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert a breakpoint number.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
return
# breakpoint disable only accepts breakpoint numbers not addresses
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value - only a breakpoint number is valid.")
print("")
print(help)
return
target = get_target()
for bpt in target.breakpoint_iter():
if bpt.id == value and bpt.IsEnabled() == True:
bpt.SetEnabled(False)
print("[+] Disabled breakpoint #{:d}".format(value))
# disable all breakpoints
def cmd_bpda(debugger, command, result, dict):
'''Disable all breakpoints. Use \'bpda help\' for more information.'''
help = """
Disable all breakpoints.
Syntax: bpda
"""
cmd = command.split()
if len(cmd) != 0:
if cmd[0] == "help":
print(help)
return
print("[-] error: command doesn't take any arguments.")
print("")
print(help)
return
target = get_target()
if target.DisableAllBreakpoints() == False:
print("[-] error: failed to disable all breakpoints.")
print("[+] Disabled all breakpoints.")
# enable breakpoint number
def cmd_bpe(debugger, command, result, dict):
'''Enable a breakpoint. Use \'bpe help\' for more information.'''
help = """
Enable a breakpoint.
Syntax: bpe <breakpoint_number>
Note: only breakpoint numbers are valid, not addresses. Use \'bpl\' to list breakpoints.
Note: expressions supported, do not use spaces between operators.
"""
cmd = command.split()
if len(cmd) != 1:
print("[-] error: please insert a breakpoint number.")
print("")
print(help)
return
if cmd[0] == "help":
print(help)
return
# breakpoint enable only accepts breakpoint numbers not addresses
value = evaluate(cmd[0])
if value is None:
print("[-] error: invalid input value - only a breakpoint number is valid.")
print("")
print(help)
return
target = get_target()
for bpt in target.breakpoint_iter():
if bpt.id == value and bpt.IsEnabled() == False:
bpt.SetEnabled(True)
print("[+] Enabled breakpoint #{:d}".format(value))
# enable all breakpoints
def cmd_bpea(debugger, command, result, dict):
'''Enable all breakpoints. Use \'bpea help\' for more information.'''
help = """
Enable all breakpoints.
Syntax: bpea
"""
cmd = command.split()
if len(cmd) != 0:
if cmd[0] == "help":
print(help)
return
print("[-] error: command doesn't take any arguments.")
print("")
print(help)
return
target = get_target()
if target.EnableAllBreakpoints() == False:
print("[-] error: failed to enable all breakpoints.")
print("[+] Enabled all breakpoints.")
# skip current instruction - just advances PC to next instruction but doesn't execute it
def cmd_skip(debugger, command, result, dict):
'''Advance PC to instruction at next address. Use \'skip help\' for more information.''& E4F7 #039;
help = """
Advance current instruction pointer to next instruction.
Syntax: skip
Note: control flow is not respected, it advances to next instruction in memory.
"""
cmd = command.split()
if len(cmd) != 0:
if cmd[0] == "help":
print(help)
return
print("[-] error: command doesn't take any arguments.")
print("")
print(help)
return
start_addr = get_current_pc()
next_addr = start_addr + get_inst_size(start_addr)
if is_x64():
get_frame().reg["rip"].value = format(next_addr, '#x')
elif is_i386():
get_frame().reg["eip"].value = format(next_addr, '#x')
# show the updated context
lldb.debugger.HandleCommand("context")
# XXX: ARM breakpoint
def cmd_int3(debugger, command, result, dict):
'''Patch byte at address to an INT3 (0xCC) instruction. Use \'int3 help\' for more information.'''
help = """
Patch process memory with an INT3 byte at given address.
Syntax: int3 [<address>]
Note: useful in cases where the debugger breakpoints aren't respected but an INT3 will always trigger the debugger.
Note: ARM not yet supported.
Note: expressions supported, do not use spaces between operators.
"""
global Int3Dictionary
error = lldb.SBError()
target = get_target()
cmd = command.split()
# if empty insert a int3 at current PC
if len(cmd) == 0:
int3_addr = get_current_pc()
if int3_addr == 0:
print("[-] error: invalid current address.")
return
elif len(cmd) == 1:
if cmd[0] == "help":
print(help)
return
int3_addr = evaluate(cmd[0])
if int3_addr is None:
print("[-] error: invalid input address value.")
print("")
print(help)
return
else:
print("[-] error: please insert a breakpoint address.")
print("")
print(help)
return
bytes_string = target.GetProcess().ReadMemory(int3_addr, 1, error)
if error.Success() == False:
print("[-] error: Failed to read memory at 0x{:x}.".format(int3_addr))
return
bytes_read = bytearray(bytes_string)
patch_bytes = str('\xCC')
result = target.GetProcess().WriteMemory(int3_addr, patch_bytes, error)
if error.Success() == False:
print("[-] error: Failed to write memory at 0x{:x}.".format(int3_addr))
return
# save original bytes for later restore
Int3Dictionary[str(int3_addr)] = bytes_read[0]
print("[+] Patched INT3 at 0x{:x}".format(int3_addr))
return
def cmd_rint3(debugger, command, result, dict):
'''Restore byte at address from a previously patched INT3 (0xCC) instruction. Use \'rint3 help\' for more information.'''
help = """
Restore the original byte at a previously patched address using \'int3\' command.
Syntax: rint3 [<address>]
Note: expressions supported, do not use spaces between operators.
"""
global Int3Dictionary
error = lldb.SBError()
target = get_target()
cmd = command.split()
# if empty insert a int3 at current PC
if len(cmd) == 0:
int3_addr = get_current_pc()
if int3_addr == 0:
print("[-] error: invalid current address.")
return
elif len(cmd) == 1:
if cmd[0] == "help":
print(help)
return
int3_addr = evaluate(cmd[0])
if int3_addr is None:
print("[-] error: invalid input address value.")
print("")
print(help)
return
else:
print("[-] error: please insert a INT3 patched address.")
print("")
print(help)
return
if len(Int3Dictionary) == 0:
print("[-] error: No INT3 patched addresses to restore available.")
return
bytes_string = target.GetProcess().ReadMemory(int3_addr, 1, error)
if error.Success() == False:
print("[-] error: Failed to read memory at 0x{:x}.".format(int3_addr))
return
bytes_read = bytearray(bytes_string)
if bytes_read[0] == 0xCC:
#print("Found byte patched byte at 0x{:x}".format(int3_addr))
try:
original_byte = Int3Dictionary[str(int3_addr)]
except:
print("[-] error: Original byte for address 0x{:x} not found.".format(int3_addr))
return
patch_bytes = chr(original_byte)
result = target.GetProcess().WriteMemory(int3_addr, patch_bytes, error)
if error.Success() == False:
print("[-] error: Failed to write memory at 0x{:x}.".format(int3_addr))
return
# remove element from original bytes list
del Int3Dictionary[str(int3_addr)]
else:
print("[-] error: No INT3 patch found at 0x{:x}.".format(int3_addr))
return
def cmd_listint3(debugger, command, result, dict):
'''List all patched INT3 (0xCC) instructions. Use \'listint3 help\' for more information.'''
help = """
List all addresses patched with \'int3\' command.
Syntax: listint3
"""
cmd = command.split()
if len(cmd) != 0:
if cmd[0] == "help":
print(help)
return
print("[-] error: command doesn't take any arguments.")
print("")
print(help)
return
if len(Int3Dictionary) == 0:
print("[-] No INT3 patched addresses available.")
return
print("Current INT3 patched addresses:")
for address, byte in Int3Dictionary.items():
print("[*] {:s}".format(hex(int(address, 10))))
0