安卓逆向实战:内存Dump与签名算法还原全流程解析
1. 项目概述与核心目标这次要聊的是一个硬核的安卓逆向实战项目核心目标非常明确对一个经过商业加固的安卓应用进行脱壳从内存中提取出被保护的原始代码DEX并最终定位、分析并还原其核心的签名算法。整个过程就像一场外科手术需要精准地找到应用在运行时暴露出的“内脏”然后进行解剖分析。这个项目标题里的“手撕”二字非常传神它意味着这不是一个依赖自动化工具的简单过程而是需要大量手动分析、调试和代码还原的深度操作。对于从事移动安全研究、风控对抗或者对应用底层机制有浓厚兴趣的开发者来说掌握这套从内存Dump到算法还原的完整链条是进阶的必经之路。我们面对的是一个典型的“加固App”。所谓加固可以理解为给应用穿上了一层或多层盔甲。常见的加固手段包括代码混淆、加密、虚拟机保护VMP、以及将核心的Java代码DEX文件加密或隐藏在运行时再动态解密加载到内存中。我们的目标就是穿透这层盔甲拿到最原始的、未被保护的代码逻辑特别是用于与服务器通信时生成签名sign或令牌token的那部分算法。这个签名参数往往是客户端身份验证和数据完整性的关键还原它对于理解应用协议、进行安全审计或兼容性开发至关重要。整个流程可以拆解为几个关键阶段首先是环境搭建与目标分析确定加固类型和切入点其次是动态脱壳利用工具在应用运行时从内存中抓取解密后的DEX文件接着是静态分析对脱壳后的代码进行反编译和审计定位目标算法最后是算法还原与验证将混淆或虚拟化的代码逻辑还原成可读、可复现的原始逻辑。下面我们就一步步拆解这个“手撕”的过程。2. 逆向环境准备与工具链选型工欲善其事必先利其器。安卓逆向是一个高度依赖工具链的领域选择合适的工具能事半功倍。我的工作环境通常基于一台性能足够的x86电脑运行Windows或Linux系统同时准备一台已Root的安卓真机或一个高性能的模拟器如雷电模拟器、夜神模拟器并配置为可调试模式。真机的运行效率更高更适合动态调试但模拟器在快照、多开等方面有优势。核心工具链我习惯称之为“三板斧”动态调试框架、静态分析工具和辅助脚本环境。动态调试框架的首选是Frida。这是一个功能强大的动态代码插桩工具它允许你将自己的JavaScript代码片段注入到目标进程中从而拦截函数调用、监控内存访问、甚至动态修改逻辑。对于脱壳来说Frida的核心价值在于能够Hook住Android系统底层加载DEX的关键函数如dalvik.system.DexClassLoader或android.app.LoadedApk相关方法在DEX被解密并映射到内存的瞬间将其二进制数据Dump到本地文件。相较于XposedFrida更轻量、灵活且支持对Native层SO库的Hook是当前逆向工程的事实标准。静态分析工具则离不开JADX和IDA Pro。JADX是一款强大的DEX反编译工具能将安卓的字节码smali或DEX文件反编译成可读性很高的Java代码。脱壳后得到的DEX文件主要就靠JADX来打开和分析寻找关键的包名、类名和方法。而IDA Pro则是逆向工程界的瑞士军刀主要用于分析Native层的SO库文件。很多加固方案会把核心算法或校验逻辑放在Native层用C/C实现并用OLLVM等工具进行控制流扁平化等混淆这时就需要用IDA进行反汇编和动态调试一点点理清逻辑。辅助环境包括ADBAndroid Debug Bridge、Python和一些必备的脚本。ADB用于与设备通信推送文件、执行命令。Python环境则用于运行各种自动化脚本比如基于Frida的脱壳脚本、通信数据抓包解析脚本等。此外像objection基于Frida的运行时移动安全评估工具和r0capture针对安卓的抓包工具也经常能派上用场。注意工具版本兼容性是个大坑。特别是Frida-server的版本必须与PC端Frida的Python库版本严格匹配否则会出现连接失败或注入错误。建议使用pip install frida-tools安装最新稳定版然后去GitHub Releases页面下载对应架构和版本号的frida-server推送到设备中运行。3. 目标加固识别与初步分析在开始“手撕”之前我们必须先搞清楚对手是谁。不同的加固厂商如360加固保、腾讯乐固、梆梆安全、爱加密等其加固方案和对抗手段各有特点。盲目动手很可能事倍功半。初步分析可以从APK文件本身开始。使用apktool对目标APK进行解包apktool d target.apk -o output_dir。解包后重点观察几个地方assets目录和lib目录很多加固方案会将原始的classes.dex加密后隐藏在这里或者放入一个自定义格式的文件中。同时会植入自己的SO库如libshell.so,libmain.so这些库负责在运行时进行解密和加载。解包后的classes.dex用文本编辑器打开这个文件如果看到大量的无效字符串或者文件头明显不正常这很可能是一个“壳dex”。它的作用仅仅是初始化加固环境然后去加载真正的应用代码。AndroidManifest.xml查看Application节点。很多加固会替换掉你声明的Application类替换成一个来自加固厂商的代理Application如com.stub.StubApp。这个代理Application会最早被系统加载从而获得应用生命周期的控制权完成解密和初始化。接下来可以尝试运行应用并用ps命令查看进程或者用logcat查看日志。加固方案通常会在启动时打印特定的日志Tag这有助于识别其身份。更直接的方法是使用Frida快速扫描。写一个简单的Frida脚本枚举当前进程加载的所有SO库看看有没有已知加固厂商的特征库名或导出函数。例如一个简单的枚举SO库的Frida脚本Java.perform(function() { var modules Process.enumerateModules(); modules.forEach(function(module) { console.log(module.name - Base: module.base.toString() - Size: module.size.toString()); // 可以在这里加过滤条件比如 if(module.name.indexOf(shell)!-1) ... }); });通过以上步骤我们基本能确定目标使用的加固类型。假设我们确定它使用了某种将DEX加密后放在assets、运行时由Native层解密加载的方案。那么我们的主攻方向就很明确了在内存中找到那个被完整解密并准备被Dalvik/ART虚拟机执行的DEX镜像并把它导出来。4. 动态脱壳从内存中Dump解密后的DEX这是整个流程中最关键、也最体现“实战”的一步。原理是无论加固如何加密、隐藏最终为了让App正常运行原始的Java类代码必须被解密并加载到内存中形成DexFile对象或对应的内存映射区域。我们的任务就是抓住这个瞬间。核心思路是Hook DEX加载的关键函数。在Android系统中加载DEX的路径有很多常见的有dalvik.system.DexClassLoader.loadDexdalvik.system.DexFile.openDexdalvik.system.DexFile.initART虚拟机下的相关函数如art::DexFile::Open等。由于Android版本和加固方案的不同Hook点可能需要调整。一个比较通用且高效的方法是Hooklibdvm.so或libart.so中打开DEX文件的函数。但更简单直接的方法是Hook Java层的DexClassLoader或BaseDexClassLoader的构造函数或loadDex方法。下面是一个经典的、用于Dump内存DEX的Frida脚本框架。它的逻辑是当DexClassLoader被调用时其内部会最终打开一个DEX文件可能是文件路径也可能是内存地址。我们通过回溯找到包含DEX数据的字节数组byte[]然后将其写入文件。Java.perform(function() { var DexClassLoader Java.use(dalvik.system.DexClassLoader); var ByteString Java.use(com.android.okhttp.okio.ByteString); DexClassLoader.$init.overload(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader).implementation function(dexPath, optimizedDirectory, librarySearchPath, parent) { console.log([] DexClassLoader.$init called!); console.log( dexPath: dexPath); console.log( optimizedDirectory: optimizedDirectory); // 调用原方法确保应用正常运行 var ret this.$init(dexPath, optimizedDirectory, librarySearchPath, parent); // 关键尝试从dexPath读取文件并Dump // 但很多壳的dexPath是一个不存在的路径或内存地址所以我们需要更底层的方法 // 这里只是打印信息真正的Dump逻辑可能需要更底层的Hook dumpToFile(dexPath, dex_from_path); return ret; }; // 一个更底层的Hook示例Hook libart.so 中的 OpenMemory 函数 (需要针对不同Android版本调整) var module_libart Process.findModuleByName(libart.so); if (module_libart) { // 这里需要根据实际函数符号来定位例如_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_ // 这通常需要通过逆向libart.so或查阅资料获得 console.log(libart base:, module_libart.base); // 省略具体的Native Hook代码因为它复杂且版本依赖性强 } function dumpToFile(data, filename) { var file new File(/sdcard/Download/ filename .dex, wb); if (Array.isArray(data)) { // 假设data是byte[] var buffer Java.array(byte, data); file.write(buffer); } else if (typeof data string) { // 如果是文件路径尝试读取 var fileInput new File(data, rb); var fileBuffer fileInput.read(); file.write(fileBuffer); fileInput.close(); } file.flush(); file.close(); console.log([] Dumped to /sdcard/Download/ filename .dex); } });实际上由于加固对抗的升级单纯Hook Java层往往拿不到完整的DEX。更可靠的方法是直接扫描进程内存。我们知道一个有效的DEX文件在内存中是以一种连续的结构存在的并且其文件头有固定的魔数dex\n035或dex\n037等。我们可以写一个Frida脚本遍历进程的内存范围通过Process.enumerateRanges(r-x)或r--搜索这个魔数一旦找到就认为这可能是一个DEX的起始地址然后根据DEX头中的file_size字段将后续相应大小的内存数据Dump下来。Java.perform(function() { // 定义DEX文件头魔数 var DEX_MAGIC 6465780a30333500; // dex\n035\0 的 hex ART运行时常见 var DEX_MAGIC_037 6465780a30333700; // dex\n037\0 Process.enumerateRanges(r--).forEach(function(range) { // 只扫描可读的内存页提高效率 try { var magic Memory.readByteArray(range.base, 8); // 读取前8字节 var magicHex bytesToHex(magic); if (magicHex.indexOf(DEX_MAGIC) 0 || magicHex.indexOf(DEX_MAGIC_037) 0) { console.log([] Potential DEX found at: range.base.toString() , size: range.size.toString()); // 读取DEX头解析文件大小DEX头偏移32的位置4字节小端序 var fileSize Memory.readU32(range.base.add(32)); console.log( DEX file size from header: fileSize.toString()); // 确保要Dump的大小不超过内存范围且是合理的DEX大小例如大于1KB小于20MB var dumpSize Math.min(range.size, fileSize); if (dumpSize 1024 dumpSize 20 * 1024 * 1024) { var dexBuffer Memory.readByteArray(range.base, dumpSize); var filename /sdcard/Download/dex_mem_ range.base.toString() .dex; var file new File(filename, wb); file.write(dexBuffer); file.close(); console.log( Dumped to: filename); } } } catch(e) { /* 忽略不可读的内存区域 */ } }); function bytesToHex(bytes) { var arr []; for (var i 0; i bytes.length; i) { arr.push((0 (bytes[i] 0xFF).toString(16)).slice(-2)); } return arr.join(); } });运行这个脚本后我们会在设备的/sdcard/Download/目录下得到若干个.dex文件。它们的大小可能各异其中包含了壳本身的DEX、应用主DEX以及可能被分割的次级DEX。我们需要用file命令或十六进制编辑器检查哪个才是我们需要的、完整的应用代码DEX。通常最大的、结构最完整的那个就是目标。实操心得内存扫描法虽然暴力但非常有效尤其是对付那些自定义加载器的加固。不过它可能会Dump出多个DEX片段需要人工筛选。另外有些加固会抹去或修改DEX魔数来对抗扫描这时就需要调整搜索的特征码比如搜索class_defs_off等关键结构体的特征。5. 脱壳后处理与代码反编译成功Dump出内存中的DEX文件假设我们得到了classes.dex后事情还没完。这个DEX文件可能因为加固的修改如抽取方法体、填充无效指令而无法被正常反编译或执行。这就是所谓的“修复”阶段。首先用file命令确认它确实是一个有效的DEX文件。然后尝试用JADX打开它jadx -d output_dir dumped_classes.dex。如果JADX能顺利打开并看到大部分Java代码恭喜你脱壳基本成功了。但更常见的情况是JADX会报错比如“Error decoding dex file”或显示大量“nop”指令的方法。这时就需要进行修复。修复的手段因加固类型而异指令抽取修复某些加固会将方法体method implementation中的实际指令code_item移除替换为无效指令或跳转真正的指令被加密存储在别处如assets运行时由Native层解密并动态填充。对于这种情况脱壳时如果时机不对Dump下来的DEX里方法体就是空的。修复需要找到运行时填充后的内存并手动或借助工具如dexfixer等将正确的指令写回DEX文件的相应偏移处。这需要对DEX文件格式有深入理解。DEX整体修复有时Dump下来的DEX文件头或某些数据结构被故意破坏。可以使用baksmali/smali工具尝试反汇编java -jar baksmali.jar disassemble dumped_classes.dex -o out_smali如果失败可能需要用十六进制编辑器手动对照DEX文件格式规范进行修补这是一个极其繁琐的过程。多DEX合并大型应用可能被拆分成多个DEXclasses.dex, classes2.dex...。加固可能将它们加密后分散存放。你需要将所有Dump出来的有效DEX文件都收集起来然后用JADX的--export-gradle参数或者手动将它们放入一个APK结构中再重新编译以确保代码索引的完整性。在我们的实战场景中假设我们运气不错或者目标加固的对抗性不强Dump下来的DEX能够被JADX较好地反编译。我们用JADX打开后得到一个结构清晰的Java项目。接下来就是大海捞针寻找与“签名”相关的代码。6. 静态分析与签名算法定位面对反编译后成千上万个类和方法如何快速定位签名算法这需要一些技巧和经验。第一步关键词搜索。签名参数在网络上传输时其参数名通常是固定的比如sign、signature、token、_s、x-sign等。在JADX的全局搜索Shift F中搜索这些关键词。同时搜索网络请求库的调用比如OkHttpClient、HttpURLConnection、Retrofit的接口定义或者搜索包含“api”、“request”、“network”等字眼的包名和类名。第二步调用链分析。找到一处设置签名参数的地方例如request.addHeader(“sign”, signStr)或params.put(“sign”, calculateSign(params))然后右键点击calculateSign这个方法选择“查找用例”或“跳转到声明”。这会带你到生成签名的方法。如果这个方法内部又调用了其他方法就继续跟进直到找到最核心的加密或哈希函数比如MD5、SHA256、HMAC、AES、RSA等。JADX的“查找用例”和“调用层级”功能是理清代码逻辑的神器。第三步关注工具类。签名算法通常会被封装在一个独立的工具类中类名可能包含SignUtil、SecurityHelper、EncryptUtils、HashUtils等。直接搜索这些常见的工具类名也能快速定位。第四步动态辅助验证。在静态分析的同时可以结合动态调试来验证猜想。例如用Frida Hook你怀疑的签名方法打印其输入参数和返回值然后与抓包工具如Charles、Fiddler捕获到的真实网络请求中的签名进行比对。如果一致那就找对了地方。假设我们通过搜索定位到了一个名为com.xxx.security.SignGenerator的类其中有一个核心方法public static String generateSign(MapString, String params, String appSecret) { // 1. 参数排序并拼接成字符串 String sortedStr sortAndConcat(params); // 2. 拼接上appSecret String toBeSigned sortedStr appSecret; // 3. 计算MD5 return md5(toBeSigned); }看起来是一个标准的MD5签名算法。但事情往往没这么简单。appSecret从哪里来它可能硬编码在代码里经过混淆也可能从服务器动态获取。params的排序规则是什么是按键名ASCII码升序吗是否有参数不参与签名这些细节都需要仔细阅读代码来确认。7. 算法还原与代码复现定位到核心算法后下一步就是理解并还原它。对于上面的MD5例子还原相对简单。但实战中你可能会遇到更复杂的情况算法混淆核心计算过程可能被代码混淆工具如ProGuard或加固自带的混淆打乱变量名变成a,b,c控制流变得复杂。这时需要耐心地阅读汇编或反编译后的代码理解其数学本质。可以尝试用笔和纸画出数据流或者写一小段测试代码来模拟验证。Native层实现最关键、最核心的算法很可能被放在Native层SO库中以JNIJava Native Interface的形式供Java层调用。你会看到类似native String generateSignNative(Map params);的声明。这时静态分析的主战场就要从JADX转移到IDA Pro了。用IDA打开对应的SO文件通常在lib/armeabi-v7a或lib/arm64-v8a目录下。找到Java_com_xxx_security_SignGenerator_generateSignNative这个导出函数函数名遵循JNI规范。分析这个Native函数的逻辑。它可能内部调用了其他复杂的C/C函数可能使用了内联汇编还可能被OLLVM等工具进行了控制流扁平化、指令替换等混淆逆向难度极大。需要结合动态调试用IDA或Frida附加进程下断点来理解输入输出。白盒加密与代码虚拟化最高级别的保护会使用白盒加密或虚拟机保护VMP。算法和密钥被深度融合代码被转换成自定义的字节码在虚拟机上执行。逆向这种保护需要极高的专业知识和耐心往往需要跟踪自定义虚拟机的解释执行过程分析其指令集相当于逆向一个编译器。这超出了大多数常规逆向的范畴。在我们的案例中假设算法就在Java层且逻辑清晰。我们需要将分析清楚的算法用自己熟悉的编程语言如Python、Java重新实现一遍。还原时要注意所有细节参数的编码是UTF-8还是GBK排序规则空值如何处理大小写敏感吗拼接方式用还是连接哈希/加密的具体算法和模式MD5后是16进制小写还是Base64AES是CBC模式还是ECBIV是什么密钥的来源和处理是否经过二次哈希一个完整的还原示例Pythonimport hashlib import urllib.parse def generate_sign(params, app_secret): # 1. 过滤并排序参数 filtered_params {k: v for k, v in params.items() if v is not None and k ! sign} sorted_items sorted(filtered_params.items(), keylambda x: x[0]) # 2. 拼接成 key1value1key2value2 格式 sorted_str .join([f{k}{v} for k, v in sorted_items]) # 3. 拼接appSecret to_be_signed sorted_str app_secret # 4. 计算MD5并转为小写16进制 m hashlib.md5() m.update(to_be_signed.encode(utf-8)) return m.hexdigest() # 测试 test_params {uid: 12345, timestamp: 1685432100, action: query} secret your_app_secret_here signature generate_sign(test_params, secret) print(fGenerated Sign: {signature})8. 验证、测试与常见问题排查算法还原后必须进行严格的验证。验证分两步第一步单元测试验证。用抓包工具获取一组真实的、成功的网络请求数据包括所有请求参数和服务器返回的签名。将除签名外的参数输入你自己实现的算法计算出的签名与抓包得到的签名进行比对。必须完全一致包括大小写和编码格式。第二步集成测试验证。模拟完整的请求流程用你还原的算法生成签名替换到请求参数中然后发送请求到服务器。如果服务器返回了正常的业务数据而非“签名错误”那么恭喜你大功告成。在整个过程中你会遇到无数坑。下面是一些常见问题及排查思路问题现象可能原因排查思路JADX反编译失败或代码混乱DEX文件损坏或指令被抽取1. 尝试用baksmali反汇编看报错信息。2. 用十六进制编辑器查看DEX文件头是否完整。3. 检查Dump时机是否在方法体被填充之后。内存扫描找不到DEX魔数加固修改了魔数或DEX被整体加密1. 尝试搜索DEX文件的其他特征如class_defs_off的偏移值。2. 尝试Hook更底层的art运行时函数在解密后、映射前Dump。3. 考虑使用针对特定加固的脱壳机如果有。找到的签名算法计算结果不一致算法细节未还原准确1.编码问题确认所有字符串的编码UTF-8/GBK。2.参数遗漏确认是否所有参数都参与签名特别是Cookie或Header中的某些字段。3.排序规则确认排序是按键名还是键值ASCII序还是字典序空值是否参与排序4.密钥错误appSecret是否正确是否动态变化是否经过了预处理如截取前N位5.哈希细节MD5后是32位小写还是截取了16位还是做了Base64Frida脚本注入失败或应用崩溃反调试或Frida检测1. 检查Frida-server是否正常运行ps | grep frida。2. 尝试使用-f参数以Spawn方式启动应用并注入。3. 应用可能检测了Frida的默认端口27042或特征。尝试修改Frida的端口或使用frida -l script.js --no-pause -f com.example.app。4. 使用objection的android hooking watch等命令尝试绕过简单检测。Native层函数找不到函数名混淆或动态注册1. 在IDA中查看JNI_OnLoad函数动态注册的函数会在这里通过RegisterNatives关联。2. 搜索字符串引用找到可能对应的Java类名和方法名。3. 使用Frida的Module.enumerateExports或Module.enumerateSymbols列出SO的所有导出符号寻找可疑函数。避坑指南在动态调试时尤其是Hook Native层函数时很容易导致应用崩溃。务必注意线程安全和参数/返回值类型。在Frida的implementation函数中对于指针类型的参数不要轻易直接读取或修改除非你很清楚它的内存布局。先使用console.log(hexdump(ptr))打印出来观察再谨慎操作。另外对于高强度对抗的应用单纯的技术分析可能走到死胡同需要结合对业务逻辑的理解进行推测和验证。逆向工程是一场与软件作者之间的智力博弈。从内存Dump到算法还原每一步都需要耐心、细心和扎实的基础知识。这个过程没有一成不变的银弹每一个新的目标都可能带来新的挑战。但万变不离其宗理解系统原理Android运行时、文件格式、网络协议、熟练使用工具Frida, IDA, JADX、掌握分析方法静态阅读、动态调试、代码跟踪是应对所有挑战的基石。最后务必在法律法规和道德规范的框架内进行技术研究和学习尊重知识产权。

相关新闻

Linux蓝牙调试利器hcitool:从基础命令到实战排查

Linux蓝牙调试利器hcitool:从基础命令到实战排查

1. 项目概述:为什么你需要了解hcitool?如果你在折腾蓝牙设备,比如连接一个蓝牙键盘、调试一个BLE传感器,或者排查耳机断连的问题,在Linux命令行下绕不开的一个工具就是hcitool。它就像是蓝牙世界里的“瑞士军刀”&…

2026/8/5 7:01:03 阅读更多 →
Reloaded-II下载安装终极指南:从零开始到畅玩模组的完整教程

Reloaded-II下载安装终极指南:从零开始到畅玩模组的完整教程

Reloaded-II下载安装终极指南:从零开始到畅玩模组的完整教程 【免费下载链接】Reloaded-II Universal .NET Core Powered Modding Framework for any Native Game X86, X64. 项目地址: https://gitcode.com/gh_mirrors/re/Reloaded-II 你是否曾经因为模组下载…

2026/8/5 7:01:03 阅读更多 →
联想拯救者笔记本终极控制方案:轻量级工具箱完全指南

联想拯救者笔记本终极控制方案:轻量级工具箱完全指南

联想拯救者笔记本终极控制方案:轻量级工具箱完全指南 【免费下载链接】LenovoLegionToolkit Lightweight Lenovo Vantage and Hotkeys replacement for Lenovo Legion laptops. 项目地址: https://gitcode.com/gh_mirrors/le/LenovoLegionToolkit 你是否厌倦…

2026/8/5 7:01:03 阅读更多 →

最新新闻

【金仓数据库征文】200 万行订单表调优实录:KingbaseES V9R1C10 执行计划分析与索引优化

【金仓数据库征文】200 万行订单表调优实录:KingbaseES V9R1C10 执行计划分析与索引优化

摘要上两篇写了部署和 AI 直连。这篇调优。200 万行,报表慢。我造了 200 万行,揪出慢查询,sys_hypo 试水,再落地索引。region 查询 655.9→181.9 ms。amount 查询 583.4→257.4 ms。复合索引 174.9→42.7 ms。大排序 6.3 秒→2.5 秒。数字全是机器跑的,截图在下边。一、为什么调…

2026/8/5 7:49:23 阅读更多 →
Kerberos协议深度解析:从核心原理到企业级部署实战

Kerberos协议深度解析:从核心原理到企业级部署实战

1. 项目概述:为什么我们需要Kerberos?在分布式系统和大型企业网络里,身份认证是个老大难问题。想象一下,你每天上班要登录邮箱、访问文件服务器、连接数据库,如果每个系统都让你输一遍用户名密码,不仅麻烦&…

2026/8/5 7:49:23 阅读更多 →
Bearer Token 认证详解:从 HTTP 认证演进到 JWT 实战应用

Bearer Token 认证详解:从 HTTP 认证演进到 JWT 实战应用

1. 从一次调试说起:Authorization头里的Bearer前缀 那天下午,我正在排查一个棘手的API调用问题。客户端日志里清晰地打印着请求头: Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp... ,一个标准的JWT令牌。服务器端却固执地返…

2026/8/5 7:49:23 阅读更多 →
OCP(过流保护)从入门到精通

OCP(过流保护)从入门到精通

一文搞懂 OCP(过流保护):是什么、哪些芯片有、怎么区分、还需不需要其他保护器件? 在硬件设计领域,OCP(Over Current Protection,过流保护) 是电源和功率电路中绕不开的话题。很多工…

2026/8/5 7:49:23 阅读更多 →
中小企业通信选型:公司用什么邮箱比较好,开通企业邮箱运维实操方案

中小企业通信选型:公司用什么邮箱比较好,开通企业邮箱运维实操方案

在企业信息化架构搭建中,企业邮箱承担商务函件传输、业务数据留存、内外协同沟通等重要作用。不少运维、行政人员常会思考:公司用什么邮箱比较好,如何标准化开通企业邮箱。本文从运维落地视角,讲解企业邮箱注册流程、企业邮箱安全…

2026/8/5 7:49:23 阅读更多 →
Windows右键菜单终极清理指南:ContextMenuManager让你的右键菜单重获新生

Windows右键菜单终极清理指南:ContextMenuManager让你的右键菜单重获新生

Windows右键菜单终极清理指南:ContextMenuManager让你的右键菜单重获新生 【免费下载链接】ContextMenuManager 🖱️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 你是否厌倦了每次右键点击文…

2026/8/5 7:48:23 阅读更多 →

日新闻

Java缓存框架:JetCache

Java缓存框架:JetCache

TOC 一、简介 JetCache 是一个 Java 缓存抽象框架,为不同的缓存解决方案提供了统一的使用方式。 它提供的注解比 Spring Cache 更加强大。 JetCache 的注解支持原生 TTL、两级缓存以及在分布式环境中的自动刷新功能,同时你也可以通过代码直接操作 Cach…

2026/8/5 0:00:43 阅读更多 →
AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

需求:通孔焊盘 十字花;过孔 Via 实心直连;贴片焊盘按需设置 AD 测试版本AD24 很多工程师踩坑:全部统一十字,导致接地过孔阻抗高、大电流发热! 一、快捷键打开规则 PCB 界面按下:D R 展开…

2026/8/5 0:00:43 阅读更多 →
AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

更多请点击: https://kaifayun.com 第一章:AI生成素描效果 AI生成素描效果是计算机视觉与风格迁移技术融合的典型应用,其核心在于将彩色照片或RGB图像转换为具有手绘质感、明暗对比强烈、边缘清晰的单色素描图像。该过程通常依赖于深度学习模…

2026/8/5 0:00:43 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/4 13:24:41 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/4 11:41:39 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/4 5:26:40 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/4 13:38:24 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/4 11:09:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/4 13:38:40 阅读更多 →