看雪CTF逆向练习题-[乘风破浪] 难度171
题目链接: https://ctf.pediy.com/itembank.htm上传统
无壳,放心干。
看图标跟library,是个MFC程序,用xspy工具查响应事件函数。
两个事件相应函数对应两个函数,查下按钮的ID,ID为1,那么ID为1的事件函数我们需要逆的函数。
拖到IDA,跳到0401830 Look Look,F5看下伪代码
看到SetEvent函数,向一个事件发信号,大胆推断,这个程序使用了多线程。所以我们拖到OD去xxoo它。
多次拖OD后发现地址会变化,估计是搞了动态基址,我们用PE工具干掉。
NT头-》可选头-》DllCharacteristics,把动态基址的位去掉即可。
拖到OD后,会断在主模块,这是线程还没创建,我们给创建线程函数下断 bp CreateThread后运行
断下后,我们看下CreateThread的回调函数,有一些是输入法的回调函数,我们要过滤掉。
所以一共有两个本模块的回调函数,4011B0 和 401220。
我们在这些回调函数的WaitForSingleObject 函数的后面下断点,看看那个函数会断下,最后是发现401220 函数会断下。
所以我们到IDA跳到401220结合OD,动静态结合分析。
void __stdcall sub_401220(LPVOID lpThreadParameter)
{
_DWORD *v1; // edi
DWORD v2; // esi
int V3; // ecx
_DWORD *v4; // ebp
int v5; // eax
int v6; // ebx
int v7; // eax
int v8; // edx
int v9; // edi
int v10; // ecx
v1 = lpThreadParameter; // 我们输入的用户名
if ( lpThreadParameter && dword_442A64 )
{
while ( 1 )
{
v2 = WaitForSingleObject(hEvent, 0xFFFFFFFF);
ResetEvent(hEvent);
if ( !v2 )
{
V3 = *(_DWORD *)(v1 - 12); // V3是用户名长度
v4 = v1 + 30; // V4 = 用户名
if ( V3 )
{
v5 = *(_DWORD *)(v1 - 12); // V5 = 注册码长度
if ( v5 )
{
if ( V3 == v5 && !(unsigned __int8)sub_401870(v1 + 30, v1 + 31) )// V1+30 = 用户名 ; V1+31 = 注册码
// 这里判断 用户名 == 注册码 && strcmp(用户名,注册码)
{
v6 = *(_DWORD *)(*v4 - 12); // V6 = 注册码长度
if ( v6 >= 8 ) // 长度 >=8
{
v7 = 0;
v8 = v6 - 1;
v9 = 2 * v6 - 2;
while ( 1 )
{
if ( v7 < 0
|| v7 > *(_DWORD *)(*v4 - 12)// *(_DWORD *)(*v4 - 12) = 用户名长度
|| v8 < 0 // V8 = 长度 -1
|| (v10 = *((_DWORD *)lpThreadParameter + 31), v8 > *(_DWORD *)(v10 - 12)) )// *(_DWORD *)(v10 - 12)) 注册码长度
//
// V10= *((_DWORD *)lpThreadParameter + 31) 注册码
{
sub_401E00(-2147024809);
}
if ( *(_WORD *)(*v4 + 2 * v7) != *(_WORD *)(v9 + v10) )// *(_WORD *)(*v4 + 2 * v7) 取出用户名每个子串,V7是下标,从0开始+2
//
// V10是注册码,V9是(注册码的长度 *2-2),下标从长度开始,每个循环-2
//
// 用户名跟注册码的缓冲区都处理过,变成了宽字符,每个字符占2字节。
//
break;
++v7;
v9 -= 2;
--v8;
if ( v7 >= v6 ) // 用户名下标 >= 注册码长度
{
if ( hObject ) // 成功
SetEvent(hObject);
break;
}
}
}
}
}
}
}
if ( !dword_442A64 )
break;
v1 = lpThreadParameter;
}
}
}
以上算法就能得出,注册码与用户名的长度必须一致,并且注册码长度必须大于等于8,。
注册码就是用户名倒过来的(裤子都脱了,你就给我看这个?)
謝謝分享,學習學習 if ( V3 == v5 && !(unsigned __int8)sub_401870(v1 + 30, v1 + 31) )// V1+30 = 用户名 ; V1+31 = 注册码
// 这里判断 用户名 == 注册码 && strcmp(用户名,注册码)
楼主,这个应该是 用户名长度== 注册码长度吧 大佬厉害 谢谢楼主的实例,分析很到位,谢谢 虽然我看不懂,但顶大佬 可以学习一下, 谢谢楼主实例 最好能把crackme以附件形式上传一下。 感谢分享,学习了
页:
[1]
2