[{"data":1,"prerenderedAt":1152},["ShallowReactive",2],{"navigation_docs":3,"-android-hidden-hardening-memory-load":173,"-android-hidden-hardening-memory-load-surround":1147},[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":68,"body":175,"description":1130,"extension":1131,"links":1132,"meta":1135,"navigation":1142,"path":69,"seo":1143,"stem":70,"__hash__":1146},"docs\u002F3.android\u002F02.hidden-hardening\u002F03.memory-load.md",{"type":176,"value":177,"toc":1123},"minimark",[178,203,214,219,233,473,488,599,615,618,625,792,847,865,868,874,991,1001,1012,1015,1037,1096,1099,1102,1119],[179,180,181,182,186,187,190,191,194,195,198,199,202],"p",{},"常见动态加载会把 dex 写到 ",[183,184,185],"code",{},"getDir(\"dex\", …)","，再用 ",[183,188,189],{},"DexClassLoader"," 加载。这份工程不这样做。明文只存在 native 堆和一块 Java ",[183,192,193],{},"byte[]"," 里，随即 ",[183,196,197],{},"ByteBuffer.wrap","，交给 ",[183,200,201],{},"dalvik.system.InMemoryDexClassLoader","。",[204,205,206,209,210,213],"tip",{},[183,207,208],{},"InMemoryDexClassLoader"," 需要 API 26。这也是 ",[183,211,212],{},"minSdk 26"," 的原因之一。",[215,216,218],"h2",{"id":217},"把明文交给-classloader","把明文交给 ClassLoader",[179,220,221,224,225,228,229,232],{},[183,222,223],{},"nativeInit"," 确认文件头是 ",[183,226,227],{},"dex"," 后，把 C 缓冲拷进 ",[183,230,231],{},"jbyteArray","，并立即清除 C 侧明文：",[234,235,241],"pre",{"className":236,"code":237,"filename":238,"language":239,"meta":240,"style":240},"language-cpp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","jbyteArray arr = env->NewByteArray(static_cast\u003Cjsize>(out_len));\nenv->SetByteArrayRegion(arr, 0, static_cast\u003Cjsize>(out_len),\n                        reinterpret_cast\u003Cjbyte *>(plain));\nhidden_secure_zero(plain, pt_cap);\nfree(plain);\n\njclass buf_cls = env->FindClass(\"java\u002Fnio\u002FByteBuffer\");\njmethodID wrap = env->GetStaticMethodID(buf_cls, \"wrap\", \"([B)Ljava\u002Fnio\u002FByteBuffer;\");\njobject buffer = env->CallStaticObjectMethod(buf_cls, wrap, arr);\n","hidden-sdk\u002Fsrc\u002Fmain\u002Fcpp\u002Fhidden_bridge.cpp","cpp","",[183,242,243,281,319,336,354,366,373,401,442],{"__ignoreMap":240},[244,245,248,252,256,259,262,266,269,272,275,278],"span",{"class":246,"line":247},"line",1,[244,249,251],{"class":250},"sTEyZ","jbyteArray arr ",[244,253,255],{"class":254},"sMK4o","=",[244,257,258],{"class":250}," env",[244,260,261],{"class":254},"->",[244,263,265],{"class":264},"s2Zo4","NewByteArray",[244,267,268],{"class":254},"(static_cast\u003C",[244,270,271],{"class":250},"jsize",[244,273,274],{"class":254},">(",[244,276,277],{"class":250},"out_len",[244,279,280],{"class":254},"));\n",[244,282,284,287,289,292,295,298,301,305,307,310,312,314,316],{"class":246,"line":283},2,[244,285,286],{"class":250},"env",[244,288,261],{"class":254},[244,290,291],{"class":264},"SetByteArrayRegion",[244,293,294],{"class":254},"(",[244,296,297],{"class":250},"arr",[244,299,300],{"class":254},",",[244,302,304],{"class":303},"sbssI"," 0",[244,306,300],{"class":254},[244,308,309],{"class":254}," static_cast\u003C",[244,311,271],{"class":250},[244,313,274],{"class":254},[244,315,277],{"class":250},[244,317,318],{"class":254},"),\n",[244,320,322,325,328,331,334],{"class":246,"line":321},3,[244,323,324],{"class":254},"                        reinterpret_cast\u003C",[244,326,327],{"class":250},"jbyte ",[244,329,330],{"class":254},"*>(",[244,332,333],{"class":250},"plain",[244,335,280],{"class":254},[244,337,339,342,344,346,348,351],{"class":246,"line":338},4,[244,340,341],{"class":264},"hidden_secure_zero",[244,343,294],{"class":254},[244,345,333],{"class":250},[244,347,300],{"class":254},[244,349,350],{"class":250}," pt_cap",[244,352,353],{"class":254},");\n",[244,355,357,360,362,364],{"class":246,"line":356},5,[244,358,359],{"class":264},"free",[244,361,294],{"class":254},[244,363,333],{"class":250},[244,365,353],{"class":254},[244,367,369],{"class":246,"line":368},6,[244,370,372],{"emptyLinePlaceholder":371},true,"\n",[244,374,376,379,381,383,385,388,390,393,397,399],{"class":246,"line":375},7,[244,377,378],{"class":250},"jclass buf_cls ",[244,380,255],{"class":254},[244,382,258],{"class":250},[244,384,261],{"class":254},[244,386,387],{"class":264},"FindClass",[244,389,294],{"class":254},[244,391,392],{"class":254},"\"",[244,394,396],{"class":395},"sfazB","java\u002Fnio\u002FByteBuffer",[244,398,392],{"class":254},[244,400,353],{"class":254},[244,402,404,407,409,411,413,416,418,421,423,426,429,431,433,435,438,440],{"class":246,"line":403},8,[244,405,406],{"class":250},"jmethodID wrap ",[244,408,255],{"class":254},[244,410,258],{"class":250},[244,412,261],{"class":254},[244,414,415],{"class":264},"GetStaticMethodID",[244,417,294],{"class":254},[244,419,420],{"class":250},"buf_cls",[244,422,300],{"class":254},[244,424,425],{"class":254}," \"",[244,427,428],{"class":395},"wrap",[244,430,392],{"class":254},[244,432,300],{"class":254},[244,434,425],{"class":254},[244,436,437],{"class":395},"([B)Ljava\u002Fnio\u002FByteBuffer;",[244,439,392],{"class":254},[244,441,353],{"class":254},[244,443,445,448,450,452,454,457,459,461,463,466,468,471],{"class":246,"line":444},9,[244,446,447],{"class":250},"jobject buffer ",[244,449,255],{"class":254},[244,451,258],{"class":250},[244,453,261],{"class":254},[244,455,456],{"class":264},"CallStaticObjectMethod",[244,458,294],{"class":254},[244,460,420],{"class":250},[244,462,300],{"class":254},[244,464,465],{"class":250}," wrap",[244,467,300],{"class":254},[244,469,470],{"class":250}," arr",[244,472,353],{"class":254},[179,474,475,476,479,480,483,484,487],{},"父 ClassLoader 来自 ",[183,477,478],{},"context.getClassLoader()","。实现类以 ",[183,481,482],{},"compileOnly"," 依赖的 ",[183,485,486],{},"HiddenIncomingKeepAlive"," 位于主 DEX，必须能从父 loader 解析。",[234,489,491],{"className":236,"code":490,"filename":238,"language":239,"meta":240,"style":240},"jclass loader_cls = env->FindClass(\"dalvik\u002Fsystem\u002FInMemoryDexClassLoader\");\njmethodID loader_ctor = env->GetMethodID(\n        loader_cls, \"\u003Cinit>\",\n        \"(Ljava\u002Fnio\u002FByteBuffer;Ljava\u002Flang\u002FClassLoader;)V\");\njobject loader = env->NewObject(loader_cls, loader_ctor, buffer, parent);\n",[183,492,493,517,534,551,563],{"__ignoreMap":240},[244,494,495,498,500,502,504,506,508,510,513,515],{"class":246,"line":247},[244,496,497],{"class":250},"jclass loader_cls ",[244,499,255],{"class":254},[244,501,258],{"class":250},[244,503,261],{"class":254},[244,505,387],{"class":264},[244,507,294],{"class":254},[244,509,392],{"class":254},[244,511,512],{"class":395},"dalvik\u002Fsystem\u002FInMemoryDexClassLoader",[244,514,392],{"class":254},[244,516,353],{"class":254},[244,518,519,522,524,526,528,531],{"class":246,"line":283},[244,520,521],{"class":250},"jmethodID loader_ctor ",[244,523,255],{"class":254},[244,525,258],{"class":250},[244,527,261],{"class":254},[244,529,530],{"class":264},"GetMethodID",[244,532,533],{"class":254},"(\n",[244,535,536,539,541,543,546,548],{"class":246,"line":321},[244,537,538],{"class":250},"        loader_cls",[244,540,300],{"class":254},[244,542,425],{"class":254},[244,544,545],{"class":395},"\u003Cinit>",[244,547,392],{"class":254},[244,549,550],{"class":254},",\n",[244,552,553,556,559,561],{"class":246,"line":338},[244,554,555],{"class":254},"        \"",[244,557,558],{"class":395},"(Ljava\u002Fnio\u002FByteBuffer;Ljava\u002Flang\u002FClassLoader;)V",[244,560,392],{"class":254},[244,562,353],{"class":254},[244,564,565,568,570,572,574,577,579,582,584,587,589,592,594,597],{"class":246,"line":356},[244,566,567],{"class":250},"jobject loader ",[244,569,255],{"class":254},[244,571,258],{"class":250},[244,573,261],{"class":254},[244,575,576],{"class":264},"NewObject",[244,578,294],{"class":254},[244,580,581],{"class":250},"loader_cls",[244,583,300],{"class":254},[244,585,586],{"class":250}," loader_ctor",[244,588,300],{"class":254},[244,590,591],{"class":250}," buffer",[244,593,300],{"class":254},[244,595,596],{"class":250}," parent",[244,598,353],{"class":254},[600,601,602,603,606,607,610,611,614],"warning",{},"Java 侧注释仍写「把结果交给 InMemoryDexClassLoader」，但 ",[183,604,605],{},"HiddenSdk"," 已经不再调用 ",[183,608,609],{},"HiddenDecrypt","，也不再自行 ",[183,612,613],{},"loadClass","。加载、查找类、构造实例都在 so 里完成。反编译主 DEX 看不到实现类名。",[215,616,617],{"id":617},"构造实现对象",[179,619,620,621,624],{},"类名同样以 XOR 存放。解码后调用 ",[183,622,623],{},"ClassLoader.loadClass","，再做无参构造，并保留三个 GlobalRef：",[234,626,628],{"className":236,"code":627,"filename":238,"language":239,"meta":240,"style":240},"jobject impl_obj = env->CallObjectMethod(loader, load_class, jname);\njmethodID ctor = env->GetMethodID(impl, \"\u003Cinit>\", \"()V\");\njobject instance = env->NewObject(impl, ctor);\n\ng_loader = env->NewGlobalRef(loader);\ng_impl_class = static_cast\u003Cjclass>(env->NewGlobalRef(impl));\ng_instance = env->NewGlobalRef(instance);\n",[183,629,630,661,698,722,726,746,772],{"__ignoreMap":240},[244,631,632,635,637,639,641,644,646,649,651,654,656,659],{"class":246,"line":247},[244,633,634],{"class":250},"jobject impl_obj ",[244,636,255],{"class":254},[244,638,258],{"class":250},[244,640,261],{"class":254},[244,642,643],{"class":264},"CallObjectMethod",[244,645,294],{"class":254},[244,647,648],{"class":250},"loader",[244,650,300],{"class":254},[244,652,653],{"class":250}," load_class",[244,655,300],{"class":254},[244,657,658],{"class":250}," jname",[244,660,353],{"class":254},[244,662,663,666,668,670,672,674,676,679,681,683,685,687,689,691,694,696],{"class":246,"line":283},[244,664,665],{"class":250},"jmethodID ctor ",[244,667,255],{"class":254},[244,669,258],{"class":250},[244,671,261],{"class":254},[244,673,530],{"class":264},[244,675,294],{"class":254},[244,677,678],{"class":250},"impl",[244,680,300],{"class":254},[244,682,425],{"class":254},[244,684,545],{"class":395},[244,686,392],{"class":254},[244,688,300],{"class":254},[244,690,425],{"class":254},[244,692,693],{"class":395},"()V",[244,695,392],{"class":254},[244,697,353],{"class":254},[244,699,700,703,705,707,709,711,713,715,717,720],{"class":246,"line":321},[244,701,702],{"class":250},"jobject instance ",[244,704,255],{"class":254},[244,706,258],{"class":250},[244,708,261],{"class":254},[244,710,576],{"class":264},[244,712,294],{"class":254},[244,714,678],{"class":250},[244,716,300],{"class":254},[244,718,719],{"class":250}," ctor",[244,721,353],{"class":254},[244,723,724],{"class":246,"line":338},[244,725,372],{"emptyLinePlaceholder":371},[244,727,728,731,733,735,737,740,742,744],{"class":246,"line":356},[244,729,730],{"class":250},"g_loader ",[244,732,255],{"class":254},[244,734,258],{"class":250},[244,736,261],{"class":254},[244,738,739],{"class":264},"NewGlobalRef",[244,741,294],{"class":254},[244,743,648],{"class":250},[244,745,353],{"class":254},[244,747,748,751,753,755,758,760,762,764,766,768,770],{"class":246,"line":368},[244,749,750],{"class":250},"g_impl_class ",[244,752,255],{"class":254},[244,754,309],{"class":254},[244,756,757],{"class":250},"jclass",[244,759,274],{"class":254},[244,761,286],{"class":250},[244,763,261],{"class":254},[244,765,739],{"class":264},[244,767,294],{"class":254},[244,769,678],{"class":250},[244,771,280],{"class":254},[244,773,774,777,779,781,783,785,787,790],{"class":246,"line":375},[244,775,776],{"class":250},"g_instance ",[244,778,255],{"class":254},[244,780,258],{"class":250},[244,782,261],{"class":254},[244,784,739],{"class":264},[244,786,294],{"class":254},[244,788,789],{"class":250},"instance",[244,791,353],{"class":254},[793,794,795,808],"table",{},[796,797,798],"thead",{},[799,800,801,805],"tr",{},[802,803,804],"th",{},"全局引用",[802,806,807],{},"作用",[809,810,811,822,837],"tbody",{},[799,812,813,819],{},[814,815,816],"td",{},[183,817,818],{},"g_loader",[814,820,821],{},"保住 ClassLoader，避免实现类被回收",[799,823,824,829],{},[814,825,826],{},[183,827,828],{},"g_impl_class",[814,830,831,834,835],{},[183,832,833],{},"nativeDispatch"," 用来 ",[183,836,530],{},[799,838,839,844],{},[814,840,841],{},[183,842,843],{},"g_instance",[814,845,846],{},"单例实现对象",[179,848,849,852,853,856,857,860,861,864],{},[183,850,851],{},"nativeReady"," 只看 ",[183,854,855],{},"g_instance != nullptr","。Java 的 ",[183,858,859],{},"ready()"," \u002F ",[183,862,863],{},"isInitialized()"," 都走这条 JNI，不在 Java 堆上再存一份「已加载」标志。",[215,866,867],{"id":867},"对照实现类约束",[179,869,870,871,873],{},"加密 dex 里的入口类必须使用无参构造，方法名也必须保持稳定，因为 so 用 ",[183,872,530],{}," 按名称查找：",[234,875,880],{"className":876,"code":877,"filename":878,"language":879,"meta":240,"style":240},"language-kotlin shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","class HiddenLandingPage {\n    val abiVersion: Int = 12\n\n    fun configure(landingActivityClassName: String?) { ... }\n    fun registerPhoneAccount(context: Context): Boolean = ...\n    fun startIncomingCall(context: Context): Boolean = ...\n}\n","hidden-landing-page\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fexample\u002Fminidex\u002Fhidden\u002FHiddenLandingPage.kt","kotlin",[183,881,882,894,911,915,938,965,986],{"__ignoreMap":240},[244,883,884,887,891],{"class":246,"line":247},[244,885,886],{"class":254},"class",[244,888,890],{"class":889},"sBMFI"," HiddenLandingPage",[244,892,893],{"class":250}," {\n",[244,895,896,899,902,905,908],{"class":246,"line":283},[244,897,898],{"class":254},"    val",[244,900,901],{"class":250}," abiVersion: ",[244,903,904],{"class":889},"Int",[244,906,907],{"class":254}," =",[244,909,910],{"class":303}," 12\n",[244,912,913],{"class":246,"line":321},[244,914,372],{"emptyLinePlaceholder":371},[244,916,917,920,923,926,929,932,935],{"class":246,"line":338},[244,918,919],{"class":254},"    fun",[244,921,922],{"class":264}," configure",[244,924,925],{"class":250},"(landingActivityClassName: ",[244,927,928],{"class":889},"String",[244,930,931],{"class":250},"?) { ",[244,933,934],{"class":254},"..",[244,936,937],{"class":250},". }\n",[244,939,940,942,945,948,951,954,957,959,962],{"class":246,"line":356},[244,941,919],{"class":254},[244,943,944],{"class":264}," registerPhoneAccount",[244,946,947],{"class":250},"(context: ",[244,949,950],{"class":889},"Context",[244,952,953],{"class":250},"): ",[244,955,956],{"class":889},"Boolean",[244,958,907],{"class":254},[244,960,961],{"class":254}," ..",[244,963,964],{"class":250},".\n",[244,966,967,969,972,974,976,978,980,982,984],{"class":246,"line":368},[244,968,919],{"class":254},[244,970,971],{"class":264}," startIncomingCall",[244,973,947],{"class":250},[244,975,950],{"class":889},[244,977,953],{"class":250},[244,979,956],{"class":889},[244,981,907],{"class":254},[244,983,961],{"class":254},[244,985,964],{"class":250},[244,987,988],{"class":246,"line":375},[244,989,990],{"class":250},"}\n",[179,992,993,994,997,998,202],{},"KDoc 写明了约束：不要加构造参数，不要改方法名，不要对 ",[183,995,996],{},":hidden-sdk"," 使用 ",[183,999,1000],{},"implementation",[1002,1003,1004,1005,1008,1009,1011],"note",{},"系统能按清单绑定的组件（",[183,1006,1007],{},"ConnectionService","、来电路由页）必须留在主 DEX。",[183,1010,208],{}," 加载的类不能写进 Manifest 当导出组件。",[215,1013,1014],{"id":1014},"处理失败回滚",[179,1016,1017,1018,1021,1022,1025,1026,1029,1030,1032,1033,1036],{},"加载过程中任一步失败，",[183,1019,1020],{},"release_locked"," 会 ",[183,1023,1024],{},"DeleteGlobalRef"," 这三个引用。进程内可以再次 ",[183,1027,1028],{},"init","。一旦成功，再次 ",[183,1031,1028],{}," 会直接返回 ",[183,1034,1035],{},"ALREADY_INITIALIZED","，不会用新密钥重新解密。",[234,1038,1041],{"className":876,"code":1039,"filename":1040,"language":879,"meta":240,"style":240},"if (nativeReady()) {\n    val already = HiddenInitResult.alreadyInitialized()\n    initResult = already\n    return already\n}\n","hidden-sdk\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Fexample\u002Fminidex\u002Fsdk\u002FHiddenSdk.kt",[183,1042,1043,1057,1075,1085,1092],{"__ignoreMap":240},[244,1044,1045,1049,1052,1054],{"class":246,"line":247},[244,1046,1048],{"class":1047},"s7zQu","if",[244,1050,1051],{"class":250}," (",[244,1053,851],{"class":264},[244,1055,1056],{"class":250},"()) {\n",[244,1058,1059,1061,1064,1066,1069,1072],{"class":246,"line":283},[244,1060,898],{"class":254},[244,1062,1063],{"class":250}," already ",[244,1065,255],{"class":254},[244,1067,1068],{"class":250}," HiddenInitResult.",[244,1070,1071],{"class":264},"alreadyInitialized",[244,1073,1074],{"class":250},"()\n",[244,1076,1077,1080,1082],{"class":246,"line":321},[244,1078,1079],{"class":250},"    initResult ",[244,1081,255],{"class":254},[244,1083,1084],{"class":250}," already\n",[244,1086,1087,1090],{"class":246,"line":338},[244,1088,1089],{"class":1047},"    return",[244,1091,1084],{"class":250},[244,1093,1094],{"class":246,"line":356},[244,1095,990],{"class":250},[179,1097,1098],{},"要更换密钥，只能结束进程。这样可以避免运行中途用错误密钥替换已加载的实现。",[215,1100,1101],{"id":1101},"下一步",[1103,1104,1105,1113],"ul",{},[1106,1107,1108,1112],"li",{},[1109,1110,1111],"a",{"href":74},"指令分发","：加载成功后如何按整数调用方法",[1106,1114,1115,1118],{},[1109,1116,1117],{"href":104},"ABI门禁","：构造之后立刻核对版本",[1120,1121,1122],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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}",{"title":240,"searchDepth":283,"depth":283,"links":1124},[1125,1126,1127,1128,1129],{"id":217,"depth":283,"text":218},{"id":617,"depth":283,"text":617},{"id":867,"depth":283,"text":867},{"id":1014,"depth":283,"text":1014},{"id":1101,"depth":283,"text":1101},"解密后的 dex 只存在于 ByteBuffer 中，用 InMemoryDexClassLoader 加载，不写入 filesDir。","md",[1133,1134],{"label":63,"icon":66,"to":64},{"label":73,"icon":76,"to":74},{"date":1136,"categories":1137,"tags":1139},"2026-09-21",[1138],"android",[37,1140,1141],"ClassLoader","DEX",{"icon":71},{"title":1144,"description":1145},"安卓代码加固（3）：用 InMemoryDexClassLoader 加载加密 DEX","hidden-dex-minidemo 解密后不落盘，把明文包进 ByteBuffer，交给 InMemoryDexClassLoader，再 loadClass HiddenLandingPage。","UEsGiGQnoK7NYqIAHTp57XLEEHK2p_9Qio4uTV3bzw0",[1148,1150],{"title":63,"path":64,"stem":65,"description":1149,"icon":66},"libhiddendecrypt.so 自实现 AES-256-GCM。Java 不接触明文 DEX，用完立刻清零。",{"title":73,"path":74,"stem":75,"description":1151,"icon":76},"公开入口只有 invoke(Int, Any?, Any?)。指令含义不进入 AAR，native 按整数查找方法。",1790767046164]