题目
查壳
先查壳(PKiD等),有壳脱壳,没壳用AndroidKiller等反编译工具打开查看JAVA代码
无壳APK
Java Decompiler - MainActivity-onClick
答案
Tctf{H3ll0_Do_Y0u_Lov3_Tenc3nt!}
Writeup
解题
文件头
下载后文件后缀为“ab”,拖入010查看,文件头是“ANDROID BACKUP”:
搜索“ANDROID BACKUP”后确定是安卓备份文件,完整的文件头信息应该是“ANDROID BACKUP.2.1.none”:
其中参数含义为:
“2”:版本
“1”:是否压缩
“none”:是否加密
这些参数用来确定文件是可以通过工具直接解压不需要密码的。
工具
Android backup extractor(或android-backup-processor等)
使用“abe.jar”对.ab文件进行解压处理:
java -jar abe.jar unpack <backup.ab> <backup.tar>
将.tar解压后,“tree /f”查看都有哪些文件:
└─apps
└─com.example.yaphetshan.tencentwelcome
│ Encryto.db
│ _manifest
│
├─a
│ base.apk
│
└─db
Demo.db
解题思路
MainActivity
搜不出来或者没有思路时,应该先看Android程序的入口——一般来说是MainActivity函数,为了保险可以从“AndroidManifest.xml”查找入口点。
本题解压的apk运行后黑屏,入口为“com.example.yaphetshan.tencentwelcome.MainActivity”:
代码
MainActivity
public class MainActivity
extends AppCompatActivity
implements View.OnClickListener
{
private SQLiteDatabase a;
private a b;
private Button c;
private void a()
{
SQLiteDatabase.loadLibs(this);
this.b = new a(this, "Demo.db", null, 1);
ContentValues localContentValues = new ContentValues();
localContentValues.put("name", "Stranger");
localContentValues.put("password", Integer.valueOf(123456));
com.example.yaphetshan.tencentwelcome.a.a locala = new com.example.yaphetshan.tencentwelcome.a.a();
String str1 = locala.a(localContentValues.getAsString("name"), localContentValues.getAsString("password"));
String str2 = locala.b(str1, localContentValues.getAsString("password"));
str2 = locala.a(str1 + str2);
this.a = this.b.getWritableDatabase(str2.substring(0, 7));
this.a.insert("TencentMicrMsg", null, localContentValues);
}
public void onClick(View paramView)
{
if (paramView == this.c)
{
paramView = new Intent();
paramView.putExtra("name", "name");
paramView.putExtra("password", "pass");
paramView.setClass(this, AnotherActivity.class);
startActivity(paramView);
}
}
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130968603);
this.c = ((Button)findViewById(2131427417));
this.c.setOnClickListener(this);
paramBundle = getSharedPreferences("test", 0).edit();
paramBundle.putString("Is_Encroty", "1");
paramBundle.putString("Encryto", "SqlCipher");
paramBundle.putString("ver_sion", "3_4_0");
paramBundle.apply();
a();
}
}
a类
- 实例化一个数据库对象,并赋值“Demo.db”;
- 实例化一个对象ContentValues,并赋值“name”字段为“Stranger”和“password”字段为“123456”;
- 实例化“com.example.yaphetshan.tencentwelcome.a.a”,调用其中的函数a处理传入的“name”值和“password”值后保存到str1,str1传入函数b后返回str2;
再调用getWritableDatabase函数处理str2。
打开数据库
打开一个名为“TencentMicrMsg”的数据库,前两个参数是列名“name”和“password”,第三列是“F_l_a_g”:
new a(this, "Demo.db", null, 1); ……省略…… param SQLiteDatabase.execSQL("create table TencentMicrMsg(name text,password integer,F_l_a_g text)");
com.example.yaphetshan.tencentwelcome.a.a
函数a
public String a(String paramString1, String paramString2) { paramString1 = paramString1.substring(0, 4); paramString2 = paramString2.substring(0, 4); return paramString1 + paramString2; }
取前4个字节相加,“Stranger”[0-4]+“123456”[0-4]结果为“Stra1234”。
函数b
太长了就不放代码了,语雀放太多代码很卡。传参部分代码为:
String str2 = locala.b(str1, localContentValues.getAsString("password")); *参数1为str1(“Stra1234”)
通过“MessageDigest”类计算字符串“Stra1234”的MD5值;
- 将“Stra1234”与MD5值与“yaphetshan”拼接为新字符串;
- 计算2中字符串的SHA-1值
- 取SHA-1的前7个字符串
🐍Python🐍调用hashlib库对字符串进行MD5和SHA-1计算
如果计算机能安装Python的“pycipher”或“pysqlcipher3”等有解密功能的库,就不用下载数据库软件,但是我Python版本太高了,懒得整,没有一气呵成,就有点不舒服😑😑😑 ```python import hashlib md5 = hashlib.md5() sha1 = hashlib.sha1()
a = “yaphetshan” str1 = ‘Stra1234’ md5.update(str1.encode(‘utf8’)) str2 = md5.hexdigest()
tosha1 = str1 + str2 + a sha1.update(tosha1.encode(‘utf8’)) str2SHA1 = sha1.hexdigest()
ae56f99
print(“SHA-1后的字符串前7字节为:”, str2SHA1[0:7]) ```
打开加密数据库
尝试搜索“在线打开.db数据库”,基本都是解析无加密的数据库的,上传文件基本都是解析为无数据。
搜索“db数据库查看器”下载了“DB Browser for SQLite”,打开“DB Browser for SQLCipher.exe”(不是“DB Browser for SQLite.exe”,会出现无法识别的问题),拖入.db文件“Encryto.db”。
加密设置默认是4,手动改成3,输入密码“ae56f99”:
查看列“F_l_a_g”,值为“VGN0ZntIM2xsMF9Eb19ZMHVfTG92M19UZW5jM250IX0=”:
明显是Base64编码后的字符串,Base64解码为: