资讯动态

NS-USBloader 构建指南:从 Maven 打包到跨平台 JNI 原生库编译全解析

发布时间:2026/10/15 3:41:59 来源:尧图企业网站定制
桌面应用CLI【免费下载链接】ns-usbloaderAwoo Installer and GoldLeaf uploader of the NSPs (and other files), RCM payload injector, application for split/merge files.项目地址https://gitcode.com/gh_mirrors/ns/ns-usbloader点击查看免费下载本文以仓库根目录的 BUILD.md 为核心系统讲解 NS-USBloader一款运行在 PC 端的 NSP 安装器 / RCM 载荷注入工具 / 文件拆分合并工具的完整构建流程包括一条 Maven 命令完成 Java 应用打包、构建 legacy 版本的依赖修改方法以及为 RCM 注入功能编译 Linuxamd64/x86、Raspberry Pi ARM、Windowsx86/amd64四套smashlibJNI 原生库的操作步骤与底层原理。读完本文你能够在本机从零构建出可运行的ns-usbloader-version.jar并能按需重新编译打包进 JAR 的跨平台原生库。1. 构建总览两个层次、四套原生库NS-USBloader 的构建分为两个相互独立的层次Java 应用层必需一个标准 Maven 工程mvn package即产出 fat JAR含依赖Windows 场景下还会由 launch4j 生成.exe启动器。JNI 原生库层可选JNI sources/目录下按平台存放的 C 源码与 Makefile产物为smashlib.so/smashlib.dll最终被安装到src/main/resources/native/os/arch/并随 JAR 一起分发。为什么原生库是可选的从源码结构看RCM payload 的主发送路径由纯 Java 实现 Rcm.java 承担基于 usb4java注释中说明其 Fusée Gelée RCM 载荷实现参考了 fusee-launcher 项目的思路。而smashlib通过 RcmSmash.java 暴露两个native方法作为低层 USB 操作的补充通道public static native int smashLinux(final int bus_id, final int device_addr); public static native int smashWindows(); public static boolean isSupported() { return supported; }isSupported()的返回值由静态块中的 JNIRcmLoader.load() 决定——它按os.name/os.arch拼接资源路径/native/linux|windows/x86|amd64|arm/smashlib.so|dll定位库文件从磁盘file 协议或 JAR 内部jar 协议先解压到临时目录加载找不到对应架构的库则返回false应用降级为纯 Java 路径而不会崩溃。这正是 BUILD.md 中把 JNI 部分标注为OPTIONAL的原因仓库中不携带编译好的.so/.dllsrc/main/resources/下无native/目录发布构建流程中另行编译注入。目标平台源码目录构建命令产物安装位置Linux x86JNI sources/linuxmake x86-m32交叉编译x86/smashlib.sosrc/main/resources/native/linux/x86/Linux amd64JNI sources/linuxmake amd64amd64/smashlib.sosrc/main/resources/native/linux/amd64/Raspberry Pi (ARM)JNI sources/linuxmake arm交叉工具链arm/smashlib.sosrc/main/resources/native/linux/arm/Windows x86JNI sources/windowsmake x86MinGWx86/smashlib.dllsrc/main/resources/native/windows/x86/Windows amd64JNI sources/windowsmake amd64MinGW-w64amd64/smashlib.dllsrc/main/resources/native/windows/amd64/注意Linux 的x86目标是 amd64 主机上以-m32交叉编译出的 32 位库需要 32 位 glibc 开发头文件并非只能在 32 位系统上编译。2. 前置条件Java 应用层JDK 23pom.xml 中maven.compiler.release与maven-compiler-plugin的release均为23即必须使用 Java 23 或更高版本编译这与 README 中运行只需 JRE 17是两回事——运行版本低于编译版本要求即可放宽但构建不行。MavenBUILD.md 明确要求 Install Maven。OpenJFX 25GUI 依赖通过 Maven 依赖自动拉取javafx.version属性为25graphics/controls/fxml三件套同时声明了linux、win、mac三个 classifier因此单一 JAR 可跨平台运行。JNI 原生库层BUILD.md 原文概括为 install JDK, GCC, make, kernel headers and whatever else (or use Gentoo 3)JDK 且设置好JAVA_HOMELinux Makefile 通过-I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux引用jni.h。GCC make Linux 内核头文件linux/usbdevice_fs.h、linux/usb/ch9.h见 smashlib.c 头文件引用。Raspberry Pi 目标另需 ARM 交叉编译工具链Makefile_raspberry 中CCarm-linux-gnueabihf-gcc。Windows 目标需要 MinGWx86与 MinGW-w64amd64及 JDKJAVA_HOME指向 JDK 根目录。3. 构建 Java 应用一条 mvn 命令BUILD.md 给出的标准构建命令为# 安装 Maven 后在仓库根目录执行 mvn -B -DskipTests clean package-Bbatch mode批处理模式不输出交互式进度条适合 CI 与脚本。-DskipTests跳过 JUnit 5 测试测试位于src/test/java/包括需要真实 USB 设备的集成测试如src/main/test下的EsIntegrationTest、FsIntegrationTest、LoaderIntegrationTest本地无设备时跳过是合理的默认。产物名由finalName${project.artifactId}-${project.version}/finalName决定当前 pom 版本为7.3因此得到target/ns-usbloader-7.3.jar。3.1 打包链路jar-with-dependencies launch4jpom.xml 的插件配置决定了这条命令背后实际发生了什么这里完整列出构建链maven-jar-plugin 的default-jar被禁用phasenone/phase——pom 中注释写明 Dont generate default JAR without dependencies即不产出无依赖的瘦 JAR。maven-assembly-plugin 生成 fat JARdescriptorRef为jar-with-dependencies且appendAssemblyId为false所以最终 JAR 名就是ns-usbloader-7.3.jar不带-jar-with-dependencies后缀manifest 的mainClass为nsusbloader.Main——它只是一个转发类Main.java 注释 Its a workaround to execute JavaFX application把main直接委托给NSLMain.main(args)以此规避 JavaFX 应用类被LauncherHelper拦截的问题。launch4j-maven-plugin 在package阶段生成 Windows 启动器产物为target/NS-USBloader.exeheaderType为gui无控制台窗口、图标取自appicon.ico并配置了 JRE 探测minVersion23.0.0/minVersion)。该插件绑定 Windows 资源versionInfo、messages如 JDK not found / JDK Version mismatch实际用于产物的 Windows 分发场景。测试插件surefire / failsafe 均为 2.22.2对应 JUnit Jupiter 5.9.0不加-DskipTests时构建会执行src/test/java/下的用例含 USB 传输相关的TransferModuleTest、SplitTest、MergeTest等。3.2 资源过滤版本号如何进入应用pom 中声明了两组资源src/main/resources不过滤与src/main/resources-filteredfilteringtrue。后者目前只有一个文件 app.properties内容为_versionv${project.version}构建时 Maven 会把${project.version}替换为7.3打入 JAR运行时由应用读取以显示/校验版本——这就是版本号构建期注入而非硬编码的实现方式。3.3 版本号与 NSIS 安装器的联动pom 第 11 行注释明确linked via script to NSIS system. Should have format of 2 blocks of numbers即版本必须是X.Y两段数字格式。联动脚本 misc/windows/update_version.sh 会从pom.xml中grep出主/次版本号sed改写 misc/windows/NSIS/installer.nsi 中的!define VERSIONMAJOR/VERSIONMINOR、BrandingText为 NS-USBloader vX.Y无参数运行时把OutFile置为Installer-X.Y.exe带任意参数运行时改写为Installer-legacy-X.Y.exe——这正是构建 legacy 版安装器的入口。4. 构建 legacy 版本修改 usb4java 依赖BUILD.md 对 legacy 版本的唯一要求是把 pom.xml 中的 usb4java 依赖替换为 1.2.0dependency groupIdorg.usb4java/groupId artifactIdusb4java/artifactId version1.2.0/version scopecompile/scope /dependency当前仓库中该依赖为1.3.0并附注释 Must be 1.2.0 for macOS lower than Mojave。README 对两者差异的解释是usb4java 在不同版本中对 USB 栈的封装行为不同涉及 libusb 与 AppleIOKit/IOUSB等后端的桥接1.3.0 在 Mojave 之前的 macOS 上行为异常故为老系统单独产出-legacyJAR 与-legacy安装器在 Linux/Windows 上 legacy JAR 同样可用但偶尔在 Windows 上失效。因此完整的 legacy 构建流程为修改 pom 中 usb4java 版本 → 照常mvn -B -DskipTests clean package→ Windows 分发场景执行./misc/windows/update_version.sh anyarg生成Installer-legacy-X.Y.exe脚本改写 → NSIS 打包。5. 构建 JNI 原生库可选但推荐深入5.1 JNI 头文件生成通常可跳过BUILD.md 指出仓库已附带生成好的头文件无需重新生成。其生成流程为$ cp NS-USBloader/src/main/java/nsusbloader/Utilities/RcmSmash.java . $ javac -h . RcmSmash.javajavac -h会扫描类中的native方法并产出 C 头文件。仓库中已生成的 nsusbloader_Utilities_RcmSmash.h 声明了两个导出符号与 Java 侧签名一一对应JNIEXPORT jint JNICALL Java_nsusbloader_Utilities_RcmSmash_smashLinux (JNIEnv *, jclass, jint, jint); /* (II)I */ JNIEXPORT jint JNICALL Java_nsusbloader_Utilities_RcmSmash_smashWindows (JNIEnv *, jclass); /* ()I */C 实现侧JNI sources/linux/smashlib.c 与 JNI sources/windows/smashlib.c按平台各自实现真实逻辑另一个平台则提供返回-1的桩函数——因此 Linux 版.so中smashWindows()恒返回失败Windows 版.dll中smashLinux()恒返回-1。5.2 Linuxamd64 主机make install clean$ cd JNI sources/linux $ make install cleanmake无参数时命中all: x86 amd64目标。查看 JNI sources/linux/Makefile 可确认其细节CCgcc CFLAGS-O2 APP_NAME smashlib.so all: x86 amd64 x86: $(MKDIR_P) ./x86 $(CC) ${CFLAGS} -m32 -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux smashlib.c -o smashlib_x86.o $(CC) ${CFLAGS} -m32 -shared -fPIC -o ./x86/${APP_NAME} smashlib_x86.o -lc amd64: # 同上-m64 编译 install: x86 amd64 install ./x86/${APP_NAME} ../../src/main/resources/native/linux/x86/ install ./amd64/${APP_NAME} ../../src/main/resources/native/linux/amd64/要点-fPIC -shared产出位置无关的共享库-lc显式链接 C 标准库。-m32目标要求安装 32 位开发包如lib32gcc/glibc-devel.i686一类否则编译失败。install目标直接把两个架构的.so复制到../../src/main/resources/native/linux/{x86,amd64}/——即 JAR 内资源路径/native/linux/arch/smashlib.so与JNIRcmLoader的加载路径完全对应。clean清理.o与产物目录uninstall删除已安装的资源文件。5.3 Raspberry PiARM 32 位BUILD.md 的步骤是用专用 Makefile 顶替默认 Makefile 再构建$ cd JNI sources/linux $ mv Makefile_rapsberry Makefile # BUILD.md 原文拼写为 Makefile_rapsberry实际文件名为 Makefile_raspberry $ make install clean注意 BUILD.md 中文件名有笔误rapsberry当前仓库实际文件为 Makefile_raspberry。两个值得注意的实现细节相对 BUILD.md 的直接展开编译器为arm-linux-gnueabihf-gccARMv7 硬浮点交叉工具链只产出arm/smashlib.so安装到../../src/main/resources/native/linux/arm/。该 Makefile 对JAVA_HOME做了兜底未设置时回落到/usr/lib/jvm/default-java/include这对应 Debian/Raspberry Pi OS 上default-jdk的默认布局比 Linux amd64 版 Makefile 的硬性要求JAVA_HOME更宽松。ifeq ($(JAVA_HOME),) JAVA_LIB_PATH : /usr/lib/jvm/default-java/include JAVA_LIB_PATH_LINUX : /usr/lib/jvm/default-java/include/linux else JAVA_LIB_PATH ${JAVA_HOME}/include JAVA_LIB_PATH_LINUX ${JAVA_HOME}/include/linux endif5.4 Windowsx86 与 amd64BUILD.md 将 Windows 段标注为[ This part should be updated ]因此以文档步骤 当前仓库实际 Makefile两者结合来看。环境准备文档原文步骤安装 MinGWx86文档建议装入C:\MinGW\、msys文档原文以 msy (?) 标注表明作者自己也不确定是否必需与 MinGW-w64amd64以及 JDK设置JAVA_HOME将 MinGW、MSYS、JDK/bin 等目录加入PATH。x86 场景下文档明确列出C:\MinGW\bin、C:\MinGW\msys\1.0\bin。x86 构建Update sources: set (uncomment) line BUILD_FOR_X86$ cd JNI sources/windows $ make x86当前 JNI sources/windows/Makefile 中 x86 目标的实际命令为x86: $(MKDIR_P) ./x86 export PATHC/MinGW/bin/:${PATH} $(CC32) ${CFLAGS} -m32 -c -fPIC -I C:/MinGW/include/ddk -I ${JAVA_HOME}/include -I ${JAVA_HOME}/include/win32 smashlib.c -o ./smashlib_x86.o $(CC32) ${CFLAGS} -shared -o ./x86/${APP_NAME} ./smashlib_x86.o -lsetupapi -lhid -Wl,--add-stdcall-alias其中CC32C:/MinGW/bin/gcc路径是写死的与 BUILD.md Install MinGw to C:\MinGW 的建议一致链接参数-lsetupapi -lhid对应setupapi.h设备枚举与 HID 支持--add-stdcall-alias兼容调用方使用__stdcall别名导入。关于 BUILD.md 提到的BUILD_FOR_X86宏当前 JNI sources/windows/smashlib.c 第 16 行存在的是#define _BUILD_FOR_X86带下划线前缀而第 25 行实际判断的是#ifdef BUILD_FOR_X86不带下划线二者并不对应。可以推断该宏用于在编译 x86 版时条件引入ntddser.h等头文件从源码现状看若要按文档set (uncomment) line BUILD_FOR_X86的说法使条件编译真正生效可能需要在源码中把宏名对齐这属于文档与源码尚未完全同步的遗留问题。amd64 构建Update sources: remove line BUILD_FOR_X86 $ make amd64Makefile 中CC64指向C:/Program Files/mingw-w64/x86_64-8.1.0-win32-seh-rt_v6-rev0/mingw64/bin/gcc——即文档所说 Install MinGw-w64 的具体发行版8.1.0 win32-seh 构建如果本机安装的是别的 MinGW-w64 版本/路径需要相应修改该变量。install目标与 Linux 对称把smashlib.dll分别装入src/main/resources/native/windows/{x86,amd64}/。5.5 原生库做了什么smashlib 的工作原理理解构建产物装进去有什么用有助于判断是否值得投入编译。以 Linux 版 smashlib.c 为例smashLinux(bus_id, device_addr)的完整流程拼出/dev/bus/usb/%03d/%03d设备路径并open(O_RDWR)要求对应 udev 规则放权README 中 RCM 设备规则为SUBSYSTEMusb, ATTRS{idVendor}0955, ATTRS{idProduct}7321, MODE0666构造一条USBDEVFS_URB_TYPE_CONTROLURBbRequestType0x82设备→接口/设备级输入控制请求、bRequestUSB_REQ_GET_STATUS、wLength0x7000即向设备请求读取一段状态块——这正是 Fusée Gelée 式攻击中触发 Tegra X1 状态读取的关键控制传输ioctl(fd, USBDEVFS_SUBMITURB, urb)提交 URB等待 1/4 秒后USBDEVFS_REAPURBNDELAY非阻塞收割结果遇到EAGAIN则DISCARDURB取消、再等 40ms 重试收割一次代码注释直接指向内核实现/usr/src/linux/drivers/usb/core/devio.c的行为成功返回 0任何一步失败返回负值/错误码。Windows 版 smashlib.c 思路相同但走 Win32 栈用SetupDiGetClassDevsGUID_DEVINTERFACE_USB_DEVICE枚举 USB 接口设备按vid_0955pid_7321Switch RCM 模式下的设备标识匹配设备路径随后CreateFile打开设备句柄向 libusb 兼容的LIBUSB_IOCTL_GET_STATUSCTL_CODE(..., 0x807, ...)发起DeviceIoControl完成同样的控制传输。文件头注释明确了返回值约定-2设备未连接、-1无法打开句柄、0成功。这也解释了为什么 BUILD.md 中 JNI 一节可以整体标注 OPTIONAL不编译时JNIRcmLoader.load()返回falseRcmSmash.isSupported()为false应用退回 Rcm.java 的纯 Java usb4java 路径发送 payload编译并安装到资源目录后原生路径才会在相应平台被启用。6. 构建排错速查现象原因与处理mvn package报编译错误如 invalid target release构建 JDK 低于 23。pom 的release与maven.compiler.release均锁定 23请升级构建 JDKMaven 拉取ru.redrise:libKonogonka:0.1失败该依赖托管在 pomrepositories声明的私有仓库redrise.ru需网络可达该镜像源make x86Linux报缺头文件未装 32 位开发环境32 位 glibc/gcc 支持或JAVA_HOME未设置Makefile 依赖${JAVA_HOME}/include/{,linux}下的jni.hRaspberry Pi Makefile 找不到arm-linux-gnueabihf-gcc未安装交叉工具链或在 Pi 本机编译时应使用本机 gcc 而非交叉编译器Windows 下找不到 gccCC32/CC64是硬编码绝对路径与文档建议的安装位置不符时需修改 Makefile 变量JAR 中无native/资源、RCM 注入走 Java 路径属预期行为仓库不携带预编译原生库需按第 5 节make install后再执行一次mvn package才会被打进 JAR7. 小结版本号的单一来源NS-USBloader 的构建体系以 pom.xml 的version为唯一事实来源它同时驱动 fat JAR 文件名finalName、app.properties过滤注入的_version、launch4j 的versionInfo并经 update_version.sh 同步到 NSIS 安装器的!define与OutFile。只要遵循 两段数字 的版本格式约束一次mvn -B -DskipTests clean package加可选的 JNImake install前置步骤即可在 Linux/macOS/Windows 上得到一致的分发产物需要兼容 Mojave 之前 macOS 时仅改动 usb4java 至 1.2.0 重跑同一命令即得到 legacy 变体。相关仓库入口供进一步深入BUILD.md、pom.xml、JNI sources/linux/Makefile、JNI sources/windows/Makefile、src/main/java/nsusbloader/Utilities/JNIRcmLoader.java、src/main/java/nsusbloader/Utilities/Rcm.java。赞分享桌面应用CLI【免费下载链接】ns-usbloaderAwoo Installer and GoldLeaf uploader of the NSPs (and other files), RCM payload injector, application for split/merge files.项目地址https://gitcode.com/gh_mirrors/ns/ns-usbloader点击查看免费下载相关推荐TuxGuitar 源码构建与多平台打包实战从 SWT 依赖配置到 Maven 原生模块编译TuxGuitar 源码构建与多平台打包实战从 SWT 依赖配置到 Maven 原生模块编译 本文围绕 TuxGuitar 仓库的 INSTALL.md ht桌面应用音视频AionUi 跨平台构建脚本全解析从 electron-vite 编译到原生模块重建AionUi 跨平台构建脚本全解析从 electron vite 编译到原生模块重建 AionUi 是 iOfficeAI 旗下基于 Electron 的跨平人工智能AI 应用AI Agent交互助手桌面应用移动开发RocksDB Java 跨平台 JNI 静态库构建与 Maven 中央仓库发布指南RocksDB Java 跨平台 JNI 静态库构建与 Maven 中央仓库发布指南 本文基于当前仓库的 java/RELEASE.md https://lin数据库KV存储嵌入式数据库存储上一篇CopilotKit 与 CrewAI Conversational Flows 集成之 Agentic Chat 深度测试与验证指南下一篇Angular Material Toolbar 测试 Harness API 全解析从 API 报告到 TestBed 实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑