七十二小时挂机测试进行到第十二个小时,林谦的电脑突然发出一声刺耳的蜂鸣。
王浩从上铺弹起来:“怎么了?”
“没事。”林谦盯着屏幕,“反检测模块触发了一次异常报警。”
“什么意思?被封号了?”
“不是。是暴雪的Warden反作弊系统扫描了悟空的内存空间,反检测模块成功把关键数据转移到了安全区域。Warden什么都没扫到,自己退了。”
王浩听不懂技术细节,但听懂了结论——悟空从暴雪的眼皮子底下溜过去了。
“牛。”他嘟囔了一句,倒回床上。
林谦没有放松。他打开监控志,把Warden扫描的时间点、扫描范围、持续时长全部记录下来。然后打开CommView,把刚才那段时间内游戏客户端与服务器的通信数据全部抓取下来。
CommView的界面上密密麻麻全是十六进制的数据包。每一个数据包都有时间戳、源地址、目标地址、数据长度和原始内容。林谦按时间排序,定位到Warden扫描前后三十秒的数据。
李磊从上铺探出头:“谦哥,你在看什么?”
“封包。”
“Warden的扫描能抓到?”
“能。Warden扫描内存之前会先向服务器发送一个心跳包,报告自己的版本号和待扫描的区域范围。服务器收到之后回复一个确认包,然后Warden才开始扫描。扫描结束后再发一个结果包上去。”
李磊从床上跳下来,凑到屏幕前。
“这三个包就是?”
“对。”林谦指着屏幕上高亮的三行数据,“心跳包、确认包、结果包。三个包的时间间隔是零点三秒,扫描过程持续了零点二秒。”
“零点二秒能扫完?”
“Warden不是全内存扫描,是特征码扫描。它只检查几个关键的代码段和数据段,看有没有被篡改的痕迹。如果发现有异常,再触发深度扫描。”
李磊掏出本子开始记。
林谦把三个数据包的内容展开。CommView把十六进制数据按字节拆开,每一行十六个字节,左边是十六进制数值,右边是对应的ASCII字符。大部分内容都是乱码,但有一些字段是可读的。
“你看这里。”林谦指着心跳包中间的一段数据,“这是Warden的版本号。2.1.3。夜鹰被检测的那段时间,暴雪把Warden从2.1.2升级到了2.1.3,增加了对夜鹰特征码的识别规则。”
“你怎么知道?”
“夜鹰的加密协议里有一个固定字段,每次通信都会带上。2.1.2版本的Warden不检测这个字段,2.1.3开始检测了。所以夜鹰在新版本下大面积封号。”
李磊看着屏幕上那些密密麻麻的数字,努力消化着林谦的话。
“那我们怎么避免被2.1.3检测?”
“不让通信包带上固定特征。”林谦把悟空抓取的三个数据包也打开,并排放在Warden的数据包旁边,“你看悟空的心跳包,和正常玩家的心跳包有什么不同?”
李磊对比了几秒钟,摇头。
“看不出来。”
“看不出来就对了。”林谦说,“悟空的心跳包和正常玩家的心跳包,在数据层面完全一致。没有多任何一个字段,也没有少任何一个字段。Warden拿到这个包,只能认为它是一个正常客户端发出的心跳。”
“那悟空的功能数据怎么传输?”
“封装在正常数据包的有效载荷里。魔兽的通信协议本身就有很多冗余字段,大部分是预留的,客户端和服务器都不使用。悟空把指令压缩加密之后,塞进这些冗余字段里。暴雪看不到这些字段里有东西,悟空的服务端再把它解密还原。”
李磊的笔停住了。
“把数据藏在冗余字段里?这……暴雪不会发现吗?”
“不会。因为暴雪自己都不知道那些字段里有东西。Warden检测的是已知的特征码,悟空的数据每次都是动态加密的,没有固定特征。”
李磊沉默了好一会儿。
“谦哥,这个思路……是你自己想的?”
“嗯。”
“Ghost没教过?”
“没有。”
李磊不再问了,低头继续记笔记。但林谦注意到他握笔的手指收紧了一些。
王浩的呼噜声从上铺传下来。张鹏也没醒。
宿舍里只剩下键盘的敲击声和CommView界面上不断滚动的数据包。
林谦把接下来两个小时的数据全部抓取下来,逐帧分析。Warden每隔一段时间会扫描一次,时间间隔不固定——有时十分钟,有时半小时,有时一小时。扫描范围也不固定,每次随机选择不同的内存区域。
“它在学习。”林谦说。
李磊一愣:“学习?”
“Warden不是固定的扫描程序。它会据玩家的行为模式动态调整扫描策略。如果检测到玩家的作过于规律,就增加扫描频率。如果某个区域的访问次数异常多,就重点扫描那个区域。”
“那悟空怎么应对?”
“反其道而行之。”林谦打开反检测模块的配置文件,“悟空会监控Warden的扫描行为。当Warden的扫描频率升高时,悟空就降低功能执行频率,增加随机延迟,让自己看起来更像一个正在发呆的真人玩家。当Warden的扫描频率降低时,再恢复正常的效率。”
李磊盯着屏幕上的配置参数,眉头紧皱。
“这等于是在跟Warden玩猫捉老鼠?”
“对。而且猫永远抓不到老鼠。因为老鼠知道猫什么时候会来,猫不知道老鼠什么时候会跑。”
林谦把CommView的抓包数据保存好,然后打开一个文本文件,开始记录分析结果。
Warden扫描特征:心跳包大小固定为六十四字节,前四字节为版本号,后续六十字节为随机填充。确认包大小为三十二字节,包含扫描区域的内存地址范围。结果包大小为十六字节,包含扫描结果的哈希值。
悟空应对策略:心跳包完全模拟正常客户端格式,版本号与当前Warden版本保持一致,随机填充使用与正常客户端相同的伪随机算法。确认包正常响应。结果包上报的哈希值使用正常客户端的数据,而非悟空修改后的数据。
也就是说,Warden扫描悟空的时候,悟空给它看的是一份“假账本”。
李磊看完这段记录,抬头看着林谦。
“谦哥,我有一个问题。”
“说。”
“你从昨天开始写悟空的核心代码,到现在还不到四十八个小时。反检测模块是今天下午才写的。你怎么能在这么短的时间里,把Warden的扫描机制摸得这么清楚?”
林谦的手指在键盘上停了一下。
这个问题不好回答。真实答案是前世的记忆——他在谦云科技的时候,公司安全团队专门研究过暴雪的Warden反作弊系统,作为技术案例在内部分享过。Warden的版本从2.1到3.0,每一个版本的扫描逻辑他都了如指掌。
但这个答案不能说。
“夜鹰的分析报告里有。”林谦说。
李磊愣了一下:“夜鹰的报告是我整理的,我没看到这些内容。”
“你没看到,是因为你没往那个方向分析。夜鹰的反检测模块虽然粗糙,但它应对Warden的方式和悟空是同一个思路——监控扫描行为,动态调整执行频率。只不过夜鹰的实现太笨了,被Warden发现了规律。”
李磊打开自己整理的夜鹰分析报告,翻到反检测模块那一页,重新看了一遍。
然后他沉默了很久。
“确实有。”他说,“夜鹰在Warden扫描时会暂停功能执行,但它暂停的时间是固定的——每次三秒。Warden发现这个固定间隔之后,就把它当成了特征码。”
“对。固定间隔本身就是特征。真正的随机,不会有任何固定模式。”
李磊把这句话记在本子上,又在旁边加了三个感叹号。
凌晨三点,林谦停止了抓包分析。
十二个小时的数据已经足够。Warden的扫描规律、通信特征、检测逻辑,全部摸清了。悟空的反检测模块在这十二个小时里被扫描了四十多次,没有一次触发异常。
“今晚先到这儿。”林谦合上电脑,“明天继续测。”
李磊也合上电脑,爬上床。
宿舍里彻底安静下来。
林谦躺在上铺,双手枕在脑后。窗外的路灯透过窗帘缝隙照进来,在天花板上投下一道光。
Warden 2.1.3,这个版本的反作弊能力他太熟悉了。前世谦云科技的安全团队把暴雪从2.0到3.0的每一个版本都拆解过,作为反外挂技术的经典案例。Warden的扫描逻辑、特征码提取方式、行为分析模型,他闭着眼睛都能画出来。
这些知识,现在变成了悟空的反检测能力。
手机震了一下。
李磊发来一条QQ消息,只有一句话。
“谦哥,夜鹰的报告里真的没有Warden版本号的信息。你是从哪知道的?”
林谦看着这条消息,沉默了五秒。
李磊是三个人里技术底子最好的,也是最较真的。王浩和张鹏会被Ghost的故事说服,但李磊不会。他会一直追问,直到找到合理的答案。
林谦回复了四个字。
“逆向推出来的。”
李磊那边显示“正在输入”,显示了很久。
最后只回了一个字。
“好。”
林谦把手机塞到枕头底下。
Ghost这个挡箭牌,能挡住王浩和张鹏,但挡不住李磊太久。李磊迟早会意识到,有些东西不是“一个美国黑客教的”能解释的。
不过那是以后的事。
现在,先把悟空跑稳。
本章完