- 最近看新机会,故整理一份求职贴,寻找气场相合的团队,有需求的大佬欢迎联系。
- 下面主要按照我的技术演进及时间线,聊聊我这些年折腾过的一些底层技术和填过的坑。
0x00 驱动力:好奇心 && 兴趣
和大部分 C/C++/Qt 开发者一样,我早期也着重于常规的业务开发。但我属于那种只要时间充裕‘就想看看底层原理’的性格,比起堆叠业务代码,我更喜欢去向下拆解系统机制,这也促使我一步步走向了系统底层和安全的深水区。
0x01 交叉编译:从“造轮子”到“魔改 ELF”
-
从 ARM 到手搓 MIPS64el 工具链:
-
最初接触交叉编译是从折腾 ARM 开发板开始。
- GitHub:嵌入式学习记录(该仓库建立于 23 年底学习 uboot 时,学习裸机程序则是在 21 年初)
- 后来在工作中为了简化工作流,在不知道社区有现成轮子的情况下,通过源码摸索编译出了 mips64el 交叉工具链。虽然这套轮子最后没投入生产,但让我了解到了底层硬件编译参数,并在 24 年借此帮同事精准定位了一个由于硬件不支持硬浮点引发的深层崩溃。
-
最初接触交叉编译是从折腾 ARM 开发板开始。
-
Qt 工具链:
- 为了实现底层服务与 UI 界面在同一套流水线下的单条命令编译,深扒网上资料,最后从 Stack Overflow 找到了一篇关于 Qt4 交叉编译的古早线索,随后通过不断摸索,试错,取巧,手搓出了 Qt5 交叉编译工具链,打通了前后端同构编译的闭环。
-
国产架构溯源与三方库兼容:
- 早期深入研究了国产化架构的发展演进史。后期在遇到部分开源三方库不支持国产芯片架构交叉编译时,利用“架构溯源”的思路——将目标架构强制指定为其前身,成功绕过了棘手的编译限制。
-
魔改 ELF 绕过 GLIBC 依赖:
-
在将出包平台规模化部署到一台 CentOS 6 老机器时,为了让基于高版本 GLIBC 构建的工具链能在低版本系统上运行,我没有使用妥协性的环境变量或 rpath ,而是直接通过修改已编译好的 ELF 文件实现了向下兼容。这让我对 ELF 文件结构和 GLIBC 版本校验逻辑形成了深刻的肌肉记忆,也为后期开发内核模块适配工具埋下了伏笔。
- GitHub:GLIBC 版本适配工具(源于从网上找的别人的修改方法并阅读、注解、改造)
- GitHub:内核模块适配工具(灵感源于上面这个“GLIBC 版本适配工具”)
-
在将出包平台规模化部署到一台 CentOS 6 老机器时,为了让基于高版本 GLIBC 构建的工具链能在低版本系统上运行,我没有使用妥协性的环境变量或 rpath ,而是直接通过修改已编译好的 ELF 文件实现了向下兼容。这让我对 ELF 文件结构和 GLIBC 版本校验逻辑形成了深刻的肌肉记忆,也为后期开发内核模块适配工具埋下了伏笔。
-
旧世界生态架构跃升:
- 针对 CentOS 6 默认 GCC 4.9.x 对 C++11 支持不完整、C++ ABI std::string 版本冲突以及现代三方库的依赖断代问题,我对交叉编译平台进行了一次底层大升级。将其整体对齐到了申威与龙芯“旧世界”的 8.3 版本,不仅完美支持了 C++17 特性,也保证了编译产物对老旧系统的兼容性,为整个项目的现代化平滑过渡打下了基石。
0x02 逆向与攻防:代码注入
- 这原本是本人在职期间找工作的过程中,深感底层与安全攻防圈子更看重纯粹的“真实战斗力”而学历其次,动了转行的念头,然后就对两者都涉及的 ShellCode 产生了浓厚兴趣并进行了学习,最初也没料到,这竟然为后来业务上实现内核热补丁( LivePatch )的 inline hook 埋下了伏笔,那时也不知道两者技术底色一脉相承😑。
0x03 主防平台:从“应用层”到“内核态”
- 针对主防平台,我们的需求是“接收事件 -> 行为分析 -> 杀毒引擎 -> 决定是否放行”。基于上述需求,我研究并采集了多种 Linux 应用层 + 内核态 的监控方式并实现了两套。最初因为驱动方案需要逐一编译,对应用层方案不死心,也消耗了一定的时间。由于陈述出来又太多了,故详见博客园。
0x04 性能调优:从“内核态”到“应用层”
-
在主防平台搭建结束后,便开始着手优化性能。
- 首先是优化等待队列的唤醒逻辑,对唤醒行为进行分桶,并引入键控唤醒机制,避免一次唤醒太多挂起的进程产生“惊群效应”。
- 查阅相关资料,了解了 DPDK 的底层原理,于是实现了基于设备文件映射的、核心绑定的、全链路分片的消息传递逻辑,解决了由于事件消息体中包含了可变长数组,导致 netlink 要先嗅探,再读取需要加锁的问题,消除了瓶颈效应。
- 在驱动性能调优的过程中,本人也接触并使用了内存屏障,掌握了其底层原理,并顺便了解了 RCU 锁及其底层原理,于是又将两者的思想应用到了应用层的性能调优过程中。下面是一个典型的代码片段用于“过滤策略”的更新,具体如下所示:
class ProductMgrNotLockMgr
{
public:
ProductMgrNotLockMgr()
: m_productMgr(nullptr), m_productMgrVer(0){}
~ProductMgrNotLockMgr(){}
shared_ptr<ProductMgr> getProductMgr()
{
static thread_local uint64_t m_productMgrVerTls = 0;
static thread_local shared_ptr<ProductMgr> m_productMgrTls = nullptr;
uint64_t globalVer = m_productMgrVer.load(memory_order_acquire);
if(m_productMgrVerTls != globalVer)
{
m_productMgrTls = atomic_load_explicit(&m_productMgr, memory_order_acquire);
m_productMgrVerTls = globalVer;
}
return m_productMgrTls;
}
void setProductMgr(shared_ptr<ProductMgr> mgr)
{
atomic_store_explicit(&m_productMgr, mgr, memory_order_release);
m_productMgrVer.fetch_add(1, memory_order_release);
}
private:
shared_ptr<ProductMgr> m_productMgr;
atomic<uint64_t> m_productMgrVer;
};
- 业务层中的每一个事件对象调用 get 方法取走自己的过滤策略,而更新时仅需要初始化新的策略配置,然后调用 set 即可,旧的策略配置在引用计数清零后会自动释放,至于策略配置为什么叫 ProductMgr 而不是 ConfigMgr 这属于历史遗留问题,不要在意这些细节🤭。
-
其中的内存屏障部分:
- memory_order_acquire 等同于内核中的 smp_rmb ,用于刷新失效队列,保证数据最新。
- memory_order_release 等同于内核中的 smp_wmb ,用于保证指令执行顺序、刷新写缓冲区并通知。
-
其中的 RCU 锁部分 本质就是对智能指针的原子替换过程:
- 内核中的 RCU 锁需要写者阻塞等待最后一个读者结束对老内存的使用然后手动释放,而此处巧妙利用 C++ 的智能指针,不需要写者等待。
- 其中的 static 关键字是为了延长局部变量的生命周期。
- 其中的 thread_local 关键字是为了让每个线程都有自己的变量副本,避免缓存竞争。
- 其中的 VerTls 变量,则是为了进一步提高性能,毕竟 shared_ptr 是个对象,内部存在多个变量。
0x05 鸿蒙原生拓荒
-
近几个月主导了底层服务与 UI 向鸿蒙系统的全面移植适配。在这个缺乏现成文档的“拓荒期”,填平了大量底层生态差异的深坑:
- 一是 代码的 POSIX 化,一些 GNU 扩展接口在鸿蒙中根本不存在,鸿蒙使用的是基于 muslc 的工具链。
- 二是 界面、服务的库化、线程化,应用在鸿蒙中只允许单进程,原有的可执行程序需要包装为线程再编译为库,然后导出启停符号……,而后就是杜绝一切 system 、popen 、execve 家族调用。
- 对于界面从 Linux 平台的移植,本人选用了 gitcode 的版本,没有使用 QT 官方维护的版本,原因是行为差异较大,很多行为与 Linux 系统中并不一致。
- 对于原有代码的复用,本人实现了 桥接库 以及 Ark 实现层,部分业务在桥接库中使用鸿蒙提供的 C++ 库实现,另一部分穿透桥接库,使用 Ark 代码实现。
- 关于出包,鸿蒙当前只提供了 Windows 和 Mac 的教程,于是结合前两者摸索了一套 Linux 平台 的出包模板。
- 关于 QT 与 Ark 画布的转接,gitcode 和 QT 官方的 QT ,在画布转接上完完全全是两套不同的逻辑……,最后是配合 Ai 边猜边试实现的,记得一遍遍调整得(děi)有十几二十次吧😹。
0x06 问题处理能力
-
除了上述开发过程中遇到的各种问题外,还处理过其它的形形色色的问题,展开讲又很多,故一笔带过吧:
- 符号表冲突、暴力隐藏了不该隐藏的符号(编译器 bug )、ELF 页对齐问题、代码不规范导致唯独龙芯(mips64el+loongarch64)Release 包进程崩溃、优化级别引起的汇编指令错误、早期三方库不支持国产化架构编译问题、C++不同 std 库的正则表达式行为不同问题、Qt 插件装载问题、冷门信创系统与 Qt 兼容性问题、各类资源泄漏问题……
0x07 结语
- 以上除了主防的上层服务和鸿蒙的业务层代码适配两项,有同事配合我进行实现之外,其余大部分都是自己独立做出来的。
-
目前的话,除去一些规模较小、不太对口,或是因为学历受限的机会外,已经面试过两家知名的安全公司了:
- 一个二面通过,三面官直接根据前两面的结果定级低了些。
- 另一个四面通过,目前需要横向对比,对我的面评我认为很客观,大意是重实战轻理论了。
-
所以乾坤未定😋,我再接着找找看,目前我感兴趣的行业有:
- 终端安全行业(我的老本行)
- 性能调优领域
- 逆向与攻防
- 嵌入式领域