安卓 day1
怎么才刚开始学?

Intent

android.content.Intent 是安卓中用于组件间通信的核心类,描述一个操作的意图,例如启动一个 Activity、Service 或发送 Broadcast。

分为显式(指定确切组件类,new Intent(this, TargetActivity.class)),隐式(不确定组件,只描述操作,如打开网页的 ACTION_VIEW

1
2
3
4
5
6
7
8
9
10
// 显式 Intent:启动指定 Activity
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("message", "Hello");
startActivity(intent);

// 隐式 Intent:发送邮件
Intent intent = new Intent(Intent.ACTION_SEND); // 此处只给行为,不指定具体目标 app
intent.setType("text/plain"); // 设置携带数据的类型,便于过滤 app
intent.putExtra(Intent.EXTRA_TEXT, "Hello World");
startActivity(Intent.createChooser(intent, "选择应用")); // 弹出对话框,由用户选择 app

sendBroadcast(Intent intent)

向系统发送一个普通广播(Unordered Broadcast),异步分发 Intent 到所有注册了匹配 action 的 BroadcastReceiver ,接收器并行处理。

一个题

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
27
28
29
30
31
32
33
34
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="com.example.test.ctf02"
platformBuildVersionCode="24"
platformBuildVersionName="7">
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="24"/>
<application
android:theme="@style/AppTheme"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:debuggable="true"
android:allowBackup="true"
android:supportsRtl="true">
<activity android:name="com.example.test.ctf02.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<receiver
android:name="com.example.test.ctf02.GetAndChange"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.is.very.fun"/>
</intent-filter>
</receiver>
<activity android:name="com.example.test.ctf02.NextContent"/>
<activity android:name="com.example.test.ctf02.MainActivity2"/>
</application>
</manifest>

MainActivity 是一个简单的加密,过了之后进入 MainActivity2

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
27
28
public class MainActivity2 extends AppCompatActivity {
Button button;
EditText editText;
ImageView imageView;

@Override // android.support.v7.app.AppCompatActivity, android.support.v4.app.FragmentActivity, android.support.v4.app.BaseFragmentActivityGingerbread, android.app.Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_2);
init();
this.button.setOnClickListener(new View.OnClickListener() { // from class: com.example.test.ctf02.MainActivity2.1
@Override // android.view.View.OnClickListener
public void onClick(View v) {
String str = MainActivity2.this.editText.getText().toString();
Intent intent = new Intent(str);
MainActivity2.this.sendBroadcast(intent);
}
});
}

public void init() {
this.imageView = (ImageView) findViewById(R.id.image);
this.imageView.setImageResource(R.drawable.timg);
this.editText = (EditText) findViewById(R.id.pwd);
this.button = (Button) findViewById(R.id.button);
}
}

onClick() 中,输入值 str 作为 action 传入 intent ,到这里可以去 AndroidManifest.xml 看一眼。

1
2
3
4
5
6
7
8
<receiver
android:name="com.example.test.ctf02.GetAndChange"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.is.very.fun"/>
</intent-filter>
</receiver>

注册了一个 receiver GetAndChange,内容就是启动第三个 Activity NextContent,intent-filter 标签代表匹配条件,这说明传入 android.is.very.fun 就能触发接收器。

这里是静态注册,receiver 还能在运行时用 Context.registerReceiver() 动态注册。

1
2
3
4
5
6
7
// 在 onCreate 或其他方法中
IntentFilter filter = new IntentFilter("com.example.CUSTOM_ACTION");
MyReceiver receiver = new MyReceiver();
registerReceiver(receiver, filter); // 注册

// 在 onDestroy 或 onPause 中注销
unregisterReceiver(receiver);

MainActivity 启动 MainActivity2 当然也是用到 Intent

1
2
3
4
Intent intent = new Intent(MainActivity.this, (Class<?>) MainActivity2.class);
MainActivity.this.startActivity(intent);
MainActivity.this.finish();
return; // onClick() 返回

这是 app 中界面导航的范式。

这题的 apk 其实有很多可疑的地方,比如 assets 里面有个压缩包,export 出来又打不开,010 看一眼发现是 .jpg,直接改一下后缀名就可以看到图片里的 flag。并且直接去看 NextContent 的话也可以发现很可疑的东西

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
27
28
29
30
public void Change() throws IOException {
String strFile = getApplicationContext().getDatabasePath("img.jpg").getAbsolutePath();
try {
File f = new File(strFile);
if (f.exists()) {
f.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
InputStream is = getApplicationContext().getResources().getAssets().open("timg_2.zip");
FileOutputStream fos = new FileOutputStream(strFile);
byte[] buffer = new byte[1024];
while (true) {
int count = is.read(buffer);
if (count <= 0) {
break;
} else {
fos.write(buffer, 0, count);
}
}
fos.flush();
fos.close();
is.close();
} catch (Exception e2) {
e2.printStackTrace();
}
this.imageView.setImageBitmap(BitmapFactory.decodeFile(strFile));
}

是一个图片覆盖的逻辑,把压缩包盖到图片上了,不难想到去看这个压缩包。