文章目錄
- 一、反編譯查看源代碼
- 二、源代碼分析
- 三、方法1:正向暴力破解
- 四、方法二:按照篩選條件,逐步縮小范圍
先下載軟體,發現是個安卓的apk安裝包,安裝之后打開:

一、反編譯查看源代碼
只有一個輸入框,其他的點不了,應該是要輸入某個字串然后判斷是否正確,之后回傳flag,
打開apk反編譯:


發現有兩個Activity,而且代碼高度相似,查看AndroidManifest.xml:

多個Activity可以顯示多個不同的界面,setContentView就是設定一個Activity的顯示界面,使用setContentView可以在Activity中動態切換顯示的View,這樣,不需要多個Activity就可以顯示不同的界面,
其中它們呼叫的id:2130968603 = 0x7F04001B,2130968604 = 0x7F04001C,
在public.xml中找到相應id對應的資源:

打開layout檔案夾,找到activity_main.xml和build.xml檔案:


發現兩個檔案一模一樣:

二、源代碼分析
再查看兩個類的源代碼:
MainActivity.class
package com.geekerchina.hi;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity
extends AppCompatActivity
{
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130968603);
((Button)findViewById(2131427415)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
int i1 = Integer.parseInt(this.val$Et1.getText().toString());
int k;
int i;
int n;
int j;
if ((i1 > 10000000) && (i1 < 99999999))
{
k = 1;
i = 10000000;
n = 1;
if ((Math.abs(i1 / 1000 % 100 - 36) == 3) && (i1 % 1000 % 584 == 0)) {
j = 0;
}
}
for (;;)
{
int m = n;
if (j < 4)
{
if (i1 / k % 10 != i1 / i % 10) {
m = 0;
}
}
else
{
if (m == 1)
{
char c1 = (char)(i1 / 1000000);
char c2 = (char)(i1 / 10000 % 100);
char c3 = (char)(i1 / 100 % 100);
this.val$Et1.setText("NJCTF{" + c1 + c2 + c3 + "f4n}");
}
return;
}
k *= 10;
i /= 10;
j += 1;
}
}
});
}
public boolean onCreateOptionsMenu(Menu paramMenu)
{
getMenuInflater().inflate(2131558400, paramMenu);
return true;
}
public boolean onOptionsItemSelected(MenuItem paramMenuItem)
{
if (paramMenuItem.getItemId() == 2131427439) {
return true;
}
return super.onOptionsItemSelected(paramMenuItem);
}
}
androidTest.class
package com.geekerchina.hi;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class androidTest
extends AppCompatActivity
{
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130968604);
((Button)findViewById(2131427415)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
int i1 = Integer.parseInt(this.val$Et1.getText().toString());
int k;
int i;
int n;
int j;
if ((i1 > 10000000) && (i1 < 99999999))
{
k = 1;
i = 10000000;
n = 1;
if ((Math.abs(i1 / 1000 % 100 - 36) == 3) && (i1 % 1000 % 584 == 0)) {
j = 0;
}
}
for (;;)
{
int m = n;
if (j < 3)
{
if (i1 / k % 10 != i1 / i % 10) {
m = 0;
}
}
else
{
if (m == 1)
{
char c1 = (char)(i1 / 1000000);
char c2 = (char)(i1 / 10000 % 100);
char c3 = (char)(i1 / 100 % 100 + 10);
this.val$Et1.setText("NJCTF{have" + c1 + c2 + c3 + "f4n}");
}
return;
}
k *= 10;
i /= 10;
j += 1;
}
}
});
}
public boolean onCreateOptionsMenu(Menu paramMenu)
{
getMenuInflater().inflate(2131558400, paramMenu);
return true;
}
public boolean onOptionsItemSelected(MenuItem paramMenuItem)
{
if (paramMenuItem.getItemId() == 2131427439) {
return true;
}
return super.onOptionsItemSelected(paramMenuItem);
}
}
兩個類主要的差別就是:
MainActivity.class


androidTest.class


androidTest相比于MainActivity,就是為了不限制中間4,5兩位的數字必須相等,而且出c3有加10再轉換成字符,
三、方法1:正向暴力破解
直接用反編譯的class代碼暴力破解:
MainActivity.java
public class MainActivity {
public static void main(String[] args) {
int k;
int i;
int n;
int j;
for(int i1 = 10000001; i1 < 99999999 ; i1++){
k = 1;
i = 10000000;
n = 1;
if ((Math.abs(i1 / 1000 % 100 - 36) == 3) && (i1 % 1000 % 584 == 0)) {
j = 0;
}else {
continue;
}
for (;;) {
int m = n;
if (j < 3) {
if (i1 / k % 10 != (i1 / i % 10) ) {
//m = 0;
//當m = 0 時,表明當前的i1已經不符合條件,直接break;否則程式還會進入下一層回圈,m又會重新等于n,導致程式還會繼續運行,在j=4時始侄訓輸出
break;
}
} else {
if (m == 1) {
char c1 = (char) (i1 / 1000000);
char c2 = (char) (i1 / 10000 % 100);
char c3 = (char) (i1 / 100 % 100 + 10);
System.out.println(i1);
System.out.println("NJCTF{have" + c1 + c2 + c3 + "f4n}");
}
break;
}
k *= 10;
i /= 10;
j += 1;
}
}
}
}
運行結果截圖:

得到的flag為NJCTF{05#f4n},
androidTest.java
public class androidTest {
public static void main(String[] args) {
int k;
int i;
int n;
int j;
for(int i1 = 10000001; i1 < 99999999 ; i1++)
{
k = 1;
i = 10000000;
n = 1;
if ((Math.abs(i1 / 1000 % 100 - 36) == 3) && (i1 % 1000 % 584 == 0)) {
j = 0;
}else {
continue;
}
for (;;)
{
int m = n;
if (j < 3)
{
if (i1 / k % 10 != i1 / i % 10) {
m = 0;
break;
}
}
else
{
if (m == 1)
{
char c1 = (char)(i1 / 1000000);
char c2 = (char)(i1 / 10000 % 100);
char c3 = (char)(i1 / 100 % 100 + 10);
System.out.println(i1);
System.out.println("NJCTF{have" + c1 + c2 + c3 + "f4n}");
}
return;
}
k *= 10;
i /= 10;
j += 1;
}
}
}
}
運行結果截圖:

得到的flag為:NJCTF{have05-f4n}和NJCTF{have05if4n},
Bugku的提示:flag格式NJCTF{xxx} 并且 xxx只包含[a-z][A-Z][0-9],
所以真正的flag是NJCTF{have05if4n},
其實網鼎杯原題的題目提示是:tips:Don’t believe what you saw.
The flag’s format is NJCTF{xxx} and xxx only include [a-z][A-Z][0-9].讓我們不要相信看到的,意思就是程式的入口MainActivity這個表面上的類得到的答案是錯誤的,隱藏在它后面相似的androidTest才是真正的答案,
四、方法二:按照篩選條件,逐步縮小范圍
il要滿足的條件:
1、首先范圍是在10000000到99999999之間,一個8位數
2、之后是滿足Math.abs(i1 / 1000 % 100 - 36) == 3 && (i1 % 1000 % 584 == 0):
Math.abs(i1 / 1000 % 100 - 36) == 3:il/1000得到的就是前5位的數字,i1 / 1000 % 100得到的就是第4、5位的數字,Math.abs(i1 / 1000 % 100 - 36) == 3就是第4、5位的數字減36的絕對值是3,所以第4、5位是33或者39,符合條件的數格式為ABC33EFG或者ABC39EFG;
i1 % 1000 % 584 == 0:i1 % 1000,得到的就是后面的第6、7、8位的數字,i1 % 1000 % 584 == 0就是第6、7、8位的數字是584的倍數,第6、7、8位就是一個三位數所以就是584,符合條件的數格式為ABC33584或者ABC39584,
3、這里就是MainActivity和androidTest有差異的地方:
MainActivity.class:
for (;; )
{
int m = n;
if (j < 4)
{
if (i1 / k % 10 != i1 / i % 10) {
m = 0;
}
}
else
{
if (m == 1)
{
char c1 = (char)(i1 / 1000000);
char c2 = (char)(i1 / 10000 % 100);
char c3 = (char)(i1 / 100 % 100);
this.val$Et1.setText("NJCTF{" + c1 + c2 + c3 + "f4n}");
}
return;
}
k *= 10;
i /= 10;
j += 1;
}
androidTest.class:
for (;; )
{
int m = n;
if (j < 3)
{
if (i1 / k % 10 != i1 / i % 10) {
m = 0;
}
}
else
{
if (m == 1)
{
char c1 = (char)(i1 / 1000000);
char c2 = (char)(i1 / 10000 % 100);
char c3 = (char)(i1 / 100 % 100 + 10);
this.val$Et1.setText("NJCTF{have" + c1 + c2 + c3 + "f4n}");
}
return;
}
k *= 10;
i /= 10;
j += 1;
}
這兩段代碼的主要判斷是相似的,在MainActivity類中就是if (j < 4){ if (i1 / k % 10 != i1 / i % 10) { m = 0;}}
k *= 10;
i /= 10;
j += 1;
k的初始值是1,i的初始值是10000000,所以i1 / k % 10就是分別獲得第8、7、6、5位上的數字,i1 / i % 10就是分別獲得第1、2、3、4位上的數字,再要求它們分別相等,也就是ABCDDCBA的形式,結合上面的條件,符合條件的數為48533584,
48533584經過
char c1 = (char)(i1 / 1000000);//第1、2位數字
char c2 = (char)(i1 / 10000 % 100);//第3、4位數字
char c3 = (char)(i1 / 100 % 100);//第3、4位數字
this.val$Et1.setText("NJCTF{" + c1 + c2 + c3 + "f4n}");
得到的字串為NJCTF{05#f4n},
而在androidTest類中,androidTest相比于MainActivity,就是j<4變成j<3,目的是為了不限制中間4,5兩位的數字必須相等,這樣就只用第8、7、6位上的數字和第1、2、3位的數字分別相等了,也就是ABCDECBA的形式,結合上面的條件得到了符合條件的兩個數為48533584和48539584,
48533584和48539584經過
char c1 = (char)(i1 / 1000000);//第1、2位數字
char c2 = (char)(i1 / 10000 % 100);//第3、4位數字
char c3 = (char)(i1 / 100 % 100 + 10);//第5、6位數字再加10
this.val$Et1.setText("NJCTF{have" + c1 + c2 + c3 + "f4n}");
得到的字串為NJCTF{have05-f4n}和NJCTF{have05if4n}, 其中c3字符有額外加10再轉換成字符,是為了讓第5、6位上的數字轉化的字符#和_變成字符-和i,從而讓i在[a-z][A-Z][0-9]的范圍內,得到唯一一個滿足題目提示flag格式NJCTF{xxx} 并且 xxx只包含[a-z][A-Z][0-9]的flag:NJCTF{have05if4n},
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/142301.html
標籤:其他
上一篇:使用Cordova打包H5到安卓
