首页
社区
课程
招聘
[原创]一个GDB MCP服务
发表于: 2025-11-26 19:19 567

[原创]一个GDB MCP服务

2025-11-26 19:19
567

说明

这是一个gdb mcp服务端程序,主要封装了启动调试、停止调试、用户输入(命令输入与程序输入)三个基本操作(还有个Ctrl+C信号中断),相当于把人能做的事情赋能给大模型了。另外,封装了一个执行系统命令的操作,相当于万能指令了。功能虽然简单,但是 我相信随着大模型能力的不断加强,简单的功能就足够了。 目前配合IDA-Pro-MCP,使用稍微靠谱的大模型,对于简单的PWN题,可以一句话解,而稍复杂一些的,还不太行,感觉在交互调试(MCP设计)、PWN知识库、PWN专用Agent框架、大模型本身能力、提示词优化这几块还有潜力继续加强。

my_gdb_mcp_server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
import sys
import pexpect
from fastmcp import FastMCP
 
# 定义 MCP 服务
mcp = FastMCP("GDB-MCP-Server")
 
class GDBManager:
    def __init__(self):
        self.child = None
        self.timeout_message = "[MCP Info] Execution timed out (likely running)."
 
    def start(self, command="gdb"):
        """启动 GDB 进程并配置环境"""
        if self.child and self.child.isalive():
            self.child.close()
         
        try:
            # 启动 GDB,使用 utf-8 编码
            self.child = pexpect.spawn(command, encoding='utf-8', timeout=5)
             
            # 1. 先等待启动完成,获取纯净的 Banner 信息
            # 这样可以避免初始化命令的回显混入启动信息中
            try:
                self.child.expect([r'\(gdb\)', r'pwndbg>', r'gef>', r'gdb-peda\$', r'\$'], timeout=5)
                startup_msg = self.child.before
            except pexpect.TIMEOUT:
                startup_msg = self.child.before if self.child.before else "GDB started (no prompt detected yet)"
 
            # 2. 发送初始化命令,并消耗掉回显
            # 逐条发送并等待,确保 Buffer 干净
            init_cmds = [
                "set pagination off",
                "set confirm off",
                "set width 0",
                "set height 0"
            ]
             
            for cmd in init_cmds:
                self.child.sendline(cmd)
                try:
                    # 快速等待提示符,消耗掉命令回显
                    self.child.expect([r'\(gdb\)', r'pwndbg>', r'gef>', r'gdb-peda\$', r'\$'], timeout=1)
                except pexpect.TIMEOUT:
                    pass
             
            return f"GDB Started successfully.\nCommand: {command}\n\nInitial Output:\n{startup_msg}"
             
        except Exception as e:
            if self.child:
                self.child.close()
                self.child = None
            return f"Failed to start GDB: {str(e)}"
 
    def execute(self, cmd, timeout=10):
        """执行命令并获取输出"""
        if not self.child or not self.child.isalive():
            return "Error: GDB is not running. Please use start_debugging first."
 
        # 发送命令
        self.child.sendline(cmd)
         
        try:
            # 尝试匹配常见提示符
            # 注意:如果不改提示符,我们需要匹配各种可能的提示符
            # 这可能会导致在程序输出类似提示符的内容时误判,但在不做修改的前提下这是必须的
            index = self.child.expect([r'\(gdb\)', r'pwndbg>', r'gef>', r'gdb-peda\$', r'\$'], timeout=timeout)
             
            # 获取输出(包含 ANSI 码)
            output = self.child.before
             
            # 补上匹配到的提示符(为了完整性)
            # output += self.child.after # 通常不需要返回提示符,但为了原样输出可以考虑
             
            return output
             
        except pexpect.TIMEOUT:
            # 超时处理:通常意味着程序在运行中
            current_output = self.child.before if self.child.before else ""
            return f"{current_output}\n\n{self.timeout_message}"
 
        except Exception as e:
            return f"Error executing command: {str(e)}"
 
    def interrupt(self):
        """发送 SIGINT (Ctrl+C)"""
        if not self.child or not self.child.isalive():
            return "Error: GDB not running"
         
        self.child.sendintr()
         
        # 中断后,尝试读取输出
        try:
            self.child.expect([r'\(gdb\)', r'pwndbg>', r'gef>', r'gdb-peda\$', r'\$'], timeout=2)
            return f"Interrupted.\n{self.child.before}"
        except pexpect.TIMEOUT:
            return "Signal sent, but GDB prompt did not appear immediately."
 
    def stop(self):
        """停止调试会话"""
        if self.child:
            self.child.close()
            self.child = None
        return "GDB Session ended."
 
# 全局实例
gdb = GDBManager()
 
@mcp.tool()
def run_shell_command(command: str, timeout: int = 10):
    """
    在 MCP 服务器的宿主环境中执行系统 Shell 命令。
     
    该工具允许你直接运行宿主机的系统命令,如 `ps`, `ls`, `grep` 等,这对于辅助调试(如查找进程 ID、检查文件存在)非常有用。
     
    Args:
        command: 要执行的完整 Shell 命令字符串(例如 "ps aux | grep my_process")。
        timeout: 命令执行的超时时间(秒),默认为 10 秒。
     
    Returns:
        包含 stdout, stderr 和退出码的完整输出。
    """
    try:
        import subprocess
         
        # 使用 subprocess.run 替代 os.popen 以获得更好的控制(包括超时)
        # capture_output=True 捕获 stdout 和 stderr
        # text=True 将输出解码为字符串
        result = subprocess.run(
            command,
            shell=True,
            capture_output=True,
            text=True,
            timeout=timeout
        )
         
        output = f"Command: {command}\n"
        output += f"Exit Code: {result.returncode}\n\n"
         
        if result.stdout:
            output += f"STDOUT:\n{result.stdout}\n"
         
        if result.stderr:
            output += f"STDERR:\n{result.stderr}\n"
             
        return output.strip()
         
    except subprocess.TimeoutExpired as e:
        output = f"Command: {command}\n"
        output += f"Error: Execution timed out after {timeout} seconds.\n"
        if e.stdout:
             output += f"\nPartial STDOUT:\n{e.stdout.decode('utf-8', errors='ignore')}\n"
        if e.stderr:
             output += f"\nPartial STDERR:\n{e.stderr.decode('utf-8', errors='ignore')}\n"
        return output
         
    except Exception as e:
        return f"Error executing shell command: {str(e)}"
 
@mcp.tool()
def start_debugging(command: str = "gdb"):
    """
    启动一个新的 GDB 调试会话。
     
    这是进行调试的第一步。该工具会启动 GDB 进程并建立通信管道。
    支持本地启动、附加进程和远程调试模式。
     
    Args:
        command: 启动 GDB 的完整 Shell 命令字符串。
            - 本地调试(推荐): "gdb ./my_program"
              此模式下,MCP 可以完整捕获被调试程序的标准输入输出(I/O)。
            - 自动执行脚本: "gdb -x debug_script.gdb ./my_program"
              支持通过 -x 参数在启动时加载并执行 GDB 脚本。
            - 附加到现有进程: "gdb -p <PID>"
            - 远程调试准备: "gdb"
              启动空 GDB 后,请接着调用 `execute_command` 发送 `target remote <host>:<port>`。
    """
    return gdb.start(command)
 
@mcp.tool()
def send_gdb_command(command: str, timeout: int = 10):
    """
    向 GDB 会话发送命令或向被调试程序发送标准输入。
     
    这是与 GDB 进行双向交互的核心工具。
     
    功能:
    1. 执行 GDB 调试命令:如 `break main`, `step`, `print x`。
    2. 向程序发送输入:如果程序正在等待标准输入(stdin),通过此工具发送的内容会被传递给程序。
     
    Args:
        command: 要发送的命令字符串或输入数据。
        timeout: 等待输出的超时时间(秒)。
            - 对于耗时操作或程序持续运行(continue),超时是正常的,会返回当前已产生的输出。
    """
    return gdb.execute(command, timeout)
 
@mcp.tool()
def interrupt():
    """
    向 GDB 进程发送中断信号 (SIGINT/Ctrl+C)。
     
    使用场景:
    当程序正在运行(例如执行了 `continue` 后)且你想暂停它以检查状态时,调用此工具。
    这相当于在终端中按下了 Ctrl+C。
    """
    return gdb.interrupt()
 
@mcp.tool()
def stop_debugging():
    """
    终止当前的 GDB 调试会话。
     
    该工具会关闭 GDB 进程并清理资源。
    注意:如果只是想暂停程序运行,请使用 `interrupt` 工具,而不是这个。
    """
    return gdb.stop()
 
if __name__ == "__main__":
    mcp.run(transport="sse")

软件依赖

1
2
3
4
5
6
7
8
root@Jtian:/app# python -V
Python 3.12.3
root@Jtian:/app# pip list |grep fastmcp
fastmcp                   1.0
root@Jtian:/app#
root@Jtian:/app# pip list |grep pexpect
pexpect                   4.9.0
root@Jtian:/app#

测试

启动mcp服务端

1
2
3
4
5
6
root@Jtian:/app#
root@Jtian:/app# python my_gdb_mcp_server.py
INFO:     Started server process [624]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

测试mcp服务端

1
npx @modelcontextprotocol/inspector --url http://127.0.0.1:8000/sse --transport sse

图片描述
图片描述

其他

工具配置参考

1
2
3
4
5
6
"gdb-mcp-server": {
    "type": "sse",
    "url": "d2bK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0R3H3x3o6m8Q4x3V1k6K6M7$3f1`.",
    "timeout": 1800,
    "disabled": false
}

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2025-12-1 00:15 被Jtian编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (2)
雪    币: 2506
活跃值: (5180)
能力值: ( LV7,RANK:105 )
在线值:
发帖
回帖
粉丝
2
原本想直接使用 b31K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6&6P5i4N6*7x3e0V1&6z5g2)9J5c8X3N6V1j5W2)9J5k6r3#2U0M7q4)9J5k6s2y4W2M7Y4k6W2M7W2)9J5y4X3&6T1M7%4m8Q4x3@1u0Q4c8e0W2Q4b7e0q4Q4b7U0W2Q4c8e0N6Q4z5f1u0Q4b7f1g2Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0c8Q4b7V1c8Q4z5o6k6Q4c8e0k6Q4z5e0S2Q4b7f1k6Q4c8e0k6Q4b7U0g2Q4z5p5u0Q4c8e0S2Q4b7f1k6Q4z5e0g2Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0k6Q4z5e0N6Q4b7U0k6Q4c8e0g2Q4z5o6m8Q4z5e0W2Q4c8e0g2Q4z5p5k6Q4z5e0q4Q4c8e0N6Q4z5p5g2Q4b7U0m8Q4c8e0g2Q4z5f1y4Q4b7e0S2g2j5Y4g2F1N6s2f1J5y4q4)9J5k6e0l9@1i4@1f1%4i4K6W2m8i4K6R3@1c8r3!0U0K9$3g2J5i4@1f1%4i4K6S2q4i4@1q4r3i4@1f1#2i4@1p5J5i4K6R3K6i4@1f1&6i4K6R3%4i4K6S2o6i4@1g2r3i4@1u0o6i4K6S2o6i4@1f1^5i4@1q4r3i4@1p5#2i4@1f1&6i4@1p5I4i4@1t1&6i4@1f1%4i4K6W2n7i4@1q4q4i4@1f1@1i4@1u0m8i4@1p5@1i4@1f1@1i4@1u0m8i4K6V1J5i4@1f1$3i4K6W2o6i4K6R3&6i4@1f1&6i4K6V1%4i4@1q4q4i4@1f1&6i4@1p5J5i4K6V1^5i4@1g2r3i4@1u0o6i4K6R3^5b7f1W2Q4c8e0S2Q4b7f1k6Q4b7U0c8Q4c8e0S2Q4b7f1k6Q4b7e0g2Q4c8e0W2Q4b7e0q4Q4b7U0W2Q4c8e0N6Q4z5f1u0Q4b7f1g2Q4c8e0W2Q4z5o6m8Q4z5o6u0Q4c8e0N6Q4z5e0c8Q4b7e0S2Q4c8e0c8Q4b7V1q4Q4z5p5g2y4b7f1y4Q4c8e0N6Q4z5e0c8Q4b7U0g2Q4c8e0S2Q4z5o6c8Q4z5e0q4Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0k6Q4z5f1y4Q4b7f1q4Q4c8e0k6Q4b7U0g2Q4z5p5u0Q4c8e0S2Q4b7f1k6Q4z5e0g2Q4c8f1k6Q4b7V1y4Q4z5o6W2Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0g2Q4z5f1u0Q4b7e0m8Q4c8e0k6Q4b7f1c8Q4b7e0c8Q4c8e0S2Q4b7f1g2Q4b7e0W2m8d9g2!0q4y4g2!0n7z5q4!0m8c8g2!0q4y4g2!0n7c8W2)9&6z5g2!0q4z5g2)9^5y4#2)9^5c8q4!0q4y4g2)9^5y4W2)9&6z5g2!0q4y4q4!0n7b7g2)9^5y4W2!0q4y4q4!0n7z5q4)9^5x3q4!0q4y4g2!0m8y4g2)9&6y4#2!0q4x3#2)9^5x3q4)9^5x3W2!0q4y4W2)9^5c8W2)9&6x3q4!0q4z5q4!0n7c8W2)9&6z5g2!0q4y4q4!0n7z5q4!0m8b7g2!0q4z5g2!0m8x3g2!0n7z5g2!0q4y4#2)9&6b7W2!0m8c8g2!0q4c8W2!0n7b7#2)9^5b7#2!0q4y4q4!0n7z5q4!0n7b7W2!0q4z5q4!0m8y4W2)9^5x3g2!0q4y4W2)9&6z5q4!0m8c8W2!0q4z5g2)9^5x3#2!0m8z5q4!0q4y4g2)9^5z5q4)9^5y4W2!0q4y4#2)9^5x3g2!0n7y4g2!0q4y4W2)9^5y4q4)9&6c8W2!0q4y4W2)9&6c8q4!0m8y4g2!0q4z5q4)9^5y4#2!0m8b7g2!0q4z5q4!0n7c8W2)9&6z5g2!0q4y4q4!0n7z5q4!0m8b7g2!0q4z5g2!0m8x3g2!0n7z5g2!0q4y4#2)9&6b7W2!0m8c8g2!0q4x3#2)9^5x3q4)9^5x3R3`.`.
2025-11-26 19:33
0
雪    币: 2506
活跃值: (5180)
能力值: ( LV7,RANK:105 )
在线值:
发帖
回帖
粉丝
3
以pwndbg为代表的,其输出可能有很多颜色编码,这个可以过滤掉,也可以不过滤掉,一方面现在的大模型识别这些颜色编码毫无压力(虽然对人来说,像乱码一样),另一方面,这些颜色编码本身带有特定的信息,是有些用的。
2025-11-26 19:37
0
游客
登录 | 注册 方可回帖
返回