初见
题目除了一个apk附件外,还有一条提示信息:“备注:本题提交大括号内值即可”。
还是先来具体体验一下,先安装APP:
上图中,最后的“TopCtf”就是本题的APP。打开它:
就一个输入控件,一个按钮。
随便输入一个字符串,点击确定,提示“错误”:
从体验上就这些信息,下面对APP的apk文件进行静态分析。
静态分析
使用jadx打开apk文件,可以看到该APP除了资源类“R”和配置类“BuildConfig”,只有一个类“MainActivity”。重点分析MainActivity。
MainActivity
在MainActivity的onCreate函数中,可以看到注册按钮事件响应函数的代码:
public void onCreate(Bundle savedInstanceState) {
... ...
this.btn_register.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (!MainActivity.this.checkSN(MainActivity.this.edit_userName.trim(), MainActivity.this.edit_sn.getText().toString().trim())) {
Toast.makeText(MainActivity.this, (int) R.string.unsuccessed, 0).show();
return;
}
Toast.makeText(MainActivity.this, (int) R.string.successed, 0).show();
MainActivity.this.btn_register.setEnabled(false);
MainActivity.this.setTitle(R.string.registered);
}
});
}
按钮事件响应函数的核心流程是:
- 调用checkSN检查输入是否正确。
- 检查成功,打印“恭喜您!”
- 检查失败,打印“错误”。
所以,重点在checkSN函数对输入内容的检查。
调用checkSN时传入了两个参数,第一个参数为edit_userName控件的内容,第二个参数为edit_sn控件的内容。
edit_userName控件的内容在MainActivity的onCreate函数中能找到赋值:
this.edit_userName = "Tenshine";
edit_sn控件的内容就是我们的输入。
checkSN
checkSN函数有两个参数,一个是userName,一个是sn。核心代码为:
public boolean checkSN(String userName, String sn) {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.reset();
digest.update(userName.getBytes());
String hexstr = toHexString(digest.digest(), "");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hexstr.length(); i += 2) {
sb.append(hexstr.charAt(i));
}
if (("flag{" + sb.toString() + "}").equalsIgnoreCase(sn)) {
return true;
}
return false;
}
核心功能为:
- 对userName计算MD5
- 将计算得到的MD5转换为16进制字符串
- 取MD5字符串的所有下标为偶数(0/2/......)的字符,组成新字符串
- 在新字符串前面加上“flag{”,在后面加上“}”,组成校验字符串
- 比较输入字符串和校验字符串是否相同
从上面可知,userName为“Tenshine”。
其MD5值为“b9c77224ff234f27ac6badf83b855c76”
取下标为偶数的字符得到字符串“bc72f242a6af3857”
加上前面的“flag{”和后面的“}”为“flag{bc72f242a6af3857}”。
在APP的界面输入“flag{bc72f242a6af3857}”,提示成功:
根据题目的提示信息“备注:本题提交大括号内值即可”,flag为“bc72f242a6af3857”。