-
-
[原创]【2019看雪CTF】Q1赛季 第二题变形金钢 WP
-
2019-3-23 12:59
5299
-
[原创]【2019看雪CTF】Q1赛季 第二题变形金钢 WP
【2019看雪CTF】Q1赛季 第二题变形金钢 WP
此题是安卓题,开始在java层看到这样的校验代码:
class MyHandler extends Handler {
WeakReference mWeakReference;
public MyHandler(MainActivity arg2) {
super();
this.mWeakReference = new WeakReference(arg2);
}
public void handleMessage(Message arg6) {
String v6_1;
StringBuilder v1;
super.handleMessage(arg6);
Object v0 = this.mWeakReference.get();
if(v0 == null) {
return;
}
switch(arg6.what) {
case 0: {
Object v6 = arg6.obj;
if(!TextUtils.isEmpty(((CharSequence)v6))) {
v1 = new StringBuilder();
int v3;
for(v3 = 0; v3 < ((String)v6).length() / 2; ++v3) {
v1.append(((String)v6).charAt(v3));
}
v6_1 = v1.toString();
}
v1 = new StringBuilder();
v1.append("flag{");
v1.append(v6_1);
v1.append("}");
Toast.makeText(((Context)v0), v1.toString(), 1).show();
break;
}
case 1: {
Toast.makeText(((Context)v0), "登录失败", 1).show();
break;
}
default: {
break;
}
}
((MainActivity)v0).login.setEnabled(true);
}
}
private void login(String arg3, String arg4, Handler arg5) {
Toast.makeText(((Context)this), "登录中。。。", 1).show();
MainActivity.runnable = new Runnable(arg4, arg3, arg5) {
public void run() {
Message v0 = Message.obtain();
StringBuilder v1 = new StringBuilder(this.val$password);
if(this.val$name.equals(v1.reverse().toString())) {
v0.obj = v1.toString();
}
else {
v0.what = 1;
}
this.val$handler.sendMessage(v0);
}
};
MainActivity.cachedThreadPool.execute(MainActivity.runnable);
}
似乎password
就是name
的逆序,但是不对。。。卡了好一会,后来回头来看才发现猫腻所在。
public class MainActivity extends AppCompiatActivity {
中的AppCompiatActivity
是自写类,并非系统中的AppCompatActivity
。其主要代码如下:
static {
System.loadLibrary("oo000oo");
}
private static byte[] dec(byte[] arg4, byte[] arg5) {
arg5 = Base64.decode(arg5, 0);
SecretKeySpec v0 = new SecretKeySpec(arg4, "AES");
try {
((Key)v0).getEncoded();
PrintStream v4_1 = System.out;
v4_1.println("getFormat = " + ((Key)v0).getFormat() + " ; getAlgorithm = " + ((Key)v0).getAlgorithm());
Cipher v4_2 = Cipher.getInstance("AES/CFB/PKCS5Padding");
PrintStream v1_1 = System.out;
v1_1.println("getBlockSize = " + v4_2.getBlockSize());
v4_2.init(2, ((Key)v0), new IvParameterSpec(new byte[v4_2.getBlockSize()]));
return v4_2.doFinal(arg5);
}
catch(Throwable v4) {
v4.printStackTrace();
return null;
}
}
protected native boolean eq(String arg1) {
}
protected void onStart() {
super.onStart();
this.login = this.findViewById(2131165260);
this.login.setOnClickListener(new View$OnClickListener() {
public void onClick(View arg5) {
AppCompiatActivity.this.mName = AppCompiatActivity.this.name.getText().toString();
AppCompiatActivity.this.mPassword = AppCompiatActivity.this.password.getText().toString();
if(!TextUtils.isEmpty(AppCompiatActivity.this.mName)) {
if(TextUtils.isEmpty(AppCompiatActivity.this.mPassword)) {
}
else {
int v1 = 0;
AppCompiatActivity.this.login.setEnabled(false);
if(AppCompiatActivity.this.eq(AppCompiatActivity.this.mPassword)) {
byte[] v5 = AppCompiatActivity.this.mPassword.getBytes();
int v3 = 24;
if(v5.length != v3) {
byte[] v2 = new byte[v3];
while(v1 < v2.length) {
byte v3_1 = v1 < v5.length ? v5[v1] : ((byte)v1);
v2[v1] = v3_1;
++v1;
}
v5 = v2;
}
v5 = AppCompiatActivity.dec(v5, "2ggdrsLgM7iPNYPQrD58Rg==".getBytes());
AppCompiatActivity v1_1 = AppCompiatActivity.this;
StringBuilder v2_1 = new StringBuilder();
v2_1.append("flag{");
v2_1.append(new String(v5));
v2_1.append("}");
Toast.makeText(((Context)v1_1), v2_1.toString(), 1).show();
}
else {
Toast.makeText(AppCompiatActivity.this, "error", 1).show();
}
return;
}
}
Toast.makeText(AppCompiatActivity.this, "用户名或密码为空", 1).show();
}
});
this.name = this.findViewById(2131165265);
this.name.setEnabled(false);
this.password = this.findViewById(2131165277);
}
从以上代码可以看出,此app还有个native库,加载了oo000oo
。输入通过native函数eq
完成校验,最后以输入为密钥对flag进行AES解密。
函数eq
并没有注册导出,在JNI_OnLoad
中手动注册。校验算法似乎是魔改的RC4加改了表的base64编码,没细看。直接将校验串解码,动态调试,用解码后的结果替换输入串,在偏移0x9F6
处下断,从r11
寄存器获取解密结果,结果为fu0kzHp2aqtZAuY6
,输入app,正确显示。
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法