├── .gitignore ├── 001_frida-stalker-recompile-fix ├── .gitignore ├── README.md ├── app-debug.apk ├── app │ ├── .gitignore │ ├── app │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── cpp │ │ │ ├── CMakeLists.txt │ │ │ └── test_frida.cpp │ │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── frida_stalker_recompile_fix │ │ │ │ ├── MainActivity.kt │ │ │ │ └── ui │ │ │ │ └── theme │ │ │ │ ├── Color.kt │ │ │ │ ├── Theme.kt │ │ │ │ └── Type.kt │ │ │ └── res │ │ │ ├── drawable │ │ │ ├── ic_launcher_background.xml │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── mipmap-anydpi │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.webp │ │ │ └── ic_launcher_round.webp │ │ │ ├── values │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ │ └── xml │ │ │ ├── backup_rules.xml │ │ │ └── data_extraction_rules.xml │ ├── build.gradle.kts │ ├── gradle.properties │ ├── gradle │ │ ├── libs.versions.toml │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── docs │ ├── 001-正常执行.jpg │ ├── 002-frida-stalker原版.jpg │ └── 003-frida-stalker修复.jpg ├── expect_run_server.sh ├── index.ts ├── package.json ├── run_test_fix.sh └── tsconfig.json ├── 002_frida-analykit-ssl-log-secret ├── .gitignore ├── README.md ├── app-debug.apk ├── app │ ├── .gitignore │ ├── app │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── androidTest │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── frida_analykit │ │ │ │ └── ssl_log_secret │ │ │ │ └── ExampleInstrumentedTest.kt │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── frida_analykit │ │ │ │ │ └── ssl_log_secret │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ └── ui │ │ │ │ │ └── theme │ │ │ │ │ ├── Color.kt │ │ │ │ │ ├── Theme.kt │ │ │ │ │ └── Type.kt │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ └── ic_launcher_foreground.xml │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ │ ├── values │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ │ └── xml │ │ │ │ ├── backup_rules.xml │ │ │ │ ├── data_extraction_rules.xml │ │ │ │ └── network_security_config.xml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── frida_analykit │ │ │ └── ssl_log_secret │ │ │ └── ExampleUnitTest.kt │ ├── build.gradle.kts │ ├── gradle.properties │ ├── gradle │ │ ├── libs.versions.toml │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── docs │ ├── 001-wireshark中配置sslkey_log文件的位置.png │ ├── 002-wireshark中的client_random位置.png │ ├── 003-测试样本app功能说明.png │ ├── 004-wireshark选择捕获热点网卡的流量.png │ ├── 005-wireshark抓包解密后的http协议流量.png │ ├── 006-发起请求.png │ ├── 007-frida-analykit注入控制台输出.png │ ├── 008-wireshark抓包开启了ssl-pinning的流量.png │ ├── 009-charles中间人代理抓包开启了ssl-pinning的客户端.png │ └── 010-中间人代理抓包开启了ssl-pinning的客户端.png └── index.ts ├── 003_frida-analykit-static-linked-boringssl ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── app │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ ├── release │ │ │ ├── baselineProfiles │ │ │ │ ├── 0 │ │ │ │ │ └── app-release.dm │ │ │ │ └── 1 │ │ │ │ │ └── app-release.dm │ │ │ └── output-metadata.json │ │ └── src │ │ │ ├── androidTest │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── frida_analykit │ │ │ │ └── static_linked_boringssl │ │ │ │ └── ExampleInstrumentedTest.kt │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── frida_analykit │ │ │ │ │ └── static_linked_boringssl │ │ │ │ │ ├── MainActivity.kt │ │ │ │ │ ├── WebViewActivity.kt │ │ │ │ │ └── ui │ │ │ │ │ └── theme │ │ │ │ │ ├── Color.kt │ │ │ │ │ ├── Theme.kt │ │ │ │ │ └── Type.kt │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ └── ic_launcher_foreground.xml │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.webp │ │ │ │ └── ic_launcher_round.webp │ │ │ │ ├── values │ │ │ │ ├── colors.xml │ │ │ │ ├── strings.xml │ │ │ │ └── themes.xml │ │ │ │ └── xml │ │ │ │ ├── backup_rules.xml │ │ │ │ ├── data_extraction_rules.xml │ │ │ │ └── network_security_config.xml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── frida_analykit │ │ │ └── static_linked_boringssl │ │ │ └── ExampleUnitTest.kt │ ├── build.gradle.kts │ ├── flutter_module │ │ ├── .gitignore │ │ ├── .metadata │ │ ├── README.md │ │ ├── analysis_options.yaml │ │ ├── lib │ │ │ └── main.dart │ │ ├── pubspec.lock │ │ ├── pubspec.yaml │ │ └── test │ │ │ └── widget_test.dart │ ├── gradle.properties │ ├── gradle │ │ ├── libs.versions.toml │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── docs │ ├── 001-ssl_log_secret函数引用.png │ ├── 002-CLIENT_RANDOM字符串搜索.png │ ├── 003-CLIENT_RANDOM字符串引用指令.png │ ├── 004-测试样本app.png │ ├── 005-开启frida-server和启动实时编译.png │ ├── 006-注入三个场景的boringssl.png │ ├── 007-webview的wireshark抓包案例.png │ ├── 008-flutter中的dart发起请求的wireshark抓包案例.png │ └── 009-java层okhttp发起请求的wireshark抓包案例.png ├── index.ts └── samples │ ├── app-release.apk │ └── libssl.so └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vscode -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | package-lock.json 3 | .DS_Store 4 | /test/* 5 | .idea/ -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/README.md: -------------------------------------------------------------------------------- 1 | 2 | # frida基于bug的Stalker跟踪检测和修复 3 | 4 | ## 前言 5 | > Stalker 是 Frida 内部的一个模块用于动态追踪目标程序的执行流程,也就是当我们需要知道: 6 | > - 函数是怎么调用的? 7 | > - 指令是怎么一步步执行的? 8 | > - 分支是怎么跳转的? 9 | > - 有哪些函数是频繁被调用的? 10 | > 11 | > 的时候,会用到`Stalker.follow`跟踪线程将要执行的指令,可以对指令动态插桩修改。对莫名其妙的反调试行为来说,是一个通用的兜底窥探方案。 12 | 13 | ## stalker跟踪检测 14 | > 关于stalker参考官方文档: https://frida.re/docs/stalker/ 15 | 16 | **注: 这个检测手段仅对于在开启`Stalker.follow`跟踪的线程生效** 17 | 18 | - 原理:stalker会对执行过的内存地址(`block->real_start`)存储的指令会进行缓存,当再次进入要执行同一个地址的指令的时候,通过比对内存和缓存中的指令来确定是否需要重编译`block`来确保执行到正确的原指令 - 本应该是如此,但是正如标题所说,这个检测依赖当前`frida-gum`项目的`stalker`的重编译bug,而这个bug就出现在比对和重编译上,导致了当执行同一个内存地址的`block`时候,实际指令都是在跟第一次编译后的缓存`block`的原指令快照进行比对。所以这样的后果就是显而易见的,初次执行该内存地址的指令会一直存在于`stalker`的"阴影中",下面我会用一个测试例子来说明这个现象。 19 | 20 | 以上的场景说明存在简化,实际的问题路径在下面对应的代码: 21 | 1. [指令比对](https://github.com/frida/frida-gum/blob/main/gum/backend-arm64/gumstalker-arm64.c#L2596) 22 | 2. [block重编译](https://github.com/frida/frida-gum/blob/main/gum/backend-arm64/gumstalker-arm64.c#L2635) 23 | 24 | 25 | ### 通过下面一个例子来验证这个问题 26 | 27 | 28 | - 为了利用上面这个bug,我们可以简单的实现两个函数,一个函数(`add_99_func`)是对传递的第一个参数+99,另一个函数(`empty_func`)是不做任何操作直接返回原参数。 29 | 30 | ```c 31 | uint64_t add_99_func(uint64_t count) { 32 | return count + 99; 33 | } 34 | 35 | // 对应的汇编可以是: 36 | // add x0, x0, #99 37 | // ret 38 | 39 | ``` 40 | 41 | ```c 42 | uint64 empty_func(uint64_t count){ 43 | return count; 44 | } 45 | 46 | // 对应的汇编可以是: 47 | // ret 48 | ``` 49 | 50 | - 使用`mmap`来创建指定内存块用于复写和执行指令 51 | ```c 52 | 53 | static void *exec_addr = nullptr; 54 | 55 | // insnBytes: 要写入的指令字节数组 56 | // num: 调用func传递的count值 57 | jstring mmap_exec(JNIEnv *env, jobject thiz, jbyteArray insnBytes, jint num) { 58 | size_t page_size = sysconf(_SC_PAGE_SIZE); 59 | if (page_size == -1) { 60 | std::cerr << "Failed to get page size!" << std::endl; 61 | return nullptr; 62 | } 63 | 64 | void *start_addr = exec_addr; 65 | int flags = MAP_ANON | MAP_PRIVATE; 66 | if (start_addr != nullptr) { 67 | flags |= MAP_FIXED; 68 | } 69 | void *mem = mmap( 70 | start_addr, page_size, PROT_READ | PROT_WRITE | PROT_EXEC, 71 | flags, -1, 0); 72 | if (mem == MAP_FAILED) { 73 | std::cerr << "mmap failed!" << std::endl; 74 | exec_addr = nullptr; 75 | return nullptr; 76 | } 77 | if (exec_addr == nullptr) { 78 | exec_addr = mem; // 下次也使用同一内存地址来写入指令 79 | } 80 | jsize length = env->GetArrayLength((insnBytes)); 81 | 82 | jbyte *code = env->GetByteArrayElements(insnBytes, nullptr); 83 | std::memcpy(mem, code, length); 84 | 85 | aarch64_sync_cache_range(mem, page_size); // 刷新cpu指令和内存数据缓存 86 | 87 | func_t func = reinterpret_cast(mem); 88 | 89 | uint64_t sum = func(num); // 调用函数 90 | 91 | munmap(mem, page_size); 92 | 93 | env->ReleaseByteArrayElements(insnBytes, code, 0); 94 | 95 | char buff[128]; 96 | std::sprintf(buff, "[%p] sum[%lu]", mem, sum); 97 | 98 | return env->NewStringUTF(buff); 99 | } 100 | 101 | 102 | // jni native 103 | __attribute__((visibility("default"))) 104 | JNIEXPORT jobjectArray JNICALL 105 | Java_com_example_frida_1stalker_1recompile_1fix_MainActivity_mmapExec( 106 | JNIEnv *env, jobject thiz, jbyteArray inst1, jbyteArray inst2, jint base_num) { 107 | jclass stringCls = env->FindClass("java/lang/String"); 108 | const jsize test_num = 20; 109 | jobjectArray resultArray = env->NewObjectArray(test_num, stringCls, nullptr); 110 | // 每点击一次按钮,遍历交替复写执行20次 111 | for(jsize i = 0; i < test_num; i++) { 112 | jbyteArray inst = i % 2 == 0 ? inst1 : inst2; 113 | jstring result1 = mmap_exec(env, thiz, inst, base_num); 114 | env->SetObjectArrayElement(resultArray, i, result1); 115 | } 116 | return resultArray; 117 | } 118 | 119 | ``` 120 | 121 | - frida测试脚本 122 | ```typescript 123 | setImmediate(() => { 124 | Interceptor.attach( 125 | Module.getExportByName('libdl.so', 'android_dlopen_ext'), { 126 | onEnter(args) { 127 | this.filename = args[0].readCString() 128 | console.error(`[android_dlopen_ext] ${this.filename}`) 129 | }, 130 | onLeave(retval) { 131 | const filename: string = this.filename 132 | if(filename.includes('libtest_frida.so')) { 133 | attachMmapExec(Process.findModuleByName(filename)!) 134 | } 135 | }, 136 | } 137 | ) 138 | 139 | function attachMmapExec(mod: Module) { 140 | console.error(`[attachMmapExec] ${JSON.stringify(mod)}`) 141 | const target = mod.getExportByName("Java_com_example_frida_1stalker_1recompile_1fix_MainActivity_mmapExec") 142 | Interceptor.attach(target, { 143 | onEnter(args) { 144 | console.log(`[mmap_exec] follow => tid[${Process.getCurrentThreadId()}]`) 145 | Stalker.follow(Process.getCurrentThreadId(), { 146 | transform(iterator: StalkerArm64Iterator) { 147 | let inst 148 | while((inst = iterator.next()) !== null) { 149 | // console.log(`[${Process.getCurrentThreadId()}] ${inst}`) 150 | iterator.keep() 151 | } 152 | } 153 | }) 154 | }, 155 | onLeave(retval) { 156 | Stalker.unfollow() 157 | console.error(`[mmap_exec] unfollow => tid[${Process.getCurrentThreadId()}]`) 158 | }, 159 | }) 160 | } 161 | }) 162 | 163 | ``` 164 | 165 | - 通过对于同一个内存块进行来回按照`empty_func`,`add_99_func`的顺序来写入对应的的汇编来执行(假设传递的`count=1`):[代码(2)](./app/app/src/main/cpp/test_frida.cpp) 166 | 1. 第一次执行`empty_func(1)`的时候返回值是1(首次编译,缓存根据empty_func生成的插桩指令) 167 | 2. 通过比对指令,第二次进行了重编译,执行`add_99_func(1)`返回100 (第一次重编译,缓存根据add_99_func生成的插桩指令,但是指令快照却是empty_func) 168 | 3. 第三次执行,预期是执行`empty_func(1)`返回1,但实际却因为快照是第一次编译的指令(empty_func),所以误认为指令没变动,所以执行了**第一次重编译**的插桩代码add_99_func,导致了此时会返回100。 169 | 4. 第四次执行,预期是执行`add_99_func(1)`返回100,实际上也是执行了`add_99_func(1)`,但是错误的又重编译一次 170 | 5. ...接下来的都会是执行`add_99_func(1)`的结果 171 | 172 | 以下展示了三种测试结果用于说明: 173 | 174 | #### 1. 正常无frida-stalker跟踪现象 175 | 176 | 无注入执行 177 | 178 | #### 2. 使用原版frida-stalker跟踪现象 179 | 180 | frida-stalker原版跟踪 181 | 182 | #### 3. 使用修复的frida-stalker后的跟踪现象 183 | 184 | frida-stalker修复版跟踪 185 | 186 | 187 | 188 | 189 | ## 编译修复frida-server 190 | 191 | ### 拉取源项目和合并修改 192 | ```shell 193 | # 从frida中递归子模块拉取主分支(修改基于16.5.9进行,所以我编译这个版本,其他版本如果没冲突可以试试) 194 | git clone --branch 16.5.9 --single-branch --recurse-submodules https://github.com/frida/frida.git 195 | 196 | # 进入子模块下的frida-gum 197 | cd subprojects/frida-gum 198 | 199 | # 添加修复的远程代码仓库地址 200 | git remote add zsa233 https://github.com/zsa233/frida-gum.git 201 | 202 | # 拉取zsa233仓库,并且将对应的修改分支合并到本地仓库 203 | git fetch zsa233 204 | git merge zsa233/fix/stalker-wrong-recompile 205 | 206 | # 后面接着就是编译 207 | ``` 208 | 209 | ### 编译 210 | > 参考官方文档: https://frida.re/docs/building/#cross 211 | ```shell 212 | # 指定ANDROID_NDK_ROOT,我这里下载r25c版本(16.5.9要求 213 | # wget https://dl.google.com/android/repository/android-ndk-r25c-linux.zip 214 | # 其中还需要node.js >= 18之类的编译依赖,根据错误提示解决即可,这里不再赘述 215 | # 216 | export ANDROID_NDK_VERSION=r25c 217 | # !!!/mypath/改成自己的ndk路径 218 | export ANDROID_NDK_ROOT=/mypath/android-ndk-$ANDROID_NDK_VERSION/ 219 | 220 | # 回到frida项目下,配置编译android-arm64平台 221 | ./configure --host=android-arm64 222 | 223 | # 编译 224 | make 225 | 226 | # 将编译成功的frida-server上传 227 | adb push build/subprojects/frida-core/server/frida-server /data/local/tmp/frida-server 228 | # 加上x权限 229 | adb shell chmod u+x /data/local/tmp/frida-server 230 | ``` 231 | 232 | ## 测试 233 | > [修复的测试结果如上图](#3-使用修复的frida-stalker后的跟踪现象) 234 | 235 | 236 | ## 资源链接 237 | > 0. [代码仓库](./) 238 | > 1. [测试app代码](./app) 239 | > 2. [so库实现](./app/app/src/main/cpp/test_frida.cpp) 240 | > 3. [frida注入脚本](./index.ts) 241 | > 4. [编译的arm64测试apk](./app-debug.apk) 242 | -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSA233/android-reverse-examples/dcec84c28004c6e741c7562c0d6054d6f2fe760f/001_frida-stalker-recompile-fix/app-debug.apk -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.application) 3 | alias(libs.plugins.jetbrains.kotlin.android) 4 | } 5 | 6 | android { 7 | namespace = "com.example.frida_stalker_recompile_fix" 8 | compileSdk = 35 9 | 10 | defaultConfig { 11 | applicationId = "com.example.frida_stalker_recompile_fix" 12 | minSdk = 29 13 | targetSdk = 34 14 | versionCode = 1 15 | versionName = "1.0" 16 | 17 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 18 | 19 | ndk { 20 | abiFilters.add("arm64-v8a") 21 | } 22 | vectorDrawables { 23 | useSupportLibrary = true 24 | } 25 | externalNativeBuild { 26 | cmake { 27 | cppFlags += "" 28 | } 29 | } 30 | 31 | } 32 | 33 | buildTypes { 34 | release { 35 | isMinifyEnabled = false 36 | proguardFiles( 37 | getDefaultProguardFile("proguard-android-optimize.txt"), 38 | "proguard-rules.pro" 39 | ) 40 | } 41 | } 42 | compileOptions { 43 | sourceCompatibility = JavaVersion.VERSION_1_8 44 | targetCompatibility = JavaVersion.VERSION_1_8 45 | } 46 | kotlinOptions { 47 | jvmTarget = "1.8" 48 | } 49 | buildFeatures { 50 | compose = true 51 | } 52 | composeOptions { 53 | kotlinCompilerExtensionVersion = "1.5.1" 54 | } 55 | packaging { 56 | resources { 57 | excludes += "/META-INF/{AL2.0,LGPL2.1}" 58 | } 59 | } 60 | externalNativeBuild { 61 | cmake { 62 | path = file("src/main/cpp/CMakeLists.txt") 63 | version = "3.22.1" 64 | } 65 | } 66 | } 67 | 68 | dependencies { 69 | 70 | implementation(libs.androidx.core.ktx) 71 | implementation(libs.androidx.lifecycle.runtime.ktx) 72 | implementation(libs.androidx.activity.compose) 73 | implementation(platform(libs.androidx.compose.bom)) 74 | implementation(libs.androidx.ui) 75 | implementation(libs.androidx.ui.graphics) 76 | implementation(libs.androidx.ui.tooling.preview) 77 | implementation(libs.androidx.material3) 78 | testImplementation(libs.junit) 79 | androidTestImplementation(libs.androidx.junit) 80 | androidTestImplementation(libs.androidx.espresso.core) 81 | androidTestImplementation(platform(libs.androidx.compose.bom)) 82 | androidTestImplementation(libs.androidx.ui.test.junit4) 83 | debugImplementation(libs.androidx.ui.tooling) 84 | debugImplementation(libs.androidx.ui.test.manifest) 85 | } -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # For more information about using CMake with Android Studio, read the 3 | # documentation: https://d.android.com/studio/projects/add-native-code.html. 4 | # For more examples on how to use CMake, see https://github.com/android/ndk-samples. 5 | 6 | # Sets the minimum CMake version required for this project. 7 | cmake_minimum_required(VERSION 3.22.1) 8 | 9 | # Declares the project name. The project name can be accessed via ${ PROJECT_NAME}, 10 | # Since this is the top level CMakeLists.txt, the project name is also accessible 11 | # with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level 12 | # build script scope). 13 | project("test_frida") 14 | 15 | # Creates and names a library, sets it as either STATIC 16 | # or SHARED, and provides the relative paths to its source code. 17 | # You can define multiple libraries, and CMake builds them for you. 18 | # Gradle automatically packages shared libraries with your APK. 19 | # 20 | # In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define 21 | # the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME} 22 | # is preferred for the same purpose. 23 | # 24 | # In order to load a library into your app from Java/Kotlin, you must call 25 | # System.loadLibrary() and pass the name of the library defined here; 26 | # for GameActivity/NativeActivity derived applications, the same library name must be 27 | # used in the AndroidManifest.xml file. 28 | add_library(${CMAKE_PROJECT_NAME} SHARED 29 | # List C/C++ source files with relative paths to this CMakeLists.txt. 30 | test_frida.cpp) 31 | 32 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default") 33 | 34 | # Specifies libraries CMake should link to your target library. You 35 | # can link libraries from various origins, such as libraries defined in this 36 | # build script, prebuilt third-party libraries, or Android system libraries. 37 | target_link_libraries(${CMAKE_PROJECT_NAME} 38 | # List libraries link to the target library 39 | android 40 | log) 41 | -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/cpp/test_frida.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef uint64_t (*func_t)(uint64_t i); 10 | static inline uint32_t read_ctr_el0(); 11 | 12 | 13 | static uint32_t global_ctr = read_ctr_el0(); 14 | static void *exec_addr = nullptr; 15 | 16 | void aarch64_sync_cache_range(void *start, size_t len); 17 | 18 | extern "C" { 19 | 20 | __attribute__((visibility("default"))) 21 | jstring mmap_exec(JNIEnv *env, jobject thiz, jbyteArray insnBytes, jint num) { 22 | size_t page_size = sysconf(_SC_PAGE_SIZE); 23 | if (page_size == -1) { 24 | std::cerr << "Failed to get page size!" << std::endl; 25 | return nullptr; 26 | } 27 | 28 | void *start_addr = exec_addr; 29 | int flags = MAP_ANON | MAP_PRIVATE; 30 | if (start_addr != nullptr) { 31 | flags |= MAP_FIXED; 32 | } 33 | void *mem = mmap( 34 | start_addr, page_size, PROT_READ | PROT_WRITE | PROT_EXEC, 35 | flags, -1, 0); 36 | if (mem == MAP_FAILED) { 37 | std::cerr << "mmap failed!" << std::endl; 38 | exec_addr = nullptr; 39 | return nullptr; 40 | } 41 | if (exec_addr == nullptr) { 42 | exec_addr = mem; 43 | } 44 | jsize length = env->GetArrayLength((insnBytes)); 45 | 46 | jbyte *code = env->GetByteArrayElements(insnBytes, nullptr); 47 | std::memcpy(mem, code, length); 48 | 49 | aarch64_sync_cache_range(mem, page_size); 50 | 51 | func_t func = reinterpret_cast(mem); 52 | 53 | uint64_t sum = func(num); 54 | 55 | munmap(mem, page_size); 56 | 57 | env->ReleaseByteArrayElements(insnBytes, code, 0); 58 | 59 | char buff[128]; 60 | std::sprintf(buff, "[%p] sum[%lu]", mem, sum); 61 | 62 | return env->NewStringUTF(buff); 63 | } 64 | 65 | __attribute__((visibility("default"))) 66 | JNIEXPORT jobjectArray JNICALL 67 | Java_com_example_frida_1stalker_1recompile_1fix_MainActivity_mmapExec( 68 | JNIEnv *env, jobject thiz, jbyteArray inst1, jbyteArray inst2, jint base_num) { 69 | jclass stringCls = env->FindClass("java/lang/String"); 70 | const jsize test_num = 20; 71 | jobjectArray resultArray = env->NewObjectArray(test_num, stringCls, nullptr); 72 | for(jsize i = 0; i < test_num; i++) { 73 | jbyteArray inst = i % 2 == 0 ? inst1 : inst2; 74 | jstring result1 = mmap_exec(env, thiz, inst, base_num); 75 | env->SetObjectArrayElement(resultArray, i, result1); 76 | } 77 | return resultArray; 78 | } 79 | 80 | 81 | } 82 | 83 | 84 | 85 | // 读取 CTR_EL0 寄存器(缓存类型寄存器) 86 | // CTR_EL0 寄存器中: 87 | // - bits [19:16]:表示数据缓存最小行大小(DminLine),计算方式为:4 << ((CTR_EL0 >> 16) & 0xF) 88 | // - bits [3:0] :表示指令缓存最小行大小(IminLine),计算方式为:4 << (CTR_EL0 & 0xF) 89 | static inline uint32_t read_ctr_el0(){ 90 | uint64_t ctr; 91 | __asm__ volatile( 92 | "mrs %[ctr], ctr_el0" : [ctr] "=r"(ctr) 93 | ); 94 | return (uint32_t)ctr; 95 | } 96 | 97 | 98 | void aarch64_sync_cache_range(void *start, size_t len) { 99 | uint64_t addr_start = (uint64_t)start; 100 | uint64_t addr_end = addr_start + len; 101 | uint32_t ctr = global_ctr; 102 | // 数据缓存行大小 103 | int dcache_line_size = 4 << ((ctr >> 16) & 0xF); 104 | // 指令缓存行大小 105 | int icache_line_size = 4 << (ctr & 0xF); 106 | 107 | // 清理数据缓存(将数据写回到内存): 108 | // 循环遍历整个内存区域,对每个缓存行执行 "dc cvau" 操作 109 | for(uint64_t addr = addr_start & ~(dcache_line_size - 1) 110 | ; addr < addr_end 111 | ; addr += dcache_line_size) { 112 | __asm__ volatile("DC CVAU, %[addr]": : [addr]"r"(addr) : "memory"); 113 | } 114 | // 数据同步屏障,确保上面的缓存清理操作完成 115 | __asm__ volatile("dsb ish": : : "memory"); 116 | 117 | // 使指令缓存失效(让 CPU 重新加载新的指令) 118 | // 遍历整个内存区域,对每个缓存行执行 "ic ivau" 操作 119 | for(uint64_t addr = addr_start & ~(icache_line_size - 1) 120 | ; addr < addr_end 121 | ; addr += icache_line_size) { 122 | __asm__ volatile("IC IVAU, %[addr]": : [addr]"r"(addr) : "memory"); 123 | } 124 | // 再次数据同步屏障,确保失效操作完成 125 | __asm__ volatile("dsb ish": : : "memory"); 126 | // 指令同步屏障,刷新指令流水线 127 | __asm__ volatile("isb": : : "memory"); 128 | } -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/java/com/example/frida_stalker_recompile_fix/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.frida_stalker_recompile_fix 2 | 3 | import android.os.Bundle 4 | import android.text.TextUtils 5 | import androidx.activity.ComponentActivity 6 | import androidx.activity.compose.setContent 7 | import androidx.activity.enableEdgeToEdge 8 | import androidx.compose.foundation.layout.fillMaxSize 9 | import androidx.compose.foundation.layout.padding 10 | import androidx.compose.foundation.rememberScrollState 11 | import androidx.compose.foundation.verticalScroll 12 | import androidx.compose.material3.Button 13 | import androidx.compose.material3.Scaffold 14 | import androidx.compose.material3.Text 15 | import androidx.compose.runtime.* 16 | import androidx.compose.runtime.snapshots.SnapshotStateList 17 | import androidx.compose.ui.Modifier 18 | import androidx.compose.ui.platform.LocalContext 19 | import com.example.frida_stalker_recompile_fix.ui.theme.TestfridaTheme 20 | import kotlinx.coroutines.Dispatchers 21 | import kotlinx.coroutines.launch 22 | import kotlinx.coroutines.withContext 23 | import java.util.Locale 24 | 25 | class MainActivity : ComponentActivity() { 26 | override fun onCreate(savedInstanceState: Bundle?) { 27 | super.onCreate(savedInstanceState) 28 | enableEdgeToEdge() 29 | 30 | setContent { 31 | TestfridaTheme { 32 | val resultList = remember { mutableStateListOf() } 33 | 34 | Scaffold( 35 | modifier = Modifier 36 | .fillMaxSize(), 37 | floatingActionButton = { Trigger(resultList) }, 38 | ) { innerPadding -> 39 | Greeting( 40 | resultList = resultList, 41 | modifier = Modifier.padding(innerPadding) 42 | ) 43 | } 44 | 45 | System.loadLibrary("test_frida") 46 | } 47 | } 48 | } 49 | 50 | external fun mmapExec(insn1: ByteArray, insn2: ByteArray, num: Int): Array 51 | } 52 | 53 | @Composable 54 | fun Greeting(resultList: List, modifier: Modifier = Modifier) { 55 | val formattedText = resultList.joinToString("\n") 56 | val scrollState = rememberScrollState() 57 | 58 | Text( 59 | text = formattedText, 60 | modifier = modifier.verticalScroll(scrollState) 61 | ) 62 | } 63 | 64 | val emptyFunc = byteArrayOf( 65 | 0xC0.toByte(), 0x03.toByte(), 0x5F.toByte(), 0xD6.toByte(), // ret 66 | ) 67 | val add99Func = byteArrayOf( 68 | 0x00.toByte(), 0x8C.toByte(), 0x01.toByte(), 0x91.toByte(), // add x0, x0, #99 69 | 0xC0.toByte(), 0x03.toByte(), 0x5F.toByte(), 0xD6.toByte(), // ret 70 | ) 71 | 72 | 73 | @Composable 74 | fun Trigger(resultList: SnapshotStateList) { 75 | val activity = LocalContext.current as MainActivity 76 | 77 | val text = remember { mutableStateOf("执行") } 78 | val toggle = remember { mutableStateOf(false) } 79 | val counter = remember { mutableIntStateOf(0) } 80 | val isLoading = remember { mutableStateOf(false) } 81 | 82 | val coroutineScope = rememberCoroutineScope() 83 | Button( 84 | onClick = { 85 | if (!isLoading.value) { 86 | isLoading.value = true 87 | coroutineScope.launch { 88 | text.value = "进行中..." 89 | val results = withContext(Dispatchers.IO) { 90 | toggle.value = !toggle.value 91 | counter.intValue ++ 92 | val fn = listOf(emptyFunc, add99Func) 93 | activity.mmapExec(fn[0], fn[1], 1) 94 | } 95 | val i = String.format(Locale.CHINA, "%03d", counter.intValue) 96 | val result = TextUtils.join("\n", results) 97 | resultList.add(0, "[$i]: \n $result \n") 98 | isLoading.value = false 99 | } 100 | } 101 | }, 102 | enabled = !isLoading.value 103 | ) { 104 | Text("开始执行") 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/java/com/example/frida_stalker_recompile_fix/ui/theme/Color.kt: -------------------------------------------------------------------------------- 1 | package com.example.frida_stalker_recompile_fix.ui.theme 2 | 3 | import androidx.compose.ui.graphics.Color 4 | 5 | val Purple80 = Color(0xFFD0BCFF) 6 | val PurpleGrey80 = Color(0xFFCCC2DC) 7 | val Pink80 = Color(0xFFEFB8C8) 8 | 9 | val Purple40 = Color(0xFF6650a4) 10 | val PurpleGrey40 = Color(0xFF625b71) 11 | val Pink40 = Color(0xFF7D5260) -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/java/com/example/frida_stalker_recompile_fix/ui/theme/Theme.kt: -------------------------------------------------------------------------------- 1 | package com.example.frida_stalker_recompile_fix.ui.theme 2 | 3 | import android.os.Build 4 | import androidx.compose.foundation.isSystemInDarkTheme 5 | import androidx.compose.material3.MaterialTheme 6 | import androidx.compose.material3.darkColorScheme 7 | import androidx.compose.material3.dynamicDarkColorScheme 8 | import androidx.compose.material3.dynamicLightColorScheme 9 | import androidx.compose.material3.lightColorScheme 10 | import androidx.compose.runtime.Composable 11 | import androidx.compose.ui.platform.LocalContext 12 | 13 | private val DarkColorScheme = darkColorScheme( 14 | primary = Purple80, 15 | secondary = PurpleGrey80, 16 | tertiary = Pink80 17 | ) 18 | 19 | private val LightColorScheme = lightColorScheme( 20 | primary = Purple40, 21 | secondary = PurpleGrey40, 22 | tertiary = Pink40 23 | 24 | /* Other default colors to override 25 | background = Color(0xFFFFFBFE), 26 | surface = Color(0xFFFFFBFE), 27 | onPrimary = Color.White, 28 | onSecondary = Color.White, 29 | onTertiary = Color.White, 30 | onBackground = Color(0xFF1C1B1F), 31 | onSurface = Color(0xFF1C1B1F), 32 | */ 33 | ) 34 | 35 | @Composable 36 | fun TestfridaTheme( 37 | darkTheme: Boolean = isSystemInDarkTheme(), 38 | // Dynamic color is available on Android 12+ 39 | dynamicColor: Boolean = true, 40 | content: @Composable () -> Unit 41 | ) { 42 | val colorScheme = when { 43 | dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { 44 | val context = LocalContext.current 45 | if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) 46 | } 47 | 48 | darkTheme -> DarkColorScheme 49 | else -> LightColorScheme 50 | } 51 | 52 | MaterialTheme( 53 | colorScheme = colorScheme, 54 | typography = Typography, 55 | content = content 56 | ) 57 | } -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/java/com/example/frida_stalker_recompile_fix/ui/theme/Type.kt: -------------------------------------------------------------------------------- 1 | package com.example.frida_stalker_recompile_fix.ui.theme 2 | 3 | import androidx.compose.material3.Typography 4 | import androidx.compose.ui.text.TextStyle 5 | import androidx.compose.ui.text.font.FontFamily 6 | import androidx.compose.ui.text.font.FontWeight 7 | import androidx.compose.ui.unit.sp 8 | 9 | // Set of Material typography styles to start with 10 | val Typography = Typography( 11 | bodyLarge = TextStyle( 12 | fontFamily = FontFamily.Default, 13 | fontWeight = FontWeight.Normal, 14 | fontSize = 16.sp, 15 | lineHeight = 24.sp, 16 | letterSpacing = 0.5.sp 17 | ) 18 | /* Other default text styles to override 19 | titleLarge = TextStyle( 20 | fontFamily = FontFamily.Default, 21 | fontWeight = FontWeight.Normal, 22 | fontSize = 22.sp, 23 | lineHeight = 28.sp, 24 | letterSpacing = 0.sp 25 | ), 26 | labelSmall = TextStyle( 27 | fontFamily = FontFamily.Default, 28 | fontWeight = FontWeight.Medium, 29 | fontSize = 11.sp, 30 | lineHeight = 16.sp, 31 | letterSpacing = 0.5.sp 32 | ) 33 | */ 34 | ) -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-anydpi/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-hdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSA233/android-reverse-examples/dcec84c28004c6e741c7562c0d6054d6f2fe760f/001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-hdpi/ic_launcher.webp -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSA233/android-reverse-examples/dcec84c28004c6e741c7562c0d6054d6f2fe760f/001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-mdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSA233/android-reverse-examples/dcec84c28004c6e741c7562c0d6054d6f2fe760f/001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-mdpi/ic_launcher.webp -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSA233/android-reverse-examples/dcec84c28004c6e741c7562c0d6054d6f2fe760f/001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSA233/android-reverse-examples/dcec84c28004c6e741c7562c0d6054d6f2fe760f/001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSA233/android-reverse-examples/dcec84c28004c6e741c7562c0d6054d6f2fe760f/001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSA233/android-reverse-examples/dcec84c28004c6e741c7562c0d6054d6f2fe760f/001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSA233/android-reverse-examples/dcec84c28004c6e741c7562c0d6054d6f2fe760f/001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSA233/android-reverse-examples/dcec84c28004c6e741c7562c0d6054d6f2fe760f/001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSA233/android-reverse-examples/dcec84c28004c6e741c7562c0d6054d6f2fe760f/001_frida-stalker-recompile-fix/app/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | frida-stalker-recompile-fix 3 | -------------------------------------------------------------------------------- /001_frida-stalker-recompile-fix/app/app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |