基于Navigation 组件的 APK逆向分析
基于这个组件的apk一般内部结构如下
MainActivity (容器层)
├── 工具栏设置
├── Navigation 配置
├── FAB 按钮(提示信息)
└── 菜单处理
FirstFragment (业务层) ← 真正的加密逻辑在这里
├── UI 绑定
├── 输入框处理
└── 加密验证逻辑
一、架构特征识别
1. Navigation 组件的典型标志
1 2 3 4
| NavController findNavController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main); AppBarConfiguration.Builder(findNavController.getGraph()).build(); NavigationUI.setupActionBarWithNavController(this, findNavController, build);
|
逆向时的识别要点:
二、代码定位策略
传统单 Activity 架构 vs Navigation 架构
| 架构类型 |
业务逻辑位置 |
逆向重点 |
| 传统架构 |
直接在 Activity 中 |
分析 MainActivity 即可 |
| Navigation 架构 |
分散在各个 Fragment |
需要逐个分析 Fragment |
三、遇到 Navigation 组件的 APK:
- MainActivity → 只看架构,不看业务逻辑
- res/navigation/ → 找到所有 Fragment 的名称
- Fragment 类 → 这才是真正的逻辑所在
- res/layout/fragment_.xml → 查看UI控件ID
. 理解资源绑定
1 2
| this.binding.input // 对应 layout 中的输入框 this.binding.checkFlag // 对应 layout 中的按钮
|
追踪点击事件
1 2
| setOnClickListener() // 按钮点击 setOnEditorActionListener() // 输入框确认
|
三、逆向分析步骤
1 2 3
|
Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
|
MainActivity函数没啥逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| package work.pangbai.ezmydroid;
import android.content.DialogInterface; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import androidx.appcompat.app.AppCompatActivity; import androidx.navigation.NavController; import androidx.navigation.Navigation; import androidx.navigation.ui.AppBarConfiguration; import androidx.navigation.ui.NavigationUI; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.snackbar.Snackbar; import work.pangbai.ezmydroid.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity { private AppBarConfiguration appBarConfiguration; private ActivityMainBinding binding;
@Override public void onCreate(Bundle bundle) { super.onCreate(bundle); ActivityMainBinding inflate = ActivityMainBinding.inflate(getLayoutInflater()); this.binding = inflate; setContentView(inflate.getRoot()); setSupportActionBar(this.binding.toolbar); NavController findNavController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main); AppBarConfiguration build = new AppBarConfiguration.Builder(findNavController.getGraph()).build(); this.appBarConfiguration = build; NavigationUI.setupActionBarWithNavController(this, findNavController, build); this.binding.fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "喵喵喵,需要分析软件的代码呢,你安装了Jadx-Gui吗?", 0).setAnchorView(R.id.fab).setAction("Action", (View.OnClickListener) null).show(); } }); }
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; }
@Override public boolean onOptionsItemSelected(MenuItem menuItem) { if (menuItem.getItemId() == R.id.action_settings) { new MaterialAlertDialogBuilder(this).setTitle((CharSequence) "NewStarCTF2025").setMessage((CharSequence) "欢迎参加 NewStarCTF2025,你需要解出类似于 flag{} 的文本,并在比赛平台提交").setPositiveButton((CharSequence) "OK", (DialogInterface.OnClickListener) null).create().show(); return true; } return super.onOptionsItemSelected(menuItem); }
@Override public boolean onSupportNavigateUp() { return NavigationUI.navigateUp(Navigation.findNavController(this, R.id.nav_host_fragment_content_main), this.appBarConfiguration) || super.onSupportNavigateUp(); } }
|
Step 2: 找到导航图
Step 3: 逐个分析 Fragment
找到解密逻辑直接分析解密即可

解密脚本
1 2 3 4 5 6 7 8 9 10
| from Crypto.Cipher import AES import base64
key = b"1145141919810000" ciphertext = base64.b64decode("cTz2pDhl8fRMfkkJXfqs2t8JBsqLkvQZDLYpWjEtkLE=")
cipher = AES.new(key, AES.MODE_ECB) plaintext = cipher.decrypt(ciphertext) flag = plaintext.strip() print(flag.decode())
|