[{"data":1,"prerenderedAt":1257},["ShallowReactive",2],{"navigation_docs":3,"-android-hidden-hardening-native-decrypt":173,"-android-hidden-hardening-native-decrypt-surround":1252},[4,22,29,36,107,138,145,161],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"博客","i-lucide-pen-line","\u002Fblog","0.blog",[10,12,17],{"title":5,"path":7,"stem":11,"icon":6},"0.blog\u002Findex",{"title":13,"path":14,"stem":15,"icon":16},"创建基于 UIKit 的原生 iOS 项目","\u002Fblog\u002Fcreate-uikit-ios-project","0.blog\u002F01.create-uikit-ios-project","i-lucide-app-window",{"title":18,"path":19,"stem":20,"icon":21},"Lockify：把账号和密码留在自己的手机里","\u002Fblog\u002Flockify","0.blog\u002F02.lockify","i-lucide-lock",{"title":23,"path":24,"stem":25,"children":26,"icon":28},"年度总结","\u002Fannual-review","1.annual-review\u002Findex",[27],{"title":23,"path":24,"stem":25,"icon":28},"i-lucide-git-commit",{"title":30,"path":31,"stem":32,"children":33,"icon":35},"故事","\u002Fstories","2.stories\u002Findex",[34],{"title":30,"path":31,"stem":32,"icon":35},"i-lucide-feather",{"title":37,"icon":38,"path":39,"stem":40,"children":41},"Android","i-simple-icons-android","\u002Fandroid","3.android",[42,44,49],{"title":37,"path":39,"stem":43,"icon":38},"3.android\u002Findex",{"title":45,"path":46,"stem":47,"icon":48},"初探Navigation","\u002Fandroid\u002Fcompose-navigation","3.android\u002F01.compose-navigation","i-lucide-route",{"title":50,"icon":51,"path":52,"stem":53,"children":54},"安卓代码加固","i-lucide-shield","\u002Fandroid\u002Fhidden-hardening","3.android\u002F02.hidden-hardening\u002Findex",[55,58,62,67,72,77,82,87,92,97,102],{"title":56,"path":52,"stem":53,"icon":57},"安卓代码加固：总览","i-lucide-map",{"title":59,"path":60,"stem":61,"icon":21},"安卓代码加固（1）：加密DEX","\u002Fandroid\u002Fhidden-hardening\u002Fencrypt-dex","3.android\u002F02.hidden-hardening\u002F01.encrypt-dex",{"title":63,"path":64,"stem":65,"icon":66},"安卓代码加固（2）：Native解密","\u002Fandroid\u002Fhidden-hardening\u002Fnative-decrypt","3.android\u002F02.hidden-hardening\u002F02.native-decrypt","i-lucide-cpu",{"title":68,"path":69,"stem":70,"icon":71},"安卓代码加固（3）：内存加载","\u002Fandroid\u002Fhidden-hardening\u002Fmemory-load","3.android\u002F02.hidden-hardening\u002F03.memory-load","i-lucide-memory-stick",{"title":73,"path":74,"stem":75,"icon":76},"安卓代码加固（4）：指令分发","\u002Fandroid\u002Fhidden-hardening\u002Fopcode-dispatch","3.android\u002F02.hidden-hardening\u002F04.opcode-dispatch","i-lucide-hash",{"title":78,"path":79,"stem":80,"icon":81},"安卓代码加固（5）：XOR混淆","\u002Fandroid\u002Fhidden-hardening\u002Fxor-obfuscate","3.android\u002F02.hidden-hardening\u002F05.xor-obfuscate","i-lucide-shuffle",{"title":83,"path":84,"stem":85,"icon":86},"安卓代码加固（6）：密钥外置","\u002Fandroid\u002Fhidden-hardening\u002Fkey-external","3.android\u002F02.hidden-hardening\u002F06.key-external","i-lucide-key",{"title":88,"path":89,"stem":90,"icon":91},"安卓代码加固（7）：依赖隔离","\u002Fandroid\u002Fhidden-hardening\u002Fdep-isolate","3.android\u002F02.hidden-hardening\u002F07.dep-isolate","i-lucide-layers",{"title":93,"path":94,"stem":95,"icon":96},"安卓代码加固（8）：构建校验","\u002Fandroid\u002Fhidden-hardening\u002Fbuild-verify","3.android\u002F02.hidden-hardening\u002F08.build-verify","i-lucide-shield-check",{"title":98,"path":99,"stem":100,"icon":101},"安卓代码加固（9）：防录屏","\u002Fandroid\u002Fhidden-hardening\u002Fflag-secure","3.android\u002F02.hidden-hardening\u002F09.flag-secure","i-lucide-eye-off",{"title":103,"path":104,"stem":105,"icon":106},"安卓代码加固（10）：ABI门禁","\u002Fandroid\u002Fhidden-hardening\u002Fabi-gate","3.android\u002F02.hidden-hardening\u002F10.abi-gate","i-lucide-git-compare",{"title":108,"icon":109,"path":110,"stem":111,"children":112},"iOS","i-simple-icons-apple","\u002Fios","4.ios",[113,115,120,125,129,133],{"title":108,"path":110,"stem":114,"icon":109},"4.ios\u002Findex",{"title":116,"path":117,"stem":118,"icon":119},"iOS面试题1","\u002Fios\u002Fios-interview1","4.ios\u002F01.ios-interview1","i-lucide-sparkles",{"title":121,"path":122,"stem":123,"icon":124},"设置启动图","\u002Fios\u002Fset-launch-screen","4.ios\u002F02.set-launch-screen","i-lucide-image",{"title":126,"path":127,"stem":128,"icon":48},"路由管理","\u002Fios\u002Frouting","4.ios\u002F03.routing",{"title":130,"path":131,"stem":132,"icon":91},"状态管理","\u002Fios\u002Fstate-management","4.ios\u002F04.state-management",{"title":134,"path":135,"stem":136,"icon":137},"事件传递","\u002Fios\u002Fevent-delivery","4.ios\u002F05.event-delivery","i-lucide-pointer",{"title":139,"path":140,"stem":141,"children":142,"icon":144},"Flutter","\u002Fflutter","5.flutter\u002Findex",[143],{"title":139,"path":140,"stem":141,"icon":144},"i-simple-icons-flutter",{"title":146,"icon":147,"path":148,"stem":149,"children":150,"page":160},"面试","i-lucide-graduation-cap","\u002Finterview","6.interview",[151,156],{"title":152,"path":153,"stem":154,"icon":155},"Flutter面试题1","\u002Finterview\u002Fflutter-interview1","6.interview\u002F01.flutter-interview1","i-lucide-boxes",{"title":157,"path":158,"stem":159,"icon":66},"Flutter面试题2","\u002Finterview\u002Fflutter-interview2","6.interview\u002F02.flutter-interview2",false,{"title":162,"icon":163,"path":164,"stem":165,"children":166},"算法学习","i-lucide-binary","\u002Falgorithm","7.algorithm",[167,169],{"title":162,"path":164,"stem":168,"icon":163},"7.algorithm\u002Findex",{"title":170,"path":171,"stem":172},"算法基础1：复杂度分析","\u002Falgorithm\u002Ftime-space-complexity","7.algorithm\u002F01.time-space-complexity",{"id":174,"title":63,"body":175,"description":1235,"extension":1236,"links":1237,"meta":1240,"navigation":1247,"path":64,"seo":1248,"stem":65,"__hash__":1251},"docs\u002F3.android\u002F02.hidden-hardening\u002F02.native-decrypt.md",{"type":176,"value":177,"toc":1227},"minimark",[178,199,214,219,222,297,337,340,343,474,479,684,694,698,705,902,907,915,919,926,1091,1098,1102,1105,1188,1202,1205,1223],[179,180,181,182,186,187,190,191,194,195,198],"p",{},"解密不走 ",[183,184,185],"code",{},"javax.crypto.Cipher","。",[183,188,189],{},"HiddenSdk.init"," 把 64 个 hex 字符交给 ",[183,192,193],{},"nativeInit","，由 ",[183,196,197],{},"libhiddendecrypt.so"," 读取 assets、拆开密文、校验 tag。Java 层只检查密钥格式。",[200,201,202,203,206,207,210,211,213],"note",{},"仓库里仍保留 ",[183,204,205],{},"HiddenDecrypt.decryptAesGcm"," JNI，供旧路径使用。当前主流程是 ",[183,208,209],{},"hidden_bridge.cpp"," 的 ",[183,212,193],{},"，一次完成解密和加载。",[215,216,218],"h2",{"id":217},"so-如何编译","so 如何编译",[179,220,221],{},"CMake 把三份源码链成同一个动态库，并隐藏符号、设置页对齐。",[223,224,230],"pre",{"className":225,"code":226,"filename":227,"language":228,"meta":229,"style":229},"language-cmake shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","add_library(hiddendecrypt SHARED\n        hidden_decrypt.cpp\n        hidden_bridge.cpp\n        aes256_gcm.c\n)\n\ntarget_compile_options(hiddendecrypt PRIVATE -fvisibility=hidden -fno-exceptions -fno-rtti)\ntarget_link_options(hiddendecrypt PRIVATE \"-Wl,-z,max-page-size=16384\")\n","hidden-sdk\u002Fsrc\u002Fmain\u002Fcpp\u002FCMakeLists.txt","cmake","",[183,231,232,245,251,257,263,269,276,285],{"__ignoreMap":229},[233,234,237,241],"span",{"class":235,"line":236},"line",1,[233,238,240],{"class":239},"sMK4o","add_library",[233,242,244],{"class":243},"sTEyZ","(hiddendecrypt SHARED\n",[233,246,248],{"class":235,"line":247},2,[233,249,250],{"class":243},"        hidden_decrypt.cpp\n",[233,252,254],{"class":235,"line":253},3,[233,255,256],{"class":243},"        hidden_bridge.cpp\n",[233,258,260],{"class":235,"line":259},4,[233,261,262],{"class":243},"        aes256_gcm.c\n",[233,264,266],{"class":235,"line":265},5,[233,267,268],{"class":243},")\n",[233,270,272],{"class":235,"line":271},6,[233,273,275],{"emptyLinePlaceholder":274},true,"\n",[233,277,279,282],{"class":235,"line":278},7,[233,280,281],{"class":239},"target_compile_options",[233,283,284],{"class":243},"(hiddendecrypt PRIVATE -fvisibility=hidden -fno-exceptions -fno-rtti)\n",[233,286,288,291,295],{"class":235,"line":287},8,[233,289,290],{"class":243},"target_link_options(hiddendecrypt PRIVATE ",[233,292,294],{"class":293},"sfazB","\"-Wl,-z,max-page-size=16384\"",[233,296,268],{"class":243},[298,299,300,317,329],"accordion",{},[301,302,304,305,308,309,312,313,316],"accordion-item",{"icon":101,"label":303},"-fvisibility=hidden 做什么？","默认导出的 C 符号会少很多。JADX 和 ",[183,306,307],{},"nm"," 不容易扫到 ",[183,310,311],{},"hidden_aes256_gcm_decrypt"," 这类内部函数。JNI 入口仍按 ",[183,314,315],{},"Java_com_example_..."," 命名导出，否则 JVM 无法找到。",[301,318,321,324,325,328],{"icon":319,"label":320},"i-lucide-box","为什么不用系统 OpenSSL？",[183,322,323],{},"aes256_gcm.c"," 自带 S-box、密钥扩展、GHASH、GCTR。不链接系统 crypto，可以减少通过 hook 常见 JNI 或 OpenSSL 符号截取明文的路径。代价是必须自行保证实现正确。构建期由 ",[183,326,327],{},"PayloadEncryptor"," 先加密再解密核对。",[301,330,333,336],{"icon":331,"label":332},"i-lucide-align-justify","16KB 页对齐",[183,334,335],{},"-Wl,-z,max-page-size=16384"," 满足 Android 15 及以上对 64 位 so 的 LOAD 段要求。这是上架兼容，不是混淆。缺少这项时，新设备会直接加载失败。",[215,338,339],{"id":339},"拆分密文头",[179,341,342],{},"头文件固定了各段长度：HDX1 头 4 字节 + nonce 12 字节 + tag 16 字节。短于这个长度会直接失败。",[223,344,349],{"className":345,"code":346,"filename":347,"language":348,"meta":229,"style":229},"language-c shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","#define HIDDEN_GCM_MAGIC_LEN 4\n#define HIDDEN_GCM_NONCE_LEN 12\n#define HIDDEN_GCM_TAG_LEN 16\n#define HIDDEN_GCM_KEY_LEN 32\n#define HIDDEN_GCM_OVERHEAD (HIDDEN_GCM_MAGIC_LEN + HIDDEN_GCM_NONCE_LEN + HIDDEN_GCM_TAG_LEN)\n\n\u002F* 密文：HDX1 || nonce(12) || ciphertext || tag(16)。成功返回 0。 *\u002F\nint hidden_aes256_gcm_decrypt(...);\nvoid hidden_secure_zero(void *p, size_t n);\n","hidden-sdk\u002Fsrc\u002Fmain\u002Fcpp\u002Faes256_gcm.h","c",[183,350,351,365,375,385,395,420,424,430,442],{"__ignoreMap":229},[233,352,353,357,361],{"class":235,"line":236},[233,354,356],{"class":355},"s7zQu","#define",[233,358,360],{"class":359},"s2Zo4"," HIDDEN_GCM_MAGIC_LEN",[233,362,364],{"class":363},"sbssI"," 4\n",[233,366,367,369,372],{"class":235,"line":247},[233,368,356],{"class":355},[233,370,371],{"class":359}," HIDDEN_GCM_NONCE_LEN",[233,373,374],{"class":363}," 12\n",[233,376,377,379,382],{"class":235,"line":253},[233,378,356],{"class":355},[233,380,381],{"class":359}," HIDDEN_GCM_TAG_LEN",[233,383,384],{"class":363}," 16\n",[233,386,387,389,392],{"class":235,"line":259},[233,388,356],{"class":355},[233,390,391],{"class":359}," HIDDEN_GCM_KEY_LEN",[233,393,394],{"class":363}," 32\n",[233,396,397,399,402,405,408,411,414,416,418],{"class":235,"line":265},[233,398,356],{"class":355},[233,400,401],{"class":359}," HIDDEN_GCM_OVERHEAD",[233,403,404],{"class":239}," (",[233,406,407],{"class":243},"HIDDEN_GCM_MAGIC_LEN ",[233,409,410],{"class":239},"+",[233,412,413],{"class":243}," HIDDEN_GCM_NONCE_LEN ",[233,415,410],{"class":239},[233,417,381],{"class":243},[233,419,268],{"class":239},[233,421,422],{"class":235,"line":271},[233,423,275],{"emptyLinePlaceholder":274},[233,425,426],{"class":235,"line":278},[233,427,429],{"class":428},"sHwdD","\u002F* 密文：HDX1 || nonce(12) || ciphertext || tag(16)。成功返回 0。 *\u002F\n",[233,431,432,436,439],{"class":235,"line":287},[233,433,435],{"class":434},"spNyl","int",[233,437,438],{"class":359}," hidden_aes256_gcm_decrypt",[233,440,441],{"class":239},"(...);\n",[233,443,445,448,451,454,456,459,462,465,468,471],{"class":235,"line":444},9,[233,446,447],{"class":434},"void",[233,449,450],{"class":359}," hidden_secure_zero",[233,452,453],{"class":239},"(",[233,455,447],{"class":434},[233,457,458],{"class":239}," *",[233,460,179],{"class":461},"sHdIc",[233,463,464],{"class":239},",",[233,466,467],{"class":434}," size_t",[233,469,470],{"class":461}," n",[233,472,473],{"class":239},");\n",[179,475,476,478],{},[183,477,193],{}," 先把 hex 解成 32 字节，再读取整份 blob：",[223,480,485],{"className":481,"code":482,"filename":483,"language":484,"meta":229,"style":229},"language-cpp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","if (hex_len != 64 || !parse_key_hex(hex, key)) {\n    return jerr(env, \"密钥格式无效\");\n}\nuint8_t *blob = read_asset(env, context, &blob_len);\nconst int rc = hidden_aes256_gcm_decrypt(\n        key, sizeof(key), blob, blob_len, plain, &out_len);\nhidden_secure_zero(key, sizeof(key));\nhidden_secure_zero(blob, blob_len);\n","hidden-sdk\u002Fsrc\u002Fmain\u002Fcpp\u002Fhidden_bridge.cpp","cpp",[183,486,487,528,555,560,595,613,651,669],{"__ignoreMap":229},[233,488,489,492,494,497,500,503,506,509,512,514,517,519,522,525],{"class":235,"line":236},[233,490,491],{"class":355},"if",[233,493,404],{"class":239},[233,495,496],{"class":243},"hex_len ",[233,498,499],{"class":239},"!=",[233,501,502],{"class":363}," 64",[233,504,505],{"class":239}," ||",[233,507,508],{"class":239}," !",[233,510,511],{"class":359},"parse_key_hex",[233,513,453],{"class":239},[233,515,516],{"class":243},"hex",[233,518,464],{"class":239},[233,520,521],{"class":243}," key",[233,523,524],{"class":239},"))",[233,526,527],{"class":239}," {\n",[233,529,530,533,536,538,542,544,547,550,553],{"class":235,"line":247},[233,531,532],{"class":355},"    return",[233,534,535],{"class":359}," jerr",[233,537,453],{"class":239},[233,539,541],{"class":540},"swJcz","env",[233,543,464],{"class":239},[233,545,546],{"class":239}," \"",[233,548,549],{"class":293},"密钥格式无效",[233,551,552],{"class":239},"\"",[233,554,473],{"class":239},[233,556,557],{"class":235,"line":253},[233,558,559],{"class":239},"}\n",[233,561,562,565,567,570,573,576,578,580,582,585,587,590,593],{"class":235,"line":259},[233,563,564],{"class":434},"uint8_t",[233,566,458],{"class":239},[233,568,569],{"class":243},"blob ",[233,571,572],{"class":239},"=",[233,574,575],{"class":359}," read_asset",[233,577,453],{"class":239},[233,579,541],{"class":243},[233,581,464],{"class":239},[233,583,584],{"class":243}," context",[233,586,464],{"class":239},[233,588,589],{"class":239}," &",[233,591,592],{"class":243},"blob_len",[233,594,473],{"class":239},[233,596,597,600,603,606,608,610],{"class":235,"line":265},[233,598,599],{"class":434},"const",[233,601,602],{"class":434}," int",[233,604,605],{"class":243}," rc ",[233,607,572],{"class":239},[233,609,438],{"class":359},[233,611,612],{"class":239},"(\n",[233,614,615,618,620,623,626,629,632,634,637,639,642,644,646,649],{"class":235,"line":271},[233,616,617],{"class":243},"        key",[233,619,464],{"class":239},[233,621,622],{"class":239}," sizeof(",[233,624,625],{"class":243},"key",[233,627,628],{"class":239},"),",[233,630,631],{"class":243}," blob",[233,633,464],{"class":239},[233,635,636],{"class":243}," blob_len",[233,638,464],{"class":239},[233,640,641],{"class":243}," plain",[233,643,464],{"class":239},[233,645,589],{"class":239},[233,647,648],{"class":243},"out_len",[233,650,473],{"class":239},[233,652,653,656,658,660,662,664,666],{"class":235,"line":278},[233,654,655],{"class":359},"hidden_secure_zero",[233,657,453],{"class":239},[233,659,625],{"class":243},[233,661,464],{"class":239},[233,663,622],{"class":239},[233,665,625],{"class":243},[233,667,668],{"class":239},"));\n",[233,670,671,673,675,678,680,682],{"class":235,"line":287},[233,672,655],{"class":359},[233,674,453],{"class":239},[233,676,677],{"class":243},"blob",[233,679,464],{"class":239},[233,681,636],{"class":243},[233,683,473],{"class":239},[179,685,686,687,689,690,693],{},"密钥和密文缓冲用完立刻执行 ",[183,688,655],{},"。这是用 ",[183,691,692],{},"volatile"," 逐字节写 0，避免编译器把清零优化掉。",[215,695,697],{"id":696},"校验-tag-后再输出明文","校验 tag 后再输出明文",[179,699,700,701,704],{},"解密函数先用 ",[183,702,703],{},"memcmp"," 核对 HDX1 头，再计算 GHASH，最后比较 tag 时不会提前返回。tag 不对就清空输出缓冲，返回 -1。",[223,706,709],{"className":345,"code":707,"filename":708,"language":348,"meta":229,"style":229},"if (memcmp(blob, kMagic, HIDDEN_GCM_MAGIC_LEN) != 0) {\n    return -1;\n}\nghash(h, ct, ct_len, s);\naes256_encrypt_block(&aes, j0, expected);\nxor16(expected, expected, s);\nif (!ct_eq(expected, tag, HIDDEN_GCM_TAG_LEN)) {\n    goto done;\n}\ngctr(&aes, j0, ct, ct_len, out);\n","hidden-sdk\u002Fsrc\u002Fmain\u002Fcpp\u002Faes256_gcm.c",[183,710,711,745,758,762,789,812,832,859,869,873],{"__ignoreMap":229},[233,712,713,715,717,719,721,723,725,728,730,732,735,738,741,743],{"class":235,"line":236},[233,714,491],{"class":355},[233,716,404],{"class":239},[233,718,703],{"class":359},[233,720,453],{"class":239},[233,722,677],{"class":243},[233,724,464],{"class":239},[233,726,727],{"class":243}," kMagic",[233,729,464],{"class":239},[233,731,360],{"class":243},[233,733,734],{"class":239},")",[233,736,737],{"class":239}," !=",[233,739,740],{"class":363}," 0",[233,742,734],{"class":239},[233,744,527],{"class":239},[233,746,747,749,752,755],{"class":235,"line":247},[233,748,532],{"class":355},[233,750,751],{"class":239}," -",[233,753,754],{"class":363},"1",[233,756,757],{"class":239},";\n",[233,759,760],{"class":235,"line":253},[233,761,559],{"class":239},[233,763,764,767,769,772,774,777,779,782,784,787],{"class":235,"line":259},[233,765,766],{"class":359},"ghash",[233,768,453],{"class":239},[233,770,771],{"class":243},"h",[233,773,464],{"class":239},[233,775,776],{"class":243}," ct",[233,778,464],{"class":239},[233,780,781],{"class":243}," ct_len",[233,783,464],{"class":239},[233,785,786],{"class":243}," s",[233,788,473],{"class":239},[233,790,791,794,797,800,802,805,807,810],{"class":235,"line":265},[233,792,793],{"class":359},"aes256_encrypt_block",[233,795,796],{"class":239},"(&",[233,798,799],{"class":461},"aes",[233,801,464],{"class":239},[233,803,804],{"class":243}," j0",[233,806,464],{"class":239},[233,808,809],{"class":243}," expected",[233,811,473],{"class":239},[233,813,814,817,819,822,824,826,828,830],{"class":235,"line":271},[233,815,816],{"class":359},"xor16",[233,818,453],{"class":239},[233,820,821],{"class":243},"expected",[233,823,464],{"class":239},[233,825,809],{"class":243},[233,827,464],{"class":239},[233,829,786],{"class":243},[233,831,473],{"class":239},[233,833,834,836,839,842,844,846,848,851,853,855,857],{"class":235,"line":278},[233,835,491],{"class":355},[233,837,838],{"class":239}," (!",[233,840,841],{"class":359},"ct_eq",[233,843,453],{"class":239},[233,845,821],{"class":243},[233,847,464],{"class":239},[233,849,850],{"class":243}," tag",[233,852,464],{"class":239},[233,854,381],{"class":243},[233,856,524],{"class":239},[233,858,527],{"class":239},[233,860,861,864,867],{"class":235,"line":287},[233,862,863],{"class":355},"    goto",[233,865,866],{"class":540}," done",[233,868,757],{"class":239},[233,870,871],{"class":235,"line":444},[233,872,559],{"class":239},[233,874,876,879,881,883,885,887,889,891,893,895,897,900],{"class":235,"line":875},10,[233,877,878],{"class":359},"gctr",[233,880,796],{"class":239},[233,882,799],{"class":461},[233,884,464],{"class":239},[233,886,804],{"class":243},[233,888,464],{"class":239},[233,890,776],{"class":243},[233,892,464],{"class":239},[233,894,781],{"class":243},[233,896,464],{"class":239},[233,898,899],{"class":243}," out",[233,901,473],{"class":239},[179,903,904,906],{},[183,905,841],{}," 用 OR 累加差异，不会在第一个不等字节处返回。这样可以降低根据比较耗时猜测 tag 的价值。",[908,909,910,911,914],"warning",{},"GCM 解密失败和「不是 dex」在 Java 侧都会被当成密钥错误（",[183,912,913],{},"INVALID_KEY","）。使用错误密钥时，不会留下半截明文 DEX。",[215,916,918],{"id":917},"确认明文是-dex","确认明文是 dex",[179,920,921,922,925],{},"so 不信任「解密成功」这一结果，还会检查前三个字节是否为 ",[183,923,924],{},"d e x","：",[223,927,929],{"className":481,"code":928,"filename":483,"language":484,"meta":229,"style":229},"if (rc != 0 || out_len != pt_cap || plain == nullptr || out_len \u003C 4 ||\n    plain[0] != 'd' || plain[1] != 'e' || plain[2] != 'x') {\n    return jerr(env, rc != 0 ? \"解密失败\" : \"不是 dex\");\n}\n",[183,930,931,979,1047,1087],{"__ignoreMap":229},[233,932,933,935,937,940,942,944,946,949,951,954,957,960,963,966,968,970,973,976],{"class":235,"line":236},[233,934,491],{"class":355},[233,936,404],{"class":239},[233,938,939],{"class":243},"rc ",[233,941,499],{"class":239},[233,943,740],{"class":363},[233,945,505],{"class":239},[233,947,948],{"class":243}," out_len ",[233,950,499],{"class":239},[233,952,953],{"class":243}," pt_cap ",[233,955,956],{"class":239},"||",[233,958,959],{"class":243}," plain ",[233,961,962],{"class":239},"==",[233,964,965],{"class":239}," nullptr",[233,967,505],{"class":239},[233,969,948],{"class":243},[233,971,972],{"class":239},"\u003C",[233,974,975],{"class":363}," 4",[233,977,978],{"class":239}," ||\n",[233,980,981,984,987,990,993,995,998,1001,1004,1006,1008,1010,1012,1014,1016,1018,1021,1023,1025,1027,1029,1032,1034,1036,1038,1041,1043,1045],{"class":235,"line":247},[233,982,983],{"class":243},"    plain",[233,985,986],{"class":239},"[",[233,988,989],{"class":363},"0",[233,991,992],{"class":239},"]",[233,994,737],{"class":239},[233,996,997],{"class":239}," '",[233,999,1000],{"class":293},"d",[233,1002,1003],{"class":239},"'",[233,1005,505],{"class":239},[233,1007,641],{"class":243},[233,1009,986],{"class":239},[233,1011,754],{"class":363},[233,1013,992],{"class":239},[233,1015,737],{"class":239},[233,1017,997],{"class":239},[233,1019,1020],{"class":293},"e",[233,1022,1003],{"class":239},[233,1024,505],{"class":239},[233,1026,641],{"class":243},[233,1028,986],{"class":239},[233,1030,1031],{"class":363},"2",[233,1033,992],{"class":239},[233,1035,737],{"class":239},[233,1037,997],{"class":239},[233,1039,1040],{"class":293},"x",[233,1042,1003],{"class":239},[233,1044,734],{"class":239},[233,1046,527],{"class":239},[233,1048,1049,1051,1053,1055,1057,1059,1061,1063,1065,1068,1070,1073,1075,1078,1080,1083,1085],{"class":235,"line":253},[233,1050,532],{"class":355},[233,1052,535],{"class":359},[233,1054,453],{"class":239},[233,1056,541],{"class":540},[233,1058,464],{"class":239},[233,1060,605],{"class":540},[233,1062,499],{"class":239},[233,1064,740],{"class":363},[233,1066,1067],{"class":239}," ?",[233,1069,546],{"class":239},[233,1071,1072],{"class":293},"解密失败",[233,1074,552],{"class":239},[233,1076,1077],{"class":239}," :",[233,1079,546],{"class":239},[233,1081,1082],{"class":293},"不是 dex",[233,1084,552],{"class":239},[233,1086,473],{"class":239},[233,1088,1089],{"class":235,"line":259},[233,1090,559],{"class":239},[179,1092,1093,1094,1097],{},"密钥错误、文件被截断，或把其他资源改名为 ",[183,1095,1096],{},"hidden.dex.enc","，都会在这里停止。",[215,1099,1101],{"id":1100},"对照-java-入口","对照 Java 入口",[179,1103,1104],{},"Java 只检查「64 个 hex 字符」，不解析算法：",[223,1106,1111],{"className":1107,"code":1108,"filename":1109,"language":1110,"meta":229,"style":229},"language-kotlin shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","if (!HiddenCrypto.isUsableKey(normalized)) {\n    return HiddenInitResult.invalidKey(\n        \"需要 ${HiddenCrypto.KEY_HEX_LENGTH} 个 hex 字符（32 字节密钥）\",\n    )\n}\nval error = nativeInit(context.applicationContext, normalized)\n","hidden-sdk\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fexample\u002Fminidex\u002Fsdk\u002FHiddenSdk.kt","kotlin",[183,1112,1113,1131,1143,1163,1168,1172],{"__ignoreMap":229},[233,1114,1115,1117,1119,1122,1125,1128],{"class":235,"line":236},[233,1116,491],{"class":355},[233,1118,404],{"class":243},[233,1120,1121],{"class":239},"!",[233,1123,1124],{"class":243},"HiddenCrypto.",[233,1126,1127],{"class":359},"isUsableKey",[233,1129,1130],{"class":243},"(normalized)) {\n",[233,1132,1133,1135,1138,1141],{"class":235,"line":247},[233,1134,532],{"class":355},[233,1136,1137],{"class":243}," HiddenInitResult.",[233,1139,1140],{"class":359},"invalidKey",[233,1142,612],{"class":243},[233,1144,1145,1148,1151,1154,1157,1160],{"class":235,"line":253},[233,1146,1147],{"class":293},"        \"需要 ",[233,1149,1150],{"class":239},"${",[233,1152,1153],{"class":243},"HiddenCrypto.KEY_HEX_LENGTH",[233,1155,1156],{"class":239},"}",[233,1158,1159],{"class":293}," 个 hex 字符（32 字节密钥）\"",[233,1161,1162],{"class":243},",\n",[233,1164,1165],{"class":235,"line":259},[233,1166,1167],{"class":243},"    )\n",[233,1169,1170],{"class":235,"line":265},[233,1171,559],{"class":243},[233,1173,1174,1177,1180,1182,1185],{"class":235,"line":271},[233,1175,1176],{"class":239},"val",[233,1178,1179],{"class":243}," error ",[233,1181,572],{"class":239},[233,1183,1184],{"class":359}," nativeInit",[233,1186,1187],{"class":243},"(context.applicationContext, normalized)\n",[179,1189,1190,1193,1194,1197,1198,186],{},[183,1191,1192],{},"HiddenCrypto.ASSET_PATH"," 仍写着 ",[183,1195,1196],{},"\"payload\u002Fhidden.dex.enc\"","，供文档和旧代码对照。真正打开 assets 的路径在 so 里做 XOR，见 ",[1199,1200,1201],"a",{"href":79},"XOR混淆",[215,1203,1204],{"id":1204},"下一步",[1206,1207,1208,1218],"ul",{},[1209,1210,1211,1214,1215],"li",{},[1199,1212,1213],{"href":69},"内存加载","：明文如何交给 ",[183,1216,1217],{},"InMemoryDexClassLoader",[1209,1219,1220,1222],{},[1199,1221,1201],{"href":79},"：路径和类名为什么不写明文字符串",[1224,1225,1226],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":229,"searchDepth":247,"depth":247,"links":1228},[1229,1230,1231,1232,1233,1234],{"id":217,"depth":247,"text":218},{"id":339,"depth":247,"text":339},{"id":696,"depth":247,"text":697},{"id":917,"depth":247,"text":918},{"id":1100,"depth":247,"text":1101},{"id":1204,"depth":247,"text":1204},"libhiddendecrypt.so 自实现 AES-256-GCM。Java 不接触明文 DEX，用完立刻清零。","md",[1238,1239],{"label":59,"icon":21,"to":60},{"label":68,"icon":71,"to":69},{"date":1241,"categories":1242,"tags":1244},"2026-09-21",[1243],"android",[37,1245,1246],"JNI","AES-GCM",{"icon":66},{"title":1249,"description":1250},"安卓代码加固（2）：Native AES-256-GCM 解密 Hidden DEX","hidden-dex-minidemo 在 libhiddendecrypt.so 里自实现 AES-256-GCM，校验 HDX1 与 tag。成功后才把明文交给 InMemoryDexClassLoader。","7Qnd5BDURSWCxREZQMChVG6T0BSXQwnrRe2asCD6A-Q",[1253,1255],{"title":59,"path":60,"stem":61,"description":1254,"icon":21},"构建期把 :hidden-landing-page 打成 AES-256-GCM 密文，以 HDX1 头写入 AAR assets。",{"title":68,"path":69,"stem":70,"description":1256,"icon":71},"解密后的 dex 只存在于 ByteBuffer 中，用 InMemoryDexClassLoader 加载，不写入 filesDir。",1790767045965]