简体中文 | ENGLISH | русский язык
一款 x64dbg 自动化控制插件,通过Python控制X64dbg,实现了远程动态调试,解决了逆向工作者分析漏洞,寻找指令片段,原生脚本不够强大的问题,通过与Python相结合利用Python语法的灵活性以及丰富的第三方库,提高分析效率,实现自动化分析代码。
python包请安装与插件一致的版本,在cmd命令行下执行pip 命令即可安装。
pip install LyScript32
或者 pip install LyScript64
其次您需要手动下载对应x64dbg版本的驱动文件,并放入指定目录下。
插件下载好以后,请将该插件复制到x64dbg目录下的plugins目录下,程序运行后会自动加载插件文件。
当插件加载成功后,会在日志位置看到具体的绑定信息以及输出调试,该插件并不会在插件栏显示。
如果需要远程调试,则只需要在初始化MyDebug()
类是传入对端IP地址即可,如果不填写参数则默认使用127.0.0.1
地址,请确保对端放行了6589
端口,否则无法连接。
运行x64dbg程序并手动载入需要分析的可执行文件,然后我们可以通过connect()
方法连接到调试器,连接后会创建一个持久会话直到python脚本结束则连接会被强制断开,在此期间可调用is_connect()
检查该链接是否还存在,具体代码如下所示。
from LyScript32 import MyDebug
if __name__ == "__main__":
# 初始化
dbg = MyDebug()
# 连接到调试器
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag))
# 检测套接字是否还在
ref = dbg.is_connect()
print("是否在连接: ", ref)
dbg.close()
get_register() 函数: 该函数主要用于实现,对特定寄存器的获取操作,用户需传入需要获取的寄存器名字即可。
可用范围:"DR0", "DR1", "DR2", "DR3", "DR6", "DR7", "EAX", "AX", "AH", "AL", "EBX", "BX", "BH", "BL", "ECX", "CX", "CH", "CL", "EDX", "DX", "DH", "DL", "EDI", "DI", "ESI", "SI", "EBP", "BP", "ESP", "SP", "EIP"
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag))
eax = dbg.get_register("eax")
ebx = dbg.get_register("ebx")
print("eax = {}".format(hex(eax)))
print("ebx = {}".format(hex(ebx)))
dbg.close()
如果您使用的是64位插件,则寄存器的支持范围将变为E系列加R系列。
可用范围扩展: "DR0", "DR1", "DR2", "DR3", "DR6", "DR7", "EAX", "AX", "AH", "AL", "EBX", "BX", "BH", "BL", "ECX", "CX", "CH", "CL", "EDX", "DX", "DH", "DL", "EDI", "DI", "ESI", "SI", "EBP", "BP", "ESP", "SP", "EIP", "RAX", "RBX", "RCX", "RDX", "RSI", "SIL", "RDI", "DIL", "RBP", "BPL", "RSP", "SPL", "RIP", "R8", "R8D", "R8W", "R8B", "R9", "R9D", "R9W", "R9B", "R10", "R10D", "R10W", "R10B", "R11", "R11D", "R11W", "R11B", "R12", "R12D", "R12W", "R12B", "R13", "R13D", "R13W", "R13B", "R14", "R14D", "R14W", "R14B", "R15", "R15D", "R15W", "R15B"
from LyScript64 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
rax = dbg.get_register("rax")
eax = dbg.get_register("eax")
ax = dbg.get_register("ax")
print("rax = {} eax = {} ax ={}".format(hex(rax),hex(eax),hex(ax)))
r8 = dbg.get_register("r8")
print("获取R系列寄存器: {}".format(hex(r8)))
dbg.close()
set_register() 函数: 该函数实现设置指定寄存器参数,同理64位将支持更多寄存器的参数修改。
可用范围:"DR0", "DR1", "DR2", "DR3", "DR6", "DR7", "EAX", "AX", "AH", "AL", "EBX", "BX", "BH", "BL", "ECX", "CX", "CH", "CL", "EDX", "DX", "DH", "DL", "EDI", "DI", "ESI", "SI", "EBP", "BP", "ESP", "SP", "EIP"
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag))
eax = dbg.get_register("eax")
dbg.set_register("eax",100)
print("eax = {}".format(hex(eax)))
dbg.close()
get_flag_register() 函数: 用于获取某个标志位参数,返回值只有真或者假。
可用寄存器范围:"ZF", "OF", "CF", "PF", "SF", "TF", "AF", "DF", "IF"
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag))
cf = dbg.get_flag_register("cf")
print("标志: {}".format(cf))
dbg.close()
set_flag_register() 函数: 用于设置某个标志位参数,返回值只有真或者假。
可用寄存器范围:"ZF", "OF", "CF", "PF", "SF", "TF", "AF", "DF", "IF"
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
zf = dbg.get_flag_register("zf")
print(zf)
dbg.set_flag_register("zf",False)
zf = dbg.get_flag_register("zf")
print(zf)
dbg.close()
set_debug() 函数: 用于影响调试器,例如前进一次,后退一次,暂停调试,终止等。
可用动作范围:[暂停 Pause] [运行 Run] [步入 StepIn] [步过 StepOut] [到结束 StepOver] [停止 Stop] [等待 Wait]
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag))
while True:
dbg.set_debug("StepIn")
eax = dbg.get_register("eax")
if eax == 0:
print("找到了")
break
dbg.close()
set_debug_count() 函数: 该函数是set_debug()
函数的延续,目的是执行自动步过次数。
可用动作范围:[暂停 Pause] [运行 Run] [步入 StepIn] [步过 StepOut] [到结束 StepOver] [停止 Stop] [等待 Wait]
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag))
dbg.set_debug_count("StepIn",10)
dbg.close()
is_debugger() /is_running() 函数: is_debugger可用于验证当前调试器是否处于调试状态,is_running则用于验证是否在运行。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.is_debugger()
print(ref)
ref = dbg.is_running()
print(ref)
dbg.close()
set_breakpoint() 函数: 设置断点与取消断点进行了分离,设置断点只需要传入十进制内存地址。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
ref = dbg.set_breakpoint(eip)
print("设置状态: {}".format(ref))
dbg.close()
delete_breakpoint() 函数: 该函数传入一个内存地址,可取消一个内存断点。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
ref = dbg.set_breakpoint(eip)
print("设置状态: {}".format(ref))
del_ref = dbg.delete_breakpoint(eip)
print("取消状态: {}".format(del_ref))
dbg.close()
check_breakpoint() 函数: 用于检查下过的断点是否被命中,命中返回True否则返回False。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
ref = dbg.set_breakpoint(eip)
print("设置状态: {}".format(ref))
is_check = dbg.check_breakpoint(4134331)
print("是否命中: {}".format(is_check))
dbg.close()
get_all_breakpoint() 函数: 用于获取当前调试程序中,所有下过的断点信息,包括是否开启,命中次数等。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.get_all_breakpoint()
print(ref)
dbg.close()
set_hardware_breakpoint() 函数: 用于设置一个硬件断点,硬件断点在32位系统中最多设置4个。
断点类型可用范围:[类型 0 = HardwareAccess / 1 = HardwareWrite / 2 = HardwareExecute]
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug(address="127.0.0.1",port=6666)
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
ref = dbg.set_hardware_breakpoint(eip,2)
print(ref)
dbg.close()
delete_hardware_breakpoint() 函数: 用于删除一个硬件断点,只需要传入地址即可,无需传入类型。
断点类型可用范围:[类型 0 = HardwareAccess / 1 = HardwareWrite / 2 = HardwareExecute]
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug(address="127.0.0.1",port=6666)
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
ref = dbg.set_hardware_breakpoint(eip,2)
print(ref)
# 删除断点
ref = dbg.delete_hardware_breakpoint(eip)
print(ref)
dbg.close()
get_module_base() 函数: 该函数可用于获取程序载入的指定一个模块的基地址。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
user32_base = dbg.get_module_base("user32.dll")
print(user32_base)
dbg.close()
get_all_module() 函数: 用于输出当前加载程序的所有模块信息,以字典的形式返回。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.get_all_module()
for i in ref:
print(i)
print(ref[0])
print(ref[1].get("name"))
print(ref[1].get("path"))
dbg.close()
get_local_() 系列函数: 获取当前EIP所在模块基地址,长度,以及内存属性,此功能无参数传递,获取的是当前EIP所指向模块的数据。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.get_local_base()
print(hex(ref))
ref2 = dbg.get_local_size()
print(hex(ref2))
ref3 = dbg.get_local_protect()
print(ref3)
dbg.close()
get_module_from_function() 函数: 获取指定模块中指定函数的内存地址,可用于验证当前程序在内存中指定函数的虚拟地址。
成功返回地址,失败返回false
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.get_module_from_function("user32.dll","MessageBoxW")
print(hex(ref))
ref2 = dbg.get_module_from_function("kernel32.dll","test")
print(ref2)
dbg.close()
get_module_from_import() 函数: 获取当前程序中指定模块的导入表信息,输出为列表嵌套字典。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.get_module_from_import("ucrtbase.dll")
print(ref)
ref1 = dbg.get_module_from_import("win32project1.exe")
for i in ref1:
print(i.get("name"))
dbg.close()
get_module_from_export() 函数: 该函数用于获取当前加载程序中的导出表信息。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.get_module_from_export("msvcr120d.dll")
for i in ref:
print(i.get("name"), hex(i.get("va")))
dbg.close()
get_section() 函数: 该函数用于输出主程序中的节表信息。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug(address="127.0.0.1",port=6666)
connect_flag = dbg.connect()
ref = dbg.get_section()
print(ref)
dbg.close()
get_base_from_address() 函数: 根据传入的内存地址得到该模块首地址。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
ref = dbg.get_base_from_address(eip)
print("模块首地址: {}".format(hex(ref)))
get_base_from_name() 函数: 根据传入的模块名得到该模块所在内存首地址。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
ref_base = dbg.get_base_from_name("win32project.exe")
print("模块首地址: {}".format(hex(ref_base)))
dbg.close()
get_oep_from_name() 函数: 根据传入的模块名,获取该模块实际装载OEP位置。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
oep = dbg.get_oep_from_name("win32project.exe")
print(hex(oep))
dbg.close()
get_oep_from_address() 函数: 根据传入内存地址,得到该地址模块的OEP位置。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
oep = dbg.get_oep_from_address(eip)
print(hex(oep))
dbg.close()
read_memory_() 系列函数: 读内存系列函数,包括 ReadByte,ReadWord,ReadDword 三种格式,在64位下才支持Qword
目前支持:
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
ref = dbg.read_memory_byte(eip)
print(hex(ref))
ref2 = dbg.read_memory_word(eip)
print(hex(ref2))
ref3 = dbg.read_memory_dword(eip)
print(hex(ref3))
ref4 = dbg.read_memory_ptr(eip)
print(hex(ref4))
dbg.close()
write_memory_() 系列函数: 写内存系列函数,WriteByte,WriteWord,WriteDWORD,WriteQword
目前支持:
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
addr = dbg.create_alloc(1024)
print(hex(addr))
ref = dbg.write_memory_byte(addr,10)
print(ref)
dbg.close()
scan_memory_one() 函数: 实现了内存扫描,当扫描到第一个符合条件的特征时,自动输出。
这个函数需要注意,如果我们的x64dbg工具停在系统领空,则会默认搜索系统领空下的特征,如果像搜索程序里面的,需要先将EIP切过去在操作。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.scan_memory_one("ff 25")
print(ref)
dbg.close()
scan_memory_all() 函数: 实现了扫描所有符合条件的特征字段,找到后返回一个列表。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.scan_memory_all("ff 25")
for index in ref:
print(hex(index))
dbg.close()
get_local_protect() 函数: 获取内存属性传值,该函数进行更新,取消了只能得到EIP所指的位置的内存属性,用户可随意检测。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
print(eip)
ref = dbg.get_local_protect(eip)
print(ref)
set_local_protect() 函数: 新增设置内存属性函数,传入eip内存地址,设置属性32,以及设置内存长度1024即可。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
print(eip)
b = dbg.set_local_protect(eip,32,1024)
print("设置属性状态: {}".format(b))
dbg.close()
get_local_page_size() 函数: 用于获取当前EIP所指领空下,内存pagesize分页大小。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
size = dbg.get_local_page_size()
print("pagesize = {}".format(size))
dbg.close()
get_memory_section() 函数: 该函数主要用于获取内存映像中,当前调试程序的内存节表数据。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.get_memory_section()
print(ref)
dbg.close()
create_alloc() 函数: 函数CreateRemoteAlloc()
可在远程开辟一段堆空间,成功返回内存首地址。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.create_alloc(1024)
print("开辟地址: ", hex(ref))
dbg.close()
delete_alloc() 函数: 函数delete_alloc()
用于注销一个远程堆空间。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.create_alloc(1024)
print("开辟地址: ", hex(ref))
flag = dbg.delete_alloc(ref)
print("删除状态: ",flag)
dbg.close()
push_stack() 函数: 将一个十进制数压入堆栈中,默认在堆栈栈顶。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.push_stack(10)
print(ref)
dbg.close()
pop_stack() 函数: pop函数用于从堆栈中推出一个元素,默认从栈顶弹出。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
tt = dbg.pop_stack()
print(tt)
dbg.close()
peek_stack() 函数: peek则用于检查堆栈内的参数,可设置偏移值,不设置则默认检查第一个也就是栈顶。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
# 无参数检查
check = dbg.peek_stack()
print(check)
# 携带参数检查
check_1 = dbg.peek_stack(2)
print(check_1)
dbg.close()
get_thread_list() 函数: 该函数可输出当前进程所有在运行的线程信息。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.get_thread_list()
print(ref[0])
print(ref[1])
dbg.close()
get_process_handle() 函数: 用于获取当前进程句柄信息。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.get_process_handle()
print(ref)
dbg.close()
get_process_id() 函数: 用于获取当前加载程序的PID
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.get_process_id()
print(ref)
dbg.close()
get_teb_address() / get_peb_address() 系列函数: 用于获取当前进程环境块,和线程环境快。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.get_teb_address(6128)
print(ref)
ref = dbg.get_peb_address(9012)
print(ref)
dbg.close()
get_disasm_code() 函数: 该函数主要用于对特定内存地址进行反汇编,传入两个参数。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag))
# 得到EIP位置
eip = dbg.get_register("eip")
# 反汇编前100行
disasm_dict = dbg.get_disasm_code(eip,100)
for ds in disasm_dict:
print("地址: {} 反汇编: {}".format(hex(ds.get("addr")),ds.get("opcode")))
dbg.close()
get_disasm_one_code() 函数: 在用户指定的位置读入一条汇编指令,用户可根据需要对其进行判断。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
print("EIP = {}".format(eip))
disasm = dbg.get_disasm_one_code(eip)
print("反汇编一条: {}".format(disasm))
dbg.close()
get_disasm_operand_code() 函数: 用于获取汇编指令中的操作数,例如jmp 0x0401000
其操作数就是0x0401000
。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
print("EIP = {}".format(eip))
opcode = dbg.get_disasm_operand_code(eip)
print("操作数: {}".format(hex(opcode)))
dbg.close()
get_disasm_operand_size() 函数: 用于得当前内存地址下汇编代码的机器码长度。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
print("EIP = {}".format(eip))
opcode = dbg.get_disasm_operand_size(eip)
print("机器码长度: {}".format(hex(opcode)))
dbg.close()
assemble_write_memory() 函数: 实现了用户传入一段正确的汇编指令,程序自动将该指令转为机器码,并写入到指定位置。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
print(eip)
ref = dbg.assemble_write_memory(eip,"mov eax,1")
print("是否写出: {}".format(ref))
dbg.close()
assemble_code_size() 函数: 该函数实现了用户传入一个汇编指令,自动计算出该指令占多少个字节。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.assemble_code_size("sub esp, 0x324")
print(ref)
dbg.close()
set_comment_notes() 函数: 给指定位置代码增加一段注释,如下演示在eip位置增加注释。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
eip = dbg.get_register("eip")
ref = dbg.set_comment_notes(eip,"hello lyshark")
print(ref)
dbg.close()
run_command_exec() 函数: 执行内置命令,例如bp,dump等。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
ref = dbg.run_command_exec("bp MessageBoxA")
print(ref)
dbg.close()
set_loger_output() 函数: 日志的输出尤为重要,该模块提供了自定义日志输出功能,可将指定日志输出到x64dbg日志位置。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
for i in range(0,100):
ref = dbg.set_loger_output("hello lyshark -> {} \n".format(i))
print(ref)
dbg.close()
LyScript 模块中的通用案例,用于演示插件内置方法如何组合使用,用户可以学习研究。
PEFile载入内存格式: 案例演示了,如何将一个可执行文件中的内存数据通过PEfile模块打开。
from LyScript32 import MyDebug
import pefile
if __name__ == "__main__":
# 初始化
dbg = MyDebug()
dbg.connect()
# 得到text节基地址
local_base = dbg.get_local_base()
# 根据text节得到程序首地址
base = dbg.get_base_from_address(local_base)
byte_array = bytearray()
for index in range(0,4096):
read_byte = dbg.read_memory_byte(base + index)
byte_array.append(read_byte)
oPE = pefile.PE(data = byte_array)
timedate = oPE.OPTIONAL_HEADER.dump_dict()
print(timedate)
全模块特征匹配: 针对所有模块中的特征码模糊匹配,找到会返回内存地址。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
dbg.connect()
for entry in dbg.get_all_module():
eip = entry.get("entry")
if eip != 0:
dbg.set_register("eip",eip)
search = dbg.scan_memory_one("ff 25 ??")
print(hex(search))
dbg.close()
搜索汇编特征: 使用python实现方法,通过特定方法扫描内存范围,如果出现我们所需要的指令集序列,则输出该指令的具体内存地址。
from LyScript32 import MyDebug
# 检索指定序列中是否存在一段特定的指令集
def SearchOpCode(OpCodeList,SearchCode,ReadByte):
pass
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag))
# 得到EIP位置
eip = dbg.get_register("eip")
# 反汇编前1000行
disasm_dict = dbg.get_disasm_code(eip,1000)
# 搜索一个指令序列,用于快速查找构建漏洞利用代码
SearchCode = [
["push 0xC0000409", "call 0x003F1B38", "pop ecx"],
["mov ebp, esp", "sub esp, 0x324"]
]
# 检索内存指令集
for item in range(0,len(SearchCode)):
Search = SearchCode[item]
# disasm_dict = 返回汇编指令 Search = 寻找指令集 1000 = 向下检索长度
ret = SearchOpCode(disasm_dict,Search,1000)
if ret != None:
print("指令集: {} --> 首次出现地址: {}".format(SearchCode[item],hex(ret)))
dbg.close()
得到汇编指令机器码: 该功能主要实现,得到用户传入汇编指令所对应的机器码,这段代码你可以这样来实现。
from LyScript32 import MyDebug
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag))
addr = dbg.create_alloc(1024)
print("堆空间: {}".format(hex(addr)))
asm_size = dbg.assemble_code_size("mov eax,1")
print("汇编代码占用字节: {}".format(asm_size))
write = dbg.assemble_write_memory(addr,"mov eax,1")
byte_code = bytearray()
for index in range(0,asm_size):
read = dbg.read_memory_byte(addr + index)
print("{:02x} ".format(read),end="")
dbg.delete_alloc(addr)
封装上方代码,你就可以实现一个汇编指令获取工具了,如下get_opcode_from_assemble()
函数。
from LyScript32 import MyDebug
# 传入汇编代码,得到对应机器码
def get_opcode_from_assemble(dbg_ptr,asm):
pass
if __name__ == "__main__":
dbg = MyDebug()
connect_flag = dbg.connect()
print("连接状态: {}".format(connect_flag))
# 获取汇编代码
byte_array = get_opcode_from_assemble(dbg,"xor eax,eax")
for index in byte_array:
print(hex(index),end="")
print()
# 汇编一个序列
asm_list = ["xor eax,eax", "xor ebx,ebx", "mov eax,1"]
for index in asm_list:
byte_array = get_opcode_from_assemble(dbg, index)
for index in byte_array:
print(hex(index),end="")
print()
dbg.close()
如何劫持EIP: 这里我们演示一个案例,你可以自己实现一个write_opcode_from_assemble()
函数批量将列表中的指令集写出到内存,演示案例。
from LyScript32 import MyDebug
# 传入汇编指令列表,直接将机器码写入对端内存
def write_opcode_from_assemble(dbg_ptr,asm_list):
pass
if __name__ == "__main__":
dbg = MyDebug()
dbg.connect()
# 写出指令集到内存
asm_list = ['mov eax,1','mov ebx,2','add eax,ebx']
write_addr = write_opcode_from_assemble(dbg,asm_list)
print("写出地址: {}".format(hex(write_addr)))
# 设置执行属性
dbg.set_local_protect(write_addr,32,1024)
# 将EIP设置到指令集位置
dbg.set_register("eip",write_addr)
dbg.close()
如何执行函数呢?很简单,看以下代码是如何实现的,相信你能看懂,运行后会看到一个错误弹窗,说明程序执行流已经被转向了。
from LyScript32 import MyDebug
# 传入汇编指令列表,直接将机器码写入对端内存
def write_opcode_from_assemble(dbg_ptr,asm_list):
pass
if __name__ == "__main__":
dbg = MyDebug()
dbg.connect()
# 得到messagebox内存地址
msg_ptr = dbg.get_module_from_function("user32.dll","MessageBoxA")
call = "call {}".format(str(hex(msg_ptr)))
print("函数地址: {}".format(call))
# 写出指令集到内存
asm_list = ['push 0','push 0','push 0','push 0',call]
write_addr = write_opcode_from_assemble(dbg,asm_list)
print("写出地址: {}".format(hex(write_addr)))
# 设置执行属性
dbg.set_local_protect(write_addr,32,1024)
# 将EIP设置到指令集位置
dbg.set_register("eip",write_addr)
# 执行代码
dbg.set_debug("Run")
dbg.close()
内存字节变更后回写: 封装字节函数write_opcode_list()
传入内存地址,对该地址中的字节更改后再回写到原来的位置。
from LyScript32 import MyDebug
# 对每一个字节如何处理
def write_func(x):
x = x + 10
return x
# 对指定内存地址机器码进行相应处理
def write_opcode_list(dbg_ptr, address, count, function_ptr):
for index in range(0, count):
read = dbg_ptr.read_memory_byte(address + index)
ref = function_ptr(read)
print("处理后结果: {}".format(ref))
dbg.write_memory_byte(address + index, ref)
return True
if __name__ == "__main__":
dbg = MyDebug()
dbg.connect()
# 得到EIP
eip = dbg.get_register("eip")
# 对指定内存中的数据+10后写回去
write_opcode_list(dbg,eip,100,write_func)
dbg.close()
指令集探针快速检索: 快速检索当前程序中所有模块中是否存在特定的指令集片段,存在则返回内存地址。
from LyScript32 import MyDebug
# 将bytearray转为字符串
def get_string(byte_array):
ref_string = str()
for index in byte_array:
ref_string = ref_string + "".join(str(index))
return ref_string
# 传入汇编代码,得到对应机器码
def get_opcode_from_assemble(dbg_ptr,asm):
pass
if __name__ == "__main__":
dbg = MyDebug()
dbg.connect()
# 需要搜索的指令集片段
search_asm = ['pop ecx','mov edi,edi', 'push eax', 'jmp esp']
opcode = []
# 将汇编指令转为机器码,放入opcode
for index in range(len(search_asm)):
byt = bytearray()
byt = get_opcode_from_assemble(dbg, search_asm[index])
opcode.append(get_string(byt))
# 循环搜索指令集内存地址
for index,entry in zip(range(0,len(opcode)), dbg.get_all_module()):
eip = entry.get("entry")
base_name = entry.get("name")
if eip != 0:
dbg.set_register("eip",eip)
search_address = dbg.scan_memory_all(opcode[index])
if search_address != False:
print("指令: {} --> 模块: {} --> 个数: {}".format(search_asm[index],base_name,len(search_address)))
for search_index in search_address:
print("[*] {}".format(hex(search_index)))
else:
print("a")
time.sleep(0.3)
dbg.close()
使用内置脚本得到返回值: 使用内置run_command_exec()
函数时,用户只能得到内置脚本执行后的状态值,如果想要得到内置命令的返回值则你可以这样写。
from LyScript32 import MyDebug
dbg = MyDebug()
conn = dbg.connect()
# 首先定义一个脚本变量
ref = dbg.run_command_exec("$addr=1024")
# 将脚本返回值放到eax寄存器,或者开辟一个堆放到堆里
dbg.run_command_exec("eax=$addr")
# 最后拿到寄存器的值
hex(dbg.get_register("eax"))
通过中转的方式,可以很好的得到内置脚本的返回值,如下我将其封装成了一个独立的方法。
from LyScript32 import MyDebug
# 得到脚本返回值
def GetScriptValue(dbg,script):
try:
ref = dbg.run_command_exec("push eax")
if ref != True:
return None
ref = dbg.run_command_exec(f"eax={script}")
if ref != True:
return None
reg = dbg.get_register("eax")
ref = dbg.run_command_exec("pop eax")
if ref != True:
return None
return reg
except Exception:
return None
return None
if __name__ == "__main__":
dbg = MyDebug()
dbg.connect()
eax = "401000"
ref = GetScriptValue(dbg,"mod.base({})".format(eax))
print(hex(ref))
dbg.close()
批量载入移除被调试进程: 默认的LyScript插件没有批量载入功能,导致用户只能手动将被调试进程拖入到x64dbg中才可以调试,使用python模拟快捷键即可解决这个问题。
import win32api
import win32gui, win32con
import win32clipboard
import re
import time
from LyScript32 import MyDebug
class cWindow:
def __init__(self):
self._hwnd = None
def SetAsForegroundWindow(self):
win32gui.SetForegroundWindow(self._hwnd)
def Maximize(self):
# 最大化
win32gui.ShowWindow(self._hwnd, win32con.SW_MAXIMIZE)
def _window_enum_callback(self, hwnd, regex):
if self._hwnd is None and re.match(regex, str(win32gui.GetWindowText(hwnd))) is not None:
self._hwnd = hwnd
def find_window_regex(self, regex):
self._hwnd = None
win32gui.EnumWindows(self._window_enum_callback, regex)
def hide_always_on_top_windows(self):
win32gui.EnumWindows(self._window_enum_callback_hide, None)
def _window_enum_callback_hide(self, hwnd, unused):
if hwnd != self._hwnd:
if win32gui.IsWindowVisible(hwnd) and win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE) & win32con.WS_EX_TOPMOST:
className = win32gui.GetClassName(hwnd)
if not (className == 'Button' or className == 'Shell_TrayWnd'):
win32gui.ShowWindow(hwnd, win32con.SW_FORCEMINIMIZE)
def OpenFile(self,path):
# 按下F3
win32api.keybd_event(0x72, 0, 0, 0)
win32api.keybd_event(0x72, 0, win32con.KEYEVENTF_KEYUP, 0)
# 打开剪贴板
win32clipboard.OpenClipboard()
# 清空剪贴板
win32clipboard.EmptyClipboard()
# 设置剪贴板内容
win32clipboard.SetClipboardData(win32con.CF_UNICODETEXT, path)
# 获取剪贴板内容
date = win32clipboard.GetClipboardData()
print("[*] OpenFile = {}".format(date))
# 关闭剪贴板
win32clipboard.CloseClipboard()
time.sleep(0.2)
# 按下ctrl+v
win32api.keybd_event(0x11, 0, 0, 0)
win32api.keybd_event(0x56, 0, 0, 0)
win32api.keybd_event(0x56, 0, win32con.KEYEVENTF_KEYUP, 0)
win32api.keybd_event(0x11, 0, win32con.KEYEVENTF_KEYUP, 0)
# 按下回车
win32api.keybd_event(0x0D, 0, 0, 0)
win32api.keybd_event(0x0D, 0, win32con.KEYEVENTF_KEYUP, 0)
def deatch(self):
# 按下Ctrl+Alt+F2
win32api.keybd_event(0x11, 0, 0, 0)
win32api.keybd_event(0x12, 0, 0, 0)
win32api.keybd_event(0x71, 0, 0, 0)
win32api.keybd_event(0x11, 0, win32con.KEYEVENTF_KEYUP, 0)
win32api.keybd_event(0x12, 0, win32con.KEYEVENTF_KEYUP, 0)
win32api.keybd_event(0x71, 0, win32con.KEYEVENTF_KEYUP, 0)
# 打开调试程序
def OpenFile(path):
regex = ".*x32dbg.*"
cWindows = cWindow()
cWindows.find_window_regex(regex)
cWindows.SetAsForegroundWindow()
cWindows.SetAsForegroundWindow()
cWindows.OpenFile(path)
# 关闭调试程序
def DeatchFile():
regex = ".*x32dbg.*"
cWindows = cWindow()
cWindows.find_window_regex(regex)
cWindows.SetAsForegroundWindow()
cWindows.SetAsForegroundWindow()
cWindows.deatch()
# 得到脚本返回值
def GetScriptValue(dbg,script):
try:
ref = dbg.run_command_exec("push eax")
if ref != True:
return None
ref = dbg.run_command_exec(f"eax={script}")
if ref != True:
return None
reg = dbg.get_register("eax")
ref = dbg.run_command_exec("pop eax")
if ref != True:
return None
return reg
except Exception:
return None
return None
if __name__ == "__main__":
dbg = MyDebug()
dbg.connect()
# 批量打开一个列表
for item in ["D:\Win32Project.exe","D:\Windows Tools\C32ASM\c32asm.exe"]:
OpenFile(item)
time.sleep(3)
for i in range(1,100):
dbg.set_debug("StepIn")
time.sleep(0.2)
eip = dbg.get_register("eip")
print("eip = > {}".format(hex(eip)))
time.sleep(3)
DeatchFile()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。