https://back.engineering/17/05/2021/
If there is any infringement, please send an email to tu9oh0st@duck.com
and I will promptly remove the article.
如果有任何侵权行为,请发送邮件到tu9oh0st@duck.com,我会及时删除该文章。
翻译有问题,请大佬们指正,以下为原文翻译内容:
Download link: VMProtect 2 Reverse Engineering
在深入探讨这篇文章之前,我想就现有的VMProtect 2工作、这篇文章的目的以及我的意图陈述几件事,因为这些似乎有时会被误解和扭曲。
虽然已经有很多关于VMProtect 2的研究,但我觉得仍有一些信息没有被公开讨论,也没有足够的源代码披露给公众。我在这篇文章中所披露的信息旨在超越一般的架构分析,但要低得多。在这个层面上,人们可以在给定的VMProtect二进制文件中编码自己的虚拟机指令,并可以轻松地拦截和改变虚拟指令的结果。本文讨论的动态分析是基于Samuel Chevet的现有工作,我的动态分析研究和Vmtrace项目只是在他的演讲"Inside VMProtect"中展示的工作基础上的扩展。
这篇文章无意对VMProtect 2、该软件的创造者或使用该软件的人提出任何负面意见。我钦佩创造者,他们显然有令人印象深刻的技能来创造这样一个产品。
这篇文章也是在这样的印象下创建的,即这里讨论的一切很可能是由私人实体发现的,我不是第一个发现或记录有关VMProtect 2架构的事情。我并不打算把这些信息当作是突破性的或其他人已经发现的东西,恰恰相反。这只是一个现有信息的集合,加上我自己的研究。
既然如此,我谦虚地向你介绍,"VMProtect 2,虚拟机架构的详细分析"。
VIP - 虚拟指令指针,这相当于 x86-64 的 RIP 寄存器,它包含要执行的下一条指令的地址。VMProtect 2 使用本地寄存器 RSI 来保存下一条虚拟指令指针的地址。因此,RSI等同于VIP。
VSP - 虚拟堆栈指针,这相当于x86-64的RSP寄存器,包含堆栈的地址。VMProtect 2使用本地寄存器RBP来保存虚拟堆栈指针的地址。因此,RBP等同于VSP。
VM Handler - 一个包含执行虚拟指令的本地代码的例程。例如,VADD64指令将堆栈上的两个值加在一起,并将结果以及RFLAGS存储在堆栈上。
Virtual Instruction - 也被称为 "虚拟字节码 "是由虚拟机解释并随后执行的字节。每个虚拟指令至少由一个或多个操作数组成。第一个操作数包含该指令的操作码。
Virtual Opcode - 每个虚拟指令的第一个操作数。这是vm处理程序的索引。VMProtect 2操作码的大小总是一个字节。
IMM / Immediate Value - 编码到虚拟指令中的一个值,通过这个值进行操作,例如将所述值加载到堆栈或虚拟寄存器中。虚拟指令如LREG、SREG和LCONST都有即时值。
Transformations - 本篇文章中使用的术语 "转换 "特指为解密虚拟指令的操作数和vm处理程序表项而进行的操作。这些转换包括add, sub, inc, dec, not, neg, shl, shr, ror, rol, 以及最后的BSWAP。变换的大小为1、2、4和8字节。变换也可以有与之相关的即时/恒定值,如 "xor rax, 0x123456",或 "add rax, 0x123456"。
VMProtect 2是一个基于虚拟机的x86混淆器,它将x86指令转换为RISC、堆栈机的指令集。每个受保护的二进制文件都有一套独特的加密虚拟机指令,并有独特的混淆功能。该项目旨在披露每一个VMProtect 2二进制文件中非常重要的签名,以帮助进一步研究。本文还将简要地讨论不同类型的VMProtect 2混淆。所有去混淆的技术都是专门针对虚拟机例程的,对一般被混淆的例程不起作用,特别是其中有真正的JCC的例程。
VMProtect 2 在大多数情况下使用两种混淆类型,第一种是Deadstore,第二种是不透明的分支。在整个混淆的程序中,你可以看到几条指令后有一个JCC,然后是另一组指令后有另一个JCC。不透明分支的另一个贡献是影响FLAGS寄存器的随机指令。你到处都可以看到这些小家伙。它们大多是位测试指令,无用的比较,以及设置/清除标志的指令。
在这个不透明分支混淆实例中,我将介绍 VMProtect 2 不透明分支的外观,其他因素如 rflags 的状态,以及最重要的是,如何确定你看到的是不透明分支还是合法的 JCC。
考虑一下上述混淆的代码。注意JNO分支。如果你在ida中跟踪这个分支,并将指令与JNO之后的指令进行比较,你可以看到这个分支是无用的,因为两个路径执行的是同样的有意义的指令。
如果你看得足够仔细,你可以看到有几条指令在两个分支中都有。要确定哪些代码是Deadstore,哪些代码是需要的,可能很困难,但是如果你在ida中选择一个寄存器,并查看它在你所看的指令之前被写入的所有地方,你可以删除所有其他的写入指令,直到有一个对该寄存器的读取。现在,回到这个例子,在这种情况下,以下指令才是重要的。
这些不透明分支的产生使得有重复的指令出现。对于每个代码路径,还有更多的死库混淆以及不透明的条件和其他影响RFLAGS的指令。
除了不透明的位测试和比较,VMProtect 2 deadstore混淆在指令流中增加了最多的垃圾。这些指令没有任何作用,可以很容易地被发现并被手工删除。请考虑以下情况:
让我们从头开始,一条一条的指令。在0x140004149的第一条指令是 "RCL - Rotate Left Carry"。这条指令影响到FLAGS寄存器和DI。让我们看看下一次DI被引用的时候。它是读还是写?下一次对DI的引用是位于0x140004158的NOT指令。NOT读和写DI,到目前为止两条指令都是有效的。下一个引用DI的指令是POP指令。这一点很关键,因为在这条POP指令之前对RDI的所有写都可以从指令流中删除。
下一条指令是POP RAX,位于0x14000414C。RAX在整个指令流中从未被写入,只是被读出。因为它有一个读的依赖性,所以这条指令不能被删除。进入下一条指令,SHLD - 双精度左移(double precision shift left),对R11有写依赖,对BX有读依赖。下一条引用R11的指令是0x140004153的POP R11。我们可以删除SHLD指令,因为它是Deadstore。
现在只要对每一条指令重复这个过程。最终的结果应该是这样的:
这种方法对于消除Deadstore混淆并不完美,因为有第二个POP RCX在上面这个结果中缺失。POP和PUSH指令是特殊情况,不应该从指令流中发出,因为这些指令也会改变RSP。这种去除死库的方法也只适用于vm_entry和vm handler。这不能应用于一般的混淆程序。同样,这个方法不会对任何被混淆的例程起作用,它是专门为vm_entry和vm handlers定制的,因为这些例程中没有合法的JCC。
虚拟指令由被称为 "vm handlers"的虚拟指令处理程序进行解密和解释。虚拟机是一个基于RISC的堆栈机,带有scratch寄存器。在vm-entries之前,虚拟指令的加密RVA(相对虚拟地址,relative virtual address)被推入堆栈,所有的通用寄存器以及标志被推入堆栈。VIP被解密,计算,并加载到RSI。然后在RBX中启动一个滚动解密密钥,用来解密每一条虚拟指令的每一个操作数。滚动解密密钥通过与解密的操作数值进行转换来更新。
VMProtect 2使用一个滚动解密密钥。该密钥用于解密虚拟指令操作数,随后防止任何形式的hook,因为如果任何虚拟指令被不按顺序执行,滚动解密密钥将变得无效,导致虚拟操作数的进一步解密也无效。
在虚拟机内部的执行过程中,一些本地寄存器是专门用于虚拟机机制的,比如虚拟指令指针和虚拟栈。在本节中,我将讨论这些本地寄存器和它们在虚拟机中的用途。
首先,RSI总是被用来作为虚拟指令指针。操作数从存储在RSI中的地址获取。装入RSI的初始值由vm_entry完成。
RBP用于虚拟堆栈指针,存储在RBP中的地址实际上是本地堆栈内存。在分配从头开始的寄存器之前,RBP与RSP一起被加载。这给我们带来了包含scratch寄存器的RDI。RDI中的地址在vm_entry中也被初始化,并被设置为本地堆栈内部的一个地址。
R12被加载了vm处理表的线性虚拟地址。这是在vm_entry中完成的,在虚拟机内部执行的整个过程中,R12将包含这个地址。
R13在vm_entry中被加载了模块基址的线性虚拟地址,并且在虚拟机内部的整个执行过程中不会被改变。
RBX是一个非常特殊的寄存器,它包含滚动解密密钥。在每条虚拟指令的每个操作数被解密后,RBX通过对其进行转换来更新其解密的操作数的值。
RAX、RCX和RDX被用作虚拟机内部的临时寄存器,但是RAX被用来对其他寄存器进行非常特殊的临时操作。RAX用于解密虚拟指令的操作数,AL具体用于解密虚拟指令的操作码。
vm_entry是虚拟机架构中一个非常重要的组成部分。在进入虚拟机之前,一个加密的RVA到虚拟指令被推到堆栈中。这个RVA是一个四字节的值。
在这个值被推入堆栈后,一个jmp指令被执行以开始执行vm_entry。我在上面详细解释过vm_entry会被扁平化混淆处理。然后删除deadstor代码,我们可以得到一个干净的vm_entry的视图。
正如预期的那样,所有的寄存器和RFLAGS都被推到了堆栈中。最后一次推送将8个字节的0放在堆栈上,而不是我最初预期的重新定位。这些推送发生的顺序在每个版本中都是独一无二的,但是最后推送的8个0在所有二进制文件中总是相同的。这是一个非常稳定的签名,可以确定一般寄存器推送的结束时间。下面是我在本段中提到的指令的确切序列。
在所有的寄存器和RFLAGS被推入堆栈后,模块的基本地址被加载到R13。这发生在每一个二进制文件中,在虚拟机的执行过程中,R13总是包含模块的基地址。模块的基地址也被推入堆栈。
接下来,要执行的虚拟指令的相对虚拟地址被解密。这是通过从RSP+0xA0加载32位RVA到ESI来完成的。这是一个非常重要的签名,可以很容易找到。然后对ESI进行三次转换以得到虚拟指令的解密RVA。这三个转换在每个二进制中是唯一的。然而,总是有三个转换。
此外,接下来发生的值得注意的操作是在堆栈上为从头寄存器分配空间。RSP总是被移到RBP,然后RSP被减去0x140。然后按16个字节对齐。做完这些后,地址被移入RDI。在虚拟机的执行过程中,RDI总是包含一个指向scratch寄存器的指针。
下一个值得注意的操作是将vm处理程序表的地址加载到R12中。这是在每个单一的VMProtect 2二进制文件上进行的。R12总是包含vm处理表的线性虚拟地址。这是另一个重要的签名,可用于找到vm处理程序表的位置,非常简单。
然后对RSI进行另一个操作来计算VIP。在PE头中,有一个叫做 "可选头 "的头。它包含各种各样的信息。其中一个字段被称为 "ImageBase"。如果在这个字段中有任何高于32的位,这些位就会被加到RSI中。例如,vmptest.vmp.exe ImageBase字段包含值0x140000000。因此,作为计算的一部分,0x100000000被添加到RSI中。如果一个ImageBase字段包含少于32位的值,那么RSI将被添加到0。
在对RSI做了这个加法之后,一个小的、有点不重要的指令被执行。这条指令将虚拟指令的线性虚拟地址加载到RBX中。现在,RBX有一个非常特殊的用途,它包含了 "滚动解密 "的密钥。正如你所看到的,加载到RBX的第一个值将是虚拟指令本身的地址! 不是线性虚拟地址,而只是包括ImageBase字段前32位的RVA。
接下来,vmp模块的基地址被添加到RSI中,计算出虚拟指令的完整线性虚拟地址。记住,RBP包含了在分配scratch空间之前的RSP的地址。这时模块的基地址在堆栈的顶部。
vm_entry的细节到此为止,这个例程的下一部分实际上被称为 "calc_vm_handler",在除了vm_exit指令之外的每一条虚拟指令之后执行。
calc_jmp是vm_entry例程的一部分,然而它不仅仅被vm_entry例程所提及。每个vm处理程序最终都会跳转到calc_jmp(除了vm_exit)。这段代码负责解密每条虚拟指令的操作码,以及索引到vm处理程序表,解密vm处理程序表条目并跳转到结果的vm处理程序。
这段代码的第一条指令从RSI中读出一个字节,如你所知,这是VIP。这个字节是一个加密的操作码。换句话说,它是一个进入vm处理程序表的加密索引。总共有5个转换被完成。第一个转换总是应用于加密的操作码和RBX中的值作为源。这就是 "滚动加密 "的作用。值得注意的是,加载到RBX的第一个值是虚拟指令的RVA。因此BL将包含这个RVA的最后一个字节。
接下来,三个转换被直接应用于AL。这些转换可以有即时的值,但是从来没有其他寄存器的值加入这些转换中。
最后一个转换是应用于存储在RBX中的滚动加密密钥。这个变换和第一个变换是一样的。然而,寄存器的位置互换。最终的结果是解密的vm处理程序索引。然后AL的值被零扩展到RAX的其余部分。
现在,进入vm handler表的索引已经被解密,vm handler条目本身必须被获取和解密。对这些vm处理程序表条目只进行了一次转换。在这些转换中没有使用任何寄存器的值。加密后的vm表项值被加载到的寄存器总是RCX或RDX。
现在,VIP被推进。VIP可以向前或向后推进,推进操作本身可以是LEA、INC、DEC、ADD或SUB指令。
最后,模块的基地址被添加到解密后的vm处理程序RVA中,然后执行JMP,开始执行这个vm处理程序。同样,RDX或RCX总是被用于这个ADD和JMP。这是虚拟机中另一个重要的签名。
至此,calc_jmp的代码片段规范结束。正如你所看到的,有一些非常重要的签名,使用Zydis就可以找到。特别是对vm handler表项进行的解密,以及对这些加密值的获取。
与vm_entry不同,vm_exit是一个非常简单的程序。这个例程简单地将所有寄存器POP回原位,包括RFLAGS。有一些多余的POP是用来清除堆栈中的模块基数、padding以及RSP的,因为它们不需要了。pops发生的顺序与它们被vm_entry推入堆栈的顺序相反。在vm_exit例程之前,返回地址被计算并加载到堆栈。
将任何新值放在堆栈上的Vm handlers将在vm handlers执行后有一个堆栈检查。这个例程检查堆栈是否侵占了scratch寄存器。
注意 "movsb "的用法,它被用来复制从头开始寄存器的内容。
虚拟指令由两个或多个操作数组成。第一个操作数是虚拟指令的操作码。操作码是8位的无符号值,当被解密时,它是进入vm处理表的索引。可以有第二个操作数,这是一个1到8字节的即时值。
所有操作数都是加密的,必须用滚动的解密密钥来解密。解密是在calc_jmp以及vm处理程序本身内部进行的。进行解密的Vm处理程序将只对即时值而不是操作码进行操作。
VMProtect 2使用滚动解密密钥对其虚拟指令进行加密。该密钥位于RBX中,最初被设置为虚拟指令的地址。为解密操作数所做的转换包括XOR、NEG、NOT、AND、ROR、ROL、SHL、SHR、ADD、SUB、INC、DEC和BSWAP。当一个操作数被解密时,应用于该操作数的第一个转换包括滚动解密密钥。因此,只有XOR, AND, ROR, ROL, ADD, 和SUB是应用于操作数的第一个转换。然后,总是有三个转换直接应用于操作数。在这个阶段,操作数被完全解密,RAX中的值将保持解密的操作数值。最后,通过将滚动解密密钥与完全解密的操作数值进行转换,更新滚动解密密钥。一个例子是这样的。
上面这段代码对第一个操作数进行解密,这个操作数总是指令操作码。这段代码是calc_jmp例程的一部分,但是对于任何第二个操作数,转换格式都是一样的。
VM handlers包含执行虚拟指令的本地代码。每个 VMProtect 2 二进制文件都有一个 vm handler表,这是一个 256 个 QWORD 的数组。每个条目都包含一个加密的相对虚拟地址,指向相应的vm handler。有许多虚拟指令的变体,如不同大小的即时值以及符号和零扩展值。本节将介绍一些虚拟指令的例子,以及在尝试解析vm handler时必须注意的一些关键信息。
处理即时值的vm handler程序从RSI中获取加密的即时值。然后对这个加密的即时值进行传统的五次转换。转换格式与calc_jmp转换相同。第一个转换应用于加密的即时值,滚动解密密钥是操作的来源。然后,三个转换直接应用于加密的即时值,这将完全解密该值。最后,除了目标和源操作数互换外,滚动解密密钥通过第一次转换进行更新。
还要注意的是,vm handlers会受到不透明的分支以及死库混淆的影响。
最具代表性的虚拟机指令之一是LCONST。这条虚拟指令将一个常量值从虚拟指令的第二个操作数加载到堆栈中。
这是LCONSTQ VM handler的反混淆视图。你可以看到这个VM handler从VIP(RSI)中读取虚拟指令的第二个操作数。然后它解密了这个即时值并推进了VIP。解密后的立即值被放到VSP上。
这条虚拟指令从RSI加载一个DWORD大小的操作数,对其进行解密,并将其扩展为一个QWORD,最后将其放在虚拟堆栈中。
注意,这个最后的vm handler通过把值放在栈上然后应用转换来更新滚动解密密钥。这是在解析这些vm handler时可能会引起重大问题的东西。幸运的是,有一个非常简单的技巧来处理这个问题,永远记住应用于滚动密钥的转换与第一个转换是一样的。在上面的例子中,它是一个简单的XOR。
LCONSTCBW从RSI加载一个常数字节值,对其进行解密,并将结果扩展为一个WORD值。这个解密的值然后被放在虚拟堆栈中。
LCONSTCWDE从RSI加载一个常数字,对其进行解密,并将其符号扩展为一个DWORD。最后,结果值被放在虚拟堆栈中。
LCONSTDW从RSI加载一个常数字,对其进行解密,最后将结果放在虚拟栈上。还要注意,在下面的例子中,VIP是向后推进的。你可以在操作数的取值中看到这一点,因为它在取消引用之前从RSI中减去了。
让我们来看看另一个VM handler,这个程序的名字是LREG。就像LCONST一样,这条指令有很多变体,特别是针对不同的大小。LREG也将出现在每一个二进制文件中,因为它在虚拟机内部被用来将寄存器值加载到Scratch寄存器中。稍后会有更多关于这个的内容。
LREGQ有一个字节的即时值。这就是Scratch寄存器的索引。一个指向Scratch寄存器的指针总是被加载到RDI中。正如上面多次描述的那样,总共有五个变换应用于即时值,以解密它。第一个转换来自于滚动解密密钥,接着是三个直接应用于即时值的转换,对其进行完全解密。最后,滚动解密密钥被更新,以解密后的即时值为源,对其应用第一次转换。
LREGDW是LREG的一个变体,它将一个DWORD从一个Scratch寄存器加载到堆栈中。它有两个操作数,第二个是代表scratch寄存器索引的单字节。下面的代码片断是LREGDW的一个解密视图。
另一条标志性的虚拟指令是SREG,它在每个二进制文件中都有。这条指令有许多变体,它们将Scratch寄存器设置为某些大小的值。这条虚拟指令有两个操作数,第二个操作数是一个包含scratch寄存器索引的单字节即时值。
SREGQ在虚拟堆栈的顶部用一个QWORD的值来设置一个虚拟Scratch寄存器。这条虚拟指令由两个操作数组成,第二个操作数是一个代表虚拟Scratch寄存器的单字节。
SREGDW在虚拟堆栈的顶部用一个DWORD值设置一个虚拟Scratch寄存器。这条虚拟指令由两个操作数组成,第二个操作数是一个代表虚拟Scratch寄存器的单字节。
SREGW从虚拟堆栈的顶部用一个WORD值设置一个虚拟的Scratch寄存器。这条虚拟指令由两个操作数组成,第二个操作数是一个代表虚拟Scratch寄存器的单字节。
SREGB在虚拟堆栈的顶部设置一个具有BYTE值的虚拟Scratch寄存器。这条虚拟指令由两个操作数组成,第二个操作数是一个代表虚拟Scratch寄存器的单字节。
虚拟ADD指令将堆栈中的两个值相加,并将结果存储在堆栈的第二个值位置。由于ADD指令改变了RFLAGS,所以RFLAGS被推到了堆栈上。
ADDQ添加两个存储在虚拟堆栈顶部的QWORD值。RFLAGS也被推入堆栈,因为本地ADD指令改变了标志。
ADDW添加两个存储在虚拟堆栈顶部的WORD值。RFLAGS也被推入堆栈,因为本地ADD指令改变了标志。
ADDB添加两个存储在虚拟堆栈顶部的BYTE值。RFLAGS也被推入堆栈,因为本地ADD指令改变了标志。
虚拟MUL指令将存储在堆栈中的两个值相乘。这些vm处理程序使用本地MUL指令,另外RFLAGS被推入堆栈。最后,它是一条单操作数指令,这意味着没有与该指令相关的即时值。
MULQ将两个QWORD值相乘,结果存储在VSP+24的堆栈中,另外RFLAGS被推到堆栈中。
虚拟DIV指令使用本地DIV指令,除法中使用的顶级操作数位于虚拟堆栈的顶部。这是一条单操作数的虚拟指令,因此没有即时值。RFLAGS也被推入堆栈,因为本地DIV指令也可以RFLAGS。
DIVQ对位于虚拟堆栈上的两个QWORD值进行分割。将RFLAGS推到栈上。
READ指令可以读取不同大小的内存。这个指令有一个变体,可以读取一个、两个、四个和八个字节。
READQ从存储在堆栈顶部的地址中读取一个QWORD值。这条虚拟指令有时似乎有一个段预置在上面。然而并不是所有的READQ vm处理程序都有这个ss与之相关。现在QWORD值被存储在虚拟堆栈的顶部。
READDW从存储在虚拟栈顶的地址中读取一个DWORD值。然后,该DWORD值被放在虚拟堆栈的顶部。下面是READDW的两个例子,一个使用了这个段索引语法,另一个没有使用。
注意下面的分段偏移用法与ss...
READW从存储在虚拟栈顶的地址中读取一个WORD值。然后,该WORD值被放在虚拟栈的顶部。下面是这个vm处理程序使用段索引语法的一个例子,但是请记住,还有一些vm处理程序没有这个段索引。
WRITE虚拟指令最多可以向一个地址写入八个字节。这个虚拟指令有四个变体,2的每一个次幂都有一个,包括8。每个vm处理程序也有使用段偏移类型指令编码的版本。然而在长模式下,一些段基地址是零。似乎总是被使用的段是SS段,它的基数为0,因此段基数在这里没有影响,它只是使解析这些vm处理程序更加困难。
WRITEQ将一个QWORD值写到位于虚拟堆栈顶部的地址。堆栈增加了16个字节。
WRITEDW将一个DWORD值写到位于虚拟堆栈顶部的地址。堆栈被增加了12个字节。
注意下面的分段偏移ss的用法...
WRITEW虚拟指令将一个WORD值写到位于虚拟堆栈顶部的地址。然后,堆栈被增加10个字节。
WRITEB虚拟指令将一个BYTE值写到位于虚拟堆栈顶部的地址。然后,堆栈被增加10个字节。
SHL vm handler将位于堆栈顶部的一个值向左移动若干位。要移位的位数被存储在堆栈上要移位的值的上方。然后将结果和RFLAGS一起放入堆栈。
SHLCBW将一个字节值向左移动,并将结果扩展为一个WORD。RFLAGS被推到堆栈中。
SHLW将一个WORD值向左移动。RFLAGS被推到虚拟堆栈中。
SHLDW将一个DWORD向左移动。RFLAGS被推到虚拟堆栈中。
SHLQ将一个QWORD向左移动。RFLAGS被推到虚拟堆栈中。
SHLD虚拟指令使用本地指令SHLD将一个值向左移动。然后,结果被放到堆栈和RFLAGS中。这条指令有一个变体,用于一个、两个、四个和八个字节的移位。
SHLDQ以双精度将一个QWORD向左移位。然后,结果被放到虚拟堆栈中,RFLAGS被推到虚拟堆栈中。
SHLDDW虚拟指令以双精度将一个DWORD值向左移动。其结果被推入虚拟堆栈以及RFLAGS。
SHR指令是对SHL的补充,这条虚拟指令改变了RFLAGS,因此执行这条虚拟指令后,RFLAGS值将在堆栈的顶部。
SHRQ将一个QWORD值向右移动。其结果和RFLAGS一样被放到虚拟堆栈中。
SHRD虚拟指令以双精度将一个值向右移动。这条指令有一个变体,用于一个、两个、四个和八个字节的移位。这条虚拟指令的结论是RFLAGS被推到虚拟堆栈中。
SHRDQ以双精度将一个QWORD值向右移动。其结果被放到虚拟堆栈中。然后RFLAGS被推到虚拟堆栈中。
SHRDDW以双精度将一个DWORD值向右移动。其结果被放到虚拟堆栈中。然后RFLAGS被推到虚拟堆栈中。
NAND指令包括对堆栈顶部的数值应用一个Not,然后将这个Not的结果以比特的方式并入堆栈的下一个数值。and指令改变了RFLAGS,因此,RFLAGS将被推到虚拟堆栈中。
NANDW将两个WORD值进行NOT处理,然后将它们进行位操作并在一起。然后RFLAGs被推到虚拟堆栈中。
READCR3虚拟指令是一个围绕本地mov寄存器cr3的封装vm处理程序。这条指令将把CR3的值放到虚拟堆栈中。
WRITECR3虚拟指令是一个围绕本地mov cr3, reg的封装vm处理程序。这条指令将把一个值放入CR3。
PUSHVSP虚拟指令将本地寄存器RBP中的值推到虚拟堆栈中。这条指令有一个变体,用于1、2、4和8个字节。
PUSHVSPQ将虚拟堆栈指针的整个值推到虚拟堆栈上。
PUSHVSPDW将虚拟堆栈指针的底部四个字节推到虚拟堆栈中。
PUSVSPW将虚拟堆栈指针的底部WORD值推送到虚拟堆栈中。
这条虚拟指令用堆栈顶部的值加载虚拟堆栈指针寄存器。
这条虚拟指令用堆栈顶部的WORD值加载虚拟堆栈指针寄存器。
这条虚拟指令用栈顶的DWORD值加载虚拟堆栈指针寄存器。
这条虚拟指令用堆栈顶部的QWORD值加载本地标志寄存器。
虚拟JMP指令改变RSI寄存器,指向一组新的虚拟指令。堆栈顶部的值是RVA从模块基础到虚拟指令的低32位。然后这个值被加到PE文件的可选头中找到的图像基值的前32位。然后,基址被加到这个值上。
虚拟调用指令获取虚拟堆栈顶部的一个地址,然后调用它。RDX被用来保存地址,所以你只能用它来真正调用具有单一参数的函数。
现在,VMProtect 2 的虚拟机架构已被记录下来,我们可以思考重要的签名。此外,VMProtect 2 产生的混淆也可以用相当简单的技术处理。这可以使解析vm_entry例程变得微不足道。vm_entry没有合法的JCC,所以每次遇到JCC时,我们可以简单地跟踪它,从指令流中删除JCC,然后一旦遇到JMP RCX/RDX就停止。我们可以通过跟踪指令如何被Zydis使用,特别是跟踪指令的目标寄存器的读写依赖性,来删除大部分deadstore。最后,有了清理过的vm_entry,我们现在可以遍历所有的指令,找到vm处理程序,解密vm处理程序表项所需的转换,最后是解密跳转到vm_entry之前推到堆栈的虚拟指令的相对虚拟地址所需的转换。
最好的,也是最知名的签名之一是LEA r12,vm_handlers。这条指令位于vm_entry代码段内,将vm处理程序表的线性虚拟地址加载到R12中。使用Zydis,我们可以很容易地找到并解析这个LEA,从而自己找到vm handler表的位置。
上述Zydis例程将静态地定位虚拟机处理表的地址。它只需要一个ZydisDecodedInstructions的向量,vm_entry例程中的每个指令都有一个。我的实现(vmprofiler)将首先对vm_entry进行解密,然后再传递这个向量。
你可以很容易地以编程方式确定对虚拟机处理程序表条目应用了什么转换,首先找到从该表获取条目的指令。这条指令记录在vm_entry部分,它由一条SIB指令组成,RDX或RCX为目标,R12为基数,RAX为索引,8为比例。
使用Zydis可以很容易地找到这一点。所要做的就是找到一条以RCX或RDX为目标的SIB mov指令,R12为基数,RAX为索引,最后是8为索引。现在,使用Zydis我们可以找到下一条以RDX或RCX为目标的指令,这条指令将是应用于VM处理表项的转换。
这个函数将解析vm_entry例程,并返回为解密虚拟机处理表项所做的转换。在C++中,每个转换操作都可以用lambdas来实现,可以用一个函数编码来返回必须应用的转换的相应lambda例程。
上面的代码等同于下面的C++代码。这将解密vm处理程序条目。为了加密新的数值,必须进行逆向操作。然而对于XOR来说,这只是简单的XOR。
上述解密和加密处理程序可以通过创建每个转换类型的映射和该指令的C++ lambda再实现来动态生成。此外,还可以创建一个处理动态值的例程,如字节大小。这可以防止每次需要转换时都要创建一个开关案例。
这一小段代码将允许在考虑到溢出的情况下轻松实现C++中的转换。在转换过程中,重视大小是非常重要的,因为如果没有正确的大小,溢出以及滚动和移位都是不正确的。下面的代码是一个例子,说明如何通过在C++中动态地实现转换来解密虚拟指令的操作数。
重新实现转换的能力是很重要的,然而,能够从vm处理程序和calc_jmp中解析出转换是另一个需要自己解决的问题。为了确定转换的位置,我们必须首先确定是否有转换的需要。变换只适用于虚拟指令的操作数。虚拟指令的第一个操作数总是在同一个地方进行转换,这个代码被称为calc_jmp,我在前面解释过。转化的第二个地方是在处理即时值的vm处理程序中发现的。换句话说,如果一条虚拟指令有一个即时值,那么对于这个操作数将有一套独特的转换。即时值是从VIP中读出的(RSI),所以我们可以使用这个关键细节来确定是否有即时值以及即时值的大小。值得注意的是,从VIP中读出的即时值并不总是等于为LCONST等指令在堆栈中分配的解密值的大小。这是因为符号扩展和零扩展的虚拟指令。让我们来看看一个有即时值的虚拟指令的例子。这条虚拟指令被称为LCONSTWSE,代表 "加载大小为word的常量值,但符号扩展为DWORD"。这条虚拟指令的解密vm处理程序看起来像这样。
如你所见,有两个字节从VIP中读出。这是第一条指令。这是我们可以在zydis中寻找的东西。任何以RAX为目的,RSI为源的MOVZX、MOVSX或MOV都表明有一个即时值,因此我们知道在指令流中预计有五个转换。然后我们可以搜索一条指令,其中RAX是目标,RBX是源。这将是第一个转换。在上面的例子中,第一条减法指令就是我们要找的。
接下来我们可以寻找三条对RAX有写入依赖性的指令。这三条指令将是应用于操作数的通用转换。
在这一点上,操作数被完全解密了。唯一剩下的是对滚动解密密钥(RBX)进行的一次转换。这最后一次转换更新了滚动解密密钥。
所有这些转换指令现在都可以由C++的lambdas在飞行中重新实现。使用std::find_if对于这些类型的搜索算法非常有用,因为你可以一步步来。首先找到关键的转换,然后找到写给RAX的下三个指令。
正如你所看到的,除了源操作数和目的操作数互换外,第一个转换与最后一个转换是一样的。VMProtect 2 在应用最后一次转换时有一些创造性的自由,有时会将滚动解密密钥推到堆栈中,应用转换,然后将结果弹回 RBX。这个小但重要的不便可以通过简单地交换ZydisDecodedInstruction变量中的目标和源寄存器来处理,如上面的代码所示。
试图静态分析虚拟指令的困境是,虚拟机内部的分支操作非常难以处理。为了计算一个虚拟JMP的跳转位置,需要进行仿真。我将在不久的将来进行这方面的研究(独角兽)。
追踪虚拟指令的方法很简单,就是把每一个vm处理程序表的条目修补成一个加密的值,当解密的时候指向一个陷阱处理程序。这将允许对寄存器进行指令间检查,并有可能改变vm处理器的结果。为了很好地利用这一功能,重要的是要了解哪些寄存器包含哪些值。你可以参考这篇文章的 "概述部分"。
在拦截虚拟指令时,首先要记录的重要信息是位于AL的操作码值。记录这个将告诉我们所有执行的虚拟指令。下一个必须被记录的值是位于BL的滚动解密密钥值。这将使vmprofiler能够静态地解密操作数。
既然我们能够做到,在每一条虚拟指令之后记录所有的scratch寄存器是对记录信息的一个重要补充,因为这将描绘出一幅更大的画面,说明哪些值被操纵了。最后,记录虚拟堆栈上的前五个QWORD值是为了提供更多的信息,因为这个虚拟指令集架构是基于堆栈机的。
为了结束这篇文章的动态分析部分,我为这些运行时数据创建了一个小文件格式。该文件格式被称为 "vmp2",包含所有的运行时日志信息。这个文件格式的结构非常简单,它们被列在下面。
如果提供一个 "vmp2"文件,vmprofiler将产生伪虚拟指令,包括即时值以及受影响的scratch寄存器。这绝不是去虚拟化,也不提供多个代码路径的视图,但是它确实提供了一个非常有用的已执行虚拟指令的跟踪。Vmprofiler还可以用来静态地定位vm handler表,并确定使用什么转换来解密这些vm handler条目。
vmprofiler的一个示例输出将产生关于每个vm处理程序的所有信息,包括即时值的位数,虚拟指令的名称,以及应用于即时值的五个转换(如果有即时值)。
如果有的话,这些转换也会从vm处理程序中提取出来,并可以动态地执行以解密操作数。
为了显示所有的跟踪信息,如本地寄存器的值、从动寄存器的值和虚拟堆栈的值,我创建了一个非常小的Qt项目,它可以让你在跟踪中一步步的进行。我觉得控制台的限制性太大,而且我也发现很难对需要在控制台显示的内容进行优先排序,因此需要一个GUI。
在vm_entry例程执行后,所有被推入堆栈的寄存器都被加载到虚拟机的scratch寄存器。这也延伸到了模块基数和RFLAGS,它们也被推入了堆栈。本机寄存器到scratch寄存器的映射不被尊重。
虚拟机架构表现出的另一个行为是,如果一条本地指令没有用vm处理程序实现,那么vmexit将发生,以执行本地指令。在我的VMProtect 2版本中,CPUID没有用vm处理程序实现,所以会发生退出。
在vmexit之前,从零开始的寄存器的值被加载到虚拟堆栈。vmexit虚拟指令将把这些值放回本地寄存器中。你可以看到,从头开始的寄存器和直接在vmentry之后的寄存器是不同的。这是因为就像我之前说的,从头开始的寄存器没有被映射到本地寄存器。
在这个Demo中,我将虚拟一个非常简单的二进制文件,它只是执行CPUID,如果支持AVX则返回真,否则返回假。下面显示的是它的汇编代码。
在保护这段代码时,为了简化演示,我选择了不使用打包。我使用了 "Ultra "设置来保护二进制文件,这只是混淆+虚拟化。看一下输出文件的PE头,我们可以看到入口点RVA是0x1000,图像基数是0x140000000。我们现在可以把这些信息给vmprofiler-cli,它应该给我们提供虚拟机处理表RVA以及所有虚拟机处理信息。
我们可以看到vmprofiler-cli已经对vm_entry代码进行了扁平化和去模糊化处理,并找到了vm handler表。我们还可以看到为解密vm handler实体所做的转换,它是在mov rdx, [r12+rax*8]之后的直接XOR。
我们还可以看到,由于RSI被INC指令递增,VIP的进展是积极的。
有了这些信息,我们现在可以编译一个vmtracer程序,它将把所有的vm处理程序表条目修补到我们的陷阱处理程序中,这将使我们能够跟踪虚拟指令以及改变虚拟指令的结果。
我省略了一些其他的代码,如ofstream代码和vmtracer类实例化,你可以在这里找到这些代码。显示这些信息的主要目的是告诉你如何解析一个vm_entry并提取创建跟踪所需的信息。
在我的演示追踪器中,我只是简单地将受保护的二进制文件LoadLibraryExA,初始化一个vmtracer类,修补vm处理程序表,然后调用模块的入口点。这不是很理想,但对于演示目的来说,这就足够了。
现在已经创建了一个跟踪文件,我们现在可以通过vmprofiler-cli或vmprofiler-qt来检查跟踪。 不过我建议使用后者,因为这个程序是明确为查看跟踪文件而创建的。
当把跟踪文件加载到vmprofiler-qt中时,必须知道vm_entry RVA以及在PE文件的可选头中发现的镜像基础。考虑到所有这些信息以及原始的受保护二进制文件,vmprofiler-qt将显示跟踪文件中的所有虚拟指令,并允许你 "单步 "通过它。
让我们看一下这个跟踪文件,看看我们是否能找到原来的指令,这些指令现在已经被转换为基于RISC、堆栈机的架构。在vm_entry之后执行的第一个代码块似乎不包含与原始二进制文件有关的代码。它在这里只是为了混淆视听,防止对虚拟指令进行静态分析,因为要了解虚拟JMP指令的落点,需要对虚拟指令集进行仿真。这第一个跳转块位于每个受保护的二进制文件中。
在虚拟JMP指令之后的下一个块做了一些与堆栈有关的有趣的数学运算。如果你仔细观察,你可以看到正在执行的数学运算是:sub(x, y) = ~((~(x) & ~(x)) + y) & ~((~(x) & ~(x)) + y); sub(VSP, 10)
。
如果我们简化这个数学操作,我们可以看到这个操作是对VSP做的减法。sub(x, y) = ~((~x) + y)
。这等同于本地操作sub rsp, 0x10
。如果我们看一下原始的二进制,也就是没有被虚拟化的二进制,我们可以看到事实上有这个指令。
在虚拟指令中可以看到上面显示的MOV EAX, 1紧随在VSP上做的减法之后。MOV EAX, 1是通过一个LCONSTBSX和一个SREGDW完成的。SREG的位数与本地寄存器的宽度32bits相匹配,同时也与被加载的常数值相匹配。
接下来我们看到一个vmexit发生了。我们可以通过查看vmexit之前的最后一个ADDQ来了解代码执行在虚拟机之外的情况。堆栈上的前两个值应该是模块的基本地址和将被返回的例程的32位相对虚拟地址。在这个跟踪中,RVA是0x140008236。如果我们在IDA中检查这个地址,我们可以看到指令 "CPUID "在这里。
正如你所看到的,在CPUID指令之后,代码执行直接回到了虚拟机中。在用位于虚拟堆栈上的本地寄存器值设置所有的虚拟scratch寄存器后,直接将一个常数加载到堆栈中,其值为0x1C。然后,CPUID的结果值被这个常数移到了右边。
AND操作是通过两个NAND操作完成的。第一个NAND操作简单地反转了SHR的结果;invert(x) = ~(x) & ~(x)
。这是通过将DWORD值两次加载到堆栈中来完成的,以形成一个QWORD。
这个AND操作的结果将被设置到虚拟scratch寄存器7(SREGDW 0x38)。然后,它被移到scratch寄存器16中。如果我们看一下vmexit指令和LREGQ的执行顺序,我们可以看到这确实是正确的。
最后,我们还可以看到ADD指令和LVSP指令向VSP增加了一个值。这是预料之中的,因为在原始二进制中存在一个ADD RSP,0x10。
从上面的信息我们可以重建以下的本地指令。
正如你所看到的,有几条指令被遗漏了,特别是RBX的push's和pop's,以及XOR将ECX的内容清零。我认为这些指令没有直接转换为虚拟指令,而是以一种迂回的方式实现。
为了改变虚拟指令,必须首先重新实现整个vm处理程序。如果vm处理程序对第二个操作数进行解密,必须记住解密密钥有效性的重要性。因此,必须计算出原始的即时值,并通过原始转换应用到解密密钥上。然而,在更新解密密钥后,这个值可以随后被丢弃。这方面的一个例子可以是改变上节中SHR之前的LCONST的常数值。
这个虚拟指令有两个操作数,第一个是要执行的vm handler索引,第二个是即时值,在这个例子中是一个单字节。由于有两个操作数,所以在vm处理程序中会有五个转换。
我们可以重新编码这个vm处理程序,将解密后的即时值与0x1C进行比较,然后分支到一个子程序,将一个不同的值加载到堆栈。这将导致SHR计算一个不同的结果。本质上我们可以欺骗CPUID的结果。另一种方法是重新创建SHR处理程序,然而为了简单起见,我只是要转移到一个被设置的位。在这种情况下,如果支持VMX,CPUID之后的ECX第5位将被设置,由于我的CPU支持虚拟化,这个位将是高的。下面是新的vm处理程序。
如果我们现在再次运行vm tracer,将这个新的vm处理程序设置为索引0x55,我们应该能够看到LCONSTBZX的变化。为了方便这个钩子,我们必须把新的vm处理程序的虚拟地址设置为vm::handler::table_t对象。
如果我们现在运行二进制,它将返回1。你可以在下面看到这个。
由于VMProtect 2生成的虚拟机执行的是以其自身字节码编码的虚拟指令,因此,如果能够对其进行编码,就可以在虚拟机上运行自己的虚拟指令。编码的虚拟指令也必须在4GB的地址空间范围内,因为虚拟指令的RVA是32bits宽。在本节中,我将编码一组非常简单的虚拟指令,将两个QWORD值相加并返回结果。
首先,对虚拟指令进行编码需要在二进制文件中加入上述虚拟指令的vm处理程序。通过'vmprofiler'来定位这些vm处理程序。vm处理程序的索引是第一个操作码,即时值(如果有的话)是第二个。结合这两组操作数将产生一个编码的虚拟指令。这是组装虚拟指令的第一阶段,第二阶段是对操作数进行加密。
一旦我们有了编码的虚拟指令,我们现在就可以使用vm handler变换的逆操作以及calc_jmp的逆操作来加密它们。值得注意的是,在加密时必须考虑到VIP的推进方式,因为操作数和虚拟指令的顺序取决于这个推进方向。
为了执行这些新装配的虚拟指令,必须把虚拟指令放在vm_entry例程的32位地址范围内,然后把这些虚拟指令的加密rva放到堆栈中,最后再调用到vm_entry。我建议使用VirtualAllocEx在受保护模块的正下方分配一个RW页面。下面显示了一个运行虚拟指令的例子。
最后,我的动态分析方案不是最理想的方案,但是它应该允许对受保护的二进制文件进行基本的反向工程。随着时间的推移,对虚拟指令的静态分析将成为可能,然而目前动态分析将不得不做。在未来,我将使用unicorn来模拟虚拟机的处理程序。
尽管我已经记录了少数的虚拟指令,但还有更多的指令没有被记录。我记录这些虚拟指令的目的是让本文的读者获得一种感觉,即虚拟机处理程序应该是什么样子,以及如何改变这些虚拟机处理程序的结果。本文中记录的虚拟指令也是最常见的。这些虚拟指令很可能会出现在每个虚拟机中。
我在资源库中添加了一些参考构建,供你尝试通过改变虚拟机处理程序使它们返回1。还有一个构建是在一个二进制文件中使用多个虚拟机。
最后,我想重申,这项研究肯定已经由私人实体完成,我不是第一个记录这篇文章中讨论的一些虚拟机架构的人。我已经记下了那些我已经研究过的人的名字,但是可能还有很多人已经做了关于VMProtect 2的研究,我没有列出,只是因为我没有遇到过他们的工作。
.vmp0:
00000001400073B4
D0 C8 ror al,
1
.vmp0:
00000001400073B6
0F
CA bswap edx
.vmp0:
00000001400073B8
66
0F
CA bswap dx
.vmp0:
00000001400073BB
66
0F
BE D2 movsx dx, dl
.vmp0:
00000001400073BF
48
FF C6 inc rsi
.vmp0:
00000001400073C2
48
0F
BA FA
0F
btc rdx,
0Fh
.vmp0:
00000001400073C7
F6 D8 neg al
.vmp0:
00000001400073C9
0F
81
6F
D0 FF FF jno loc_14000443E
.vmp0:
00000001400073CF
66
C1 FA
04
sar dx,
4
.vmp0:
00000001400073D3
81
EA EC
94
CD
47
sub edx,
47CD94ECh
.vmp0:
00000001400073D9
28
C3 sub bl, al
.vmp0:
00000001400073DB
D2 F6 sal dh, cl
.vmp0:
00000001400073DD
66
0F
BA F2
0E
btr dx,
0Eh
.vmp0:
00000001400073E2
8B
14
38
mov edx, [rax
+
rdi]
.vmp0:
00000001400073B4
D0 C8 ror al,
1
.vmp0:
00000001400073B6
0F
CA bswap edx
.vmp0:
00000001400073B8
66
0F
CA bswap dx
.vmp0:
00000001400073BB
66
0F
BE D2 movsx dx, dl
.vmp0:
00000001400073BF
48
FF C6 inc rsi
.vmp0:
00000001400073C2
48
0F
BA FA
0F
btc rdx,
0Fh
.vmp0:
00000001400073C7
F6 D8 neg al
.vmp0:
00000001400073C9
0F
81
6F
D0 FF FF jno loc_14000443E
.vmp0:
00000001400073CF
66
C1 FA
04
sar dx,
4
.vmp0:
00000001400073D3
81
EA EC
94
CD
47
sub edx,
47CD94ECh
.vmp0:
00000001400073D9
28
C3 sub bl, al
.vmp0:
00000001400073DB
D2 F6 sal dh, cl
.vmp0:
00000001400073DD
66
0F
BA F2
0E
btr dx,
0Eh
.vmp0:
00000001400073E2
8B
14
38
mov edx, [rax
+
rdi]
loc_14000443E:
.vmp0:
000000014000443E
F5 cmc
.vmp0:
000000014000443F
0F
B3 CA btr edx, ecx
.vmp0:
0000000140004442
0F
BE D3 movsx edx, bl
.vmp0:
0000000140004445
66
21
F2
and
dx, si
.vmp0:
0000000140004448
28
C3 sub bl, al
.vmp0:
000000014000444A
48
81
FA
38
04
AA
4E
cmp
rdx,
4EAA0438h
.vmp0:
0000000140004451
48
8D
90
90
50
F5 BB lea rdx, [rax
-
440AAF70h
]
.vmp0:
0000000140004458
D2 F2 sal dl, cl
.vmp0:
000000014000445A
D2 C2 rol dl, cl
.vmp0:
000000014000445C
8B
14
38
mov edx, [rax
+
rdi]
loc_14000443E:
.vmp0:
000000014000443E
F5 cmc
.vmp0:
000000014000443F
0F
B3 CA btr edx, ecx
.vmp0:
0000000140004442
0F
BE D3 movsx edx, bl
.vmp0:
0000000140004445
66
21
F2
and
dx, si
.vmp0:
0000000140004448
28
C3 sub bl, al
.vmp0:
000000014000444A
48
81
FA
38
04
AA
4E
cmp
rdx,
4EAA0438h
.vmp0:
0000000140004451
48
8D
90
90
50
F5 BB lea rdx, [rax
-
440AAF70h
]
.vmp0:
0000000140004458
D2 F2 sal dl, cl
.vmp0:
000000014000445A
D2 C2 rol dl, cl
.vmp0:
000000014000445C
8B
14
38
mov edx, [rax
+
rdi]
.vmp0:
0000000140004448
28
C3 sub bl, al
.vmp0:
000000014000445C
8B
14
38
mov edx, [rax
+
rdi]
.vmp0:
0000000140004448
28
C3 sub bl, al
.vmp0:
000000014000445C
8B
14
38
mov edx, [rax
+
rdi]
.vmp0:
0000000140004149
66
D3 D7 rcl di, cl
.vmp0:
000000014000414C
58
pop rax
.vmp0:
000000014000414D
66
41
0F
A4 DB
01
shld r11w, bx,
1
.vmp0:
0000000140004153
41
5B
pop r11
.vmp0:
0000000140004155
80
E6 CA
and
dh,
0CAh
.vmp0:
0000000140004158
66
F7 D7
not
di
.vmp0:
000000014000415B
5F
pop rdi
.vmp0:
000000014000415C
66
41
C1 C1
0C
rol r9w,
0Ch
.vmp0:
0000000140004161
F9 stc
.vmp0:
0000000140004162
41
58
pop r8
.vmp0:
0000000140004164
F5 cmc
.vmp0:
0000000140004165
F8 clc
.vmp0:
0000000140004166
66
41
C1 E1
0B
shl r9w,
0Bh
.vmp0:
000000014000416B
5A
pop rdx
.vmp0:
000000014000416C
66
81
F9 EB D2
cmp
cx,
0D2EBh
.vmp0:
0000000140004171
48
0F
A3 F1 bt rcx, rsi
.vmp0:
0000000140004175
41
59
pop r9
.vmp0:
0000000140004177
66
41
21
E2
and
r10w, sp
.vmp0:
000000014000417B
41
C1 D2
10
rcl r10d,
10h
.vmp0:
000000014000417F
41
5A
pop r10
.vmp0:
0000000140004181
66
0F
BA F9
0C
btc cx,
0Ch
.vmp0:
0000000140004186
49
0F
CC bswap r12
.vmp0:
0000000140004189
48
3D
97
74
7D
C7
cmp
rax,
0FFFFFFFFC77D7497h
.vmp0:
000000014000418F
41
5C
pop r12
.vmp0:
0000000140004191
66
D3 C1 rol cx, cl
.vmp0:
0000000140004194
F5 cmc
.vmp0:
0000000140004195
66
0F
BA F5
01
btr bp,
1
.vmp0:
000000014000419A
66
41
D3 FE sar r14w, cl
.vmp0:
000000014000419E
5D
pop rbp
.vmp0:
000000014000419F
66
41
29
F6 sub r14w, si
.vmp0:
00000001400041A3
66
09
F6
or
si, si
.vmp0:
00000001400041A6
01
C6 add esi, eax
.vmp0:
00000001400041A8
66
0F
C1 CE xadd si, cx
.vmp0:
00000001400041AC
9D
popfq
.vmp0:
00000001400041AD
0F
9F
C1 setnle cl
.vmp0:
00000001400041B0
0F
9E
C1 setle cl
.vmp0:
00000001400041B3
4C
0F
BE F0 movsx r14, al
.vmp0:
00000001400041B7
59
pop rcx
.vmp0:
00000001400041B8
F7 D1
not
ecx
.vmp0:
00000001400041BA
59
pop rcx
.vmp0:
00000001400041BB
4C
8D
A8 ED
19
28
C9 lea r13, [rax
-
36D7E613h
]
.vmp0:
00000001400041C2
66
F7 D6
not
si
.vmp0:
00000001400041CB
41
5E
pop r14
.vmp0:
00000001400041CD
66
F7 D6
not
si
.vmp0:
00000001400041D0
66
44
0F
BE EA movsx r13w, dl
.vmp0:
00000001400041D5
41
BD B2
6B
48
B7 mov r13d,
0B7486BB2h
.vmp0:
00000001400041DB
5E
pop rsi
.vmp0:
00000001400041DC
66
41
BD CA
44
mov r13w,
44CAh
.vmp0:
0000000140007AEA
4C
8D
AB
31
11
63
14
lea r13, [rbx
+
14631131h
]
.vmp0:
0000000140007AF1
41
0F
CD bswap r13d
.vmp0:
0000000140007AF4
41
5D
pop r13
.vmp0:
0000000140007AF6
C3 retn
.vmp0:
0000000140004149
66
D3 D7 rcl di, cl
.vmp0:
000000014000414C
58
pop rax
.vmp0:
000000014000414D
66
41
0F
A4 DB
01
shld r11w, bx,
1
.vmp0:
0000000140004153
41
5B
pop r11
.vmp0:
0000000140004155
80
E6 CA
and
dh,
0CAh
.vmp0:
0000000140004158
66
F7 D7
not
di
.vmp0:
000000014000415B
5F
pop rdi
.vmp0:
000000014000415C
66
41
C1 C1
0C
rol r9w,
0Ch
.vmp0:
0000000140004161
F9 stc
.vmp0:
0000000140004162
41
58
pop r8
.vmp0:
0000000140004164
F5 cmc
.vmp0:
0000000140004165
F8 clc
.vmp0:
0000000140004166
66
41
C1 E1
0B
shl r9w,
0Bh
.vmp0:
000000014000416B
5A
pop rdx
.vmp0:
000000014000416C
66
81
F9 EB D2
cmp
cx,
0D2EBh
.vmp0:
0000000140004171
48
0F
A3 F1 bt rcx, rsi
.vmp0:
0000000140004175
41
59
pop r9
.vmp0:
0000000140004177
66
41
21
E2
and
r10w, sp
.vmp0:
000000014000417B
41
C1 D2
10
rcl r10d,
10h
.vmp0:
000000014000417F
41
5A
pop r10
.vmp0:
0000000140004181
66
0F
BA F9
0C
btc cx,
0Ch
.vmp0:
0000000140004186
49
0F
CC bswap r12
.vmp0:
0000000140004189
48
3D
97
74
7D
C7
cmp
rax,
0FFFFFFFFC77D7497h
.vmp0:
000000014000418F
41
5C
pop r12
.vmp0:
0000000140004191
66
D3 C1 rol cx, cl
.vmp0:
0000000140004194
F5 cmc
.vmp0:
0000000140004195
66
0F
BA F5
01
btr bp,
1
.vmp0:
000000014000419A
66
41
D3 FE sar r14w, cl
.vmp0:
000000014000419E
5D
pop rbp
.vmp0:
000000014000419F
66
41
29
F6 sub r14w, si
.vmp0:
00000001400041A3
66
09
F6
or
si, si
.vmp0:
00000001400041A6
01
C6 add esi, eax
.vmp0:
00000001400041A8
66
0F
C1 CE xadd si, cx
.vmp0:
00000001400041AC
9D
popfq
.vmp0:
00000001400041AD
0F
9F
C1 setnle cl
.vmp0:
00000001400041B0
0F
9E
C1 setle cl
.vmp0:
00000001400041B3
4C
0F
BE F0 movsx r14, al
.vmp0:
00000001400041B7
59
pop rcx
.vmp0:
00000001400041B8
F7 D1
not
ecx
.vmp0:
00000001400041BA
59
pop rcx
.vmp0:
00000001400041BB
4C
8D
A8 ED
19
28
C9 lea r13, [rax
-
36D7E613h
]
.vmp0:
00000001400041C2
66
F7 D6
not
si
.vmp0:
00000001400041CB
41
5E
pop r14
.vmp0:
00000001400041CD
66
F7 D6
not
si
.vmp0:
00000001400041D0
66
44
0F
BE EA movsx r13w, dl
.vmp0:
00000001400041D5
41
BD B2
6B
48
B7 mov r13d,
0B7486BB2h
.vmp0:
00000001400041DB
5E
pop rsi
.vmp0:
00000001400041DC
66
41
BD CA
44
mov r13w,
44CAh
.vmp0:
0000000140007AEA
4C
8D
AB
31
11
63
14
lea r13, [rbx
+
14631131h
]
.vmp0:
0000000140007AF1
41
0F
CD bswap r13d
.vmp0:
0000000140007AF4
41
5D
pop r13
.vmp0:
0000000140007AF6
C3 retn
.vmp0:
000000014000414C
58
pop rax
.vmp0:
000000014000414D
66
41
0F
A4 DB
01
shld r11w, bx,
1
.vmp0:
0000000140004153
41
5B
pop r11
.vmp0:
0000000140004155
80
E6 CA
and
dh,
0CAh
.vmp0:
000000014000415B
5F
pop rdi
.vmp0:
000000014000414C
58
pop rax
.vmp0:
000000014000414D
66
41
0F
A4 DB
01
shld r11w, bx,
1
.vmp0:
0000000140004153
41
5B
pop r11
.vmp0:
0000000140004155
80
E6 CA
and
dh,
0CAh
.vmp0:
000000014000415B
5F
pop rdi
.vmp0:
000000014000414C
58
pop rax
.vmp0:
0000000140004153
41
5B
pop r11
.vmp0:
0000000140004155
80
E6 CA
and
dh,
0CAh
.vmp0:
000000014000415B
5F
pop rdi
.vmp0:
000000014000414C
58
pop rax
.vmp0:
0000000140004153
41
5B
pop r11
.vmp0:
0000000140004155
80
E6 CA
and
dh,
0CAh
.vmp0:
000000014000415B
5F
pop rdi
.vmp0:
000000014000414C
58
pop rax
.vmp0:
0000000140004153
41
5B
pop r11
.vmp0:
000000014000415B
5F
pop rdi
.vmp0:
0000000140004162
41
58
pop r8
.vmp0:
000000014000416B
5A
pop rdx
.vmp0:
0000000140004175
41
59
pop r9
.vmp0:
000000014000417F
41
5A
pop r10
.vmp0:
000000014000418F
41
5C
pop r12
.vmp0:
000000014000419E
5D
pop rbp
.vmp0:
00000001400041AC
9D
popfq
.vmp0:
00000001400041B7
59
pop rcx
.vmp0:
00000001400041B7
59
pop rcx
.vmp0:
00000001400041CB
41
5E
pop r14
.vmp0:
00000001400041DB
5E
pop rsi
.vmp0:
0000000140007AF4
41
5D
pop r13
.vmp0:
0000000140007AF6
C3 retn
.vmp0:
000000014000414C
58
pop rax
.vmp0:
0000000140004153
41
5B
pop r11
.vmp0:
000000014000415B
5F
pop rdi
.vmp0:
0000000140004162
41
58
pop r8
.vmp0:
000000014000416B
5A
pop rdx
.vmp0:
0000000140004175
41
59
pop r9
.vmp0:
000000014000417F
41
5A
pop r10
.vmp0:
000000014000418F
41
5C
pop r12
.vmp0:
000000014000419E
5D
pop rbp
.vmp0:
00000001400041AC
9D
popfq
.vmp0:
00000001400041B7
59
pop rcx
.vmp0:
00000001400041B7
59
pop rcx
.vmp0:
00000001400041CB
41
5E
pop r14
.vmp0:
00000001400041DB
5E
pop rsi
.vmp0:
0000000140007AF4
41
5D
pop r13
.vmp0:
0000000140007AF6
C3 retn
.vmp0:
000000014000822C
68
FA
01
00
89
push
0FFFFFFFF890001FAh
.vmp0:
000000014000822C
68
FA
01
00
89
push
0FFFFFFFF890001FAh
>
0x822c
: push
0xFFFFFFFF890001FA
>
0x7fc9
: push
0x45D3BF1F
>
0x48e4
: push r13
>
0x4690
: push rsi
>
0x4e53
: push r14
>
0x74fb
: push rcx
>
0x607c
: push rsp
>
0x4926
: pushfq
>
0x4dc2
: push rbp
>
0x5c8c
: push r12
>
0x52ac
: push r10
>
0x51a5
: push r9
>
0x5189
: push rdx
>
0x7d5f
: push r8
>
0x4505
: push rdi
>
0x4745
: push r11
>
0x478b
: push rax
>
0x7a53
: push rbx
>
0x500d
: push r15
>
0x6030
: push [
0x00000000000018E2
]
>
0x593a
: mov rax,
0x7FF634270000
>
0x5955
: mov r13, rax
>
0x5965
: push rax
>
0x596f
: mov esi, [rsp
+
0xA0
]
>
0x5979
:
not
esi
>
0x5985
: neg esi
>
0x598d
: ror esi,
0x1A
>
0x599e
: mov rbp, rsp
>
0x59a8
: sub rsp,
0x140
>
0x59b5
:
and
rsp,
0xFFFFFFFFFFFFFFF0
>
0x59c1
: mov rdi, rsp
>
0x59cb
: lea r12, [
0x0000000000000AA8
]
>
0x59df
: mov rax,
0x100000000
>
0x59ec
: add rsi, rax
>
0x59f3
: mov rbx, rsi
>
0x59fa
: add rsi, [rbp]
>
0x5a05
: mov al, [rsi]
>
0x5a0a
: xor al, bl
>
0x5a11
: neg al
>
0x5a19
: rol al,
0x05
>
0x5a26
: inc al
>
0x5a2f
: xor bl, al
>
0x5a34
: movzx rax, al
>
0x5a41
: mov rdx, [r12
+
rax
*
8
]
>
0x5a49
: xor rdx,
0x7F3D2149
>
0x5507
: inc rsi
>
0x7951
: add rdx, r13
>
0x7954
: jmp rdx
>
0x822c
: push
0xFFFFFFFF890001FA
>
0x7fc9
: push
0x45D3BF1F
>
0x48e4
: push r13
>
0x4690
: push rsi
>
0x4e53
: push r14
>
0x74fb
: push rcx
>
0x607c
: push rsp
>
0x4926
: pushfq
>
0x4dc2
: push rbp
>
0x5c8c
: push r12
>
0x52ac
: push r10
>
0x51a5
: push r9
>
0x5189
: push rdx
>
0x7d5f
: push r8
>
0x4505
: push rdi
>
0x4745
: push r11
>
0x478b
: push rax
>
0x7a53
: push rbx
>
0x500d
: push r15
>
0x6030
: push [
0x00000000000018E2
]
>
0x593a
: mov rax,
0x7FF634270000
>
0x5955
: mov r13, rax
>
0x5965
: push rax
>
0x596f
: mov esi, [rsp
+
0xA0
]
>
0x5979
:
not
esi
>
0x5985
: neg esi
>
0x598d
: ror esi,
0x1A
>
0x599e
: mov rbp, rsp
>
0x59a8
: sub rsp,
0x140
>
0x59b5
:
and
rsp,
0xFFFFFFFFFFFFFFF0
>
0x59c1
: mov rdi, rsp
>
0x59cb
: lea r12, [
0x0000000000000AA8
]
>
0x59df
: mov rax,
0x100000000
>
0x59ec
: add rsi, rax
>
0x59f3
: mov rbx, rsi
>
0x59fa
: add rsi, [rbp]
>
0x5a05
: mov al, [rsi]
>
0x5a0a
: xor al, bl
>
0x5a11
: neg al
>
0x5a19
: rol al,
0x05
>
0x5a26
: inc al
>
0x5a2f
: xor bl, al
>
0x5a34
: movzx rax, al
>
0x5a41
: mov rdx, [r12
+
rax
*
8
]
>
0x5a49
: xor rdx,
0x7F3D2149
>
0x5507
: inc rsi
>
0x7951
: add rdx, r13
>
0x7954
: jmp rdx
>
0x48e4
: push r13
>
0x4690
: push rsi
>
0x4e53
: push r14
>
0x74fb
: push rcx
>
0x607c
: push rsp
>
0x4926
: pushfq
>
0x4dc2
: push rbp
>
0x5c8c
: push r12
>
0x52ac
: push r10
>
0x51a5
: push r9
>
0x5189
: push rdx
>
0x7d5f
: push r8
>
0x4505
: push rdi
>
0x4745
: push r11
>
0x478b
: push rax
>
0x7a53
: push rbx
>
0x500d
: push r15
>
0x6030
: push [
0x00000000000018E2
] ; pushes
0
’s
>
0x48e4
: push r13
>
0x4690
: push rsi
>
0x4e53
: push r14
>
0x74fb
: push rcx
>
0x607c
: push rsp
>
0x4926
: pushfq
>
0x4dc2
: push rbp
>
0x5c8c
: push r12
>
0x52ac
: push r10
>
0x51a5
: push r9
>
0x5189
: push rdx
>
0x7d5f
: push r8
>
0x4505
: push rdi
>
0x4745
: push r11
>
0x478b
: push rax
>
0x7a53
: push rbx
>
0x500d
: push r15
>
0x6030
: push [
0x00000000000018E2
] ; pushes
0
’s
>
0x593a
: mov rax,
0x7FF634270000
>
0x5955
: mov r13, rax
>
0x5965
: push rax
>
0x593a
: mov rax,
0x7FF634270000
>
0x5955
: mov r13, rax
>
0x5965
: push rax
>
0x596f
: mov esi, [rsp
+
0xA0
]
>
0x5979
:
not
esi
>
0x5985
: neg esi
>
0x598d
: ror esi,
0x1A
>
0x596f
: mov esi, [rsp
+
0xA0
]
>
0x5979
:
not
esi
>
0x5985
: neg esi
>
0x598d
: ror esi,
0x1A
>
0x599e
: mov rbp, rsp
>
0x59a8
: sub rsp,
0x140
>
0x59b5
:
and
rsp,
0xFFFFFFFFFFFFFFF0
>
0x59c1
: mov rdi, rsp
>
0x599e
: mov rbp, rsp
>
0x59a8
: sub rsp,
0x140
>
0x59b5
:
and
rsp,
0xFFFFFFFFFFFFFFF0
>
0x59c1
: mov rdi, rsp
>
0x59cb
: lea r12, [
0x0000000000000AA8
]
>
0x59cb
: lea r12, [
0x0000000000000AA8
]
>
0x59df
: mov rax,
0x100000000
>
0x59ec
: add rsi, rax
>
0x59df
: mov rax,
0x100000000
>
0x59ec
: add rsi, rax
>
0x59f3
: mov rbx, rsi
>
0x59fa
: add rsi, [rbp]
>
0x59fa
: add rsi, [rbp]
>
0x5a05
: mov al, [rsi]
>
0x5a0a
: xor al, bl
>
0x5a11
: neg al
>
0x5a19
: rol al,
0x05
>
0x5a26
: inc al
>
0x5a2f
: xor bl, al
>
0x5a34
: movzx rax, al
>
0x5a41
: mov rdx, [r12
+
rax
*
8
]
>
0x5a49
: xor rdx,
0x7F3D2149
>
0x5507
: inc rsi
>
0x7951
: add rdx, r13
>
0x7954
: jmp rdx
>
0x5a05
: mov al, [rsi]
>
0x5a0a
: xor al, bl
>
0x5a11
: neg al
>
0x5a19
: rol al,
0x05
>
0x5a26
: inc al
>
0x5a2f
: xor bl, al
>
0x5a34
: movzx rax, al
>
0x5a41
: mov rdx, [r12
+
rax
*
8
]
>
0x5a49
: xor rdx,
0x7F3D2149
>
0x5507
: inc rsi
>
0x7951
: add rdx, r13
>
0x7954
: jmp rdx
>
0x5a05
: mov al, [rsi]
>
0x5a2f
: xor bl, al ; transformation
is
unique to each build
>
0x5a05
: mov al, [rsi]
>
0x5a2f
: xor bl, al ; transformation
is
unique to each build
>
0x5a11
: neg al
>
0x5a19
: rol al,
0x05
>
0x5a26
: inc al
>
0x5a11
: neg al
>
0x5a19
: rol al,
0x05
>
0x5a26
: inc al
>
0x5a2f
: xor bl, al
>
0x5a34
: movzx rax, al
>
0x5a2f
: xor bl, al
>
0x5a34
: movzx rax, al
>
0x5a41
: mov rdx, [r12
+
rax
*
8
]
>
0x5a49
: xor rdx,
0x7F3D2149
>
0x5a41
: mov rdx, [r12
+
rax
*
8
]
>
0x5a49
: xor rdx,
0x7F3D2149
>
0x5507
: inc rsi
>
0x7951
: add rdx, r13
>
0x7954
: jmp rdx
>
0x7951
: add rdx, r13
>
0x7954
: jmp rdx
.vmp0:
000000014000635F
48
89
EC mov rsp, rbp
.vmp0:
0000000140006371
58
pop rax ; pop module base of the stack
.vmp0:
000000014000637F
5B
pop rbx ; pop zero’s off the stack
.vmp0:
0000000140006387
41
5F
pop r15
.vmp0:
0000000140006393
5B
pop rbx
.vmp0:
000000014000414C
58
pop rax
.vmp0:
0000000140004153
41
5B
pop r11
.vmp0:
000000014000415B
5F
pop rdi
.vmp0:
0000000140004162
41
58
pop r8
.vmp0:
000000014000416B
5A
pop rdx
.vmp0:
0000000140004175
41
59
pop r9
.vmp0:
000000014000417F
41
5A
pop r10
.vmp0:
000000014000418F
41
5C
pop r12
.vmp0:
000000014000419E
5D
pop rbp
.vmp0:
00000001400041AC
9D
popfq
.vmp0:
00000001400041B7
59
pop rcx ; pop RSP off the stack.
.vmp0:
00000001400041BA
59
pop rcx
.vmp0:
00000001400041CB
41
5E
pop r14
.vmp0:
00000001400041DB
5E
pop rsi
.vmp0:
0000000140007AF4
41
5D
pop r13
.vmp0:
0000000140007AF6
C3 retn
.vmp0:
000000014000635F
48
89
EC mov rsp, rbp
.vmp0:
0000000140006371
58
pop rax ; pop module base of the stack
.vmp0:
000000014000637F
5B
pop rbx ; pop zero’s off the stack
.vmp0:
0000000140006387
41
5F
pop r15
.vmp0:
0000000140006393
5B
pop rbx
.vmp0:
000000014000414C
58
pop rax
.vmp0:
0000000140004153
41
5B
pop r11
.vmp0:
000000014000415B
5F
pop rdi
.vmp0:
0000000140004162
41
58
pop r8
.vmp0:
000000014000416B
5A
pop rdx
.vmp0:
0000000140004175
41
59
pop r9
.vmp0:
000000014000417F
41
5A
pop r10
.vmp0:
000000014000418F
41
5C
pop r12
.vmp0:
000000014000419E
5D
pop rbp
.vmp0:
00000001400041AC
9D
popfq
.vmp0:
00000001400041B7
59
pop rcx ; pop RSP off the stack.
.vmp0:
00000001400041BA
59
pop rcx
.vmp0:
00000001400041CB
41
5E
pop r14
.vmp0:
00000001400041DB
5E
pop rsi
.vmp0:
0000000140007AF4
41
5D
pop r13
.vmp0:
0000000140007AF6
C3 retn
.vmp0:
00000001400044AA
48
8D
87
E0
00
00
00
lea rax, [rdi
+
0E0h
]
.vmp0:
00000001400044B2
48
39
C5
cmp
rbp, rax
.vmp0:
000000014000429D
0F
87
5B
17
00
00
ja calc_jmp
.vmp0:
00000001400042AC
48
89
E2 mov rdx, rsp
.vmp0:
0000000140005E5F
48
8D
8F
C0
00
00
00
lea rcx, [rdi
+
0C0h
]
.vmp0:
0000000140005E75
48
29
D1 sub rcx, rdx
.vmp0:
000000014000464C
48
8D
45
80
lea rax, [rbp
-
80h
]
.vmp0:
0000000140004655
24
F0
and
al,
0F0h
.vmp0:
000000014000465F
48
29
C8 sub rax, rcx
.vmp0:
000000014000466B
48
89
C4 mov rsp, rax
.vmp0:
0000000140004672
9C
pushfq
.vmp0:
000000014000467C
56
push rsi
.vmp0:
0000000140004685
48
89
D6 mov rsi, rdx
.vmp0:
00000001400057D6
48
8D
BC
01
40
FF FF FF lea rdi, [rcx
+
rax
-
0C0h
]
.vmp0:
00000001400051FC
57
push rdi
.vmp0:
000000014000520C
48
89
C7 mov rdi, rax
.vmp0:
0000000140004A34
F3 A4 rep movsb
.vmp0:
0000000140004A3E
5F
pop rdi
.vmp0:
0000000140004A42
5E
pop rsi
.vmp0:
0000000140004A48
9D
popfq
.vmp0:
0000000140004A49
E9 B0
0F
00
00
jmp calc_jmp
.vmp0:
00000001400044AA
48
8D
87
E0
00
00
00
lea rax, [rdi
+
0E0h
]
.vmp0:
00000001400044B2
48
39
C5
cmp
rbp, rax
.vmp0:
000000014000429D
0F
87
5B
17
00
00
ja calc_jmp
.vmp0:
00000001400042AC
48
89
E2 mov rdx, rsp
.vmp0:
0000000140005E5F
48
8D
8F
C0
00
00
00
lea rcx, [rdi
+
0C0h
]
.vmp0:
0000000140005E75
48
29
D1 sub rcx, rdx
.vmp0:
000000014000464C
48
8D
45
80
lea rax, [rbp
-
80h
]
.vmp0:
0000000140004655
24
F0
and
al,
0F0h
.vmp0:
000000014000465F
48
29
C8 sub rax, rcx
.vmp0:
000000014000466B
48
89
C4 mov rsp, rax
.vmp0:
0000000140004672
9C
pushfq
.vmp0:
000000014000467C
56
push rsi
.vmp0:
0000000140004685
48
89
D6 mov rsi, rdx
.vmp0:
00000001400057D6
48
8D
BC
01
40
FF FF FF lea rdi, [rcx
+
rax
-
0C0h
]
.vmp0:
00000001400051FC
57
push rdi
.vmp0:
000000014000520C
48
89
C7 mov rdi, rax
.vmp0:
0000000140004A34
F3 A4 rep movsb
.vmp0:
0000000140004A3E
5F
pop rdi
.vmp0:
0000000140004A42
5E
pop rsi
.vmp0:
0000000140004A48
9D
popfq
.vmp0:
0000000140004A49
E9 B0
0F
00
00
jmp calc_jmp
.vmp0:
0000000140005A0A
30
D8 xor al, bl ; decrypt using rolling key...
.vmp0:
0000000140005A11
F6 D8 neg al ;
1
/
3
transformations...
.vmp0:
0000000140005A19
C0 C0
05
rol al,
5
;
2
/
3
transformations...
.vmp0:
0000000140005A26
FE C0 inc al
3
/
3
transformations...
.vmp0:
0000000140005A2F
30
C3 xor bl, al ; update rolling key...
.vmp0:
0000000140005A0A
30
D8 xor al, bl ; decrypt using rolling key...
.vmp0:
0000000140005A11
F6 D8 neg al ;
1
/
3
transformations...
.vmp0:
0000000140005A19
C0 C0
05
rol al,
5
;
2
/
3
transformations...
.vmp0:
0000000140005A26
FE C0 inc al
3
/
3
transformations...
.vmp0:
0000000140005A2F
30
C3 xor bl, al ; update rolling key...
.vmp0:
00000001400076D2
48
8B
06
mov rax, [rsi] ; fetch immediate value...
.vmp0:
00000001400076D9
48
31
D8 xor rax, rbx ; rolling key transformation...
.vmp0:
00000001400076DE
48
C1 C0
1D
rol rax,
1Dh
;
1
/
3
transformations...
.vmp0:
0000000140007700
48
0F
C8 bswap rax ;
2
/
3
transformations...
.vmp0:
000000014000770F
48
C1 C0
30
rol rax,
30h
;
3
/
3
transformations...
.vmp0:
0000000140007714
48
31
C3 xor rbx, rax ; update rolling key...
.vmp0:
00000001400076D2
48
8B
06
mov rax, [rsi] ; fetch immediate value...
.vmp0:
00000001400076D9
48
31
D8 xor rax, rbx ; rolling key transformation...
.vmp0:
00000001400076DE
48
C1 C0
1D
rol rax,
1Dh
;
1
/
3
transformations...
.vmp0:
0000000140007700
48
0F
C8 bswap rax ;
2
/
3
transformations...
.vmp0:
000000014000770F
48
C1 C0
30
rol rax,
30h
;
3
/
3
transformations...
.vmp0:
0000000140007714
48
31
C3 xor rbx, rax ; update rolling key...
mov rax, [rsi]
xor rax, rbx ; transformation
bswap rax ; transformation
lea rsi, [rsi
+
8
] ; advance VIP…
rol rax,
0Ch
; transformation
inc rax ; transformation
xor rbx, rax ; transformation (update rolling decrypt key)
sub rbp,
8
mov [rbp
+
0
], rax
mov rax, [rsi]
xor rax, rbx ; transformation
bswap rax ; transformation
lea rsi, [rsi
+
8
] ; advance VIP…
rol rax,
0Ch
; transformation
inc rax ; transformation
xor rbx, rax ; transformation (update rolling decrypt key)
sub rbp,
8
mov [rbp
+
0
], rax
mov eax, [rsi]
xor eax, ebx
xor eax,
32B63802h
dec eax
lea rsi, [rsi
+
4
] ; advance VIP
xor eax,
7E4087EEh
; look below
for
details on this...
push rbx
xor [rsp], eax
pop rbx
cdqe ; sign extend EAX to RAX…
sub rbp,
8
mov [rbp
+
0
], rax
mov eax, [rsi]
xor eax, ebx
xor eax,
32B63802h
dec eax
lea rsi, [rsi
+
4
] ; advance VIP
xor eax,
7E4087EEh
; look below
for
details on this...
push rbx
xor [rsp], eax
pop rbx
cdqe ; sign extend EAX to RAX…
sub rbp,
8
mov [rbp
+
0
], rax
movzx eax, byte ptr [rsi]
add al, bl
inc al
neg al
ror al,
0x06
add bl, al
mov ax, [rax
+
rdi
*
1
]
sub rbp,
0x02
inc rsi
mov [rbp], ax
movzx eax, byte ptr [rsi]
add al, bl
inc al
neg al
ror al,
0x06
add bl, al
mov ax, [rax
+
rdi
*
1
]
sub rbp,
0x02
inc rsi
mov [rbp], ax
mov ax, [rsi]
add rsi,
0x02
xor ax, bx
rol ax,
0x0E
xor ax,
0xA808
neg ax
xor bx, ax
cwde
sub rbp,
0x04
mov [rbp], eax
mov ax, [rsi]
add rsi,
0x02
xor ax, bx
rol ax,
0x0E
xor ax,
0xA808
neg ax
xor bx, ax
cwde
sub rbp,
0x04
mov [rbp], eax
mov eax, [rsi
-
0x04
]
bswap eax
add eax, ebx
dec eax
neg eax
xor eax,
0x2FFD187C
push rbx
add [rsp], eax
pop rbx
sub rbp,
0x04
mov [rbp], eax
add rsi,
0xFFFFFFFFFFFFFFFC
mov eax, [rsi
-
0x04
]
bswap eax
add eax, ebx
dec eax
neg eax
xor eax,
0x2FFD187C
push rbx
add [rsp], eax
pop rbx
sub rbp,
0x04
mov [rbp], eax
add rsi,
0xFFFFFFFFFFFFFFFC
mov al, [rsi]
sub al, bl
ror al,
2
not
al
inc al
sub bl, al
mov rdx, [rax
+
rdi]
sub rbp,
8
mov [rbp
+
0
], rdx
inc rsi
mov al, [rsi]
sub al, bl
ror al,
2
not
al
inc al
sub bl, al
mov rdx, [rax
+
rdi]
sub rbp,
8
mov [rbp
+
0
], rdx
inc rsi
mov al, [rsi]
sub al, bl
add al,
97h
ror al,
1
neg al
sub bl, al
mov edx, [rax
+
rdi]
sub rbp,
4
mov [rbp
+
0
], edx
mov al, [rsi]
sub al, bl
add al,
97h
ror al,
1
neg al
sub bl, al
mov edx, [rax
+
rdi]
sub rbp,
4
mov [rbp
+
0
], edx
movzx eax, byte ptr [rsi]
sub al, bl
ror al,
2
not
al
inc al
sub bl, al
mov rdx, [rbp
+
0
]
add rbp,
8
mov [rax
+
rdi], rdx
movzx eax, byte ptr [rsi]
sub al, bl
ror al,
2
not
al
inc al
sub bl, al
mov rdx, [rbp
+
0
]
add rbp,
8
mov [rax
+
rdi], rdx
movzx eax, byte ptr [rsi
-
0x01
]
xor al, bl
inc al
ror al,
0x02
add al,
0xDE
xor bl, al
lea rsi, [rsi
-
0x01
]
mov dx, [rbp]
add rbp,
0x02
mov [rax
+
rdi
*
1
], dx
movzx eax, byte ptr [rsi
-
0x01
]
xor al, bl
inc al
ror al,
0x02
add al,
0xDE
xor bl, al
lea rsi, [rsi
-
0x01
]
mov dx, [rbp]
add rbp,
0x02
mov [rax
+
rdi
*
1
], dx
movzx eax, byte ptr [rsi
-
0x01
]
sub al, bl
ror al,
0x06
neg al
rol al,
0x02
sub bl, al
mov edx, [rbp]
add rbp,
0x04
dec rsi
mov [rax
+
rdi
*
1
], edx
movzx eax, byte ptr [rsi
-
0x01
]
sub al, bl
ror al,
0x06
neg al
rol al,
0x02
sub bl, al
mov edx, [rbp]
add rbp,
0x04
dec rsi
mov [rax
+
rdi
*
1
], edx
mov al, [rsi
-
0x01
]
xor al, bl
not
al
xor al,
0x10
neg al
xor bl, al
sub rsi,
0x01
mov dx, [rbp]
add rbp,
0x02
mov [rax
+
rdi
*
1
], dl
mov al, [rsi
-
0x01
]
xor al, bl
not
al
xor al,
0x10
neg al
xor bl, al
sub rsi,
0x01
mov dx, [rbp]
add rbp,
0x02
mov [rax
+
rdi
*
1
], dl
mov rax, [rbp
+
0
]
add [rbp
+
8
], rax
pushfq
pop qword ptr [rbp
+
0
]
mov rax, [rbp
+
0
]
add [rbp
+
8
], rax
pushfq
pop qword ptr [rbp
+
0
]
mov ax, [rbp]
sub rbp,
0x06
add [rbp
+
0x08
], ax
pushfq
pop [rbp]
mov ax, [rbp]
sub rbp,
0x06
add [rbp
+
0x08
], ax
pushfq
pop [rbp]
mov al, [rbp]
sub rbp,
0x06
add [rbp
+
0x08
], al
pushfq
pop [rbp]
mov al, [rbp]
sub rbp,
0x06
add [rbp
+
0x08
], al
pushfq
pop [rbp]
mov rax, [rbp
+
0x08
]
sub rbp,
0x08
mul rdx
mov [rbp
+
0x08
], rdx
mov [rbp
+
0x10
], rax
pushfq
pop [rbp]
mov rax, [rbp
+
0x08
]
sub rbp,
0x08
mul rdx
mov [rbp
+
0x08
], rdx
mov [rbp
+
0x10
], rax
pushfq
pop [rbp]
mov rdx, [rbp]
mov rax, [rbp
+
0x08
]
div [rbp
+
0x10
]
mov [rbp
+
0x08
], rdx
mov [rbp
+
0x10
], rax
pushfq
pop [rbp]
mov rdx, [rbp]
mov rax, [rbp
+
0x08
]
div [rbp
+
0x10
]
mov [rbp
+
0x08
], rdx
mov [rbp
+
0x10
], rax
pushfq
pop [rbp]
mov rax, [rbp]
mov rax, ss:[rax]
mov [rbp], rax
mov rax, [rbp]
mov rax, ss:[rax]
mov [rbp], rax
mov rax, [rbp]
add rbp,
0x04
mov eax, [rax]
mov [rbp], eax
mov rax, [rbp]
add rbp,
0x04
mov eax, [rax]
mov [rbp], eax
mov rax, [rbp]
add rbp,
0x04
mov eax, ss:[rax]
mov [rbp], eax
mov rax, [rbp]
add rbp,
0x04
mov eax, ss:[rax]
mov [rbp], eax
mov rax, [rbp]
add rbp,
0x06
mov ax, ss:[rax]
mov [rbp], ax
mov rax, [rbp]
add rbp,
0x06
mov ax, ss:[rax]
mov [rbp], ax
.vmp0:
0000000140005A74
48
8B
45
00
mov rax, [rbp
+
0
]
.vmp0:
0000000140005A82
48
8B
55
08
mov rdx, [rbp
+
8
]
.vmp0:
0000000140005A8A
48
83
C5
10
add rbp,
10h
.vmp0:
00000001400075CF
48
89
10
mov [rax], rdx
.vmp0:
0000000140005A74
48
8B
45
00
mov rax, [rbp
+
0
]
.vmp0:
0000000140005A82
48
8B
55
08
mov rdx, [rbp
+
8
]
.vmp0:
0000000140005A8A
48
83
C5
10
add rbp,
10h
.vmp0:
00000001400075CF
48
89
10
mov [rax], rdx
mov rax, [rbp]
mov edx, [rbp
+
0x08
]
add rbp,
0x0C
mov [rax], edx
mov rax, [rbp]
mov edx, [rbp
+
0x08
]
add rbp,
0x0C
mov [rax], edx
mov rax, [rbp]
mov edx, [rbp
+
0x08
]
add rbp,
0x0C
mov ss:[rax], edx ; note the SS usage here...
mov rax, [rbp]
mov edx, [rbp
+
0x08
]
add rbp,
0x0C
mov ss:[rax], edx ; note the SS usage here...
mov rax, [rbp]
mov dx, [rbp
+
0x08
]
add rbp,
0x0A
mov ss:[rax], dx
mov rax, [rbp]
mov dx, [rbp
+
0x08
]
add rbp,
0x0A
mov ss:[rax], dx
mov rax, [rbp]
mov dl, [rbp
+
0x08
]
add rbp,
0x0A
mov ss:[rax], dl
mov rax, [rbp]
mov dl, [rbp
+
0x08
]
add rbp,
0x0A
mov ss:[rax], dl
mov al, [rbp
+
0
]
mov cl, [rbp
+
2
]
sub rbp,
6
shl al, cl
mov [rbp
+
8
], ax
pushfq
pop qword ptr [rbp
+
0
]
mov al, [rbp
+
0
]
mov cl, [rbp
+
2
]
sub rbp,
6
shl al, cl
mov [rbp
+
8
], ax
pushfq
pop qword ptr [rbp
+
0
]
mov ax, [rbp]
mov cl, [rbp
+
0x02
]
sub rbp,
0x06
shl ax, cl
mov [rbp
+
0x08
], ax
pushfq
pop [rbp]
mov ax, [rbp]
mov cl, [rbp
+
0x02
]
sub rbp,
0x06
shl ax, cl
mov [rbp
+
0x08
], ax
pushfq
pop [rbp]
mov eax, [rbp]
mov cl, [rbp
+
0x04
]
sub rbp,
0x06
shl eax, cl
mov [rbp
+
0x08
], eax
pushfq
pop [rbp]
mov eax, [rbp]
mov cl, [rbp
+
0x04
]
sub rbp,
0x06
shl eax, cl
mov [rbp
+
0x08
], eax
pushfq
pop [rbp]
mov rax, [rbp]
mov cl, [rbp
+
0x08
]
sub rbp,
0x06
shl rax, cl
mov [rbp
+
0x08
], rax
pushfq
pop [rbp]
mov rax, [rbp]
mov cl, [rbp
+
0x08
]
sub rbp,
0x06
shl rax, cl
mov [rbp
+
0x08
], rax
pushfq
pop [rbp]
mov rax, [rbp]
mov rdx, [rbp
+
0x08
]
mov cl, [rbp
+
0x10
]
add rbp,
0x02
shld rax, rdx, cl
mov [rbp
+
0x08
], rax
pushfq
pop [rbp]
mov rax, [rbp]
mov rdx, [rbp
+
0x08
]
mov cl, [rbp
+
0x10
]
add rbp,
0x02
shld rax, rdx, cl
mov [rbp
+
0x08
], rax
pushfq
pop [rbp]
mov eax, [rbp]
mov edx, [rbp
+
0x04
]
mov cl, [rbp
+
0x08
]
sub rbp,
0x02
shld eax, edx, cl
mov [rbp
+
0x08
], eax
pushfq
pop [rbp]
mov eax, [rbp]
mov edx, [rbp
+
0x04
]
mov cl, [rbp
+
0x08
]
sub rbp,
0x02
shld eax, edx, cl
mov [rbp
+
0x08
], eax
pushfq
pop [rbp]
mov rax, [rbp]
mov cl, [rbp
+
0x08
]
sub rbp,
0x06
shr rax, cl
mov [rbp
+
0x08
], rax
pushfq
pop [rbp]
mov rax, [rbp]
mov cl, [rbp
+
0x08
]
sub rbp,
0x06
shr rax, cl
mov [rbp
+
0x08
], rax
pushfq
pop [rbp]
mov rax, [rbp]
mov rdx, [rbp
+
0x08
]
mov cl, [rbp
+
0x10
]
add rbp,
0x02
shrd rax, rdx, cl
mov [rbp
+
0x08
], rax
pushfq
pop [rbp]
mov rax, [rbp]
mov rdx, [rbp
+
0x08
]
mov cl, [rbp
+
0x10
]
add rbp,
0x02
shrd rax, rdx, cl
mov [rbp
+
0x08
], rax
pushfq
pop [rbp]
mov eax, [rbp]
mov edx, [rbp
+
0x04
]
mov cl, [rbp
+
0x08
]
sub rbp,
0x02
shrd eax, edx, cl
mov [rbp
+
0x08
], eax
pushfq
pop [rbp]
mov eax, [rbp]
mov edx, [rbp
+
0x04
]
mov cl, [rbp
+
0x08
]
sub rbp,
0x02
shrd eax, edx, cl
mov [rbp
+
0x08
], eax
pushfq
pop [rbp]
not
dword ptr [rbp]
mov ax, [rbp]
sub rbp,
0x06
and
[rbp
+
0x08
], ax
pushfq
pop [rbp]
not
dword ptr [rbp]
mov ax, [rbp]
sub rbp,
0x06
and
[rbp
+
0x08
], ax
pushfq
pop [rbp]
mov rax, cr3
sub rbp,
0x08
mov [rbp], rax
mov rax, cr3
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2022-12-7 14:30
被TUGOhost编辑
,原因: