某软件ollvm混淆登录参数分析

news2026/3/14 8:14:55
这次案例使用的是最新某马拉雅直接豌豆荚即可抓包​ 首先就是进行抓包了下面是抓到的数据包123456789101112POST/mobile/login/pwd/v3 HTTP/2host: passportws.ximalaya.comcookie:1_deviceandroid386501be-0e5c-3773-8b4b-d2f40c257a9a9.4.52;channeland-d3;implcom.ximalaya.ting.android;osversion33;fp009317657x2222q22264v0500q00000220020000000000012000000000000;device_modelPixel7;XIM;c-oper%E6%9C%AA%E7%9F%A5;net-modeWIFI;res1080%2C2219;AIDMWFiYjhmN2U4OGM4MWY1Mg;manufacturerGoogle;XDSWVzJyp9dAqYNR2NV/TpWj32w93g1JQRPZp94Qh4YkOIDrTzHvhcg7DkwZddPJEEo8SpjypYaAptOHvZ34ujAtl7b57bnLDLTGMOQXm6dRZdGAIpQYNJaXMKDZ1dOR;umid4051f75d0861f70a9723a837b71ae290ia;xm_grade0;specialModeStatus0;cookie2: $version1accept:*/*user-agent: ting_9.4.52(Pixel7,Android33)x-tk: TACaa2BczhlAb4OXDdzi0vS9AwlepoCuKX6lSN7MhFEYXGnikMYJO-ycVZWJ81G8Ka6U0hO-anu4NP90d1yExsZuYTs68ljb20ueGltYWxheWEudGluZy5hbmRyb2lkITEuMy4yNyE5LjQuNTIuMyFiPXBhc3Nwb3J0JnM9bG9naW4mdT0wcontent-type: application/json; charsetutf-8content-length:1338accept-encoding: gzip{password:Tv97ethyYCbW1cu28wKT6LoYasOlozs1bW6XkMsdesPTbWrcUxP0OzDFsBK56J9V6NQCKCoxEpa\nsjbAd6P7rdGrUMVFQ9VFuJhucxTbZn3FtCT4DdxW0okyw1/7CHxVVo6SESazZqCvdYX6JduejQzg\nsHSx/uilKXMvMymhTmY\u003d\n,fdsOtp:{\captcha_id\:\3723312ce42a04b5c0b40e605a882037\,\lot_number\:\f4cc6449828648b4a7482fcb187e0fe7\,\pass_token\:\29e78908983de432362042dfa8709d798254c6a5788b046b598bb849a162bab3\,\gen_time\:\1772978512\,\captcha_output\:\u9reFROUhQ6l5CNk-Y40DVpFm0A5jhpxZAMu8kiKIQFHmCtbVGvr_4a-HewecbuH_vgp4hEw_THRvGykOEhBHfIDOK2mngR_rxYH5LSZFntK0h-JrAso3IZc_a06v3Roo7cw7GARksy9__4dkEt5yro5gqzZbcZBGD1ByeVUK2qxlCiTZXqacspeuZTwmJgbSGLUZt8tnLAcnutND4K1rlpmk6D4NkEqjwyGz_3O_Sosrapf9KCpJiT76IJPprj0sdbRpmHzaV3dbltgA7WmUSqU-GmZly9HWALit1_qljzgrHq6TGb6C60noDZJ82qq5Ainym8HU7Ug4CTO9AO51GliCpeyVckKGNxA0EKZAi9LpVUIW5HHZDUs8-dG87PP43h4RbsyfL3fNYGFh5eHgLNFgg7SKEY9iNhCghPU7PJwWJ6QvwpqDOEqRHZK_yMj_KS54z8drWeu38v5Zr-K0Os3ABsdHcOCKad7JrKl08bl6NsWAWIj5J8ek9I7SbnsF-OBspi0BHAdJLO2snYWJYfTp7CuHu95XRIHzfyZaOI\u003d\},signature:90cf350f2fd44f466325a7210cc34fa7553dc60d,nonce:0-8D0B9F3600C47d912f9545b45cf0ef55d34f40b311136eb6adf183382af41e,account:PJlxL0CidJteJXvLypUoVliyTsh1RjQQ7DBuTsmqBKUg4qcpMf85TSUjZYT1ChwVzjyBDkHcJ\ngBM0gSRznapMGVfAx3Q4ewy8GuvzdWKdfO8h30HZD4lr92cp6tcPGY9pER8VHdrKWVW8iyR9gbs\n4YINBi3EWDB//KWb4qI\u003d\n}​ 接下来需要定位到登录函数调用的位置可以通过关键字段的搜索、或者是hook函数打印调用堆栈。这里我直接hook了HashMap来打印堆栈找到登录点123456789101112131415Java.perform(function(){console.log([*] Script loaded. Waiting for signature to be put into a Map or JSONObject...);varlog Java.use(android.util.Log);varHashMap Java.use(java.util.HashMap);HashMap.put.implementation function(key, value){if(key !null){varkeyStr key.toString();if(keyStr signature){console.log([] 找到拼接 signature, 即将打印调用堆栈....);console.log(log.getStackTraceString(Java.use(java.lang.Throwable).$new()) \r\n);}}returnthis.put(key,value);}})定位请求体组装位置1234567891011121314151617181920[Pixel 7::喜马拉雅 ]- [] 找到拼接 signature, 即将打印调用堆栈....java.lang.Throwableat java.util.HashMap.put(Native Method)at com.ximalaya.ting.android.loginservice.LoginRequest$4$1.b(Unknown Source:386)at com.ximalaya.ting.android.loginservice.LoginRequest$4$1.a(Unknown Source:365)at com.ximalaya.ting.android.loginservice.d.b$2.onSuccess(Unknown Source:73)at com.geetest.captcha.q.run(Unknown Source:1)at android.os.Handler.handleCallback(Handler.java:942)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loopOnce(Looper.java:201)at android.os.Looper.loop(Looper.java:288)at android.os.XimaCrashHandler$1.run(Unknown Source:232)at android.os.Handler.handleCallback(Handler.java:942)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loopOnce(Looper.java:201)at android.os.Looper.loop(Looper.java:288)at android.app.ActivityThread.main(ActivityThread.java:7898)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)这里重定义了两个a函数除了从调用链上判断使用的是第一个a函数外还可以通过frida的overload来判断使用的是哪个函数。这里就是signature进行拼接的位置需要通过LoginRequest.b进行跟进最后发现调用的是LoginEncryptUtil的a当中的WTWEctUfLf函数。​ 通过函数声明可以看到这是个native函数属于liblogin_encrypt.so这个库接下来就需要对这个库当中的这个native函数进行分析了。so层分析进入so当中的WTWEctUfLf通过CFG可以查看到这个函数是被控制流平坦化了。Unidbg模拟执行​ 这里想试试用Unidbg模拟执行一下看看能不能找到一些线索这里传入的参数需要注意一下通过jadx的反编译可以看到传入了3个参数分别是上下文context布尔值z以及拼接后的参数sb.toString。这里已经知道了参数一和参数三的形式了但是参数二是true还是false依旧不清楚。那么这里可以直接对这个a方法进行hook看看传入的是什么hook脚本如下1234567Java.perform(function(){varLoginEncryptUtil Java.use(com.ximalaya.ting.android.loginservice.LoginEncryptUtil);LoginEncryptUtil.a.overload(android.content.Context,boolean,java.util.Map).implementation function(ctx,z ,map){console.log( [param2] z : z \r\n);returnthis.a(ctx,z,map);}});最后打印的是false1[param2] z :false那么此时就知道了参数二。此外为了确保模拟执行WTWEctUfLf的逻辑没有错误这里将传入的sb.toString()以及返回值都hook出来用作模拟执行的校验使用Frida框架进行hook12345678910111213141516171819202122232425262728293031varWTWEctUfLf_offset 0x39BC;functionhook_login_enc(){varliblogin_encrypt Process.findModuleByName(liblogin_encrypt.so);console.log([] 找到liblogin_encrypt的基址: liblogin_encrypt.base);varWTWEctUfLf_addr liblogin_encrypt.base.add(WTWEctUfLf_offset);console.log([] 目标函数地址: WTWEctUfLf_addr);Interceptor.attach(WTWEctUfLf_addr,{onEnter:function(args){varjstringArg args[4];console.log(args_4 : args[4]);if(!jstringArg.isNull()){varjniEnv Java.vm.getEnv();varcString jniEnv.getStringUtfChars(jstringArg,null);varstrValue cString.readUtf8String();console.log([] 传入的明文 (sb.toString()):\n\n strValue \n);jniEnv.releaseStringUtfChars(jstringArg, cString);}},onLeave:function(retval) {if(!retval.isNull()) {varjniEnv Java.vm.getEnv();varcString jniEnv.getStringUtfChars(retval,null);console.log([] 返回的密文 (signature): cString.readUtf8String());jniEnv.releaseStringUtfChars(retval, cString);}console.log(\n);}}}hook_login_enc();​ 最终得到的数据如下12345678910111213[] 传入的明文 (sb.toString()):accountB8vZmyyyzbNpd7bPvNYYYGL8Idvddn85ENtGFFxj5An9vCQjv3yXNcli6I24KyRBje/9bADfYpna4FywwajYUMmu6ef25tTPTwaDI1Jq7I5hBbS3PNi0E079ic8m/KPlD3GG8GXjF1woNcY0UphWEp4LXqBoZv1wa1FE9ZofdsOtp{captcha_id:3723312ce42a04b5c0b40e605a882037,lot_number:6ac21b439ee744cd86b7c462eddc3930,pass_token:4c82b272afc4b59df1057cf66838a7bd3327afdfefe1be2456580fbcb0de869d,gen_time:1772978707,captcha_output:2Z76G2CapbcJxb3z0NRv6IFLTIZJ15mHQYRlVlkywBquuBg9auDb78p_hyS26NaSWJddIYSKQ83ixvuXQfCJWeMiXfURka9GYWuWyS6TkZQEEszgpPITemgwA5BntSqWd54TlHATrcJLgCSPoh81t0rr3Wgz2rJiU4_eTqL7aekJxSCVJ6mADxUzOUMC4q8J_YuyefL7SJlKGx_RXe6PZZYkOt2LDMl-E7qRTMYQlp6r2GCVcGQNJheZovQ1ZzFgzSX_PDFuq3Fm2Ir3y-nI5By57Kar1ohGJv8jGZtE5WEIFV2hoIlC0brWStgKwrTrXmJjnxBh_3S3ak1Xs1Zfaeaov4hPlfGpwW-Lh8OdX6WgAtxb7TsN0XyTpX3j-r8HKz7D71M4UFxSuhgl3OdrCjR5s--JcFybjIy6ANxjR7VlsxWJjyyxJ1x8M331UFD6wksJZjJpKX7LoWgFS48v1_DVxDAWmE4xis6YQYfIumMXS0PicjaxMcSLFyBEreWO4IiYHafv_7GVj5Qns-KihnUBgFLeBsG4b3CvU9-zvzg}nonce0-CCFB9B6F4E55df4ea842b75758d257361290d8f504ec1a1633b85d3010803bpasswordQpHGc4OjScTQRP9PTdYxn7ABdCmwS1JqfsBD00gX5UJ0/CSZ8HtNB/K4GrERFODfqKttLqI6RkoiFn15KquI1pMytM8/D9yvvLbg8FpWr2E2JKoMWrZ/J/f3oH4XFFtBgfzWQXTNZe4dHrdqjjPOcIgrhSHyNDyZvz2zktdDo[] 返回的密文 (signature): 9d54907ba45d54eaed4bed58cd18de8cb30c7c05# 9d54907ba45d54eaed4bed58cd18de8cb30c7c05模拟执行时主动调用就可以直接传入这个明文作为字符串参数并在结束后打印返回值。​ 这里Unidbg代码篇幅比较长就不放在文章当中了。有需要的话可以到附件进行下载。总的来说就是补完环境之后能够通过JNI日志看到大部分信息了。下面展示一些JNI的日志​ 首先就是获取包名然后将输入的字符串转成字符指针方便后续调用接着就是newStringUTF通过这个可以发现这里的字符串后面拼接了一串新的东西1MOBILE-V1-PRODUCT-7D74899B338B4F348E2383970CC09991E8E8D8F2BC744EF0BEE94D76D718C089​ 接着就是使用toUpperCase将参数转成大写。接着就是获取了SHA-1哈希算法的实例接着调用update这里传入的参数就是拼接上特定字符串的新参数最后调用digest进行哈希运算。然后toHexString之后通过StringBuilder.append进行拼接最后拼接的就是明文字符串​ 最后可以观察到特征串和我们hook到的一模一样。说明这个模拟执行流程正确了。​ 其实通过这个Unidbg已经几乎把这个signature生成方式给看得差不多了首先就是拼接一串特定字符串接着转大写然后进行SHA-1。从而完成signature参数的生成。这个加密函数貌似并没有自己实现加密逻辑全都是通过JNI来调用java层的函数以及加密标准库的。​ 那么Unidbg分析完了接下来可以试试IDA来分析这个ollvm静态分析​ 进入大致浏览了一下好像只有1千多行试着分析一下。进入函数后开始先通过TLS读取了一个值然后就开始获取包名了分析之后得出。来看看这个get_package_name函数是怎么样的处理ollvm中BCF的方法方法一 静态分析可以看到这个函数也被ollvm混淆了一下不过代码量不多这里直接从头分析一下​ 首先进来就是给v12进行赋值用作下面状态机的一个流程跳转。在ollvm中很多这种永真或者永假的条件此时可以进行化简实在不会的丢给ai化简。这里可以看到实际上执行的是a×(a−)a×(a−1) 那么起始就是偶数乘奇数结果就是偶数最低位为0接着取反此时最低位为1或上0xFFFFFFFE运算得出0xFFFFFFFF那么这个判断条件就为真所以v12 1。​ 所以这里事实上就只是对x_149的最低位做判断。继续往下看并记录状态12v12 1;v3 0xB5E7D523;方法二 利用IDA的分析引擎​ 这里点击x_149然后给这个x_149一个值这里我使用的是IDA Python来进行赋值接着将.bss段的可写权限(W)关掉这样就能够利用IDA引擎自动将这些虚假控制流去掉了。x_150处理手法也差不多效果如下接着回到函数继续分析。另外两个先不管如果用到了再进行分析。​ 接着进入while(1)循环由于此时的v3 0xB5E7D523不满足while和if的条件直接走到了if-else这个位置经过化简之后这里的条件判断其实就是if(v12 || v13)。此时的v12 1所以这里v3被赋值成0xEA4F3F0B接着就重新进行while循环此时v3满足了while ( v3 (int)0xCF812BC6 )则进入循环此时会进入到这个else分支​ 这里通过调用JNI的函数来获取context接着获取pkgname如果获取成功的话v15 0。这里调用函数用到的字符串都是加密的这里先分析完整个大体流程之后再讲如何解决这个问题。​ 执行完成这个else分支之后v3 0xB19E5A69接着就会因为不满足循环条件而跳出循环。接着就是这里的if继续break接着给v3继续赋值:接着到下一个while循环先走else块然后v3 -8285439接着就是if块通过CallObjectMethod调用getPackageName获取pkgName存放到v16。然后v3被设置成1958226928接着往下给将v16也就是pkgName赋值给v11然后调整状态码进入下一轮循环后直接就从if ( v3 ! 1958226928 )处返回pkgName了。所以这个函数其实原本的逻辑就是获取pkgName后返回去掉混淆之后就是这样的12345678910jstring sub_154C(JNIEnv *env, jobject ctx){jclass cls (*env)-FindClass(env,android/content/ContextWrapper);jmethodID mid (*env)-GetMethodID(env, cls,getPackageName,()Ljava/lang/String;);(*env)-DeleteLocalRef(env, cls);if(mid NULL) {return(*env)-NewStringUTF(env,);}return(jstring)(*env)-CallObjectMethod(env, ctx, mid);}​ 接下来就来解决一下字符串加密的问题解决字符串加密的方式方法一 分析解密函数​ 可以看到做的操作就是获取JNI的方法ID方便后续调用。可以看到这里的本该传入的字符串好像都是被加密的点击xmmword_2C010进入看看情况很明显确实是被加密了那么要怎么还原回原本的字符串呢这里可以使用交叉引用发现只有这里是进行了写操作的直接跳转到这个位置接着就是一步步往上跟踪最后定位到这个位置这里其实就是一个简单的异或加密但是数据量太多这个就交给AI来帮忙了xmmword_2C010这里的字符串并不只是这个地方的还延伸到了0x2C02E这个位置遇到了ALIGN才算结束​ 按照上面的方法定位解密的位置最后能够写出下面的脚本12345678910datasets[[15,0,10,28,1,7,10,65,13,1,0,26,11,0,26,65,0x2D,0x01,0x00,0x1A,0x0B,0x16,0x1A,0x39,0x1C,0x0F,0x1E,0x1E,0x0B,0x1C,0x6E],]keys[0x6E]fori, (data, key)inenumerate(zip(datasets, keys)):outbytes(b ^ keyforbindata)print(f[{i}] hex:, out.hex())print( bytes:, out)​ 这里用到的加密字符串基本上都能按照这个方法进行解密。方法二 dump文件​ 使用上面的方法来获取解密函数效率会非常慢而且写注释看的不舒服。通过刚才的分析可以发现这些字符串解密之后都是存放到原来的位置上的那么我们如果可以直接在这些位置上修改成明文的话反编译当中也可以看到明文字符串了。爽歪歪~~​ 那么来分析一下这个解密函数在什么时候会被调用以此来确定dump点:通过交叉引用可以看到是在init_array当中被调用的而这个so会在进行了一次登录之后加载。这样就很方便了直接先登录一次让so加载加载完成后字符串解密完成。接着就可以直接dump了连dump点都不需要找这里使用Frida进行dump123456789101112131415161718192021222324252627282930313233varTARGET_SO liblogin_encrypt.so;varAPP_PACKAGE_NAME com.ximalaya.ting.android;functiondump_login_enc_lib(moduleName) {varmodule Process.getModuleByName(moduleName);if(module null) {console.log([-] 找不到模块: moduleName);return;}console.log([] 找到模块: module.name);console.log([] 基址: module.base);console.log([] 大小: module.size);vardumpPath /data/data/ APP_PACKAGE_NAME /files/ module.name _dump.so;try{varfile newFile(dumpPath,wb);if(file) {// 读取整个模块的内存Memory.protect(module.base, module.size,rwx);varmemoryBuffer module.base.readByteArray(module.size);file.write(memoryBuffer);file.flush();file.close();console.log([*] Dump 成功文件已保存至: dumpPath);console.log([*] 请使用命令将文件 pull 到电脑: adb pull dumpPath);}}catch(e) {console.log([-] Dump 失败: e);}}dump_login_enc_lib(TARGET_SO);​ dump下来的so使用soFixed来修复一下由于在加载到内存之后got表会被污染这里将对应解密的字符串数据移植到原来的so上便于分析。移植的过程中要注意soFixed修复的so节的文件偏移和内存地址是一样的但是原来的so可能有区别需要注意。这里写个python脚本跑一下再拿来分析123456789101112131415161718192021222324252627282930deffixSo():original_so_pathliblogin_encrypt.so# 原始加密的SOdumped_so_pathliblogin_encrypt_fixed.so# Frida Dump出来的明文SOoutput_so_pathliblogin_encrypt_decrypted.so# 最终缝合产物data_vaddr_in_dump0x2c000data_offset_in_orig0x1c000data_size0x2d316-0x2c000print(fdata size : {data_size})print([*] 开始执行底层指令缝合手术...)# 读取 Dump 文件中的明文代码withopen(dumped_so_path,rb) as f_dump:f_dump.seek(data_vaddr_in_dump)decrypted_opcodesf_dump.read(data_size)# 读取 原 SO 并进行替换withopen(original_so_path,rb) as f_orig:orig_databytearray(f_orig.read())# 将明文代码直接覆盖到原 SO 的对应物理位置orig_data[data_offset_in_orig : data_offset_in_origdata_size]decrypted_opcodeswithopen(output_so_path,wb) as f_out:f_out.write(orig_data)print(f[] 缝合成功产物已保存至: {output_so_path})if__name____main__:fixSo()这样看起来就非常舒服了。ollvm分析​ 接下来继续进行ollvm的分析。这里一开始一步步分析ollvm也是通过上面get_package_name的方法进行分析。发现太牢了然后试着用交叉引用逃课。首先这里会获取包名正常来说这个包名一般来说就是app的包名​ 接着对这个pkg_nname进行交叉引用并搜索app的包名:发现了然后跳转过去这里就是校验获取的包名和app包名是否一致然后设置op状态码。然后继续跟踪大致三四个状态码切换之后就会来到这个位置可以看到这两个字符串就是我们Unidbg模拟的时候发现拼接到参数当中的特定字符串。接下来可以继续分析状态机这里我就直接交叉引用看调用了。首先对v160进行状态引用​ 可以发现除了一堆字符指针的赋值就是将v160赋值给了v193。那么此时就到这个地方看看有没有什么特别的。并没有发现什么特别之处这里再对193进行交叉引用发现有用到了memcpy这种东西经过简单分析发现了几个这种结构都是开辟空间然后进行参数拼接。这里猜测就是参数进行拼接的地方。如果需要更加准确的知道到底是调用了哪一个的话需要跟着状态机分析。最后这里会通过newStringUTF将拼接后的参数转成jstring。接着就是继续对v175进行交叉引用接着就是这个位置转大写然后调用MessageDigest.digest接着继续引用最后就是这个位置也就是进行SHA-1哈希然后toHexString。​ 至此整个signature就差不多完成了。到这里整个Signature生成应该是比较明确的了大致过程就是将登录参数按固定格式拼接后追加固定字符串MOBILE-V1-PRODUCT-7D74899B338B4F348E2383970CC09991E8E8D8F2BC744EF0BEE94D76D718C089转大写再做SHA-1并转十六进制输出。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…