利用GDB动态调试AndroidAPP应用程序

原创 橙留香Park 2022-09-17 02:00

也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大

少走了弯路,也就错过了风景,无论如何,感谢经历


本篇文章遇到排版混乱的地方,可点击文末阅读原文或前往该地址:https://orangey.blog.csdn.net/article/details/126219940

更多关于Android安全的知识,可前往:https://blog.csdn.net/ananasorangey/category11955914.html


0x01 前言

由于 Android 原生程序的软件保护技术日趋成熟,很多软件和病毒都开始用加密和混淆技术强化自己,对此,静态分析已很难奏效,要用到动态调试

用 C、C++ 开发的原生程序,其语言的先天特性决定其二进制代码的分析难度比 Java 开发的 DEX 高得多,加上高强度的代码加密和混淆技术,逆向分析更加困难。因此,使用调试器配合脚本自动化技术,实现原生程序的自动化分析、自动化去除混淆与动态脱壳,已成为逆向分析中必须掌握的技能

1.1 GDB远程调试原理图

如图上所示,我们需要使用gdbserver依附到要调试的进程上,gdb通过adbd和手机上的gdbserver 进行socket通信

1.2 什么是 GDB 调试器?

Android NDK 早期只支持用 gcc 开发原生程序(现在只支持 Clang),那时原生程序的调试器主要是 gdb(The GNU Project Debugger,GNU 工程调试器),即使是现在,用 gdb 调试原生程序也是一种选择

GDB是gnu组织开发的一个强大的unix程序调试工具,可以用它来调试Android上的C、C++代码

GDB主要做四件事情

  • 随心所欲地启动你的程序

  • 设置断点,程序执行到断点处会停住(断点可以是表达式)

  • 程序被停住后,可以查看此时程序中发生的事

  • 动态改变程序的执行环境

1.3 Android SDK GDB 安装路径

使用gdb进行嵌入式调试的必需品,是gdb和gdbserver二进制文件,对于Android平台而言,Google已经提供了预编译的版本,所以无需自行编译它(非要自己手动去编译的,麻烦的一批,反正我放弃了),你可以在Android SDK的目录下找到它们(高版本已经被舍弃了,版本不要超过Android NDK r23 LTS)

网上的一些教程是说通过Android Studio SDK Tools来安装,但默认会安装最新版本的,我们这里手动安装即可

 

  • windows 安装NDK-gdb(版本不要超过Android NDK r23 LTS(2021 年 8 月),在这个版本以上的默认去除了对GDB的支持)

https://developer.android.com/ndk/downloads/revision_history?hl=zh-cn

 

  • Android SDK 工具包的gdb和不同系统版本下的gdbserver路径

android_ndk_r23b/prebuilt/windows-x86_64/bin/gdb.exe

android_ndk_r23b/prebuilt/android-x86_64/gdbserver/gdbserver
android_ndk_r23b/prebuilt/android-x86/gdbserver/gdbserve
android_ndk_r23b/prebuilt/android-arm64/gdbserver/gdbserve
android_ndk_r23b/prebuilt/android-arm/gdbserver/gdbserve

:同时对Android手机需要做的准备工作,则是打开开发者选项以启用ADB调试,并且需要具有root权限。同时在某些机型上,SELinux可能会阻止gdbserver附加到目标进程,这种情况下建议暂时将SELinux改为宽容模式:

adb shell setenforce 0

1.4 NDK-GDB 脚本

在 Android NDK 目录下有个 ndk-gdb 脚本,它是由 Android NDK 提供且经过配置的 gdb 调试器的启动器,内容如下:

  • ndk-gdb 对应 ndk-gdb.py,ndk-gdb.py 主要执行了如下操作:

    • 解析 Android NDK 工程的工程信息。读取项目的 AndroidManifest.xml,解析原生程序的包名和由 APK 启动的 Activity

    • 解析 Android NDK 工程的 ABI 信息。读取原生程序支持的 ABI,将其与当前连接到计算机中的设备的 ABI 进行比对,找出适合当前设备的 ABI 版本的原生程序

    • 设置调试器的 stl_pretty_printer。当 APP_STL 为 stlport 或 gnustl 时,为 gdb 设置不同的 stl_pretty_printer

    • 获取已安装的原生程序在设备上的数据目录和 gdbserver 的位置

    • 以调试模式启动原生程序所在 APK 的主 Activity

    • 从设备上拉取(pull)一些调试中要用的系统动态库和原生程序

    • 启动 gdbserver

    • 启动 gdb,连接待调试的进程,开始调试

  • 从以上步骤可看出,用 ndk-gdb 动态调试原生程序时有如下限制:

    • 独立的原生程序无法调试。原生程序必须和 APK “绑定”,且 APK 必须包含主 Activity

    • 包含原生程序的 APK 必须是可调试的,且要先安装到设备上

    • 无法便携设置 gdb 调试器前端

0x02 GDB 调试器命令

  • gdb 尚在不断更新(变化),要想掌握其使用方法,最好的办法是去 gdb 官网查看其手册(gdb 用户手册)

  • gdb 调试器成功连接 gdbserver 后,会进入以 (gdb) 显示的 Shell 环境,在这里,既可执行 gdb 提供的所有命令,以驱动 gdb 调试 Android 原生程序,也可执行 help 命令,查看所有可用的命令。在调试场景中按 Tab 键,gdb 会显示当前所有可用命令

2.1 断点(BreakPoint)

在代码的指定位置中断,这个是我们用得最多的一种。设置断点的命令是break,它通常有如下方式:

  • break  在进入指定函数时停住

  • break  在指定行号停住。

  • break +/-offset 在当前行号的前面或后面的offset行停住。offiset为自然数。

  • break filename:linenum 在源文件filename的linenum行处停住。

  • break ... if ... 可以是上述的参数,condition表示条件,在条件成立时停住。比如在循环境体中,可以设置break if i=100,表示当i为100时停住程序

可以通过info breakpoints [n] 命令查看当前断点信息。此外,还有如下几个配套的常用命令:

  • delete 删除所有断点

  • delete breakpoint [n] 删除某个断点

  • disable breakpoint [n] 禁用某个断点

  • enable breakpoint [n] 使能某个断点

2.2 观察点(WatchPoint)

在变量读、写或变化时中断,这类方式常用来定位bug

  • watch  变量发生变化时中断

  • rwatch  变量被读时中断

  • awatch  变量值被读或被写时中断

可以通过info watchpoints [n] 命令查看当前观察点信息

2.3 捕捉点(CatchPoint)

捕捉点用来补捉程序运行时的一些事件。如:载入共享库(动态链接库)、C++的异常等。通常也是用来定位bug

捕捉点的命令格式是:catch ,event 可以是下面的内容

  • throw C++抛出的异常时中断

  • catch C++捕捉到的异常时中断

  • exec 调用系统调用exec时(只在某些操作系统下有用)

  • fork 调用系统调用fork时(只在某些操作系统下有用)

  • vfork 调用系统调用vfork时(只在某些操作系统下有用)

  • load 或 load  载入共享库时(只在某些操作系统下有用)

  • unload 或 unload  卸载共享库时(只在某些操作系统下有用)

另外,还有一个tcatch ,功能类似,不过它只设置一次捕捉点,当程序停住以后,应点被自动删除。捕捉点信息的查看方式和代码断点的命令是一样的

2.4 在特定线程中中断

你可以定义你的断点是否在所有的线程上,或是在某个特定的线程。GDB很容易帮你完成这一工作

  • break thread

  • break thread if ...

linespec指定了断点设置在的源程序的行号。threadno指定了线程的ID,注意,这个ID是GDB分配的,你可以通过"info threads"命令来查看正在运行程序中的线程信息。如果你不指定thread  则表示你的断点设在所有线程上面。还可以为某线程指定断点条件,如:

(gdb) break frik.c:13 thread 28 if bartab > lim

当你的程序被GDB停住时,所有的运行线程都会被停住。这方便你你查看运行程序的总体情况。而在你恢复程序运行时,所有的线程也会被恢复运行。那怕是主进程在被单步调试时。

2.5 恢复程序运行和单步调试

在gdb中,和调试步进相关的命令主要有如下几条:

  • continue :继续运行程序直到下一个断点(类似于VS里的F5)

  • next :逐过程步进,不会进入子函数(类似VS里的F10)

  • setp :逐语句步进,会进入子函数(类似VS里的F11)

  • until :运行至当前语句块结束

  • finish :运行至函数结束并跳出,并打印函数的返回值(类似VS的Shift+F11)

2.6 常用的GDB命令

  • 常用的 gdb 命令(按功能区分):

    • append:如append memory 用于将内存中的数据添加到指定文件的最后

    • call:调用一个函数,功能类似 IDA 的 AppCall

    • disassemble:反汇编当前栈帧的函数

    • display:每次程序停止运行时打印表达式的值

    • dump:读取内存中的数据和代码,并将其保存到文件中。如dump binary memory 用于将指定内存中的数据保存到文件中

    • explore:打印表达式的值(gdb 要能识别它的类型)

    • find:在内存中查找数据

    • print:打印表达式的值

    • printf:不仅和 print 一样可用于打印表达式的值,还可用于指定格式化字符串

    • set:修改表达式的值

    • info:如info frame 用于打印当前栈帧的信息

    • backtrace:打印所有栈帧的信息

    • down:选择并打印下一个栈帧的信息

    • up:选择并打印上一个栈帧的信息

    • frame:选择并打印指定栈帧的信息

    • return:将所选栈帧返回调用者

    • info:如info registers、info all-registers 可用于查看所有寄存器的信息;info registers x0 可用于查看 x0 寄存器的值

    • print:如print/x $pc 表示以十六进制形式显示 pc 寄存器的值

    • set:如set $sp += 4 用于将栈指针的值加4;set $x0 = 0 用于将x0 寄存器的值设为 0

    • stepi:单步步入。当遇到函数调用时,可进入此函数体

    • nexti:单步步过。当遇到函数调用时,不进入此函数体

    • until:快速退出循环

    • finish:执行程序,直到当前函数执行结束后返回

    • continue:继续运行被断点中断的程序

    • run:运行程序

    • kill:强行终止当前正在调试的程序

    • quit:退出 gdb

    • break:如break printf 表示在printf() 上设置断点

    • rbreak:用正则表达式的方式设置断点

    • tbreak:设置临时断点

    • delete:如delete n 表示删除第 n 个断点

    • disable:如disable n 表示禁用第 n 个断点

    • enable:如enable n 表示启用第 n 个断点

    • save:如save breakpoints 表示将当前断点信息保存为脚本文件

    • info:如info break 用于查看所有断点信息

    • watch:设置监视点(需要硬件支持)。在没有源码的情况下,可对内存地址进行监视,功能类似 OllyDbg(Windows 平台调试器)的硬件读写断点

    • catch:如catch syscall 用于捕获所有系统调用

    • 与断点相关的命令

    • 与调试相关的命令

    • 与寄存器相关的命令

    • 与堆栈相关的命令

    • 与数据相关的命令

0x03 GDB调试实例

1)在手机或模拟机启动gdbserver并attach想调试的进程,并指定监听调试命令的端口

# 注意这里的路径,第一个需在当前目录下,否则需带绝对路径,第二个可自己选择
adb push gdbserver /system/bin

:push到/system/bin可能会报错,需确保手机或模拟机已经root,输入命令: adb remount,然后再push进去,同样,下面的chmod权限赋予如果报错,可以使用su命令

  • push到/system/bin可能会报错,赋予gdbserver权限

adb shell
su
chmod 777 /system/bin

或使用mount命令查看,然后更改权限(将/system 从挂载“ro”权限变为挂载“rw”权限)

mount
mount -o rw,remount /dev/block/sda6 /system

  • 有可能上传的时候又会出现如下错误,使用如下命令:

adb remount
adb push gdbserver /system/bin

2)使用adb做端口映射,将pc机上的端口定向到手机上gdbserver监听的端口

adb forward tcp:54321 tcp:54321 #端口映射,将pc机的1234端口映射到手机的1234端口

$ adb shell
# ps #查看要调试进程的PID

3)gdbserver附加进程方式

在手机上启动gdbserver并附加到目标进程

./gdbserver :54321 --attach $(pidof process_name)

  • 在PC上启动gdb

$ gdb
(gdb) target remote 127.0.0.1:54321

4)自行启动进程方式

  • 有时因为某些原因,需要自行启动一个进程进行调试,而不是直接附加到现有进程,参数就直接附加在后面,就像正常启动进程一样

./gdbserver :54321 elf_name[文件名] params[参数]

5)在PC上启动gdb的方法是相同的

$ gdb
(gdb) target remote 127.0.0.1:54321

6)启动gdb向指定的pc机端口发信息开始调试,运行gdbserver 两种方法

方法1:adb shell; 命令: cd gdbserver路径; 命令: ./gdbserver

./gdbserver :54321 --attach 1419 #:54321是端口号,1419 是进程ID

方法2: 命令 adb shell gdbserver (适用于将gdbserver放在/system/bin下的情况)

adb shell gdbserver :23946 –attach [PID](PID可以在adb shell中使用 ps命令查询)

我们这里选择方法1:

adb shell
cd /system/bin
chmod 777 gdbserver
./gdbserver gdbserver :54321 –attach 1419

:要使用项目下的gdb客户端去连接gdbserver,gdb的类型要选择针对手机或模拟器平台的,版本要和gdbserver一致

  • gdb客户端执行远程链接,成功监听如下所示:

$ gdb
(gdb) target remote 127.0.0.1:54321

  • 列出当前进程的所有寄存器

info registers

3.1 设置断点

break 命令设置断点,简写b
break main 在main()函数的入口处设置断点
break 5 在源代码的第5行设置断点
break hello.c:5 指定源码文件的代码第5行设置断点

单个断点:

b+设置断点所在行:设置断点
b+函数名:函数名处设定断点
b+文件名:行号/函数名:在别的函数设置断点

无效断点:对于函数中的,大括号和注释,设置的断点是无效的。看断点是否有效,看Enb这个项(如下图),y就是有效。其中Num为断点的标号

  • 在main()函数的入口处设置断点

b main

条件断点:b+ 行号+if 变量==var :当某行的变量等于某个值的时候停止

b 19 if i==5

3.2 查看断点

info breakpoints ,显示当前全部的断点,简写为i b

i b

3.3 清除断点

单个删除:每个断点号用空格隔开;delete + 断点的数值标识符,delete 1 ,删除第1个断点,简写为d 1

d 1

连续删除:断点号范围表示,例如4-7;d+ 断点号范围

d 4-7

clear + 函数名 、 +行号、+文件名:行号 ,清除断点main()函数处的断点:clear main 或者clear 5 (本质是main函数的第一条语句所在)

3.4 启用与禁用断点

  • disable + 断点的数值标识符,disable 1: 禁用第1个断点,简写为dis+ 断点号

  • enable + 断点的数值标识符,enable 1: 启用第1个断点,简写为enb+ 断点号

  • Enb字段,表明断点是禁用(n)还是启用(y)的

3.5 单步调试

  • next,n ,越过 函数调用(函数会在背地里自己悄悄运行完),单步执行

  • step,s ,进入 函数体内部,单步执行

3.6 恢复执行

  • continue ,c,恢复执行,直到遇到下一个断点

  • continue 命令执行期间,按下CTRL-C瞬间停止

3.7 查看变量

  • disp,使得每次有暂停,都会输出指定的变量的值;

  • print,p,只显示一次变量的值;

  • 要求变量名在当前的域是可见的,比如某个变量i是函数foo()的局部变量,那么只有是在进入到这个函数的里面时才可以使用print i 或者 disp i,不然gdb也不知道i是谁;

3.8 TUI模式,双开 汇编代码 窗口

  • Ctrl + X + A 进入TUI模式

  • (gdb) list :显示10行C源码

  • (gdb) layout split :同时显示C源码以及汇编源码

  • (gdb) info registers :显示使用到的寄存器信息

  • (gdb) set disassembly-flavor intel :改变显示的汇编语法

  • 再次输入(gdb) layout split :使语法改变生效

set disassembly-flavor intel
set disassembly-flavor att

3.9 查看文件信息

查看当前文件:

  • :查看当前文件的调试信息,默认10行

  • l+ 行号:显示特定行号的上下文

  • l + 函数名:查看当前文件特定函数

查看当前文件:

  • l + 文件名:行号:查看文件信息

  • l + 文件名:函数名:查看特定函数的信息

设置显示行数:

  • show listsize :显示输出行

  • set listsize (number) :设置输出行号

参考链接

http://beej.us/guide/bggdb/

https://blog.csdn.net/zlmm741/article/details/105511833

https://blog.csdn.net/weixin_46185705/article/details/114498377

https://blog.csdn.net/weixin_46185705/article/details/114498377

https://www.cnblogs.com/TianFang/archive/2013/01/20/2868889.html

https://www.jianshu.com/p/8a5aade09ec0?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation


你以为你有很多路可以选择,其实你只有一条路可以走



橙留香Park 橙留香来自一位三流剑客之乡,担任威胁猎手,脑子不会转弯,属于安全特学脑。橙留香同学[小菜鸟],定期分享从零入门车联网安全(包括基础知识储备)技术。只为你呈现有价值的信息,专注于车联网安全领域之Android终端反入侵技术研究。
评论
  • 故障现象 一辆2007款日产天籁车,搭载VQ23发动机(气缸编号如图1所示,点火顺序为1-2-3-4-5-6),累计行驶里程约为21万km。车主反映,该车起步加速时偶尔抖动,且行驶中加速无力。 图1 VQ23发动机的气缸编号 故障诊断接车后试车,发动机怠速运转平稳,但只要换挡起步,稍微踩下一点加速踏板,就能感觉到车身明显抖动。用故障检测仪检测,发动机控制模块(ECM)无故障代码存储,且无失火数据流。用虹科Pico汽车示波器测量气缸1点火信号(COP点火信号)和曲轴位置传感器信
    虹科Pico汽车示波器 2025-01-23 10:46 80浏览
  • 临近春节,各方社交及应酬也变得多起来了,甚至一月份就排满了各式约见。有的是关系好的专业朋友的周末“恳谈会”,基本是关于2025年经济预判的话题,以及如何稳定工作等话题;但更多的预约是来自几个客户老板及副总裁们的见面,他们为今年的经济预判与企业发展焦虑而来。在聊天过程中,我发现今年的聊天有个很有意思的“点”,挺多人尤其关心我到底是怎么成长成现在的多领域风格的,还能掌握一些经济趋势的分析能力,到底学过哪些专业、在企业管过哪些具体事情?单单就这个一个月内,我就重复了数次“为什么”,再辅以我上次写的:《
    牛言喵语 2025-01-22 17:10 178浏览
  • Ubuntu20.04默认情况下为root账号自动登录,本文介绍如何取消root账号自动登录,改为通过输入账号密码登录,使用触觉智能EVB3568鸿蒙开发板演示,搭载瑞芯微RK3568,四核A55处理器,主频2.0Ghz,1T算力NPU;支持OpenHarmony5.0及Linux、Android等操作系统,接口丰富,开发评估快人一步!添加新账号1、使用adduser命令来添加新用户,用户名以industio为例,系统会提示设置密码以及其他信息,您可以根据需要填写或跳过,命令如下:root@id
    Industio_触觉智能 2025-01-17 14:14 145浏览
  • 数字隔离芯片是一种实现电气隔离功能的集成电路,在工业自动化、汽车电子、光伏储能与电力通信等领域的电气系统中发挥着至关重要的作用。其不仅可令高、低压系统之间相互独立,提高低压系统的抗干扰能力,同时还可确保高、低压系统之间的安全交互,使系统稳定工作,并避免操作者遭受来自高压系统的电击伤害。典型数字隔离芯片的简化原理图值得一提的是,数字隔离芯片历经多年发展,其应用范围已十分广泛,凡涉及到在高、低压系统之间进行信号传输的场景中基本都需要应用到此种芯片。那么,电气工程师在进行电路设计时到底该如何评估选择一
    华普微HOPERF 2025-01-20 16:50 123浏览
  • 嘿,咱来聊聊RISC-V MCU技术哈。 这RISC-V MCU技术呢,简单来说就是基于一个叫RISC-V的指令集架构做出的微控制器技术。RISC-V这个啊,2010年的时候,是加州大学伯克利分校的研究团队弄出来的,目的就是想搞个新的、开放的指令集架构,能跟上现代计算的需要。到了2015年,专门成立了个RISC-V基金会,让这个架构更标准,也更好地推广开了。这几年啊,这个RISC-V的生态系统发展得可快了,好多公司和机构都加入了RISC-V International,还推出了不少RISC-V
    丙丁先生 2025-01-21 12:10 619浏览
  • 现在为止,我们已经完成了Purple Pi OH主板的串口调试和部分配件的连接,接下来,让我们趁热打铁,完成剩余配件的连接!注:配件连接前请断开主板所有供电,避免敏感电路损坏!1.1 耳机接口主板有一路OTMP 标准四节耳机座J6,具备进行音频输出及录音功能,接入耳机后声音将优先从耳机输出,如下图所示:1.21.2 相机接口MIPI CSI 接口如上图所示,支持OV5648 和OV8858 摄像头模组。接入摄像头模组后,使用系统相机软件打开相机拍照和录像,如下图所示:1.3 以太网接口主板有一路
    Industio_触觉智能 2025-01-20 11:04 195浏览
  •  万万没想到!科幻电影中的人形机器人,正在一步步走进我们人类的日常生活中来了。1月17日,乐聚将第100台全尺寸人形机器人交付北汽越野车,再次吹响了人形机器人疯狂进厂打工的号角。无独有尔,银河通用机器人作为一家成立不到两年时间的创业公司,在短短一年多时间内推出革命性的第一代产品Galbot G1,这是一款轮式、双臂、身体可折叠的人形机器人,得到了美团战投、经纬创投、IDG资本等众多投资方的认可。作为一家成立仅仅只有两年多时间的企业,智元机器人也把机器人从梦想带进了现实。2024年8月1
    刘旷 2025-01-21 11:15 666浏览
  • 2024年是很平淡的一年,能保住饭碗就是万幸了,公司业绩不好,跳槽又不敢跳,还有一个原因就是老板对我们这些员工还是很好的,碍于人情也不能在公司困难时去雪上加霜。在工作其间遇到的大问题没有,小问题还是有不少,这里就举一两个来说一下。第一个就是,先看下下面的这个封装,你能猜出它的引脚间距是多少吗?这种排线座比较常规的是0.6mm间距(即排线是0.3mm间距)的,而这个规格也是我们用得最多的,所以我们按惯性思维来看的话,就会认为这个座子就是0.6mm间距的,这样往往就不会去细看规格书了,所以这次的运气
    wuliangu 2025-01-21 00:15 324浏览
  • 飞凌嵌入式基于瑞芯微RK3562系列处理器打造的FET3562J-C全国产核心板,是一款专为工业自动化及消费类电子设备设计的产品,凭借其强大的功能和灵活性,自上市以来得到了各行业客户的广泛关注。本文将详细介绍如何启动并测试RK3562J处理器的MCU,通过实际操作步骤,帮助各位工程师朋友更好地了解这款芯片。1、RK3562J处理器概述RK3562J处理器采用了4*Cortex-A53@1.8GHz+Cortex-M0@200MHz架构。其中,4个Cortex-A53核心作为主要核心,负责处理复杂
    飞凌嵌入式 2025-01-24 11:21 36浏览
  • 本文介绍瑞芯微开发板/主板Android配置APK默认开启性能模式方法,开启性能模式后,APK的CPU使用优先级会有所提高。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。源码修改修改源码根目录下文件device/rockchip/rk3562/package_performance.xml并添加以下内容,注意"+"号为添加内容,"com.tencent.mm"为AP
    Industio_触觉智能 2025-01-17 14:09 206浏览
  •     IPC-2581是基于ODB++标准、结合PCB行业特点而指定的PCB加工文件规范。    IPC-2581旨在替代CAM350格式,成为PCB加工行业的新的工业规范。    有一些免费软件,可以查看(不可修改)IPC-2581数据文件。这些软件典型用途是工艺校核。    1. Vu2581        出品:Downstream     
    电子知识打边炉 2025-01-22 11:12 134浏览
  • 高速先生成员--黄刚这不马上就要过年了嘛,高速先生就不打算给大家上难度了,整一篇简单但很实用的文章给大伙瞧瞧好了。相信这个标题一出来,尤其对于PCB设计工程师来说,心就立马凉了半截。他们辛辛苦苦进行PCB的过孔设计,高速先生居然说设计多大的过孔他们不关心!另外估计这时候就跳出很多“挑刺”的粉丝了哈,因为翻看很多以往的文章,高速先生都表达了过孔孔径对高速性能的影响是很大的哦!咋滴,今天居然说孔径不关心了?别,别急哈,听高速先生在这篇文章中娓娓道来。首先还是要对各位设计工程师的设计表示肯定,毕竟像我
    一博科技 2025-01-21 16:17 159浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦