0x1: 关于v8引擎
1.1:v8的指针为真实地址+1,这样最后一位为1,据说是为了加快寻址的速度,根据最后一位直接就可以判断该值其代表的是指针还是自然数。
这点在逆向的角度就是优化后生成的指令,
a) 看到到有 add rX,1 这样的指令片段一般就是代表着开始对指针指向对象的初始化。
b) 在内存中看到的数值为真实数值*2。
1.2:在比较新版本的v8对一个地址只是存储其低4位,要进行寻址的时候再加上其高八位。
1.3:v8在多次执行一个函数的时候,会触发JIT(优化)过程,直接生成函数对应的机器码,这也是这篇分析文章的理论基础。
0x2:JIT产生的优化指令分析:
分析环境为Windows 10 x64
v8版本8.9.25
分析工具为x64debug
https://bbs.pediy.com/thread-267049.htm
紧跟着前面前面
poc为:
2.1:v8优化后生成指令对有符号数的错误处理分析
2.1.1:x64debug打开d8.exe程序加载poc之后,会在运行到在%SystemBreak()时会断下; 在断点返回以后单步运行一段时间可以看到:
00000039000C404C | 49:BA 60EB0C43F77F0000 | mov r10,<d8.Builtins_CompileLazyDeoptimizedCode> | 7FF7430CEB60:"I嫕Hi
图2.1.1.1
分析一下图2.1.1.1的指令逻辑,这里是对是否已经优化做判断,如果已经优化就执行优化后生成的指令,否则则是通过r10跳转到d8.Builtins_CompileLazyDeoptimizedCode ,先执行优化过程。
运行到这里显然已经完成了优化,继续下去执行的是优化后生成的指令。
图2.1.1.2
图2.1.1.3
2.1.2: 调试器走到图2.1.1.3所在的位置,这里的指令为:
mov ecx,edi
add rcx,r8
mov ecx,dword ptr ds:[rcx]
这里进行的是v8的数组的取值操作,取完值以后对该值进行+1操作,对应的是poc中的x=(_arr[0] ^ 0)+1的js代码
图2.1.2.1
图2.1.2.2
走到图2.1.2.1的add rcx,1这句指令后,结果为0x80000001,并将其放在rcx指令中,接下来用一些特殊指令进行处理,如下图所示:
图2.1.2.3
2.1.3:这些指令对应的是poc中的x = Math.abs(x) js语句,应该是做了些优化;
但是这些指令执行完以后,rcx还是为0x80000001,而后面的指令中使用的是ecx作为参数进行运算。
也就是说v8优化后产生的这些指令,并未正确处理x = Math.abs(x);的操作。这也是后面一连串错误操作的起始原因。
图2.1.3.1
2.1.4:流程运行到这里直接用rdi寄存器的的ecx来进行计算,由上图可以看到,导致运算为0x80000001-0x7fffffff,结果等于2。
接下来是指令
cmp ecx,0
jl 39000C40CA
这里是执行源poc里面的x = Math.max(x, 0)的js语句,最后结构返回x=2 。这段指令将结果放入到rdi寄存器中,此时edi表示参数x。
图2.1.4.1
图2.1.4.2
图2.1.4.3
2.1.5: 上图所示,edi进行-1运算(也就是poc js文件里面的参数x),此时edi=1,结果自然是不等于0xFFFFFFFF,最后越过poc 中的x==-1的判断。 对应poc中的js代码if(x==-1) x = 0;
然后在之后的流程里var corr = new Array(x);这语句执行的时候,就会生成一个大小为1的数组
2.2:漏洞数组初始化分析:
图2.2.1.1
图2.1.4.1上EIP指向的指令为
cmp rdi,0
je 39000C419D
也就是对x是否为0进行了判断
根据v8指针的特点,以及调试分析可以判断,这里执行的流程是进行数组对象的初始化。
2.2.1: 初始化r8-1指向的数组。(这里将其定义为array1)
add r8,1
lea r9d,qword ptr ds:[rdi+rdi]//rdi=x
mov r12,qword ptr ds:[r13+D0]
mov dword ptr ds:[r8-1],r12d //初始化array1数组的map。
mov dword ptr ds:[r8+3],r9d//初始化array1数组的大小,内存值为2*x。
xor r9,r9
lea r14,qword ptr ds:[r9+1]
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-4-21 10:08
被苏啊树编辑
,原因: