拿到题目先查壳,可以发现无壳
直接拖进ida分析,搜索main函数
可以看到flag的长度为19,且有个写文件的操作。我们就运行程序看看,生成的文件长啥样。
生成了一个Your_input文件,用记事本打开发现里面的内容和我们输入的内容不一致,根据题目的名称提示,怀疑这个程序hook了WriteFile这个api。
在写入文件之前有一个可疑的函数sub_401220,我们跟进去分析一下.
可以看到这里获取了当前进程的id 还获取了当前进程的句柄,加载了一个模块,以及获取了一个地址.
可以看到这两个参数分别对应kernel32.dll,以及WriteFile,说明先去加载了这个kernel32.dll,然后去获取了WriteFile的函数地址.
后面有一个0xE9 对应的汇编指令为jmp,下面有一个计算偏移的操作。再看函数sub_4010D0()
是一个前面的byte_40C9BC开始的五个字节写入。对应的就是jmp 某个地址. 而写入的地址为WriteFile的函数地址.说明调用WriteFile后会jmp到sub_401080,即跳到我们自己函数来进行处理,因此对函数sub_401080进行分析.
也是有写文件的操作 但是前面有一个sub_401000函数 对我们输入的字符串进行了处理.所以最后输出文件的内容跟我们输入的值不一样.进入sub_401000函数进行分析.
可以看到是经典的异或加密,然后和一个字符串比较.
现在回到main函数,看下sub_401240函数
也是进行了一通操作,但是并不会将numberOfBytesWritten的值修改为0,所以真正验证的函数为sub_401000.至此此程序分析结束,开始写脚本.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
unsigned int cmpstr[]={
0x61,0x6A,0x79,0x67,0x6B,0x46,0x6D,0x2E,0x7F,0x5F,0x7E,0x2D,0x53,0x56,0x7B,0x38,
0x6D,0x4C,0x6E,0x00
};
char flag[20]={0};
int v3;
for(int i=0;i<19;i++){
if(i==18){
flag[i]=cmpstr[i]^0x13;
}
else{
int v3=cmpstr[i]^i;
if(i%2){
flag[i]=v3+i;
}
else{
flag[i+2]=v3;
}
}
}
for(int i=0;i<19;i++){
cout<<flag[i];
}
system("pause");
return 0;
}
最后结果:
在最前面补0后,即为结果:
flag{Ho0k_w1th_Fun}