1、首先将APK放进模拟器中运行,查看其报错关键字“Try again”,为后面做关键词定位做准备
2、利用APKIDE加载APK并进行反汇编
3、搜索“Try again”定位到Mainactivity.class利用jd查看其java源码(如果smali基础较好可以直接看smali代码)
源码:
public class MainActivity
extends AppCompatActivity
{
private String getFlag()
{
return getBaseContext().getString(2131427360);
}
private void showMsgToast(String paramString)
{
Toast.makeText(this, paramString, 1).show();
}
public void checkPassword(String paramString)
{
if (paramString.equals(new String(Base64.decode(new StringBuffer(getFlag()).reverse().toString(), 0)))) {
showMsgToast("Congratulations !");
} else {
showMsgToast("Try again.");
}
}
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2131296283);
((Button)findViewById(2131165261)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
paramAnonymousView = ((EditText)MainActivity.this.findViewById(2131165253)).getText().toString();
MainActivity.this.checkPassword(paramAnonymousView);
}
});
}
}
4、对getflag()方法中调用的ID进行逐级搜索查看到其加密字符串:
991YiZWOz81ZhFjZfJXdwk3X1k2XzIXZIt3ZhxmZ
5、在checkPassword()方法中对该字符串进行了解密即可的flag,以下为解密步骤
reverse() ----> Base64.decode
对字符串进行反转 ----> 对反转后的字符串进行base64解密
1、利用模拟器安装该APK发现界面与signin相似,直接利用androidkiller打开并反编译
2、查看Mainactivity.class文件,并利用jd打开
部分关键源码:
onCreate方法:
public void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130968601);
setTitle(2131099677);
this.edit_userName = "Tenshine";
this.edit_sn = ((EditText)findViewById(2131492945));
this.btn_register = ((Button)findViewById(2131492946));
this.btn_register.setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
if (!MainActivity.this.checkSN(MainActivity.this.edit_userName.trim(), MainActivity.this.edit_sn.getText().toString().trim()))
{
Toast.makeText(MainActivity.this, 2131099678, 0).show();
return;
}
Toast.makeText(MainActivity.this, 2131099675, 0).show();
MainActivity.this.btn_register.setEnabled(false);
MainActivity.this.setTitle(2131099673);
}
});
}
checkSN方法:
private boolean checkSN(String paramString1, String paramString2)
{
if (paramString1 != null) {
try
{
if (paramString1.length() == 0) {
return false;
}
if ((paramString2 != null) && (paramString2.length() == 22))
{
Object localObject = MessageDigest.getInstance("MD5");
((MessageDigest)localObject).reset();
((MessageDigest)localObject).update(paramString1.getBytes());
paramString1 = toHexString(((MessageDigest)localObject).digest(), "");
localObject = new StringBuilder();
int i = 0;
while (i < paramString1.length())
{
((StringBuilder)localObject).append(paramString1.charAt(i));
i += 2;
}
paramString1 = ((StringBuilder)localObject).toString();
boolean bool = ("flag{" + paramString1 + "}").equalsIgnoreCase(paramString2);
if (bool) {
return true;
}
}
}
catch (NoSuchAlgorithmException paramString1)
{
paramString1.printStackTrace();
}
}
return false;
}
3、可见在oncreate中调用了checkSN并传递两个值(‘Tenshine’和前台输入的flag)
4、在checkSN中首先对‘Tenshine’进行了MD5加密,之后截取其偶数位的字母;将截取的字母加上flag{}恰为22个字母,与我们输入falg在验证中长度必须为22相互验证。由此可以解除flag
flag在Mainactivity.xml里(脑洞题,不解释)
1、利用Androidkiller对apk进行反编译利用jd查看其源文件定位到Mainactivity:
protected void onCreate(final Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130968602);
paramBundle = (EditText)findViewById(2131427413);
((Button)findViewById(2131427414)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
new encode();
if (encode.check(paramBundle.getText().toString()))
{
Toast.makeText(MainActivity.this.getApplicationContext(), "correct", 1).show();
return;
}
Toast.makeText(MainActivity.this.getApplicationContext(), "failed", 1).show();
}
});
}
}
2、发现其调用了encode()方法,点击查看:
public class encode
{
private static byte[] b = { 23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 32, 32 };
public static boolean check(String paramString)
{
byte[] arrayOfByte1 = paramString.getBytes();
byte[] arrayOfByte2 = new byte[16];
int i = 0;
while (i < 16)
{
arrayOfByte2[i] = ((byte)((arrayOfByte1[i] + b[i]) % 61));
i += 1;
}
i = 0;
while (i < 16)
{
arrayOfByte2[i] = ((byte)(arrayOfByte2[i] * 2 - i));
i += 1;
}
return new String(arrayOfByte2).equals(paramString);
}
}
以上为它对flag的加密算法,我们反向求解的运算法则:a[i]=122*n - 2b[i] +i (a[i]:flag对应的数列 n:任意值)对以上求解即可得到flag
1、本体通过对XMan.java进行分析,源码:
public class XMan {
public static void main(String[] args) {
String v6 = "+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
String s = "xsZDluYYreJDyrpDpucZCo";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
int tmp = v6.indexOf(s.charAt(i));
String ss = Integer.toBinaryString(tmp);
if (ss.length() == 5) {
ss = "0" + ss;
} else if (ss.length() == 4) {
ss = "00" + ss;
} else if (ss.length() == 3) {
ss = "000" + ss;
} else if (ss.length() == 2) {
ss = "0000" + ss;
} else if (ss.length() == 1) {
ss = "00000" + ss;
} else if (ss.length() == 0) {
ss = "000000" + ss;
}
sb.append(ss);
}
String x = sb.toString() + "0000";
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < x.length(); i += 8) {
String tmp = x.substring(i, i + 8);
byte b = (byte) Integer.parseInt(tmp, 2);
stringBuilder.append((char) b);
}
System.out.println(stringBuilder.toString());
}
}
2、通过对源码的分析其算法思路是:查找字符串s在v6中对应的位置–>计算该数的二进制并补足6位–>按顺序连接所有二进制并在最后补0使其为8的倍数–>按每8位截取并转化为字符串即可解得
3、从上述代码可以发现它好像是base64解密,找到base64解密源码然后调用它解密
4、更简单的方法:既然已经给了java文件,为什么不直接用他写好的算法呢–>编译一下然后运行
emmm本题分析了半天结果还是基础知识不扎实啊,直接上大神的WP链接:https://www.52pojie.cn/thread-820158-1-1.html
1、将APK反编译后发现调用了checkflag()方法,该方法存在于libcheckso.so文件中
2、利用IDA查看该方法并查看Java_com_example_p7xxtmx_1g_fakefunc_check_checkflag()方法——然后分析了半天。。。。接下来蒙蔽
3、看了大神的WP后get到新姿势(当对方法分析发现没有什么异常的时候,可以对JNI_OnLoad或者.init_array进行检查,一般会在这里面增加一些跳转代码来隐藏真正的函数)
4、在.init_array中进行了跳转到sub_E28,在这个函数里又调用了sub_E08,分析后得出这里进行了一个base64解密
5、在sub_E28里又有一个想base64但又不是base64加密的字符串
4、然后就是对后面的函数中的跳转进行查看,没用反回对下一个跳转继续查看。。。
5、当跳转到sub_F24就是我们所要的关键之一(利用findcrypt3能够查看加密算法)byte_4255-对应-RijnDael_AES_LONG_4255所以判断为AES加密
6、然后上网对前面的两个字符串试一下。得出了flag
本题的WP与上一题同出一处,因为不会不敢写。。。等以后回头再来做一做
emmm直接编译运行了一下Xman.java然后就是flag了。。。