如何通过编译器或工具禁止学生代码非法访问内存token变量?
如何阻止学生代码非法访问进程内的敏感Token?
核心需求
在大学编程课程的单元测试中,要让学生编写的foo_written_by_student函数无法通过非法内存访问(比如栈遍历)获取主进程中的secrettoken,同时保证verif(foo_written_by_student())能正常校验,杜绝学生用特殊逻辑绕过校验作弊。
int main() { char *secrettoken = randomtoken(); int x = verif(foo_written_by_student()); // <-- 要阻止该函数获取secrettoken // ... }
一、同进程方案的局限性:编译器/工具无法彻底解决
因为同进程内所有代码共享同一地址空间,栈、堆对所有函数可见,学生可以用汇编直接操控栈指针或遍历内存,编译器选项和工具只能增加难度,无法彻底阻断:
- GCC编译选项防护有限:
-fstack-protector-all:只能检测栈溢出,对主动读取栈上其他变量的行为无效,它只是在栈帧末尾加金丝雀值,溢出时崩溃,但学生代码只是读取token,不会触发检测。-fPIE -pie:开启地址随机化(ASLR),增加猜地址的难度,但学生仍能通过自身栈帧偏移计算token位置,或通过寄存器值推导。- 优化选项
-O2/-O3:可能改变变量栈布局,甚至把token放到寄存器里,但学生代码仍能枚举寄存器或内存找到它。
- Valgrind类工具不适用:
Valgrind主要用于事后检测内存错误,等它发现非法访问时,学生代码已经拿到token了,而且运行速度慢,不适合大规模测试。
二、最可靠的方案:跨进程隔离
你计划的ZeroMQ+ binn跨进程方案是正确方向,核心是把学生代码和测试代码放在不同进程,彻底隔离地址空间:
- 测试进程:生成
secrettoken,执行verif校验,负责对比两次token输出判断结果。 - 学生进程:仅运行
foo_written_by_student,把计算结果通过IPC(比如ZeroMQ消息队列)发送给测试进程,由测试进程完成校验。 - 优势:两个进程地址空间完全独立,学生代码根本无法触及测试进程的内存,彻底杜绝非法访问的可能。
三、额外防作弊手段
配合进程隔离,再加上这些手段能进一步加固:
- 限制系统调用:用
seccomp或chroot限制学生进程的权限,禁止直接调用exit、write跳过校验或打印结果,强制只能通过IPC返回数据。 - 混淆校验逻辑:对
verif函数做简单混淆,避免学生逆向后直接返回预期值。 - 随机化测试用例:每次测试生成不同的输入和token,防止学生硬编码结果作弊。
内容的提问来源于stack exchange,提问作者tobiasBora
相关产品推荐
相关产品推荐

