前些时间,我终于做了一件酝酿很久的事——从零开始入坑《最终幻想14》,也就是俗称的FF14,并且跑通了它从2.0到5.0版本的所有主线。
期间,我把两个战斗特职练到了满级,对应版本的大型副本和娱乐玩法也基本上都一一解锁体验了一遍,从建号算起,前后历时正好整整一个月。
至于为什么选择在版本末期入坑,主要是因为去年6.0版本“晓月之终焉”在国际服上线后的一些业界相关新闻:
而除去网络上的一片好评的撩拨以外,作为一名游戏时间相对有限的社畜,此前也的确没有稳定的时间和精力放在大型MMORPG上,直到春节期间由于疫情原因未能回家,顺带拥有了一段宝贵的空窗期,这才终于有机会体验一下这款近年来有口皆碑的作品。
不过在入坑前,其实我还是有些心生忐忑,尤其是担心面对这样一款国服已经运营了8年,前后横跨5个大型资料片的MMORPG,它对中途加入的“半吊子”可能不够友好——这通常是一个考验耐心的过程。
但经过一个多月的亲身体验,事实证明此前的担忧属实有些多余,因为我不仅充满动力地烧完了月卡,还发现这个沉浸的过程似乎比想象中来得要更容易。
1
慢热过后的柳暗花明
关于FF14的前世今生,早已在业内传为佳话;我们早先也推送过一篇文章聊了聊它从MMO领域吊车尾一路逆袭成为顶尖豪强的励志经历。
而作为一名初次入坑的萌新豆芽,我一个月来的游戏体验,某些程度上与它的逆袭剧本也存在高度相似的地方——可以说是从一片夹杂着平淡与手足无措的陌生环境起步,然后随着主线进度的推进一路开始上扬。
相较于此前市面流行的主流MMO,你可以说它在核心内容上的展开有些慢热,甚至拖沓,但换个角度来说,也着实有那么一丝王道小说里扮猪吃老虎的爽文味道。
比如其中的2.0版本【重生之镜】算是典型。作为FF14新生后的起始之章,它足足覆盖了角色成长的1~50级阶段,是所有萌新玩家的必经之路。但由于早年研发经验不足,导致主线剧情中充斥着大量冗长的背景设定铺陈和来回跑腿要素,因此相较于后续几个资料片而言,它的玩家风评可以说并没有那么优秀。
游戏名梗“来一趟沙之家”就是这个时期的产物
然而即便如此,设计团队依然选择将其保留了下来作为新人最重要的初见流程,宛如一道试炼一样横梗在系列口碑全面逆袭的3.0——【苍穹之禁城】之前。于是新人玩家们往往需要在主线推进的中坚持30个小时以上,才会在2.0版本尾声迎来剧情上的第一个小高潮。这便导致长久以来对于萌新“豆芽”而言,能否迈过2.0几乎成为了一道决定留存与否的“坎”。就像我导师说的——“熬过去的基本上也就不用操心了。”
不过幸运的是为了避免新人在尚未接触到核心内容前“死豆芽”,作为导师的老玩家经常会在游戏里扮演帮助新人过渡的重要角色,像我在游戏前的30个小时里几乎每天都会遇到部队同伴主动前来嘘寒问暖,排个随机本频道里喊一声立马前呼后拥,无所不答。
而除此以外,FF14官方也在后续的更新运维中对2.0阶段的内容也有所改进(在任务奖励中发放沙之家传送券就是比较典的例子),所以个人体验下来,虽然难免被早期主线东一榔头西一棒槌的跑图任务弄得晕头转向,但总体流程上还是相对顺畅的。
早年被沙之家折磨过的断腿光呆们可以瞑目了
当然,为了满足部分玩家需求,官方也在商城中提供主线直升包的售卖,虽然对于时间不太够用的玩家堪称福音,但个人并不建议刚入坑的萌新使用——毕竟对于FF14这样一款将剧情作为核心驱动之一的游戏而言,错过故事的任何一个阶段都过于可惜。
2
刷剧式体验
说到游戏剧情,在我以往的MMORPG经历中,该元素占据的印象比重往往不会特别多。虽然我在玩游戏期间也会仔细观看剧情,用来加深游玩过程中的沉浸感,但与之相比,剧情在一款网游中的为玩家所带来的驱动力,往往要比社交,团队/个人成就以及装备等级所带来的数值提升要弱上很多。
况且对于一款长线运营的网游而言,将游戏本身作为一个优秀的故事载体就不是一件容易的事。尤其是近年来WoW在剧情方面的放飞作为前车之鉴,导致我更是不敢在这方面期盼太多。
但不得不承认的是,在接触FF14后的这一个月里,以往根植于我心中的“MMO剧情服务于玩法”的认知几乎彻底被扭转,甚至在最上头的时候,“想要知道后面到底发生了什么”几乎已经成为了我每日登陆游戏的主要动力。
之所以出现上述症状,主要是因为FF14几乎将游戏剧情设计的重视程度拔高到了一个同类产品中少有的高度,某种程度上也的确实现了“玩”与“赏”之间的相互成就。或许这样说可能你更加容易理解——SE是在真的用做3A单机的思路和成本在打造这款网游。
这点单以主线剧情的表现便可管中窥豹,为了强化剧情演出,FF14没有将玩家角色设定为一个宏观叙事下的参与者和见证者。而是选择像许多传统RPG一样从游戏一开始就将“你”设定为主导整个游戏剧情推进的唯一主角。
“你”可以能够在过场动画与NPC正面互动,虽然没有专门的台词和CV,具体也不知道“你”在演出中说了啥,但通过细致的动作和神情刻画,玩家依然能够无时不刻地感受到——作为游戏主角,你是切切实实身处于故事之中的。
与此同时作为搭建起整个游戏世界观的重要元素之一,游戏中也为几乎每个主要NPC设计了相当数量的演出和文本进行细致刻画,大到一个过场CG,小到一句台词,往往都能让你在不经意间了解到一个角色的喜与悲,得与失,甚至是不同于以往的变化与成长。
也正是由于如此庞大而严丝合缝的内容支撑,使得FF14在群像塑造上的表现显得尤其出彩,以至于在游玩过程中与其说是在打游戏,我的实际体验其实更加贴近于在刷了一部连载周期多年的史诗剧集。更别说在编剧的设计下,位于每个剧情桥段末尾放置的切口还无时不刻不在撩拨着你。
“要不,再来一集?”
3
起初真的只是想玩单机
当然除去前面提到的游戏各方面品质以外,一个温和,佛系,又丰富多彩的社交氛围同样也是我在入坑FF14阶段最大的助力。
关于这点有些讽刺的是,作为一名重度社恐患者,其实刚入坑FF14的时候我是真打算将社交玩法排除在外,单纯将它当作一款单机作品来体验的,只不过到头来这款游戏并没有给我机会。
“意外”发生在我开始游戏后的第二天,在野外跑图砍怪的过程中,我迎来了第一次陌生社交。情形大致就是一个兔娘从天而降,在我身边的树杈上盯了我老半天,没过多久聊天窗一串紫红色字符(密聊)便弹了出来“新人,你需要导师吗?”
确认我是一只独狼“豆芽”后,她便热情地将我拉进队伍,招呼我有任何不明白的地方都可以跟她说。
再往后,她将我拽进了自己的部队,正巧当天碰上一位成员过生日,所有人都到场为其庆生,顺便也拉来了一脸懵逼的我。
时至今日,这张照片中的所有人都发展成了我的亲友,大家平时会经常约在一起在FF14里逛住宅,打本,听演出,看话剧,彼此之间的互动也几乎承包了我如今主线全通后的大部分游戏内容……而这一切,几乎都是从一个偶然的相遇开始的。
实际上,这段经历其实给我带来了一种既熟悉又陌生的感觉。它让人回想起了自己十多年前最早接触网游时,从每一次萍水相逢中收获的欣喜与悸动。
只不过随着近些年来游戏时间的逐渐压缩和碎片化,让人越来越难通过方便的匹配系统收获类似的画面了。
期间我也尝试过回坑网游,期待着与下一个有缘人相遇,只不过聊天窗里找上门的密语,往往都是工作室殷勤的复制粘贴,尝试为将你发展成为下一个客户。
类似的情形见过太多后,难免会有些麻木,以至于在FF14中面对陌生人们的突如其来善意,我甚至有些受宠若惊。
哦,原来网络世界依然存在这样一个地方,有这样一群温柔的玩家,真是太好了。
4
登陆国服的晓月之终途
最后聊聊这款游戏最新的6.0资料片,国内官方译名叫做【晓月之终途】。
2022年3月16日,该版本在国服正式上线,国内的玩家应该当天就能够玩到。
早在去年年底,6.0版本就已经于海外上线,当时甚至一度挤爆了SE的服务器,并得到了大多数行业媒体的高分评价。但受限于各方面条件,国内绝大多数玩家(包括我在内)依然处于拒绝剧透闷声等待的状态,准备等待国服上线之后再大展拳脚。
不过虽然没有去外服抢先体验,但根据官方宣推阶段给到的资料以及视频网站上的搬运内容,整个6.0版本的内容轮廓对于国服玩家而言倒也算不上什么秘密了。
像是在原有地图的基础上,旧萨雷安、拉札罕,加雷马帝国以及月球等新场景将面向玩家开放。
等级上线也从80提升到了90级,新增了治疗系特职贤者和与近战输出系特职钐镰师,各职业的战斗系统也进行了一定程度上的改动,这也意味着笔者刚刚熟练的输出手法,估计又要重新修炼了。
此外新人物模型兔男可以开放使用了,PVP和生活休闲玩法也得到了一定程度的强化。光从新增内容体量上来看,全部体验下来估计也够早已准备就绪的老司机们忙上一阵子。
更重要的是,作为系列的第六部大型资料片,此前贯穿整个系列,围绕着星球和生命的故事——“海德林与佐迪亚克之章”也将于这个版本迎来完结。剧情迎来阶段性落幕后,主角团成员们将何去何从,新的故事篇章又该如何开启,这一系列看点,都是玩家们在新版本的游玩过程中值得期待的地方。
当然对于此时还未入坑的萌新而言,这也是个不错的节点,毕竟不用像以往许多老玩家意义忍受追剧阶段的等候之苦,至少可以一次性从零开始体验到一个相对完整的故事——毕竟,对MMORPG这一“古老”游戏类型依然心存往的玩家而言,能够选择的余地真的不多了。
针对进程行为的监控需求,以往很多安全软件都是采用的Hook技术拦截关键的系统调用,来实现对恶意软件进程创建的拦截。但在x64架构下,系统内核做了很多安全检测措施,特别是类似于KDP这样的技术,使得Hook方法不再有效。为此OS推出了基于回调实现的行为监控方案。本文借助IDA逆向分析该技术的实现原理并给出了关键数据结构及调用链,通过双机内核调试验证了该数据结构以及调用链的正确性。
涉及到的内容如下:1、内核对象及内核对象管理;2、进程回调;3、内核调试;4、Windbg双击调试;引言近年来,各种恶意软件新变种层出不穷,攻击方法、手段多种多样,造成了巨大的经济损失。作为防守的第一个环节就是能够识别出恶意进程创建的动作,而进程创建监控技术是为了能够让安全软件有机会拦截到此动作的技术。安全软件根据匹配算法判断是否准许该进程创建,以此达到保护用户数据安全的目的。
我是渗透测试工作者,整理了多年的渗透测试学习文档。需要逆向工程文档的关注我,私信回复“逆向工程"领取,还有更多渗透测试、攻防等架构资料!!
本文基于逆向工程及内核调试技术,分析了该技术的具体实现及系统额外增加的数据检测机制。借助逆向工具IDA静态逆向分析了系统关键API的内部动作及具体的实现,相关的数据结构,得到该技术实际触发的调用源以及整个调用链。借助VMWare搭建双机调试环境,利用Windbg动态调试系统内核,查看系统中所涉及到的关键数据,并与PCHunter给出的数据做对比分析,验证了分析结论的正确性。此外还通过对调用链中的关键函数下断点,通过栈回溯技术,动态观察了整个调用链及触发时间。分析得到的关键数据结构和系统对数据做的检测校验算法可用于检测病毒木马等软件恶意构造的表项。
1 进程回调原理分析1.1 安装与卸载逆向分析根据微软官方技术文档MSDN上的说明,通过PsSetCreateProcessNotifyRoutine、PsSetCreateProcessNotifyRoutineEx和PsSetCreateProcessNotifyRoutineEx2这三API来安装一个进程创建、退出通知回调例程,当有进程创建或者退出时,系统会回调参数中指定的函数。以PsSetCreateProcessNotifyRoutine为例子,基于IDA逆向分析该API的具体实现。如图1所示,由图可知,该API内部仅仅是简单的调用另一个函数,其自身仅仅是一个stub,具体的实现在PspSetCreateProcessNotifyRoutine中,此函数的安装回调例程的关键实现如图所示。
调用ExAllocateCallBack,创建出了一个回调对象,并将pNotifyRoutine和bRemovel作为参数传入,以初始化该回调对象,代码如图所示;其中pNotifyRoutine即是需要被回调的函数例程,此处的bRemovel为false,表示当前是安装回调例程。
紧接着调用ExCompareExchangeCallBack将初始化好的CallBack对象添加到PspCreateProcessNotifyRoutine所维护的全局数组中。值得注意的是,ExCompareExchangeCallBack中在安装回调例程时,对回调例程有一个特殊的操作如图所示。
与0x0F做了或操作,等价于将低4位全部置1;若ExCompareExchangeCallBack执行失败,则接着下一轮循环继续执行。由图2中第66行代码可知,循环的最大次数是0x40次。如果一直失败,可调用ExFreePoolWithTag释放掉pCallBack所占用的内存,且返回0xC000000D错误码。
然后根据v3的值判断是通过上述三个API中的哪个安装的回调,来更新相应的全局变量。其中PspCreateProcessNotifyRoutineExCount和PspCreateProcessNotifyRoutineCount分别记录当前通过PsSetCreateProcessNotifyRoutineEx和PsSetCreateProcessNotifyRoutine安装回调例程的个数。
PspNotifyEnableMask用以表征当前数组中是否安装了回调例程,该值在系统遍历回调数组执行回调例程时,用以判断数组是否为空,加快程序的执行效率。
除了能够安装回调例程,这三个API也能卸载指定的回调例程。以PsSetCreateProcessNotifyRoutine为例,分析其实现的关键部分,如图所示。
通过一个while循环遍历PspCreateProcessNotifyRoutine数组,调用ExReferenceCallBackBlock取出数组中的每一项,该API内部会做一些检验动作且对返回的数据也做了特殊处理,如图所示。图6中*pCallBackObj即是取出回调对象中的回调例程的函数地址,通过判断其低4位是否为1来做一些数据的校验,如17行所示。
系统做这个处理也是起到保护作用,防止恶意构造数据填入表中,劫持正常的系统调用流程。此外,图中第33行处的代码,在将回调例程返回给父调用时,也将回调例程的低4位全部清零,否则返回的地址是错误的,调用立马触发CPU异常。
ExReferenceCallBackBlock成功返回后,调用ExGetCallBackBlockRoutine从返回的回调对象中取出回调例程,并判断取出的是否为当前指定需要卸载的项,如果是则调用ExDereferenceCallBackBlock递减引用计数,接着调用ExFreePoolWithTag释放掉Callback所占用的内存。期间也会更新PspCreateProcessNotifyRoutineExCount或PspCreateProcessNotifyRoutineCount的值。根据源码还可以得知,该数组总计64项,也即只能安装64个回调例程。如果遍历完数组的64项依旧没有找到,则返回0xC000007A错误码。
1.2 OS执行回调例程分析回调例程安装完之后,如果有新的进程创建或退出,内核则便会遍历该数组来执行其中安装的每一项回调例程。通过IDA的交叉引用功能,可分析出内核其他地方对PspCreateProcessNotifyRoutine的交叉引用,如图所示
共计5个地方涉及到此变量。其中PspCallProcessNotifyRoutines是直接调用回调例程的函数,该函数的关键部分如图所示。
通过while循环,遍历PspCreateProcessNotifyRoutine数组中安装的所有回调例程,依次执行。
PspNotifyEnableMask & 2的操作即为判断当前数组中是否安装有回调例程,加快程序的执行效率,这个变量的值在PsSetCreateProcessNotifyRoutine中安装回调例程时设置。bRemove & 2这个if分支,是用来判断当前的回调例程是通过PsSetCreateProcessNotifyRoutine还是PsSetCreateProcessNotifyRoutineEx安装,因为这两个API安装的回调例程的原型不同,在实际调用时传入的参数也不同。两者的回调例程原分别为:
void PcreateProcessNotifyRoutine(HANDLE ParentId,HANDLE ProcessId,BOOLEAN Create)和void PcreateProcessNotifyRoutineEx(PEPROCESS Process,HANDLE ProcessId,PPS_CREATE_NOTIFY_INFO CreateInfo)。
此外,图8中IDA给出的伪C代码RoutineFun((unsigned __int64)RoutineFun)明显不对,因为回调例程的参数个数是3个,而IDA分析出的参数只有1个,显然有问题。直接看下反汇编代码即可得知,如图所示
根据x64下的调用约定可知,函数的前4个参数是通过rcx、rdx、r8和r9这四个寄存器传递,图给出的正是回调例程的前三个参数,_guard_dispatch_icall内部会直接取rax的值调用过去,而rax的值正是ExGetCallBackBlockRoutine调用返回的回调例程函数地址。
上图中的第二个涉及到PspCreateProcessNotifyRoutine数组的是PspEnumerateCallback函数,该函数是系统内部函数,没有导出,其具体实现如图所示。
该函数根据dwEnumType来判断想要枚举的是哪个数组,由代码分析可知,系统内核维护了三个回调相关的数组,分别为镜像加载回调数组,进程创建退出回调数组,线程创建退出数组。类似之前的函数校验,这里也检测了索引是否超过0x40,超过了则返回0,以示失败。
1.3 触发调用的调用链分析上节分析了回调例程的直接调用上级函数,本节分析整个调用链,主要分析调用源及调用过程中涉及到的关键函数。根据IDA给出的交叉引用图如图所示。
涉及到的函数调用非常多,很多不相关的也被包含进来,不便于分析。经手动分析整理后的调用链,其链路中的关键API如图所示。
虚线以上部分为用户态程序,虚线以下为内核态程序,红色标注的都是标准导出的API。
根据图12可知,当用户态进程调用RtlCreateUserProcess、RtlCreateUserProcesersEx或RtlExitUserProcess时,内核都会去遍历PspCreateProcessNotifyRoutine数组,依次执行回调例程,通知给驱动程序做相应的处理。
驱动接管之后,可以做安全校验处理,分析进程的父进程或者进一步分析进程链,此外还可以对即将被拉起的子进程做特征码匹配,PE指纹识别,导入表检测等防御手段。
这种方式不需要去Hook任何API,也无需做特征码定位等重复繁琐的工作,完全基于系统提供的回调机制,且在Windows系统中都可以无缝衔接。且各个安全厂家之间也不存在相互竞争,大大缩小了系统蓝屏的风险。
图12中NtCreateUserProcess调用PspInsertThread的原因是创建进程的API内部会创建该进程的主线程。将遍历回调例程数组的工作统一到PspInsertThread中,由其去调用下层的PspCallProcessNotifyRoutines更为合理。
2 实验2.1 观察系统中已安装的回调例程实验环境如表1所示,借助于VMWare进行双机调试。
Guest OS Build 10.0.16299.125Host OS Build 10.0.17134.885Windbg版本 10.0.17134.1VMWare 14.1.1 build-7528167PCHunter V1.56
在Windbg中观察PspCreateProcessNotifyRoutine数组,共计14项有效数据,如下所示;
1: kd> dd PspCreateProcessNotifyRoutineCount l1fffff802`151f4e78 000000091: kd> dd PspCreateProcessNotifyRoutineExCount l1fffff802`151f4e7c 000000051: kd> dq PspCreateProcessNotifyRoutine l40fffff802`14da2a80 ffffcc8b`d884b9bf ffffcc8b`d8d9c96ffffff802`14da2a90 ffffcc8b`d939975f ffffcc8b`da00044ffffff802`14da2aa0 ffffcc8b`d9bd382f ffffcc8b`da41e8dffffff802`14da2ab0 ffffcc8b`da53815f ffffcc8b`da5ca8bffffff802`14da2ac0 ffffcc8b`dac5178f ffffcc8b`dbef624ffffff802`14da2ad0 ffffcc8b`dce333af ffffcc8b`dcec67dffffff802`14da2ae0 ffffcc8b`dc735def ffffcc8b`dcabd32f
拆解第一项,寻找其所对应的回调例程,如下:
1: kd> dq ffffcc8b`d884b9b0 l3ffffcc8b`d884b9b0 00000000`00000020 fffff802`13fd6268ffffcc8b`d884b9c0 00000000`00000000
由此可知,安装的回调例程起始地址为fffff802`13fd6268,且还可知道Remove为0,即这个是已经安装的。寻找该回调例程对应的驱动模块,如下:
1: kd> u fffff802`13fd6268360qpesv64+0x26268:fffff802`13fd6268 mov qword ptr [rsp+08h],rbxfffff802`13fd626d mov qword ptr [rsp+10h],rbpfffff802`13fd6272 mov qword ptr [rsp+18h],rsifffff802`13fd6277 push rdi1: kd> lmvm 360qpesv64start end module namefffff802`13fb0000 fffff802`14002000 360qpesv64Loaded symbol image file: 360qpesv64.sysImage path: 360qpesv64.sysImage name: 360qpesv64.sysTimestamp: Wed May 27 20:13:22 2020 (5ECF2C52)CheckSum: 00054A2AImageSize: 00052000
可知该回调例程是360官方提供。借助PCHunter来对比下,其给出的数据如图所示
2.2 动态调试回调例程以表项的第14项为例,内容如下,
1: kd> dq ffffcc8b`dcabd320 l3ffffcc8b`dcabd320 00000000`00000020 fffff802`13d795b4ffffcc8b`dcabd330 00000000`000000061: kd> bp fffff802`13d795b41: kd> g
断点命中,查看父进程相关信息,如下,
Breakpoint 0 hitfffff802`13d795b4 48895c2408 mov qword ptr [rsp+8],rbx1: kd> dt _EPROCESS @$proc -yn ImageFileNament!_EPROCESS +0x450 ImageFileName : [15] "svchost.exe"
由此可知,是svchost.exe这个父进程创建或者销毁了一个子进程,更具体的信息如下分析;查看下当前的上下文环境;
1: kd> rrax=fffff80213d795b4 rbx=ffffcb8050526c80 rcx=ffffcc8bdd67e080rdx=0000000000001f28 rsi=000000000000000d rdi=ffffcc8bdd67e080rip=fffff80213d795b4 rsp=ffffcb8050526c38 rbp=ffffcb8050526ca9r8=ffffcb8050526c80 r9=ffffcc8bdc735de0 r10=ffff9401cdcc2760r11=0000000000000000 r12=0000000000000001 r13=0000000000000000r14=ffffcc8bdcabd320 r15=fffff80214da2ae8iopl=0 nv up ei pl zr na po nccs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00000246根据x64的调用约定可知,rcx寄存器中存储的是EPROCESS对象指针,该对象存储的是即将被创建的子进程的相关信息,可以获取到的作为身份识别或者安全检测的关键信息如下:1: kd> dt _EPROCESS ffffcc8bdd67e080 -yn ImageFilentdll!_EPROCESS +0x448 ImageFilePointer : 0xffffcc8b`dc97c5c0 _FILE_OBJECT +0x450 ImageFileName : [15] "UpdateAssistan"1: kd> dt 0xffffcc8b`dc97c5c0 _FILE_OBJECT -yn FileNamentdll!_FILE_OBJECT +0x058 FileName : _UNICODE_STRING "\Windows\UpdateAssistant\UpdateAssistant.exe"1: kd> cess /p ffffcc8bdd67e080; !peb 186ef07000Implicit process is now ffffcc8b`dd67e080.cache forcedecodeuser donePEB at 000000186ef07000 CurrentDirectory: 'C:\Windows\system32\' WindowTitle: 'C:\Windows\UpdateAssistant\UpdateAssistant.exe' ImageFile: 'C:\Windows\UpdateAssistant\UpdateAssistant.exe'CommandLine: 'C:\Windows\UpdateAssistant\UpdateAssistant.exe /ClientID Win10Upgrade:VNL:NHV19:{} /CalendarRun'
可以获取到该进程的EXE路径,创建时的命令行参数,父进程的PID等信息,这些足以用于安全软件的检测。父进程的完整调用栈如下,
1: kd> k # Child-SP RetAddr Call Site00 ffffcb80`50526c38 fffff802`14ef4ae5 0xfffff802`13d795b401 ffffcb80`50526c40 fffff802`14ef752c nt!PspCallProcessNotifyRoutines+0x24902 ffffcb80`50526d10 fffff802`14f2797b nt!PspInsertThread+0x5a403 ffffcb80`50526dd0 fffff802`14b79553 nt!NtCreateUserProcess+0x9c704 ffffcb80`50527a10 00007ffe`547d1654 nt!KiSystemServiceCopyEnd+0x1305 0000002f`4b67d258 00007ffe`50b406df ntdll!NtCreateUserProcess+0x1406 0000002f`4b67d260 00007ffe`50b3d013 KERNELBASE!CreateProcessInternalW+0x1b3f07 0000002f`4b67dec0 00007ffe`5216ee0f KERNELBASE!CreateProcessAsUserW+0x6308 0000002f`4b67df30 00007ffe`4ce0a136 KERNEL32!CreateProcessAsUserWStub+0x5f09 0000002f`4b67dfa0 00007ffe`4ce0bdd9 UBPM!UbpmpLaunchAction+0xb360a 0000002f`4b67e280 00007ffe`4ce08ee0 UBPM!UbpmLaunchTaskExe+0x2790b 0000002f`4b67e490 00007ffe`4ce10a86 UBPM!UbpmpLaunchOneTask+0x6c00c 0000002f`4b67e8f0 00007ffe`4ce0b8bc UBPM!UbpmpHandleGroupSid+0x2360d 0000002f`4b67ea10 00007ffe`4ce0b78b UBPM!UbpmpLaunchExeAction+0xec0e 0000002f`4b67eaf0 00007ffe`4ce0b5a3 UBPM!UbpmpTakeAction+0xeb0f 0000002f`4b67eb50 00007ffe`4ce0b193 UBPM!UbpmpPerformTriggerActions+0x29310 0000002f`4b67eca0 00007ffe`4ce1316c UBPM!UbpmpHandleTriggerArrived+0x56311 0000002f`4b67ef50 00007ffe`508c32d0 UBPM!UbpmpRepetitionArrived+0x1c12 0000002f`4b67ef90 00007ffe`508c3033 EventAggregation!EaiSignalAggregateEvent+0x16c13 0000002f`4b67f060 00007ffe`508c27aa EventAggregation!EaiSignalCallback+0xe714 0000002f`4b67f140 00007ffe`508c253e EventAggregation!EaiProcessNotification+0x1aa15 0000002f`4b67f270 00007ffe`508caef8 EventAggregation!WnfEventCallback+0x50616 0000002f`4b67f3a0 00007ffe`5476769f EventAggregation!AggregateEventWnfCallback+0x3817 0000002f`4b67f3f0 00007ffe`54767a51 ntdll!RtlpWnfWalkUserSubscriptionList+0x29b18 0000002f`4b67f4e0 00007ffe`5476b510 ntdll!RtlpWnfProcessCurrentDescriptor+0x10519 0000002f`4b67f560 00007ffe`54766b59 ntdll!RtlpWnfNotificationThread+0x801a 0000002f`4b67f5c0 00007ffe`54764b70 ntdll!TppExecuteWaitCallback+0xe11b 0000002f`4b67f600 00007ffe`52171fe4 ntdll!TppWorkerThread+0x8d01c 0000002f`4b67f990 00007ffe`5479ef91 KERNEL32!BaseThreadInitThunk+0x141d 0000002f`4b67f9c0 00000000`00000000 ntdll!RtlUserThreadStart+0x21
由于前四个参数是通过的寄存器传递的,所以无法直接通过栈来回溯到参数,但可以通过手动方式分析得到。分析ntdll!NtCreateUserProcess的调用父函数,其返回地址处的汇编代码如下所示:
1: kd> ub 00007ffe`50b406dfKERNELBASE!CreateProcessInternalW+0x1b11:00007ffe`50b406b1 488b842440040000 mov rax,qword ptr [rsp+440h]00007ffe`50b406b9 4889442420 mov qword ptr [rsp+20h],rax00007ffe`50b406be b800000002 mov eax,2000000h00007ffe`50b406c3 448bc8 mov r9d,eax00007ffe`50b406c6 448bc0 mov r8d,eax00007ffe`50b406c9 488d942448010000 lea rdx,[rsp+148h]00007ffe`50b406d1 488d8c24e0000000 lea rcx,[rsp+0E0h]00007ffe`50b406d9 ff1521901600 call qword ptr [KERNELBASE!_imp_NtCreateUserProcess (00007ffe`50ca9700)]可知,NtCreateUserProcess第一个参数和第二个参数再rsp+0xE0和rsp+0x148处;查看该处的数据如下:1: kd> dpu 0000002f`4b67d260+E0 0000002f`4b67d260+148 0000002f`4b67d340 00000000`000000000000002f`4b67d348 00000000`000000040000002f`4b67d350 00000100`000000000000002f`4b67d358 00000000`000000200000002f`4b67d360 000001f2`d9b87cc0 "C:\Windows\UpdateAssistant\UpdateAssistant.exe"0000002f`4b67d368 00000000`000000000000002f`4b67d370 00000000`000000000000002f`4b67d378 0000002f`000000000000002f`4b67d380 000001f2`d8d43580 "C:\Windows\UpdateAssistant\UpdateAssistant.exe /ClientI"0000002f`4b67d388 00000000`000000000000002f`4b67d390 00000000`000086640000002f`4b67d398 000001f2`d9d73c40 "ALLUSERSPROFILE=C:\ProgramData"0000002f`4b67d3a0 00000000`000000000000002f`4b67d3a8 00000000`00000000
由此可知,svchost拉起的子进程为UpdateAssistant.exe,与之前分析得到的参数也相吻合。从调用栈可知,是在svchost创建子进程UpdateAssistant.exe时遍历的回调例程,通知给驱动软件做相应的处理。
我是渗透测试工作者,整理了多年的渗透测试学习文档。需要逆向工程文档的关注我,私信回复“逆向工程"领取,还有更多渗透测试、攻防等架构资料!!
3 结束语本文详细地分析了系统实现进程回调安全机制的内部原理,借助IDA工具逆向系统镜像文件,分析了实现的关键代码部分,得到了关键数据结构及系统额外做的数据检测校验算法。对关键全局变量的作用也做了详细解释。
此外,通过逆向分析,给出了整个机制的调用源与调用链。最后基于双机调试环境,动态查看内核中维护的进程回调例程表,并且下断点实际动态调试了整个过程。
对于驱动开发,内核安全相关方面的研究工作者提供了该技术实现原理与机制。基于得到的关键数据结构和系统数据检验保护算法,可以解密关键字段后检测表项中的恶意代码,也可以用于安全厂商在对抗过程中,完全脱离系统提供的API手工构建表项,达到监控系统行为的目的。
作者:NGA-makelend
前言
其实已经算大版本的末期了,现在回过头来,我们已经能对舞者产生相当准确的认知了。之前在NGA和B站(NGA版头攻略[1],B站顾跑跑舞者攻略视频[2],B站待宵姫[3] etc.)也有相当程度上可供参考的舞者基础/进阶攻略。
但一个职业的命运啊,又要看个人奋斗(指职业改动),又要看历史进程(指属性和手法优化),虽然经典的攻略不会过时,但是总有新的一些理论细节和新的配装被提出。
虽然我不认为舞者需要新的攻略,但需要一篇文章来拾人牙慧,把一些简单的职业理解和配装分享给大家,这就是我做这篇“拾遗”的目的。
本文大部分内容均出自个人观点和直接引用,并不是通过严格数据证明的文章,也不代表完全的真实情况,故谨慎参考。
职业评价
整个5.0大版本来看,从觉醒篇算起,舞者从伤害上限角度来讲,是当之无愧的最强远敏,在强大的团队中,随着属性的提高,逐渐拥有其它两个远敏望尘莫及的团队贡献和伤害。甚至在极端情况下,舞者的输出贡献接近近战和法系。
且即使在普通野队中,一个同等水平的舞者也完全不弱于甚至会强过其它两个远敏。尤其是版本末期的高属性情况下。
我会选择FFLOGS(www.fflogs)的数据来作为例子。FFLOGS的内容有合理的地方,也有不合理的地方,rdps数据模拟上可以认为是相对准确的[4]。
但是也存在问题,比如rdps可以相对反应出职业的团伤贡献能力,但对舞者来讲其实一定程度上忽略了舞者本身在60s和120s团辅中可以打出的恐怖爆发(也就是反应在adps上的数据,但只看adps又看不出舞者的团辅强度,所以要结合起来看)。
所以虽然我们会用FFLOGS的rpds举例子,但不要太过于在意冰冷的数字(x),提高我们的团辅理解和优化手法才是最重要的。
以“木桩本”为例:
其实整个伊甸来看“上天本”的话,除了希瓦,舞者是因为能获得更多团队爆发时间轴的关系更占优势的,而且希瓦能存100电热的机工,上限也没办法超过舞者()
以下均选用国际服数据,国际服人口基数大,且高质量团队多,样本大参考价值更多一些。
虚无行者
拉姆
影之王
相信通过上面的数据,你也能够认识到,舞者不是什么划水工具人,是远敏中拥有最高上限的机体,同时还有极其强大的60/120s团辅对齐能力,因此作为一个舞者应该好好打出自己的输出,不能只从舞伴找原因。
如果只是想划划水,拥有更高下限的机工比舞者更合适,既然选择了舞者,就最好尝试发挥上限。
关于配装
5.4版本舞者的bis配装是2.50gcd+暴击和几乎信念石头拉满,而不是其它带技能速度或者是打直击石头的配装。
我会从技能速度还有直击与信念两个方面说明为什么这样做选择。
技能速度
虽然早期攻略中提到了2.48、2.47或者更低技能速度的可能性,但实际上,技能速度对舞者是很不好的属性。而The Balance的5.3舞者职业指导[5]里面已经有了很好的结论,其中也有关于直击、信念和舞伴的结论。
技能速度只舞者的两个效果:1.增加自动攻击的伤害。2.降低的间隔(没有技能速度时为2.50s)。
对于自动攻击伤害增加:每254点技能速度可以增加1%的自动攻击伤害,和信念的阈值相同。然而自动攻击在总伤害中的占比只有约13-15%。
对于降低gcd的间隔:有很多人以“调手感”为理由来打技速石头,但是舞者真的会因为改变技速而手感变好吗?虽然技能速度会降低我们大部分技能的间隔,但是“小舞”标准舞步和“大舞”技巧舞步作为占用gcd的能力技是不会随着gcd而改变时间的,比如gcd为2.48时,标准舞步前会产生0.2s的空档期,造成gcd卡顿,我不知道这算不算手感...
而试图改变成2.49或者2.48来寻求某个转场前多打一个gcd的想法,也往往因为多这一个gcd赚到的不如技速换成直击和信念来的收益高而需要被放弃。
直击与信念
目前来讲,舞者的直击和信念的选择,大概是被人误会最多的。而且似乎流传最广的配装方案也就是“信念吃满,无脑直击”,这对于没有必定直爆和自身直爆buff的职业来讲可能没错,但舞者有自身直爆buff。
关于直击,80级时大约240点直击等于4%的直击概率,直击是1.25倍固定增伤,因此我们可以得到4% x 1.25 =1%,即240点增伤1%。
关于信念,80级时大约需要253点能够增伤1%。
所以在不考虑这两个属互作用以及必定直爆和直爆buff的时候,我们认为直击比信念更加优秀。
但恰好这个版本,装备自带的直击很高(真有你的SE,不给加暴击就狂加信直),加上舞者有作用于自身的直爆buff,使得舞者并不能再按照直击>信念的思路来镶嵌了。
配装
结合当前版本装备属性和舞者职业特点来讲,不能生搬硬套一般性的结论。在5.4版本装备下魔晶石镶嵌:
暴击>直击>信念(x)
暴击>信念>直击(√)
正如开篇所讲,配装是会随着时代变化的,当前在整个5.0大版本中,副属性在不断提高,因此(暴击伤害+暴击率)和直击率也是不断提高的。
舞者拥有进攻之探戈这一同时提高暴击和直击概率的技能,且舞者会倾向于在进攻之探戈+四色技巧舞步结束中倾泻所有积累的资源,大约有31%左右的伤害会在进攻之探戈中输出[5],因此,直击对于舞者的收益期望会降低,加上本版本(5.4)的装备大多带有大量直击,舞者的bis镶嵌方法已经可以粗略的认为是暴击>信念>直击了(其实是结合信念和直击交互作用得出的最优值)。
如果有需要的话,基于5.4装备的绝本装备:
5.4bis
绝亚历山大
70级绝本
就如FFFL所说的,不要相信那些流传的错误百出的表格,最好能自己算。
当然我不会只给结论,如果你对计算舞者的伤害感兴趣,这里有一个舞者自己本身的职业伤害计算器,你可以根据自己目前的装备进度来使用计算器计算自己能换上的最合适的装备,授人以鱼不如授人以渔。
来自the balance的舞者伤害计算器
舞伴的选择[5]
关于舞伴如何选择,并不是完全简单粗暴的选择“面板最高的”那个就好,首先我们要明确舞伴提升伤害的构成:
1.标准舞步的5%伤害提升:与舞伴造成的总伤害有关。
2.进攻之探戈的20%暴击与20%直击:与舞伴爆发期和爆发强度有关,也会因为必定直爆技能减少收益。
3.伶俐获取:根据统计显示,每个舞伴技能(能力技不会生成伶俐)有20%的概率生成10点伶俐,每个自己的技能有30%概率生成10伶俐。但伶俐获取的收益大概仅有标准舞步+进攻之探戈的5%,所以我们不以伶俐获取速度作为舞伴标准。
从理论上讲,我们应该选择120s爆发期,且拥有极高总伤害的职业作为舞伴(标准工具人盘子!)但实际上这样的职业只有武士(),总会遇到没有武士的情况,因此就可以根据上述的前两点原则来进行进一步的舞伴选择。
在5.4环境下,一般我们选择舞伴的优先级为:
1.武士
2.忍者
3.武僧/暴击黑魔
4.龙骑/召唤
5.赤魔
6.机工
7.诗人
8.舞者
大家在完全不熟悉队友的情况下,可以按照这个优先级选择舞伴。
当然,还是授人以鱼不如授人以渔,如果固定队的话,想知道选谁最好,你可以利用舞伴选谁网(误)。
一些手法,FAQ
这里我打算留下来用FAQ的形式来给大家留出问答空间,收集一些问题后再做编辑,大家可以通过:1.NGA私信 2.神秘代码1016383000来联系我问问题。
请问一些版头攻略找不到的问题()
关于我
八尾半@柔风海湾,于觉醒篇开始打零式。
最开始只会武士机工白魔和黑魔,共鸣篇后期开始每个职业都玩一点(除了战士),再生篇首发了舞者和黑魔,是练习黑魔两年半的黑魔练习生。
曾经是个被冰冷数字迷惑双眼的人,现在希望数字能有温度(x)目标是舞者十一层rdps26k,绝赞努力中。
后记
本文是因为最近看了身边有人求助舞者配装,被简单粗暴地说:“直击大于信念,信念能吃满就够”,而且发现所谓的bis表格也是不大对的,接着发现配装、舞伴选择、还有一些手法的选择不是很好找,就想着写点东西给别人看,最后写的还挺多,就干脆发来NGA了。我不算是舞者一筋玩家,甚至舞者理解在我的职业池里面不算是特别深的那一档,做攻略是肯定不够格的,不过援引一些现有的成果还是没问题的,希望这一点微薄的工作能给各位舞者带来一些帮助。