Appearance
Built in script function encapsulation
In the x64dbg debugger, there are rich built-in script commands that are very useful for developers. However, sometimes when writing native scripts, we may want to encapsulate these commands in a more readable and efficient form to improve code maintainability and development efficiency.
To achieve this goal, we can write Python functions to encapsulate these native commands. In this way, developers can directly call these functions in Python code without having to read the document or remember specific commands and parameters. This encapsulation makes the code clearer and easier to understand, and can be better integrated into the development workflow, significantly improving development efficiency.
Module command encapsulation
This code is a Python script that interacts with the debugger using the x32dbg module. It defines a ModuleInfo class that provides methods to obtain information about the module where the executing instruction is located, including base address, size, hash value, etc. Obtain the address (EIP) of the current executing instruction by connecting to the debugger, then use the ModuleInfo class to retrieve module information related to that address and print it out.
python
from x32dbg import Debugger
# Module related classes
class ModuleInfo:
def __init__(self, debugger):
self.debugger = debugger
# Accept integer type parameters passed in
def get_module_info(self, decimal_address, info_type):
try:
ref = self.debugger.script_runcmd_ex("mod.{}({})".
format(info_type, hex(decimal_address)))
return ref if ref is not None else False
except Exception:
return False
def base(self, decimal_address):
return self.get_module_info(decimal_address, "base")
def party(self, decimal_address):
return self.get_module_info(decimal_address, "party")
def size(self, decimal_address):
return self.get_module_info(decimal_address, "size")
def hash(self, decimal_address):
return self.get_module_info(decimal_address, "hash")
def entry(self, decimal_address):
return self.get_module_info(decimal_address, "entry")
def system(self, decimal_address):
return self.get_module_info(decimal_address, "system")
def user(self, decimal_address):
return self.get_module_info(decimal_address, "user")
def main(self):
return self.get_module_info(0, "main")
def rva(self, decimal_address):
return self.get_module_info(decimal_address, "rva")
def offset(self, decimal_address):
return self.get_module_info(decimal_address, "offset")
def isexport(self, decimal_address):
return self.get_module_info(decimal_address, "isexport")
if __name__ == "__main__":
dbg = Debugger(address="127.0.0.1", port=6589)
if dbg.connect() == True:
# Define module classes
module = ModuleInfo(dbg)
eip = dbg.get_eip()
# Obtain the mode number of the module.
# Returning false indicates that it is a user module,
# while returning true indicates that it is a system module
party = module.party(eip)
print("party = {}".format(party))
# Get module base address
base = module.base(eip)
print("base = {}".format(hex(base)))
# Reverse remittance module size
size = module.size(eip)
print("size = {}".format(size))
# Reverse module hash
hash = module.hash(eip)
print("hash = {}".format(hash))
# Return module entry address
entry = module.entry(eip)
print("entry = {}".format(hex(entry)))
# If eip is a system module, it is true; otherwise, it is false
system = module.system(eip)
print("system = {}".format(system))
# If eip is a user module, return true; otherwise, it is false
user = module.system(eip)
print("user = {}".format(user))
# Return the RVA offset address at the eip position
rva = module.rva(eip)
print("rva = {}".format(hex(rva)))
# Return the FOA address at the eip location
foa = module.offset(eip)
print("foa = {}".format(hex(foa)))
# Determine if the address is a function exported from the module
isexport = module.isexport(eip)
print("isexport = {}".format(isexport))
dbg.close_connect()
else:
print("Failed to connect debugger")
After the program runs successfully, it will output the following content:
python
party = False
base = 0x330000
size = 28672
hash = 303466845
entry = 0x3315bb
system = False
user = False
rva = 0x15bb
foa = 0x9bb
isexport = False
Disassembly command encapsulation
This code implements a DisassemblyInfo class to retrieve disassembly information for instructions at specific addresses through the x32dbg debugger. This class connects to the debugger and utilizes the command execution function provided by the debugger to obtain various instruction information at a specified address, such as instruction length, instruction type (conditional branch, jump, etc.), immediate value, etc.
The core purpose of the code is to obtain disassembly information at a specified address through a debugger and display various instruction properties, such as instruction length, whether it is a conditional branch, whether it is a jump instruction, whether it is a call instruction, etc. By calling different methods, various information about instructions at specific addresses can be obtained, which is helpful for debugging and analyzing binary programs.
python
from x32dbg import Debugger
# Disassembly related classes
class DisassemblyInfo:
def __init__(self, debugger):
self.debugger = debugger
def get_disassembly_info(self, decimal_address, info_type):
try:
ref = self.debugger.script_runcmd_ex("dis.{}({})".
format(info_type, hex(decimal_address)))
return ref if ref is not None else False
except Exception:
return False
def len(self, decimal_address):
return self.get_disassembly_info(decimal_address, "len")
def iscond(self, decimal_address):
return self.get_disassembly_info(decimal_address, "iscond")
def isbranch(self, decimal_address):
return self.get_disassembly_info(decimal_address, "isbranch")
def isret(self, decimal_address):
return self.get_disassembly_info(decimal_address, "isret")
def iscall(self, decimal_address):
return self.get_disassembly_info(decimal_address, "iscall")
def ismem(self, decimal_address):
return self.get_disassembly_info(decimal_address, "ismem")
def isnop(self, decimal_address):
return self.get_disassembly_info(decimal_address, "isnop")
def isunusual(self, decimal_address):
return self.get_disassembly_info(decimal_address, "isunusual")
def branchdest(self, decimal_address):
return self.get_disassembly_info(decimal_address, "branchdest")
def branchexec(self, decimal_address):
return self.get_disassembly_info(decimal_address, "branchexec")
def imm(self, decimal_address):
return self.get_disassembly_info(decimal_address, "imm")
def brtrue(self, decimal_address):
return self.get_disassembly_info(decimal_address, "brtrue")
def brfalse(self, decimal_address):
return self.get_disassembly_info(decimal_address, "brfalse")
def next(self, decimal_address):
return self.get_disassembly_info(decimal_address, "next")
def prev(self, decimal_address):
return self.get_disassembly_info(decimal_address, "prev")
def iscallsystem(self, decimal_address):
return self.get_disassembly_info(decimal_address, "iscallsystem")
def mnemonic(self, decimal_address):
return self.get_disassembly_info(decimal_address, "mnemonic")
def text(self, decimal_address):
return self.get_disassembly_info(decimal_address, "text")
if __name__ == "__main__":
dbg = Debugger(address="127.0.0.1", port=6589)
if dbg.connect() == True:
# Define Disassembly classes
disassembly = DisassemblyInfo(dbg)
eip = dbg.get_eip()
# Get the instruction length at eip
dis_len = disassembly.len(eip)
print("len = {}".format(dis_len))
# Determine whether the current eip
# position is a conditional jump instruction
dis_iscond = disassembly.iscond(eip)
print("lscond = {}".format(dis_iscond))
# Determine whether the current EIP address is a branch instruction
dis_isbranch = disassembly.isbranch(eip)
print("isbranch = {}".format(dis_isbranch))
# Determine whether the current EIP address is a RET return instruction
dis_isret = disassembly.isret(eip)
print("isret = {}".format(dis_isret))
# Determine whether the current EIP address is a call instruction
dis_iscall = disassembly.iscall(eip)
print("iscall = {}".format(dis_iscall))
# Determine whether the current EIP address is a memory operand
dis_ismem = disassembly.ismem(eip)
print("ismem = {}".format(dis_ismem))
# Determine if the current address is nop
dis_isnop = disassembly.isnop(eip)
print("ienop = {}".format(dis_isnop))
# Determine if the current address indicates an abnormal address
dis_isunusual = disassembly.isunusual(eip)
print("isunusual = {}".format(dis_isunusual))
# Branch destination eip of instructions
dis_branchdest = disassembly.branchdest(eip)
print("branchdest = {}".format(dis_branchdest))
# If a branch of at is to be executed, return true
dis_branchexec = disassembly.branchexec(eip)
print("branchexec = {}".format(dis_branchexec))
# Get the immediate value of the current instruction position
dis_imm = disassembly.imm(eip)
print("imm = {}".format(dis_imm))
# The branch destination address of the instruction is eip
dis_brtrue = disassembly.brtrue(eip)
print("brtrue = {}".format(dis_brtrue))
# If there is a conditional branch at eip,
# return the address of the next instruction
dis_brfalse = disassembly.brfalse(eip)
print("brfalse = {}".format(dis_brfalse))
# Return the address of the next instruction to the EIP address
dis_next = disassembly.next(eip)
print("next = {}".format(hex(dis_next)))
# Return the address of the previous instruction to the EIP address
dis_prev = disassembly.prev(eip)
print("dis_prev = {}".format(hex(dis_prev)))
# Determine whether the current instruction is a system module instruction
dis_iscallsystem = disassembly.iscallsystem(eip)
print("dis_iscallsystem = {}".format(dis_iscallsystem))
# Returns the mnemonic at the eip address
dis_mnemonic = disassembly.mnemonic(eip)
print("mnemonic = {}".format(dis_mnemonic))
dbg.close_connect()
else:
print("Failed to connect debugger")
After the program runs successfully, it will output the following content:
python
len = 2
lscond = 1
isbranch = 1
isret = False
iscall = False
ismem = False
ienop = False
isunusual = False
branchdest = 3347811
branchexec = 1
imm = 3347811
brtrue = 3347811
brfalse = 3347799
next = 0x331557
dis_prev = 0x331552
dis_iscallsystem = False
mnemonic = False
Memory command encapsulation
This code mainly involves the interaction function with the debugger, establishing a connection with the debugger through the x32dbg module, and implementing various operations through the Debugger class. Among them, the MemoryInfo class encapsulates methods for obtaining memory information, reading memory content, and handling exception information. By calling the corresponding command, the memory information at a given address can be obtained, including validity, base address, size, and whether it is executable. At the same time, the memory content can be read and exception information can be processed. Finally, the result is output for the user to view.
python
from x32dbg import Debugger
# Memory related classes
class MemoryInfo:
def __init__(self, debugger):
self.debugger = debugger
def get_memory_info(self, decimal_address, info_type):
try:
ref = self.debugger.script_runcmd_ex("mem.{}({})".
format(info_type, hex(decimal_address)))
return ref if ref is not None else False
except Exception:
return False
def valid(self, decimal_address):
return self.get_memory_info(decimal_address, "valid")
def base(self, decimal_address):
return self.get_memory_info(decimal_address, "base")
def size(self, decimal_address):
return self.get_memory_info(decimal_address, "size")
def iscode(self, decimal_address):
return self.get_memory_info(decimal_address, "iscode")
def decodepointer(self, decimal_address):
return self.get_memory_info(decimal_address, "decodepointer")
def bswap(self, decimal_address):
return self.debugger.script_runcmd_ex("bswap({})".format(decimal_address))
def readbyte(self, decimal_address):
return self.debugger.script_runcmd_ex("ReadByte({})".format(decimal_address))
def readword(self, decimal_address):
return self.debugger.script_runcmd_ex("ReadWord({})".format(decimal_address))
def readdword(self, decimal_address):
return self.debugger.script_runcmd_ex("ReadDword({})".format(decimal_address))
def readqword(self, decimal_address):
return self.debugger.script_runcmd_ex("ReadQword({})".format(decimal_address))
def readptr(self, decimal_address):
return self.debugger.script_runcmd_ex("ReadPtr({})".format(decimal_address))
def firstchance(self):
return self.debugger.script_runcmd_ex("ex.firstchance()")
def addr(self):
return self.debugger.script_runcmd_ex("ex.addr()")
def code(self):
return self.debugger.script_runcmd_ex("ex.code()")
def flags(self):
return self.debugger.script_runcmd_ex("ex.flags()")
def infocount(self):
return self.debugger.script_runcmd_ex("ex.infocount()")
def info(self, decimal_address):
return self.debugger.script_runcmd_ex("ex.info({})".format(decimal_address))
if __name__ == "__main__":
dbg = Debugger(address="127.0.0.1", port=6589)
if dbg.connect() == True:
# Define Memory classes
memory = MemoryInfo(dbg)
eip = dbg.get_eip()
# Check if the EIP address is valid, return true if it is valid
valid = memory.valid(eip)
print("valid = {}".format(valid))
# Obtain the base address at the eip location
base = memory.base(eip)
print("base = {}".format(hex(base)))
# Get the current size of EIP memory
size = memory.size(eip)
print("size = {}".format(size))
# Check if the current EIP is an executable page and return True successfully
iscode = memory.iscode(eip)
print("iscode = {}".format(iscode))
# Decrypting eip memory pointers
decodepointer = memory.decodepointer(eip)
print("decodepointer = {}".format(decodepointer))
# Read EIP memory integer type and pass in hexadecimal format
readbyte = memory.readbyte(hex(eip))
print("readbyte = {}".format(hex(readbyte)))
# Is the last exception the first exception
exfirstchance = memory.ex_firstchance()
print("exfirstchance = {}".format(exfirstchance))
# Last abnormal address
exaddr = memory.ex_addr()
print("exaddr = {}".format(exaddr))
# The last exception code
excode = memory.ex_code()
print("excode = {}".format(excode))
# The last exception flag
exflag = memory.ex_flags()
print("exflag = {}".format(exflag))
# Last abnormal information count
exinfocount = memory.ex_infocount()
print("exinfocount = {}".format(exinfocount))
# The last exception message is zero if the index is out of range
exinfo = memory.ex_info(1)
print("exinfo = {}".format(exinfo))
After the program runs successfully, it will output the following content:
python
valid = 1
base = 0xc21000
size = 4096
iscode = 1
decodepointer = 3832413802
readbyte = 0xe8
exfirstchance = 1
exaddr = 12719547
excode = 2147483651
exflag = False
exinfocount = 1
exinfo = False
Arithmetic command encapsulation
This code defines a class ArithmeticInfo that provides methods for performing various arithmetic operations on registers using the x32dbg debugger. The class initializes with a debugger object and allows for actions like incrementing, decrementing, addition, subtraction, multiplication, division, bitwise AND, OR, XOR, negation, left/right shifts, logical and arithmetic shifts, and bitwise NOT on registers. The script demonstrates the usage of these methods by connecting to a debugger instance and performing a series of register operations.
python
from x32dbg import Debugger
class ArithmeticInfo:
def __init__(self, debugger):
self.debugger = debugger
def set_arithmetic_info(self, action, register, decimal_int=None):
try:
if decimal_int is not None:
ref = self.debugger.script_runcmd("{} {},{}".format(action, register, decimal_int))
else:
ref = self.debugger.script_runcmd("{} {}".format(action, register))
return ref if ref is not None else False
except Exception:
return False
def reg_inc(self, register):
return self.set_arithmetic_info("inc", register)
def reg_dec(self, register):
return self.set_arithmetic_info("dec", register)
def reg_add(self, register, decimal_int):
return self.set_arithmetic_info("add", register, decimal_int)
def reg_sub(self, register, decimal_int):
return self.set_arithmetic_info("sub", register, decimal_int)
def reg_mul(self, register, decimal_int):
return self.set_arithmetic_info("mul", register, decimal_int)
def reg_div(self, register, decimal_int):
return self.set_arithmetic_info("div", register, decimal_int)
def reg_and(self, register, decimal_int):
return self.set_arithmetic_info("and", register, decimal_int)
def reg_or(self, register, decimal_int):
return self.set_arithmetic_info("or", register, decimal_int)
def reg_xor(self, register, decimal_int):
return self.set_arithmetic_info("xor", register, decimal_int)
def reg_neg(self, register):
return self.set_arithmetic_info("neg", register)
def reg_rol(self, register, decimal_int):
return self.set_arithmetic_info("rol", register, decimal_int)
def reg_ror(self, register, decimal_int):
return self.set_arithmetic_info("ror", register, decimal_int)
def reg_shl(self, register, decimal_int):
return self.set_arithmetic_info("shl", register, decimal_int)
def reg_shr(self, register, decimal_int):
return self.set_arithmetic_info("shr", register, decimal_int)
def reg_sal(self, register, decimal_int):
return self.set_arithmetic_info("sal", register, decimal_int)
def reg_sar(self, register, decimal_int):
return self.set_arithmetic_info("sar", register, decimal_int)
def reg_not(self, register, decimal_int):
return self.set_arithmetic_info("not", register, decimal_int)
if __name__ == "__main__":
dbg = Debugger(address="127.0.0.1", port=6589)
if dbg.connect() == True:
# Define Arithmetic classes
arithmetic = ArithmeticInfo(dbg)
# These methods return True if successful, False otherwise
# Increment register
arithmetic.reg_inc("eax")
# Decrement register
arithmetic.reg_dec("ebx")
# Perform add operation on register
arithmetic.reg_add("ecx", 10)
# Perform sub operation on register
arithmetic.reg_sub("edx", 5)
# Perform mul operation on register
arithmetic.reg_mul("esi", 2)
# Perform div operation on register
arithmetic.reg_div("edi", 3)
# Perform and operation on register
arithmetic.reg_and("ebp", 0xFF)
# Perform or operation on register
arithmetic.reg_or("esp", 0x0F)
# Perform xor operation on register
arithmetic.reg_xor("eax", 0xAA)
# Perform neg operation on register
arithmetic.reg_neg("ebx")
# Perform rol operation on register
arithmetic.reg_rol("ecx", 2)
# Perform ror operation on register
arithmetic.reg_ror("edx", 3)
# Perform shl operation on register
arithmetic.reg_shl("esi", 4)
# Perform shr operation on register
arithmetic.reg_shr("edi", 5)
# Perform sal operation on register
arithmetic.reg_sal("ebp", 2)
# Perform sar operation on register
arithmetic.reg_sar("esp", 3)
# Perform not operation on register
arithmetic.reg_not("eax", 0xFF)
All functions in this code return true if executed successfully, otherwise return false.