下载附件,拿到手一个zip的文件,解压出来的文件有问题,看来zip被改过
Hxd打开,去搜一下关于zip的结构,在十六进制里看到,本地文件头里显示的未加密
50 4B 03 04 14 00 00 00 08 00,这里的08 00加密标志位标识没用加密

那就很奇怪了,我们找一下有没有被隐藏的数据,搜索50 4B 01 02或者50 4B 05 06,看看中央文件头

找到了,这里的50 4B 01 02 1F 00 14 00 09 00,在zip格式里,文件头最低位如果是奇数,则表示文件被加密,这里最后的09 00,读过来也就是0009,表示文件被加密了,我们把这里改成00 00,文件就可以修复成功了,解压进去后,发现一个叫“听说大家很怕VMP?“的文件
die识别成了普通的text,还是HxD打开看看十六进制

能看到.MZ头和ELF的标志,而且还有个VMP在里面,既然有MZ头但是结尾不是PE却是ELF,看来这个文件也被改了,开头有.,那可能是ELF的开头.ELF,我们把这里改成.ELF,将7F 4D 5A 00改成7F 45 4C 46
修改后可以被识别成linux文件了,但是没查出来有什么壳或者混淆,先丢进IDA看看

明显被加壳了哇,但是还不确定是什么壳,如果按标题说的是VMP,而且十六进制里也有VMP,尝试往这个方向走一走,但是走了半天都不行,去查wp发现不是VMP,是魔改的upx壳,尝试修改十六进制改不明白,于是决定手动脱壳
在虚拟机里运行远程调试,这里脱壳的思路参考了ELF64手脱UPX壳实战 - 吾爱破解 - 52pojie.cn
IDA远程调试找OEP,ELF不像PE可以直接ESP找到OEP,在几番寻找后和大佬帮助后也是终于找到了明显的start函数开头位置

这里的xor ebp,ebp和后面的hlt是典型的linux start函数的特征,在这里用前面脱壳思路参考的脚本,但是有个问题,原先的脚本有问题,脚本内的寻址是当时别人脱壳实战的寻址,而我们这里是不一样的,在大佬的帮助下,重新撰写了脚本,改成了自动寻址
#include <idc.idc>
#define PT_LOAD 1
static qword_to_le(file, value)
{
auto i;
for (i = 0; i < 8; i++)
{
fputc(value & 0xFF, file);
value = value >> 8;
}
}
static word_to_le(file, value)
{
fputc(value & 0xFF, file);
fputc((value >> 8) & 0xFF, file);
}
static main(void)
{
auto ImageBase, magic, e_entry, e_phoff, e_phnum, e_phentsize;
auto ph, i, ph_type, p_offset, p_vaddr, p_filesz, p_memsz;
auto ea, dump_path, dumpfile, saved;
ImageBase = get_imagebase();
magic = dword(ImageBase);
if (magic != 0x464C457F && magic != 0x7F454C46)
{
msg("[-] ImageBase 0x%X is not an ELF header. Stop at OEP first.\n", ImageBase);
return;
}
e_entry = qword(ImageBase + 0x18);
e_phoff = qword(ImageBase + 0x20);
e_phentsize = word(ImageBase + 0x36);
e_phnum = word(ImageBase + 0x38);
msg("[*] ImageBase = 0x%X\n", ImageBase);
msg("[*] e_entry = 0x%X\n", e_entry);
msg("[*] e_phoff = 0x%X, e_phentsize = 0x%X, e_phnum = %d\n",
e_phoff, e_phentsize, e_phnum);
if (e_entry == 0x445040 || e_phnum == 3)
{
msg("[!] This still looks like the packed UPX stub.\n");
msg("[!] Break at 0x44531B (jmp r13), run to it, then dump.\n");
}
dump_path = get_idb_path() + ".dumped.elf";
dumpfile = fopen(dump_path, "wb");
if (!dumpfile)
{
msg("[-] Failed to create dump file: %s\n", dump_path);
return;
}
ph = ImageBase + e_phoff;
saved = 0;
for (i = 0; i < e_phnum; i++)
{
ph_type = dword(ph);
if (ph_type == PT_LOAD)
{
p_offset = qword(ph + 0x08);
p_vaddr = qword(ph + 0x10);
p_filesz = qword(ph + 0x20);
p_memsz = qword(ph + 0x28);
if (p_filesz > 0)
{
ea = p_vaddr;
if (ea < ImageBase)
ea = ImageBase + p_vaddr;
msg("[*] LOAD %d: EA=0x%X, file_off=0x%X, filesz=0x%X, memsz=0x%X\n",
i, ea, p_offset, p_filesz, p_memsz);
if (!savefile(dumpfile, p_offset, ea, p_filesz))
msg("[-] savefile failed for LOAD %d\n", i);
else
saved++;
}
}
ph = ph + e_phentsize;
}
/*
* Runtime memory normally does not contain section headers. They are not
* required for execution, and dangling section-header offsets confuse tools.
*/
fseek(dumpfile, 0x28, SEEK_SET); // e_shoff
qword_to_le(dumpfile, 0);
fseek(dumpfile, 0x3C, SEEK_SET); // e_shnum
word_to_le(dumpfile, 0);
fseek(dumpfile, 0x3E, SEEK_SET); // e_shstrndx
word_to_le(dumpfile, 0);
fclose(dumpfile);
msg("[+] Dumped %d LOAD segments to: %s\n", saved, dump_path);
msg("[+] Kept e_entry = 0x%X. If it is 0x445040, dump again at OEP.\n", e_entry);
}
在xor ebp,ebp处alt+f7,使用这个脚本即可dump出脱壳的文件,然后我们再把脱壳完的文件拖进IDA分析
进入后直接查找字符串,input_flag:,定位到关键函数
然后这里有点问题,这里最后一块区域的显示非常奇怪,我们可以看到验证区域的unk表非常的怪,进去恢复一下

可以明显看出来,unk表其实是个dd类型而不是db,我们把它恢复成dd类型,就变成了如下图的模样

然后呢,从前面的代码进行分析,前面几个明显的ascii码分别就是wasd,可以联想到经常考的走迷宫游戏,v13和v14分别就是坐标,在验证前,要求我们输入完后,得到的坐标v13乘8然后加上v14,给到v6,确认和前表内的数据比是否为1

大概可以想到,走迷宫的地图是8个一行的,把表里的数据整理一下,按8位一行的形式进行排列,如下图

走迷宫,得到dsddssaassddsddwwddsss,提交一波

ok,没问题,题目实际逻辑还是很简单的,麻烦的是看出来是upx以及脱壳的步骤非常困难

2445

被折叠的 条评论
为什么被折叠?



