这篇文章上次修改于 314 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

就是调用一下 gdb.execute,仅供参考,不是lldb用的,不过都类似。

import re

# GDB Python SDK
import gdb

# -------- for type hint --------
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from gef import *
# -------- for type hint --------

class LibModule:

    def __init__(self, name: str, path: str, base: int, end: int) -> None:
        self.name = name
        self.path = path
        self.base = base
        self.end = end

    def add(self, offset: int):
        return self.base + offset

def find_module(module_name: str):
    '''
    这里没有做缓存
    每次都从 gef.memory.maps 查找以确保地址是最新的
    '''
    modules = {} # type: Dict[str, LibModule]
    for section in gef.memory.maps:
        if isinstance(section.path, str) is False:
            continue
        if section.path == '':
            continue
        if module_name == section.path.split('/')[-1]:
            if module_name in modules:
                if section.page_start < modules[module_name].base:
                    modules[module_name].base = section.page_start
                else:
                    # 每个分段不会重叠为前提
                    modules[module_name].end = section.page_start
            else:
                modules[module_name] = LibModule(
                    module_name,
                    section.path,
                    section.page_start,
                    section.page_end,
                )
    if module_name in modules:
        return modules[module_name] 
    else:
        assert False, f'can not find {module_name}'

def main():
    # 先忽略相关信号
    gdb.execute("handle SIGSEGV nostop pass")
    gdb.execute("handle SIGQUIT nostop nopass")
    gdb.execute("handle SIG35 nostop nopass")
    print('handle signal end')

    # 先获取模块信息 计算偏移对应的实际地址
    libxxx = find_module('libxxx.so')
    dump_breakpoint = libxxx.add(0x7F36C)
    canary_breakpoint = libxxx.add(0x7F380)

    # 设置某个断点执行到一定次数的时候 才真正断下来
    # https://stackoverflow.com/questions/2956889/how-to-make-a-gdb-breakpoint-only-break-after-the-point-is-reached-a-given-numbe

    # 首先下断点
    breakpoint_info = gdb.execute(f'b *0x{dump_breakpoint:x}', to_string=True).strip()
    # Breakpoint 1 at 0x76f398836c
    breakpoint_id = re.match('Breakpoint (\d+) at .+', breakpoint_info)
    if breakpoint_id is None:
        print(f'get breakpoint_id failed ===>{breakpoint_info}<===')
        return
    print(breakpoint_info)
    # 下面命令的意思是 dump_breakpoint 这个断点经过 50 次之后才会真正断下
    gdb.execute(f'ignore {breakpoint_id.group(1)} 50')
    print(f'canary breakpoint here, copy it => b *0x{canary_breakpoint:x}')
    # - 先复制上面的 canary断点命令
    # - 本脚本执行完成后 手动输入 r 继续执行
    # - 等待断下 然后执行前面复制的 canary断点命令

# <---------------- 使用说明 ---------------->
#
# 通过脚本设置断点 需要搭配最新版 gef.py 使用 供参考
# 
# 本脚本是在 attach 成功之后执行 请视情况修改编写脚本
# 
# source breakpoint_helper.py
#
# <---------------- 使用说明 ---------------->

if __name__ == '__main__':
    main()