Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
pico2-swd-riscv — SWD 调试探针库,适用于 RP2350 RISC-V 内核。通过 PIO 位拆操作,利用两根 GPIO 线提供暂停/恢复/单步、寄存器与内存访问、代码执行以及指令跟踪功能。 | Kitploit
工具/GitHubGitHub/jackdoe/pico2-swd-riscv
嵌入式系统安全逆向工程调试器硬件黑客硬件安全固件分析
GitHubjackdoe/pico2-swd-riscv

pico2-swd-riscv

SWD 调试探针库,适用于 RP2350 RISC-V 内核。通过 PIO 位拆操作,利用两根 GPIO 线提供暂停/恢复/单步、寄存器与内存访问、代码执行以及指令跟踪功能。

查看仓库
85347个月前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

pico2-swd-riscv

用于 RP2350 RISC-V(Hazard3)内核的 SWD 调试探针。一个 Pico2 通过两根 GPIO 线调试另一个。

0. 灵能编码警告(人类编写)

大约 80% 的代码是灵能编码的;自述文件几乎完全由 AI 生成(除了整个灵能编码警告部分)。我花了很多个夜晚,带着示波器和文档,制作了一个能工作的原型,能够进行 SBA/读写寄存器、执行抽象命令和程序缓冲,其余部分是用 Claude Code 完成的。测试相当全面,我在自己的项目中使用了库的核心部分,但是,正如他们所说,“这里有龙”。我也阅读了自述文件和代码,没有发现明显问题(并删除了错误/不清晰的部分)。

这个项目是我对灵能编码更复杂项目的一个案例研究,这个项目我并没有 100% 理解,而且没有明显现成的代码可以“使用”。它始于约 1000 行我亲手编写并且非常了解的代码,通过阅读 RP2350、ARM SWD 和 RISC-V 调试文档,用示波器和 OpenOCD 捕获数据,然后解码和分析唤醒序列以及读/写命令。在我让它工作后,我把它交给 Claude,让它变成一个库以便在其他项目中使用,然后我慢慢构建它。

大约在 3000-4000 行代码后,我完全失去了跟踪,我不会把这看作是我自己编写的代码,但添加越来越多的测试感觉“不错”,或者说至少令人安心。

存在一些误导,尤其是当它误解了 dap_read_mem32,以为它是在读取 RAM,而不是 MEM-AP 的 TAR/DRW/RDBUFF 协议,这导致了大量无意义的代码。

总的来说,我觉得这是一次糟糕的体验,即使只花了 10 个小时编写了近 10000 行代码,我也不认为这是自己的项目,而且没有任何成就感或成长感。

相比之下,使用 AI 阅读所有文档(成千上万页)并编写有用的脚本来解码示波器数据、从文档创建打包的 C 结构体等,感觉非常好,之后我也确实感到满意。当我第一次读取寄存器,然后能够通过 SBA 读取内存时,我感觉棒极了。

主要问题在于“品味”,当我编写代码时,我能感觉到它是好是坏,我知道它是否错了,但使用 Claude Code 后,我很快变得麻木,就是分不清,它“读起来”还行,但我不知道它感觉如何。在这个案例中,当代码规模从 1000 行增长到 4000 行(大约 4 倍)时,这种情况就发生了。更糟的是,我对代码的心理模型完全消失了,随之消失的还有我的所有权。

这些符号没有理由或目的,这让阅读代码变得极其困难,因为每个符号都可能是完全无意义的。阅读人类代码时,符号是有目的的,有人想过“我会把这个放在一个变量里,稍后检查它的状态”,所以我假装自己是那个人,思考他们为什么会这样写?很快我就明白了,因为他们是人类,我也是人类。但 AI 符号没有理由,更糟的是,它们看起来都像是正确的,所以我要花十倍的努力去判断它是否错了。对于任何人类代码(包括你自己的),很容易判断你能信任它多少,而且它相当一致;对于 AI 代码,一个函数可能比你写的要好得多,而下面两行代码可能是盲目复制的垃圾,看起来非常好,但结构上是错的。

最后,我认为我对线路、时序以及底层 AP/DP 机制、SBA 和程序缓冲有了很好的理解,但我后悔没有亲自编写整件事,即使那样会花十倍的时间。

我他妈讨厌这个。

我只能感到厌恶和羞愧。编程现在就是这样吗?我真的希望这只是某个中间阶段,未来会变得更好,问题是我不知道“更好”是什么样子,对一些人来说是不用写代码,对另一些人来说是不用建模问题,对第三类人来说是不用思考。对我而言,我不确定,我确实想制造东西,很多时候我不想了解某些东西,但我想使用它,例如 RP2350 USB 主机控制器,那种需要重新开启中断的方式以及 EPX 寄存器共享的方式非常烦人,可能是有充分理由的,但我只想用它来做我的 CBI 驱动程序。

我想问题在于我想制造什么,因为你可以一直往上层走,从 USB 芯片寄存器到 CBI 到 UFI 到 FAT16 到我在制作的老式电脑的操作系统,但为什么要停在这里?制作原理图、PCB、CAD 文件,也许自动发送到工厂?然后直接寄给我?但为什么不继续?建立我的网店,开始销售,建立社区,投放广告,营销,制作一些开箱视频,也许一些病毒式传播的 meme?直接处理订单到工厂,按需生产,如果有问题,客服随时准备。

在此期间我做什么?坐在沙滩上?我讨厌沙滩。

在哪里停下来?

附:正如诗人所说:得到你想要的东西的代价,是得到你曾经想要的东西。

架构

root@kitploit:~
应用程序
    |
rp2350.c    RISC-V 调试模块(暂停/恢复/单步、寄存器、内存、跟踪)
    |
dap.c       调试访问端口(DP/AP 寄存器、缓存区、MEM-AP)
    |
swd_protocol.c  SWD 线路协议(PIO 位敲击、数据包编码、重试)
    |
swd.pio     PIO 状态机(4 周期 SWCLK、双向 SWDIO)

每一层维护自己的状态,并且只与相邻层通信。

用法

root@kitploit:~
swd_config_t config = swd_config_default();
config.pin_swclk = 2;
config.pin_swdio = 3;

swd_target_t *target = swd_target_create(&config);
swd_connect(target);
rp2350_init(target);

rp2350_halt(target, 0);
swd_result_t pc = rp2350_read_pc(target, 0);
rp2350_resume(target, 0);

swd_target_destroy(target);

核心控制

root@kitploit:~
rp2350_halt(target, 0);
rp2350_step(target, 0);
rp2350_resume(target, 0);
rp2350_reset(target, 0, true);

swd_result_t pc = rp2350_read_pc(target, 0);
rp2350_write_pc(target, 0, 0x20000000);

swd_result_t val = rp2350_read_reg(target, 0, 5);
rp2350_write_reg(target, 0, 5, 0xDEADBEEF);

uint32_t regs[32];
rp2350_read_all_regs(target, 0, regs);

swd_result_t csr = rp2350_read_csr(target, 0, 0x300);
rp2350_write_csr(target, 0, 0x300, value);

两个核心(0 和 1)均可独立控制。

内存访问

通过系统总线访问的非侵入式操作。核心运行时也可工作。

root@kitploit:~
swd_result_t val = rp2350_read_mem32(target, 0x20000000);
rp2350_write_mem32(target, 0x20000000, 0xDEADBEEF);

rp2350_read_mem16(target, addr);
rp2350_write_mem8(target, addr, byte);

uint32_t buf[256];
rp2350_read_mem_block(target, 0x20000000, buf, 256);
rp2350_write_mem_block(target, 0x20000000, buf, 256);

块传输使用 SBA 自动递增以提高性能。

代码执行

root@kitploit:~
const uint32_t program[] = {
    0x200415b7,  // lui  a1, 0x20040
    0xabcd0537,  // lui  a0, 0xabcd0
    0x00a5a223,  // sw   a0, 4(a1)
    0x0000006f,  // j    . (loop)
};

rp2350_execute_code(target, 0, 0x20000000, program, 4);

上传到目标 SRAM,验证,设置 PC,恢复运行。

指令跟踪

root@kitploit:~
bool on_instruction(const trace_record_t *rec, void *ctx) {
    printf("0x%08x: 0x%08x\n", rec->pc, rec->instruction);
    return true;
}

int traced = rp2350_trace(target, 0, 100, on_instruction, NULL, false);

通过 DCSR.step 单步执行指令。不捕获寄存器时每指令约 5ms,完整寄存器捕获时约 80ms。

程序缓冲

在调试上下文中直接执行 RISC-V 指令:

root@kitploit:~
uint32_t progbuf[] = {
    0x34202473,  // csrr s0, mcause
    0x00100073   // ebreak
};
rp2350_execute_progbuf(target, 0, progbuf, 2);
swd_result_t mcause = rp2350_read_reg(target, 0, 8);

内部使用此方法访问 CSR,因为 Hazard3 不支持抽象 CSR 命令。

构建

root@kitploit:~
add_subdirectory(lib/pico2-swd-riscv)
target_link_libraries(your_app pico2_swd_riscv)

调试详细程度(编译时):

root@kitploit:~
set(PICO2_SWD_DEBUG_LEVEL 3)  # 0=无, 1=警告, 2=信息, 3=调试

内部原理

线路协议

SWD 使用 8 位请求数据包(开始、APnDP、RnW、地址[3:2]、奇偶校验、停止、驻留),3 位 ACK(OK=1、WAIT=2、FAULT=4),以及带奇偶校验的 33 位数据阶段。周转周期处理 SWDIO 方向变化。WAIT 响应会自动重试(默认:5 次重试,100us 回退)。

RP2350 DP_SELECT 编码

非标准:[15:12]=APSEL, [11:8]=0xD, [7:4]=bank, [0]=ctrlsel。位 [11:8] 中的 0xD 是必需的但未在文档中说明。

DM 激活

通过 Bank 1 CSW 的三阶段握手:停用(0x00000000)、激活(0x00000001)、完整配置(0x07FFFFC1)。预期状态响应:0x04010001。

寄存器访问

通用寄存器通过抽象命令(regno 0x1000+n,32 位传输)。CSR 通过程序缓冲:保存 s0,执行 csrr s0, <csr> 或 csrw <csr>, s0,读取/恢复 s0。

系统总线访问

SBCS 配置为 sbaccess=32bit 和 sbreadonaddr。写入 SBADDRESS0 触发总线读取;数据立即可在 SBDATA0 中获得。块传输启用 sbautoincrement,实现流式读写,无需为每个字设置地址。

单步

通过程序缓冲读取 DCSR,设置步进位(位 2),恢复核心。核心执行一条指令并重新进入调试模式。之后清除步进位。

限制

  • 无硬件断点(触发器模块已移除,计划重新实现)
  • 无多分支 SWD
  • 无压缩指令解码(能正确读取,但不解码助记符)
  • 无闪存编程(可通过 rp2350_execute_code 配合存根实现)
  • 无时钟周期精确的性能分析

参考

  • RISC-V 外部调试支持 v0.13
  • ARM 调试接口架构规范 ADIv5/v6
  • RP2350 数据手册,第 3.5 章
  • ARM CoreSight SWD-DP 技术参考手册

许可证

MIT。参见 LICENSE。

下载工具