这道题真的难搞,我现在还不知道正解,不过我这搞法也可以做出来。
拿到题目之后,直接IDA打开,发现代码看不了
可以看到有大段的数据,代码却很少,可以推测加了壳。
打开string,找到了upx。。所以是upx壳,直接脱壳
运行upx自动脱壳
upx -d elf -o output
再用IDA打开output,发现恶心的死,全部都是mov指令,连跳转都没有
这里我分析了一下,程序开头调用了signaction函数,这个是用来注册异常处理程序的。
这个程序总得让人输入flag,再来验证吧,肯定得调用read和write,发现其中有一段
这里显然动调运行到这eax时等于0,这里就触发了异常,让后就会根据external的内容运行相应的函数,这大概就是这个程序调用函数的方式,其实我也只搞懂了这部分
我当时就在思考,这程序没用别的指令,而数据区段中没有一点与flag有关的数据,那么flag肯定存在于某个mov指令中(由于指令种类少,很复杂的加密肯定难的搞出来的)。
可以猜测就是mov XX,'f’之类的指令
之后有了解到有idc脚本,直接拿来全程序段搜索一下满足条件的立即数(可能是属于flag的字符)
#include<idc.idc>
static isAscii(p) //判断符合条件的字符
{
if(Byte(p)<='9' && Byte(p)>='0')
return 1;
if(Byte(p)<='z' && Byte(p)>='a')
return 1;
if(Byte(p)<='Z' && Byte(p)>='A')
return 1;
if(Byte(p)=='}' || Byte(p)=='{' || Byte(p)=='_' || Byte(p)=='@' || Byte(p)=='!' || Byte(p)=='#' || Byte(p)=='&' || Byte(p)=='*')
return 1;
return 0;
}
static main()
{
auto start=0x0804829C,end=0x08060B32; //代码段起止地址
auto point=start;
auto str="";
while(point<=end)
{
if(isAscii(point) && Byte(point+1)==0 && Byte(point+2)==0 && Byte(point+3)==0)
{ //汇编中立即数一般都是DWORD
Message("%X %c\n",point,Byte(point));
str=str+Byte(point);
}
point=point+1;
}
Message("%s\n",str); //可能是flag
}
接下来直接在ida下运行这个脚本,果不其然flag就在这个里面
flag->ALEXCTF{M0Vfusc4t0r_w0rk5_l1ke_m4g1c}
前面那个2显然是有问题的字符,舍弃掉,直接交上去发现就过了
这种做法属实憨批。。。。
不过这种变态的代码,我是真的不想去一行行看