某年的CTF大賽題目
總結:遇到算法別頭大,耐心、細心,讓自己靜下來。
點開之後長這樣子,隨便輸入幾個字符,提示錯誤。
查殼發現沒有殼。
直接使用Jeb進行反編譯。
看出來了,突破口是this.b.check()這個函數。
package ctf.bobbydylan;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class M extends T {
public M() {
super();
}
public void check(String arg10) {
String v0_1;
int v7 = 15;
int v6 = 7;
int v1 = 0;
int v5 = 5;
if(arg10.length() != 16) {
throw new RuntimeException();
}
try {
v0_1 = this.getKey();
}
catch(Exception v0) {
v0_1 = this.getKey();
System.arraycopy(v0_1, 0, arg10, v5, v5);
}
int[] v2 = new int[16];
v2[0] = 0;
v2[12] = 14;
v2[10] = v6;
v2[14] = v7;
v2[v7] = 42;
int v4 = 3;
try {
v2[1] = v4;
v2[5] = 5;
System.out.println();
}
catch(Exception v3) {
v2[v5] = 37;
v2[1] = 85;
}
v2[6] = v7;
v2[2] = 13;
v2[3] = 19;
v2[11] = 68;
v2[4] = 85;
v2[13] = v5;
v2[9] = v6;
v2[v6] = 78;
v2[8] = 22;
while(v1 < arg10.length()) {
if((v2[v1] & 0xFF) != ((arg10.charAt(v1) ^ v0_1.charAt(v1 % v0_1.length())) & 0xFF)) {
throw new RuntimeException();
}
++v1;
}
}
public String getKey() {
return "bobbydylan";
}
public void onCreate(Bundle arg4) {
super.onCreate(arg4);
this.setContentView(0x7F030000);
this.startService(new Intent(((Context)this), P.class));
this.findViewById(0x7F060001).setOnClickListener(new a(this, this.findViewById(0x7F060000)));
}
protected void onPause() {
this.stopService(new Intent(((Context)this), P.class));
super.onPause();
}
}
看到這個check,很長說實話。
裏面嵌套了好幾層的try catch語句,我不確定這個程序大體流程執行下去會是怎樣的,也許在try看起來怎麼都不會有異常拋出的地方就有異常了呢,我不想繼續審代碼了,還是動態調試更舒服。
Jeb動態調試
找到對應進程,不解釋。
Jeb沒有調試僞代碼的功能,所以就對着smali代碼和僞代碼一起看吧。
這裏的邏輯經過調通,只要輸入的字符串長度等於16,代碼邏輯就不會跳進catch裏。
經過閱讀,其實只要字符串長度滿足16,和下面的算法即可。
其實也就是
v2[v1] = arg10.charAt(v1) ^ v0_1.charAt(v1 % v0_1.length())
這個等式成立就行。
其中v2是死的,v0_1是getKey()接口返回的"bobbydylan"
也是死的。
這裏我們可以通過Jeb動態調試的時候看到v2和v0_1的值。
求出來的args10就是我們要的flag。
如果v2和v0_1類型不對,顯示的值不太好觀察時,直接修改它們的類型就可以。
直接修改類型。
我們知道對一個數異或兩次,其實就等於沒有做任何運算。
所以這個算法可以這樣去做。
v2[v1] ^ v0_1.charAt(v1 % 8) = args.charAt(v1)
貼上C語言代碼
#include <stdio.h>
#include <stdlib.h>
int main(){
int v2[16] = {0,3,13,19,85,5,15,78,0,7,7,68,14,5,15,42};
char v0_1[] = "bobdylan";
for(int i = 0; i < 16; i++){
int nIndex = i % 8;
int nTmp = v0_1[nIndex];
printf("%c", v2[i] ^ nTmp);
}
}
我使用go,結果給我的是這個玩意,而且還費了我不少時間。
很明顯不對。
有可能是自己太久沒寫代碼或者當時使用go很少做異或或者ascii之類的計算吧,果然底層運算還是選C靠譜。
結束。