关于攻防世界ph0en1x ctf的逆向
1、打开画面内容如下,需要进行flag验证
2、那么肯定有个验证函数进行判断,直接跟进对应的活动进行反编译查看比较函数,这里对应的活动是MainActivity,可以直接看到判断函数
public void onGoClick(View paramView)
{
paramView = this.etFlag.getText().toString();
if (getSecret(getFlag()).equals(getSecret(encrypt(paramView)))) {
Toast.makeText(this, "Success", 1).show();
}
for (;;)
{
return;
Toast.makeText(this, "Failed", 1).show();
}
}
3、关键看if判断语句,它是通过getSecret(getFlag()) 和 getSecret(encrypt(你输入的值)) 进行比较,如果相同则成功,那么也就是让getFlag和encrypt(你输入的值)相同就行,那么可以先进行调试getFlag返回值是什么,结果发现两个都是native方法,都是写在so层的,那么也就是需要进入so层进行调试
public native String encrypt(String paramString);
public native String getFlag();
public String getSecret(String paramString)
4、这里自己讲java层和so层的调试,顺便复习下这几天学的知识,这里调试用的是JEB,直接在函数开头进行断点,执行如下命令,然后进行JEB断点调试
adb shell am start -D -n com.ph0en1x.android_crackme/com.ph0en1x.android_crackme.MainActivity
5、总的过程就是先 CH - 14H就是获取输入框中的字符串,接着16H - 24H 获取getSecret(getFalg())的内容后面就是获取加密输入框中的字符串,最后进行比较
那么这里就可以拿到getFalg的内容是多少,1CH的时候放到v1寄存器中
值为:ekXfXXXXXXfn0mFXXXXXXrbXqanqntfgXXXXX
那么现在就是如何让 this.encrypt("输入的值") == ekXfXXXXXXfn0mFXXXXXXrbXqanqntfgXXXXX
这个条件进行成立,可以继续调试看下v2寄存器中处理的值(也就是encrypt函数处理过后),可以发现只是转换为ascii码然后进行-1再还原的操作
那么也就是让v1的寄存器全部都+1就可以进行直接相等了,还原代码如下
char s[]="ek`fz@q2^x/t^fn0mF^6/^rb`qanqntfg^E`hq|";
int main()
{
for(int i=0;i<strlen(s);i++)
{
printf("%c",s[i]+1);
}
return 0;
}
答案就是: flag{Ar3_y0u_go1nG_70_scarborough_Fair}
接着继续进so层调试,看看getFlag函数是如何实现的,直接将so文件拖入ida分析,为什么是这个文件,因为静态代码块中加载动态链接库的时候就是这个
getFlag函数如下,就是开辟了一段栈空间,然后进行赋值操作
继续看encrypt
上面也就是实现了自增1,encrypt的作用!