这是第七届职业技能竞赛山东省赛的一道赛题, 价值3分.
逆向分析
下载题目附件, 直接拖到Jadx里反编译, 代码比较简单, 同样没有加壳和混淆. 其主要逻辑部分的代码如下:
//...
while (true) {
if (this.target_data < 0) {
this.target_data *= -1;
}
if (5 < this.target_data) {
this.target_data %= 32;
this.target_data *= 16384;
((TextView) findViewById(R.id.tv_data)).setText("0");
((TextView) findViewById(R.id.tv_target)).setText("" + this.target_data);
Button btn2 = (Button) findViewById(R.id.btn2);
((Button) findViewById(R.id.btn1)).setOnClickListener(new View.OnClickListener() {
/* class com.wdkj.ctf6.ctf6.MainActivity.AnonymousClass1 */
public void onClick(View v) {
MainActivity.this.cur_data++;
((TextView) MainActivity.this.findViewById(R.id.tv_data)).setText("" + MainActivity.this.cur_data);
if (MainActivity.this.cur_data >= MainActivity.this.target_data) {
((Button) MainActivity.this.findViewById(R.id.btn2)).setClickable(true);
}
}
});
btn2.setOnClickListener(new View.OnClickListener() {
/* class com.wdkj.ctf6.ctf6.MainActivity.AnonymousClass2 */
public void onClick(View v) {
Toast.makeText(MainActivity.this.getApplicationContext(), "Flag:" + MainActivity.this.get_flag(MainActivity.this.target_data), 1).show();
}
});
btn2.setClickable(false);
return;
}
this.target_data = random.nextInt();
}
// ...
有一个native的方法, so是arm的. 为了避免C逆向, 尝试直接crack该apk.
由于比赛时为线下赛, 且不允许使用手机和自己的电脑, 我用IDA大致看了看so文件后直接放弃了这题.
Crack
在程序中有设置证书校验和调试检测的代码, 为了能正常Crack, 需要把证书校验的方法给绕过. 之后, 将属性cur_data
的值直接修改为32 * 16384
. 运行程序即可获得flag.
使用Jadx可以直接导出Gradle工程. 再使用Android Studio导入工程即可进行Crack. 但是, 用新版本的Android Studio构建项目时需要处理各种各样的Gradle和依赖库的兼容性问题, 非常烦人, 索性直接在手机上用MT管理器修改Smali了.
首先, 找到函数validateAppSignature
, 在函数返回语句return v5
前添加赋值语句const/4 v5, 0x1
:
之后, 在MainActivity
的构造器处, 删除条件判断语句, 绕过调试状态检测
最后, 在OnCreate
方法中找到为按钮R.id.btn1
设置点击监听器的代码, 发现其实例化了子类MainActivity$1
.
打开MainActivity$1
, 在OnClick
回调函数处将语句add-int/lit8 v3,v3,0x1
修改为const v3, 0x80000
.
重新打包并签名, 安装程序并运行. 点击按钮"攒一分", 一刀满级, 之后再点击"看答案", 将得到flag: 1E238A5611D4BD4A