第三届上海市大学生网络安全大赛
原创2024年3月19日大约 4 分钟
第三届上海市大学生网络安全大赛
crackme
直接用ida打开。发现会报错。
而且函数很少,内容也非常杂乱。
还有一点花指令。很大可能有壳和代码混淆。
因为此前没做过这两种情况,这是我第一次做这种题。
这道题是学长发给我的,据提示动调脱壳。
X32dbg
X32dbg动调,F9回到程序初始位置,然后F8下一位,如果遇到循环,就点到下一位并F4跳到下一位就可以了,
走到主函数已经出来然后F7进入,卡住了F7没反应,我只好重新来一遍了。
F7进来后直接dump。
这样就脱壳成功了。
然后我去网上查了一下dump是啥意思。
dump是一个计算机科学中的术语,一般指将数据导出、转存成文件或静态形式。dump可以作为动词或名词使用,例如把内存某一时刻的内容,dump成文件,或者说生成一个dump文件。dump文件是一个进程或者系统在某一个给定的时间的快照,包含了程序运行的各种信息,可以用来调试驱动程序。
把保存的文件用IDA分析一下
发现主函数就这样出来了。可以正常分析了。
int start()
{
void (__cdecl *v0)(char *); // esi
int v2; // eax
char v3; // [esp+4h] [ebp-38h] BYREF
char v4[51]; // [esp+5h] [ebp-37h] BYREF
v3 = 0;
sub_4018F4(v4, 0, 49);
v0 = (void (__cdecl *)(char *))dword_402094;//等于输出。所以后面都是输出。
dword_402094(aPleaseInputFla); //输出
dword_402090(&v3, 44); //输入
if ( strlen(&v3) == 42 ) //可以看出flag是42位。
{
v2 = 0;
while ( (v4[v2 - 1] ^ byte_402130[v2 % 16]) == dword_402150[v2] )
{
if ( ++v2 >= 42 )
{
v0(aRight);
return 0;
}
}
v0(aError);
return 0;
}
else
{
v0(aError);
return -1;
}
}
分析完之后,当达到条件时,循环才结束。
我们现在知道 dword_402150和byte_402130的值
byte_402130虽然说只有一个值,根据做题经验,和他这个地址相邻,可以推断出,他们应该是一个数组的。而且把 74h转换一下变成了 t,连起来就是
“ this_is_not_flag”。说明是一起的,都是byte_402130的值。
然后全部选中 dword_402150的值,shift+E 导出值
unsigned char ida_chars[] =
{
0x12, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x5C, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x5A, 0x00,
0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x6E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x44, 0x00,
0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3E, 0x00,
0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4C, 0x00,
0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00,
0x5B, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
发现0x48以后都是0,就不用看后面的了。
然后发现数值都是4位一个,那我们写脚本的时候乘以4就好了。
代码如下
a = 'this_is_not_flag'
b = [0x12, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x5C, 0x00, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x5A, 0x00,
0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x6E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x44, 0x00,
0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x0D, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3E, 0x00,
0x00, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4C, 0x00,
0x00, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00,
0x17, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00,
0x5B, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48]
c = []
for i in range(42):
c.append(chr(b[i*4] ^ ord(a[i % 16])))
print(''.join(c))
总结
- 虽然不在一起,地址相邻,就有可能是在一起的值。
- 学会了一些动调的基本操作。
- 导出dword_402150值得时候,会发现末尾很多0,中间也很多0,一般舍弃末尾得,中间的0不能舍弃,因为中间的是有用得值,末尾可能和空值一样(差不多那个意思,不大懂原理)然后开规律把有用的值用上,比如我得数组都乘了4。