题目附件:tlamb96/kgb_messenger: An Android CTF practice challenge (github.com)
MainActivity

这里我们需要跟踪一下R.string.User,直接点击,可以知道对应的资源id为:
1
| public static final int User = 0x7f0d0000;
|
根据这个资源id在resources.arsc
中可以搜索到对应的string标签名称为”User”:
1
| <public type="string" name="User" id="0x7f0d0000" />
|
根据标签名称直接搜索资源文件(xml文件):

解码Base64就得到了第一个flag:FLAG{57ERL1NG_4RCH3R}。
要想进入下一关,我们就需要hook系统方法System.getProperty()
、System.getenv()
,使其直接返回正确的字符串,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function MainActivity(){
Java.perform( function(){ var SystemClass = Java.use("java.lang.System"); SystemClass.getProperty.overload("java.lang.String").implementation = function(key){ var tmp = this.getProperty(key); return "Russia"; } SystemClass.getenv.overload("java.lang.String").implementation = function(name){ var tmp = this.getenv(name); return "RkxBR3s1N0VSTDFOR180UkNIM1J9Cg=="; } } )
}
setImmediate(MainActivity)
|
LoginActivity
是一个登录界面,所对应的代码逻辑如下:

如果我们只是简单的进入下一关,当然可以直接hook j()
方法,使其直接返回true。但是我们还需要得到flag,flag的生成需要依靠账号和密码(详细见i()
方法)。
其中 j()、i()
如下:

所以说我们不应hook j()
方法使其返回true,而是要逆md5码获取密码明文,推荐网站md5 hash decoder and calculator (md5hashing.net)。

得到密码明文为:guest。
为了更为方便点,我们还可以hook Toast.makeText()
方法,在控制台输出flag,毕竟toast弹窗显示时间比较短而且还不能复制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function LoginActivity(){
Java.perform( function(){ var ToastClass = Java.use("android.widget.Toast"); ToastClass.makeText.overload("android.content.Context", "java.lang.CharSequence", "int").implementation = function(context, text, duration){ console.log("flag = " + text); return this.makeText(context,text,duration); } } )
}
setImmediate(LoginActivity)
|
得到第二个flag:FLAG{G00G13_PR0}
MessengerActivity
是一个聊天界面。发送消息的代码逻辑如下:

来看a()
和b()
这两个方法:

就是两个简单的加密方法,要说有点挑战的也就是移位异或了,不过这个拿个例子在草稿上推演一遍就知道怎么做了。
解密脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| p = list("V@]EAASB\u0012WZF\u0012e,a$7(&am2(3.\u0003")
for i in range(len(p) // 2): c = chr(ord(p[-1-i]) ^ ord('A')) p[-1 - i] = chr(ord(p[i]) ^ ord('2')) p[i] = c print(''.join(_ for _ in p))
r = list("\u0000dslp}oQ\u0000 dks$|M\u0000h +AYQg\u0000P*!M$gQ\u0000") for i in range(len(r) // 2): r[i], r[-1-i] = r[-1-i], r[i] for i in range(len(r)): shiftBit = i % 8 if shiftBit == 0: continue while shiftBit < 8: r[i] = chr((ord(r[i]) >> shiftBit) ^ ord(r[i])) shiftBit *= 2 print(''.join(_ for _ in r))
|
得到的明文如下图所示:

由于存在移位为0bit的情况,这种情况最后是相同明文进行异或得到0,是无法还原出来的,所以需要我们自己手动还原。
最终flag如下图所示:
