2015XCTF&RCTF-where writeup

考察知识点

  • dex文件头修复
  • onCreate修复

前置参考

http://eternalsakura13.com/2018/02/10/dex/

赛题链接

https://github.com/eternalsakura/ctf_pwn/blob/master/android逆向/misc.apk

分析

直接反编译apk,然后得到算法:输入用户名和密码,长度要想等,用户名和密码的逆序串相等则输出字符串,返回flag。
这当然是不可能的,这题可是道misc!
实际上,检查apk解压文件发现,下图的abc大小刚好为112字节也就是70h,是一个dex头的大小。

用010editor打开后发现确实是dex头。

而CERT.RSA这个不正常的大,其实就是因为把dex主体藏在这了。
用010editor打开观察


关键信息就是KEY和aes-128-cbc这个加密方式,KEY后面有一个DEX=…
我们知道dex头后面紧接着就是字符串索引项,应该是很整齐的四字节四字节,现在明显是被加密过了。
首先把DEX=…后面的数据拷贝出来,保存成文件。

再把数据直接复制粘贴在新建的文件里就行了。
用openssl或者其他工具解密这个文件。
openssl aes-128-cbc -d -k "Misc@inf0#fjhx11" -nosalt -in encfile -out decfile
-in encfile是被加密的文件,-out decfile是解密后的文件。
打开解密后的文件,现在就很整齐了。

再把文件头拷贝到前面,就拼接出了一个dex文件,嗯,就叫flag好了。

修复dex

用010 editor打开拼接好的flag文件,执行dex解析脚本,报错。

检查后发现是因为索引区各索引分区的size(其实就是索引项的项数)为0,需要填补。

关于怎么计算,了解dex文件格式的应该很easy,我举个例子。

type_id_off为A8h,string_ids_off偏移为70h,因为每个项的大小为4字节,所以(A8-70)/4=E

string_ids size = (0x000091DC - 0x00000070) / 4 = 0x0000245B
type_ids size = (0x0000A3EC - 0x000091DC) / 4 = 0x00000484
proto_ids size = (0x0000EF28 - 0x0000A3EC) / 12 = 0x00000645
field_ids size = (0x00015DB8 - 0x0000EF28) / 8 = 0x00000DD2
method_ids size = (0x00026DC8 - 0x00015DB8) / 8 = 0x00002202

这样就算完,填入进行修补。

重新解析一下,我们的dex文件就修复好了。

修复onCreate

用jadx反编译拼接好的dex文件,发现onCreate()方法反编译失败,用IDA打开后发现全被nop掉了(抽空)
可以想到运行时动态恢复指令,但是这里没有so,明显不是(这真是道misc……)

所以藏在哪里呢?实际上被抽空的onCreate指令就在下图的y中。

用IDA打开搜索onCreate,找到nop的起始地址,CODE:00097390

用010editor找到对应空白

将y的数据拷贝进去,刚好完全填补

再次用jadx反编译修复好的dex。

解密

修复好的onCreate

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
public class MainActivity extends ActionBarActivity {
public String seed = "m3ll0t_yetFLag";

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView((int) C0095R.layout.activity_main);
StringBuilder strb = new StringBuilder(this.seed);
strb.replace(0, 1, "h");
strb.replace(5, 6, "2");
strb.replace(10, 11, "f");
strb.replace(7, 8, "G");
Toast.makeText(this, "flag is " + strb.toString(), 0).show();
}

public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(C0095R.menu.main, menu);
return true;
}

public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == C0095R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
1
public StringBuilder replace(int start, int end, String str)
  • start − This is the beginning index, inclusive.
  • end − This is the ending index, exclusive.
  • str − This is the String that will replace previous contents.

查阅文档,然后手动换了一下,得到flag是h3ll02_GetfLag

我修复好的dex文件链接

https://github.com/eternalsakura/ctf_pwn/blob/master/android%E9%80%86%E5%90%91/flag.dex