题目

CSDN免积分下载

查壳

先查壳(PKiD等),有壳脱壳,没壳用AndroidKiller等反编译工具打开查看JAVA代码
无壳APK

Java Decompiler - MainActivity-onClick

image.png

答案

Cas3_0f_A_CAK3

Writeup

解题

运行

两个输入框,第二个输入框明显是密码框(星号),自带数据(没用):
image.png
点击登录后,无吐司方式提示,在界面显示“Waiting fot you!”:(这里的一个小错误,暗示了后面悲惨的时间流逝)
image.png

解题思路

搜索字符串

使用反编译工具的字符串搜索功能,但不是搜索点击“登录”后的提示字符串“Waiting fot you!”。因为这个字符串作为界面布局的一部分,是写在资源(“res-values”)里的,对定位samli是不起作用的:
image.png
为什么APP一打开就有用户名密码呢?删除后点击“登录”,吐司消息提示“不能为空”:
image.png
因为吐司消息的代码是写在smali里的,所以通过它的参数,是可以定位到触发的代码:
image.png

MainActivity

搜不出来或者没有思路时,应该先看Android程序的入口——也就是MainActivity函数:
image.png

代码逻辑

MainActivity-onClick

  1. 先通过一个if判断,检查EditText是否有输入;
  2. 调用SecondActivity类创建Intent对象;
  3. 将输入的值保存到创建的Intent对象中;
  4. 最后调用startActivity启动Activity(有可能出题者的原意),即新建的Intent对象:

    1. if ((this.c.getText().length() == 0) || (this.d.getText().length() == 0))
    2. {
    3. Toast.makeText(this, "不能为空", 1).show();
    4. }
    5. else
    6. {
    7. String str1 = this.c.getText().toString();
    8. String str2 = this.d.getText().toString();
    9. Log.e("test", str1 + " test2 = " + str2);
    10. paramView = new Intent(this, SecondActivity.class);
    11. paramView.putExtra("ili", str1);
    12. paramView.putExtra("lil", str2);
    13. startActivity(paramView);
    14. }

    SecondActivity类

  5. 代码1-2行取出保存的编辑框的值;

  6. 将编辑框的值拼接后,通过“Encryto.doRawData”函数进行处理;
  7. 处理后的值与“VEIzd/V2UPYNdn/bxH3Xig==”对比要相等:

    String str = ((Intent)localObject).getStringExtra("ili");
    paramBundle = ((Intent)localObject).getStringExtra("lil");
    if (Encryto.doRawData(this, str + paramBundle).equals("VEIzd/V2UPYNdn/bxH3Xig=="))
    

    Encryto.doRawData函数

    public class Encryto
    {
     static
     {
         System.loadLibrary("JNIEncrypt");
     }
    
     public static native int checkSignature(Object paramObject);
    
     public static native String decode(Object paramObject, String paramString);
    
     public static native String doRawData(Object paramObject, String paramString);
    
     public static native String encode(Object paramObject, String paramString);
    
     public native String HelloLoad();
    }
    

    System.loadLibrary动态加载库文件

    System.loadLibrary(String libname)则只会从指定lib目录下查找,并加上lib前缀和.so后缀

System.loadLibrary("JNIEncrypt");

相当于libJNIEncrypt.so,这时候到APK解压路径\lib下查看,发现多个子文件夹,这是根据不同CPU架构兼容性创建的,随便挑一个分析即可(建议armeabi-v7a):
image.png

早期的Android系统几乎只支持ARMv5的CPU架构,目前支持七种CPU架构:ARMv5,ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64 (从2014年起),每一种都关联着一个相应的ABI。对应的ABI依次是:armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64,对应Android app工程中so库的不同目录。

IDA+SO

查壳为32位无壳ELF,拖入IDA反编译,搜索“doRawData”函数:
image.png
参数1明显是结构体,并且根据之前题目的经验,和Java代码可知,是“JNIEnv*”类型:
image.png
“Y”键修改:
image.png
并将一些参数重命名,便于阅读理解:
image.png

AES解密AES_Decrypt(%7B’option’:’UTF8’,’string’:’thisisatestkey%3D%3D’%7D,%7B’option’:’UTF8’,’string’:’’%7D,’ECB’,’Raw’,’Raw’,%7B’option’:’Hex’,’string’:’’%7D,%7B’option’:’Hex’,’string’:’’%7D)&input=VkVJemQvVjJVUFlOZG4vYnhIM1hpZz09)

image.png

⚠⚠⚠危险危险危险⚠⚠⚠

按照常规的逻辑,此时在APP的输入框内填入“aimagetencent”应该可以得到flag。
MainActivity已经执行完了,SecondActivity的代码中调用的“startActivity”却是和解密无关的类:
image.png
有可能是由于出题者粗心,或者考验答题者对于启动Activity的掌握😑(广播?)
实际上并没有启动输出flag的Activity(“FileDataActivity”)。

AndroidManifest.xml

可以看到有多个Activity,或者用objection列出:
安装frida和objection

FileDataActivity

搜索发现除了“AndroidManifest.xml”和本身,并没有被调用的痕迹:
image.png
被调用的“SecondActivity”搜索如下,在line153的“MainActivity”中被调用:
image.png
查看FileDataActivity类的Java代码发现功能比较简单,也是调用SO库,通过其中的函数“decode”对“9YuQ2dk8CSaCe7DTAmaqAA==”进行处理,将返回值作为“setText”的参数输出:

this.c.setText(Encryto.decode(this, "9YuQ2dk8CSaCe7DTAmaqAA=="))

Encryto.decode

对decode的参数进行类型设置以及重命名后如下:
image.png
通过AES算法128位ECB模式解密,其中密文“9YuQ2dk8CSaCe7DTAmaqAA==”,密钥“thisisatestkey==”:

strcpy(strKey, "thisisatestkey==");
strCipher = (*env)->GetStringUTFChars(env, a4, 0);
strFlag = (const char *)j_AES_128_ECB_PKCS5Padding_Decrypt(strCipher, strKey);
(*env)->ReleaseStringUTFChars(env, (jstring)a4, strCipher);
result = (*env)->NewStringUTF(env, strFlag);

解法

🐍Python脚本🐍

import base64
from Crypto.Cipher import AES

#初始化参数
strCipher = "9YuQ2dk8CSaCe7DTAmaqAA=="
strKey = "thisisatestkey=="

#转码和调用AES转发
aes = AES.new(strKey.encode("utf-8"), AES.MODE_ECB)
strFlag = aes.decrypt(base64.b64decode(strCipher))

#输出Flag
print("Flag为:", strFlag.decode("utf-8").rstrip('\x02'))

💯编码工具AES_Decrypt(%7B’option’:’UTF8’,’string’:’thisisatestkey%3D%3D’%7D,%7B’option’:’Hex’,’string’:’’%7D,’ECB’,’Raw’,’Raw’,%7B’option’:’Hex’,’string’:’’%7D,%7B’option’:’Hex’,’string’:’’%7D)&input=OVl1UTJkazhDU2FDZTdEVEFtYXFBQT09)💯

image.png
还可以动态调试,但是目前我adb调试环境没搭好。
动态调试直接调用指定Activity:

am start com.tencent.testvuln/.FileDataActivity