当前位置: 首页 > article >正文

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

这次案例使用的是最新某马拉雅直接豌豆荚即可抓包​ 首先就是进行抓包了下面是抓到的数据包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并转十六进制输出。

相关文章:

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

这次案例使用的是最新某马拉雅,直接豌豆荚即可抓包​ 首先就是进行抓包了,下面是抓到的数据包123456789101112POST /mobile/login/pwd/v3 HTTP/2host: passportws.ximalaya.comcookie: 1&_deviceandroid&386501be-0e5c-3773-8b4b-d2f40c257a9a&a…...

解锁Umi-OCR多语言识别潜能:5个专业配置技巧让准确率提升30%

解锁Umi-OCR多语言识别潜能:5个专业配置技巧让准确率提升30% 【免费下载链接】Umi-OCR Umi-OCR: 这是一个免费、开源、可批量处理的离线OCR软件,适用于Windows系统,支持截图OCR、批量OCR、二维码识别等功能。 项目地址: https://gitcode.co…...

PTA 树与二叉树 2 根据先序+中序遍历序列构造二叉树

作者 张鏖烽单位 湖南工程学院计算机与通信学院从键盘输入一个二叉树的先序遍历序列和中序遍历序列,编程实现下列函数:(1)CreateBT_PI(pre,in,n):根据先序遍历序列*pre和中序遍历*in构造二叉链树;(2&#x…...

直播分发新范式:obs-multi-rtmp的资源池化技术与全场景应用

直播分发新范式:obs-multi-rtmp的资源池化技术与全场景应用 【免费下载链接】obs-multi-rtmp OBS複数サイト同時配信プラグイン 项目地址: https://gitcode.com/gh_mirrors/ob/obs-multi-rtmp 一、技术内核:从资源竞争到协同的架构革新 1.1 核心…...

Arbitrary scale atmospheric downscaling with mixture of implicit neural networks trained on fixed

Arbitrary-scale atmospheric downscaling with mixture of implicit neural networks trained on fixed-scale data摘要大气数据降采样是推进气候和天气研究的关键,它解决了对高分辨率区域洞察日益增长的需求,同时提高了天气预报和气候建模等关键应用的…...

Markdown浏览器插件:让文档预览效率提升300%的零配置工具

Markdown浏览器插件:让文档预览效率提升300%的零配置工具 【免费下载链接】markdown-viewer Markdown Viewer / Browser Extension 项目地址: https://gitcode.com/gh_mirrors/ma/markdown-viewer 你是否曾遇到过这样的困境:下载的本地Markdown文…...

百度网盘秒传脚本:文件传输效率工具的深度解析与应用指南

百度网盘秒传脚本:文件传输效率工具的深度解析与应用指南 【免费下载链接】rapid-upload-userscript-doc 秒传链接提取脚本 - 文档&教程 项目地址: https://gitcode.com/gh_mirrors/ra/rapid-upload-userscript-doc 1.溯源文件分享痛点:传统模…...

突破小爱音箱音乐限制:XiaoMusic让你的智能音箱自由播放任何歌曲

突破小爱音箱音乐限制:XiaoMusic让你的智能音箱自由播放任何歌曲 【免费下载链接】xiaomusic 使用小爱同学播放音乐,音乐使用 yt-dlp 下载。 项目地址: https://gitcode.com/GitHub_Trending/xia/xiaomusic 一、被束缚的音乐体验:当智…...

VR禁毒学习机:禁毒宣传数字化的创新尝试

在数字化时代,禁毒教育不再局限于课堂讲解和图文展板,虚拟现实(VR)技术的加入为这一领域注入了新的活力。VR禁毒学习机的出现,打破了传统教育的枯燥模式,以沉浸式、互动式的方式让体验者在虚拟环境中学习识…...

解决语音角色识别中的误识别与长会漂移问题(陌生人机制 + 稳定性规则)

在熙瑾会悟产品研发的时候,有以下能力:说话人识别(Speaker Identification)。简单说就是:系统不仅要把语音转成文字,还要知道 “是谁在说话”。这个能力在很多场景都会用到,比如:会议…...

OpenClaw Docker 部署 · 完整速查手册

OpenClaw Docker 部署 完整速查手册 适用:Docker 安装、排错、命令解释 制作时间:2026.03.13一、基础 Docker 命令 删除旧容器(重新部署必用) docker rm -f openclaw 查看容器日志(看报错/运行状态) dock…...

FanControl风扇控制进阶指南:从问题诊断到智能调节的全面解决方案

FanControl风扇控制进阶指南:从问题诊断到智能调节的全面解决方案 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_…...

如何构建OpenCore兼容的Hackintosh硬件系统?全面的硬件选择与配置指南

如何构建OpenCore兼容的Hackintosh硬件系统?全面的硬件选择与配置指南 【免费下载链接】OpenCore-Install-Guide Repo for the OpenCore Install Guide 项目地址: https://gitcode.com/gh_mirrors/op/OpenCore-Install-Guide 构建Hackintosh系统最核心的挑战…...

倒立摆的优雅舞步:用代码解读事件触发模型的魔法

【模型参考文献】事件触发模型 基于倒立摆matlab仿真 模型为状态空间形式 事件触发机制可自行调节参数在控制理论的王国里,倒立摆是一个令人着迷的存在。它就像一个不稳定的醉汉,随时可能倾倒,却又能在控制算法的引导下优雅起舞。今天&#x…...

Windows快捷键失效?3个维度彻底解决热键冲突

Windows快捷键失效?3个维度彻底解决热键冲突 【免费下载链接】hotkey-detective A small program for investigating stolen hotkeys under Windows 8 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 当你的设计软件快捷键突然失灵&#xff…...

革新性macOS应用管理:告别命令行的图形化解决方案

革新性macOS应用管理:告别命令行的图形化解决方案 【免费下载链接】Applite User-friendly GUI macOS application for Homebrew Casks 项目地址: https://gitcode.com/gh_mirrors/ap/Applite 在macOS系统管理中,应用维护往往意味着与终端命令的长…...

2026年3月份大更新来了!小黄鸭补帧3.2.2 AI插帧软件分享,小黄鸭补帧 小黄鸭使用教程losslessscaling使用教程!胎教级别!

哈喽 大家好 今天给大家分享一下,如何用这个小黄鸭软件,让我们的老显卡再战十年! 为什么叫它小黄鸭拼好针呢?因为它可以把游戏或者视频的帧数,通过补帧的方式变得非常高,让老显卡也能流畅跑起来&#xff0c…...

从100kHz到6GHz的开源突破:LibreVNA矢量网络分析方案全解析

从100kHz到6GHz的开源突破:LibreVNA矢量网络分析方案全解析 【免费下载链接】LibreVNA 100kHz to 6GHz 2 port USB based VNA 项目地址: https://gitcode.com/gh_mirrors/li/LibreVNA LibreVNA是一款面向射频工程师、电子爱好者和科研人员的开源矢量网络分析…...

SuperPNG使用难题攻克指南:从安装到优化的3个实战技巧

SuperPNG使用难题攻克指南:从安装到优化的3个实战技巧 【免费下载链接】SuperPNG SuperPNG plug-in for Photoshop 项目地址: https://gitcode.com/gh_mirrors/su/SuperPNG SuperPNG是一款专为Photoshop打造的免费插件,核心功能是生成更高质量的P…...

Umi-OCR多引擎协同策略:实现98%文档识别准确率的实战指南

Umi-OCR多引擎协同策略:实现98%文档识别准确率的实战指南 【免费下载链接】Umi-OCR Umi-OCR: 这是一个免费、开源、可批量处理的离线OCR软件,适用于Windows系统,支持截图OCR、批量OCR、二维码识别等功能。 项目地址: https://gitcode.com/G…...

简简单单三步,让你成功更换centos7 的YUM源

centos7在2024年6月30日,生命周期结束,官方不再进行支持维护,官方的YUM源也下线了,下线的方式是使yum的域名不解析。所以现在需要配置国内的YUM源 1.打开源文件:打开CentOS-Base.repo sudo vi /etc/yum.repos.d/CentOS-Base.repo 2.替换源文件…...

扣子(Coze)实战:语文课本突然不枯燥了!输入诗名,Coze一键让古诗词“活”过来

大家好,我是吾鳴。专注于分享提升工作与生活效率的工具,无偿分享AI领域相关的精选报告,持续关注AI的前沿动向。 最近发现一个很有意思的赛道,那就是AI古诗词赛道,这个赛道的内容就是语文课本中的一篇枯燥的文言文古诗词…...

Universal Pokemon Randomizer ZX:重新定义宝可梦游戏体验的开源工具

Universal Pokemon Randomizer ZX:重新定义宝可梦游戏体验的开源工具 【免费下载链接】universal-pokemon-randomizer-zx Public repository of source code for the Universal Pokemon Randomizer ZX 项目地址: https://gitcode.com/gh_mirrors/un/universal-pok…...

【程序员转行】AI+嵌入式风口来袭,程序员/小白必看的职业突围指南

人工智能的浪潮正全面重塑全球就业市场,其中AI与嵌入式领域的人才需求呈现爆发式增长态势,成为就业市场的“香饽饽”。未来几年,就业趋势将持续向AI、大数据领域聚拢,人机协同模式普及、培养AI难以替代的核心能力、坚持终身学习&a…...

当GitHub界面成为协作障碍:如何用87KB插件实现全界面中文改造

当GitHub界面成为协作障碍:如何用87KB插件实现全界面中文改造 【免费下载链接】github-chinese GitHub 汉化插件,GitHub 中文化界面。 (GitHub Translation To Chinese) 项目地址: https://gitcode.com/gh_mirrors/gi/github-chinese 问题&#x…...

MATLAB环境下基于傅里叶分析的3级自适应信号分解方法

MATLAB环境下一种基于傅里叶分析的自适应信号分解方法。 该方法为数据驱动的傅里叶分解方法,分解的前3级的能量分布,分解的前3级基函数,分解的前3级模态分量如下。 算法可迁移至金融时间序列,地震信号,语音信号&#x…...

航空航天需求:Vue3如何扩展WebUploader支持三维模型文件的分片校验?

网工大三党文件上传救星:原生JS实现10G大文件上传(Vue3IE8兼容) 兄弟,作为刚入坑网络工程的山西老狗,我太懂你现在的处境了——老师要10G大文件上传的毕业设计,网上找的代码全是“断头路”,后端…...

告别手动描点:WebPlotDigitizer让图像数据提取效率提升10倍的实战指南

告别手动描点:WebPlotDigitizer让图像数据提取效率提升10倍的实战指南 【免费下载链接】WebPlotDigitizer Computer vision assisted tool to extract numerical data from plot images. 项目地址: https://gitcode.com/gh_mirrors/web/WebPlotDigitizer 在科…...

拥有资产,而非出售时间:这才是致富的唯一捷径!

一、财富与赚钱1. 财富不是钱,而是能在你不工作时仍然赚钱的资产。 解释:真正的财富是股票、公司股权、知识产权、软件等可以持续产生价值的东西,而不是一次性的工资收入。2. 想致富就要拥有股权,而不是只出售时间。 解释&#xf…...

夜话测试管理:一位测试负责人的深夜思考与破局之道

关注 霍格沃兹测试学院公众号,回复「资料」, 领取人工智能测试开发技术合集深夜时分,当大多数人已进入梦乡,一位测试负责人却仍在为团队面临的诸多挑战而思索。在霍格沃兹测试开发学社的私教服务中,这样的深夜对话并不少见。今晚&…...