安洵杯复现——你见过蓝色的小鲸鱼吗

发布于 2023-12-27  99 次阅读


1.思考:

拿到题后我们运行程序后可以看到是一个程序,要求我们输入用户名和密码,,题目附加的txt里面已经告诉了我们用户名,我们就只需要在程序里面找到密码就可以了

2.把程序拖入IDA:

用DIE可以看到程序是一个32位的程序,所以把程序放入32位的IDA里面,使用插件findcrypto查看一下函数用了什么算法:

可以看到是blowfish算法(查了一下是一个对称加密算法,当时的第一反应是动调)

因为找不到main函数,就要找到这个程序里面加密的算法放在哪里的:

先找到winmain函数(winmain函数是windows程序的入口函数,是一个特殊的函数,必须在 Windows GUI 应用程序中使用,在C/C++ 编程中,WinMain 函数取代了标准的 main 函数,这也是我们找不到单独的main函数的原因)

然后又找到DialogFunc函数(因为这个函数在CreateDialogParamA函数里面,CreateDialogParamA函数的作用是创建了一个对话框窗口,并且返回窗口的句柄hWnd,也就是和用户交互的地方)

继续深入,直到这里:

CHAR *__cdecl sub_4577E0(HWND hDlg)
{
 CHAR *result; // eax
 CHAR *v2; // [esp+10h] [ebp-154h]
 void *v3; // [esp+24h] [ebp-140h]
 CHAR *v4; // [esp+114h] [ebp-50h]
 CHAR *lpString; // [esp+120h] [ebp-44h]
 HWND DlgItem; // [esp+12Ch] [ebp-38h]
 HWND hWnd; // [esp+138h] [ebp-2Ch]
 int v8; // [esp+144h] [ebp-20h]
 int WindowTextLengthA; // [esp+150h] [ebp-14h]

 __CheckForDebuggerJustMyCode(&unk_52105E);
 hWnd = GetDlgItem(hDlg, 1003);
 DlgItem = GetDlgItem(hDlg, 1004);
 WindowTextLengthA = GetWindowTextLengthA(hWnd);
 v8 = GetWindowTextLengthA(DlgItem);
 lpString = (CHAR *)j__malloc(__CFADD__(WindowTextLengthA, 16) ? -1 : WindowTextLengthA + 16);
 result = (CHAR *)j__malloc(__CFADD__(v8, 16) ? -1 : v8 + 16);
 v4 = result;
 if ( lpString && result )
{
   GetWindowTextA(hWnd, lpString, WindowTextLengthA + 16);
   GetWindowTextA(DlgItem, v4, v8 + 16);
   v3 = operator new(0x10u);
   if ( v3 )
  {
     sub_451B43(0x10u);
     v2 = (CHAR *)sub_450CE3(v3);
  }
   else
  {
     v2 = 0;
  }
   sub_44FC2B(&unk_51D38C, 0x10u);   //一些初始化
   sub_45126F(lpString, WindowTextLengthA, (int)v4, v8);//算法进入
   sub_450199(v2);                   //数据校验
   j__free(lpString);
   j__free(v4);
   result = v2;
   if ( v2 )
     return (CHAR *)sub_44F77B(1);
}
 return result;
}

然后我们从这一个函数里面进入:

(因为根据代码来看,很可能是处理对话窗口的文本内容的函数,其中:lpString 是一个指向第一个控件文本内容的指针或字符串;WindowTextLengthA 是第一个控件文本内容的长度;(int)v4 是一个指向第二个控件文本内容的指针或字符串;v8 是第二个控件文本内容的长度)

其中

if ( operator new(0x2Cu) )
{
   sub_451A4E(0x2Cu);
   v8 = (void *)sub_450CBB(Src, a3);
}
 else
{
   v8 = 0;
}

里面的 v8 = (void *)sub_450CBB(Src, a3);可能就是引用用户名的作用,它的下面应该就分别是引用加密函数和password的作用

3.找出password并解出密码:

下面就得在程序里面找到password了,需要我们把对比的密文拿出来:

这一个函数里面标记的那一个函数应该是执行了某一种检查的功能,下面的if里面的比较应该就是判断用户的密码是否输入正确

如何找到这一个函数的位置呢?

回到之前找到WindowTextLengthA的那个地方,查看下面的那一个函数sub_450199(v2),可以看到这里面就是判断你输入的密码是否正确的地方

这里面v5就是密文,这个时候点进去的话什么也看不到,所以我们需要在这里下断点进行动调:

记住地址,定位到这里进行动调,弹窗就输入题目给出的用户名,密码随便写,然后看运行的结果(因为这里可以看见V5是一个指针,鼠标指向的时候下面写的地址是0x57BB250,而我点进去的时候并不是跳转到我想要的地址,可能ida出bug了,所以得手动跳转看看)

因为直到是地址,多以按d切换成这个样子:

因为是二重指针,所以同上再转变一次进去看到的结果下面就是我们的密文了:

11A51F049550E2508F17E16CF1632B47

因为之前就用插件查到是个blowfish算法加密,在网上找一个在线解密的网站直接解密就能得到flag:D0g3{UzBtZTBuZV9EMGczQHRoZWJsdWVmMXNo

(之所以这么找的原因是因为memcmp是这个程序的比较函数,它的作用是比较两个内存区域的内容是否相等, 而我们在汇编里面可以看到比较的数据是被push压入栈里面了的,所以要在栈里面去找)


The world's full of lonely people afraid to make the first move.