刚来看雪论坛,就碰上腾讯的安全竞赛,恰逢盛会,怎能错过。
这段时间参加了第一阶段的比赛,四个题目,都提交了自己的答案,这里作下总结,和各位新人朋友共勉。
第一题,30多个字节
第一题是最让我心里难受的。由于是开发人员出身,找到程序的bug还是比较快的,84个字节溢出,很快找到了,但是。。。。。。就在这里卡住了。。。卡了我一个晚上,睡觉睡得都不舒服,第二个白天也是工做不安心。。。就是不知道怎么重新定向这种间接引用的指令。
call [edx]
我的思路很简单。。。就是找到一条这样的指令:
jmp [esp+xx] 或者 add esp,xx retn,xx大于等于0x28
这种指令在user32.dll里很多,但是怎么让[edx]指向这条指令。。。。搜遍内存,没找到这样的地址。。。。。就在要放弃的时候,看到那个题目下面有人说硬编码,一下子雾开云散。。。原来可以硬编码。。。。要是第一关没过,后面的估计也没有心情了。
第二题,纯编程题,擅长啊。。。花了点时间,整了个算法。
测试数据:P4 2.8G vc2008,release O2优化,算法仅需15ms,打印30ms,共45ms左右
信心大增。
第三题,keygenme,由于之前发过一遍,【第一次keygen详解,献给各位兄弟】http://bbs.pediy.com/showthread.php?t=122264,心里有数,手上不慌。但是这个比赛日期恰是周六周日,而这两天我要陪老婆。。。。不过还是花了一个通宵把注册机找出来了。
第四题,对我很难,而且周日,周一的时间,很不凑巧。基本想放弃了。昨天晚上在看雪找到了一个pespin 1.32的脱壳机,居然可以用,还提供了ollydbg脚本。不过我一开始就使用的ollydbg2.0,不支持插件,(其实我是很喜欢指令调试的,曾经的gdb,wingdb,dbx让我者迷又经常混乱。。。)所以看不懂ollydbg sript,折腾半天后在看雪上找了个教程,对着教程一条条看指令。。。不过最后还是只提交了个脱壳机脱出来的程序。。
这7-8天时间真的是够累啊,白天上班,晚上加班学习搞这些题。不过付出总会有回报,我感觉自己在安全方面慢慢入门了。呵呵呵。
另外,由于是临时会员,下载竞赛题目就花了我不少kx。哎。。。
废话少说,现在开始第三题的分析。
第三题我主要是用IDA分析,分析完后用OD验证。
keygenme的验证主流程在函数sub_4012F0()中,使用IDA逆向后c代码如下:
char __cdecl sub_4012F0()
{
//逆向代码有删减
v19 = (int)"ABCDEFGHJKMNPQRSTVWXYZ1234567890";
v0 = SendMessageA(hWnd, 13u, 33u, (LPARAM)lParam);
v1 = v0;
if ( v0 )
{
v0 = SendMessageA(dword_40DBB4, 0xDu, 0x24u, (LPARAM)&v27);
if ( v0 == 35 )
{
v3 = 0;
v2 = &v44;
do
{
v0 = 0;
while ( v3 != byte_40CF98[v0] ) // 第9,18,27个字符是‘-‘
{
++v0;
if ( (unsigned int)v0 >= 3 )
goto LABEL_9;
}
if ( *(&v27 + byte_40CF98[v0]) != 45 )
return v0;
LABEL_9:
if ( v0 == 3 )
{
LOBYTE(v0) = sub_407FB0(&v18, *(&v27 + v3));// 校验序列号中是否含有不在"ABCDEFGHJKMNPQRSTVWXYZ1234567890"中的字符
if ( (_BYTE)v0 == -1 )
return v0;
*v2++ = *(&v27 + v3);
}
++v3;
}
while ( v3 < 35 );
LOBYTE(v0) = sub_407E40(&v18, (int)&v44, 32, (int)&v38, (int)&v17); //对密码进行加密===>v38,长度==>v17
if ( (_BYTE)v0 )
{
LOBYTE(v0) = sub_401000(v1, (int)&v20, (int)lParam); //对用户名加密 ==> v20
if ( (_BYTE)v0 )
{
v4 = 20;
v6 = &v20;
v5 = &v38;
do
{
if ( *(_DWORD *)v5 != *(_DWORD *)v6 )
goto LABEL_19;
v4 -= 4;
v6 += 4;
v5 += 4;
}
while ( (unsigned int)v4 >= 4 );
if ( v4 )
{
LABEL_19:
v7 = (unsigned __int8)*v5 - (unsigned __int8)*v6;
if ( (unsigned __int8)*v5 != (unsigned __int8)*v6
|| (v8 = v4 - 1, v10 = (int)(v6 + 1), v9 = (int)(v5 + 1), v8)
&& ((v7 = *(_BYTE *)v9 - *(_BYTE *)v10, *(_BYTE *)v9 != *(_BYTE *)v10)
|| (v11 = v8 - 1, v13 = v10 + 1, v12 = v9 + 1, v11)
&& ((v7 = *(_BYTE *)v12 - *(_BYTE *)v13, *(_BYTE *)v12 != *(_BYTE *)v13)
|| (v15 = v13 + 1, v14 = v12 + 1, v11 != 1)
&& (v7 = *(_BYTE *)v14 - *(_BYTE *)v15, *(_BYTE *)v14 != *(_BYTE *)v15))) )
{
v0 = 1;
if ( v7 <= 0 )
v0 = -1;
LABEL_29:
if ( !v0 )
LOBYTE(v0) = MessageBoxA(
dword_40DBB8,
"Congratulations! \n You will be the keygen machine!",
"Success!",
0);
return v0;
}
}
v0 = 0;
goto LABEL_29;
}
}
}
}
return v0;
}
char __usercall sub_401000<al>(int a1<ecx>, int a2<edi>, int a3)
{
//逆向代码有删减
v3 = a1;
v17 = 0;
memset(&v18, 0, 0x2Bu);
v12 = dword_40AB90;
v13 = dword_40AB94;
VolumeSerialNumber = 0;
v11 = 0;
v10 = 0;
v14 = dword_40AB98;
v15 = dword_40AB9C;
v16 = dword_40ABA0;
if ( a2 && a3 )
{
GetVolumeInformationA("C:\\", 0, 0, &VolumeSerialNumber, 0, 0, 0, 0); //获取卷标
sub_407950(&v17, a3, v3);
v5 = BYTE1(VolumeSerialNumber);
v6 = BYTE2(VolumeSerialNumber);
*(&v17 + v3) = VolumeSerialNumber; //把卷标加到username后
v7 = BYTE3(VolumeSerialNumber);
*(&v18 + v3) = v5;
*(&v19 + v3) = v6;
*(&v20 + v3) = v7;
v8 = sub_4078E0("Tencent");
sub_407950(&v21[v3], "Tencent", v8);
sub_407C40(&v10, (int)&v17, v3 + 11); //把Tencent字符串加到卷标后
sub_407D00(&v10, a2); //使用变形的sha1对username+c盘卷号+"Tencent"散列。
result = 1;
}
else
{
result = 0;
}
return result;
}
DWORD const_value_1 = 0xB1CAB1CA;
DWORD const_value_2 = 0xCCBFCCBF;
DWORD const_value_3 = 0xBFB2D6BE;
DWORD const_value_4 = 0xF8C7D8B5;
DWORD const_value_5 = 0xEEC7BCCD;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)