[DASCTF Sept 2021]pig_brain_king
-
IDA打开之后按下
Shift + F12
找到字符串定位到之后找到下面的
cls
,这是系统清屏指令。定位这个指令(原因是程序里执行了这个指令(易知))看到了大规模的变量赋值指令。但是仔细看就会发现都是在变量
v281
中取值,因而只需要写个基本的字典序翻译程序 -
字典序翻译
很容易看出来这是一个字典打印程序。这里对字典的序列进行了打印,而各个数组的值对应:whoisthestrongestpigbrainking?! canyouanswer1000questionscorrectly? nowstartdoingthequestions! pleaseenter nonono bingo! theansweris
所对应的值和对应行如下
//... sub_411154(); v282 = 0; v259 = v281[67]; // whoisthestrongestpigbrainking?! v252 = v281[66]; //... std::ostream::operator<<(v39, sub_4115F0); v260 = v281[66]; // canyouanswer1000questionscorrectly? v253 = v281[50]; //... while ( 1 ) { v261 = v281[67]; // nowstartdoingthequestions! v254 = v281[44]; //... if ( i >= 3 ) goto LABEL_10; v262 = v281[43]; // pleaseenter v255 = v281[30]; //... if ( v273 ) break; v264 = v281[40]; // nonono v257 = v281[39]; v251 = v281[40]; //... std::ostream::operator<<(v133, sub_4115F0); } v263 = v281[67]; // bingo! v256 = v281[40]; v250 = v281[32]; //... LABEL_10: *v278 = v277; if ( v277 ) { ++v280; } else { v265 = v281[44]; // theansweris v258 = v281[34]; v245 = v281[43]; //...
找到
theansweris
,else { v265 = v279[44]; v258 = v279[34]; v245 = v279[43]; v238 = v279[30]; v231 = v279[48]; v227 = v279[44]; v223 = v279[39]; v218 = v279[26]; v209 = v279[30]; v206 = v279[33]; v134 = sub_41121C(std::cout, v279[19]); v135 = sub_41121C(v134, v206); v136 = sub_41121C(v135, v209); v137 = sub_411474(v136, " "); v138 = sub_41121C(v137, v218); v139 = sub_41121C(v138, v223); v140 = sub_41121C(v139, v227); v141 = sub_41121C(v140, v231); v142 = sub_41121C(v141, v238); v143 = sub_41121C(v142, v245); v144 = sub_411474(v143, " "); v145 = sub_41121C(v144, v258); v146 = sub_41121C(v145, v265); sub_411474(v146, ":"); sub_4114BF(v266, v267); } Sleep(0); system("cls"); }
找到关键函数
int __thiscall sub_41CAE0(HANDLE *this) { //defs... struct _CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo; // [esp+124h] [ebp-38h] BYREF HANDLE *v90; // [esp+144h] [ebp-18h] int v91; // [esp+158h] [ebp-4h] v90 = this; __CheckForDebuggerJustMyCode(&unk_42F035); GetConsoleScreenBufferInfo(v90[64], &ConsoleScreenBufferInfo); *((_WORD *)v90 + 136) = ConsoleScreenBufferInfo.dwCursorPosition.X; *((_WORD *)v90 + 137) = ConsoleScreenBufferInfo.dwCursorPosition.Y; if ( *((double *)v90 + 33) > 3330.0 ) { sub_4110AA(&unk_428DD6); v91 = 0; sub_411442(v88); v91 = -1; sub_411528(); //some output.... } v86 = sub_41146F(v87); v91 = 1; v56 = sub_4114AB(std::cout, v86); std::ostream::operator<<(v56); v91 = -1; return sub_411528(); }
-
根据伪代码第603行的
//.. sub_4114BF(v266, v268); } Sleep(0xBB8u); system("cls"); }
估计程序中出现了
Sleep
延时。修改这段代码去掉延时。定位到相应的汇编代码:
将相应的硬编码改掉,也就是改成
push 00000000h
换句话说
68 00 00 00 00
同理,修正下述位置:
D870h(FOA,下同)
FF FF 8B F4 68 00 00 00 00 FF 15 04 D0 42 00 3B
DBB0h
2D FF FF 8B F4 68 00 00 00 00 FF 15 04 D0 42 00
E040h
FF E8 79 28 FF FF 8B F4 68 00 00 00 00 FF 15 04
然后更改判断的代码,即第541行伪代码
if ( v273 ) break;
对应的硬编码
改为
jnz loc_41EA40
即(jnz的硬编码是85)
DD80h:
0F 85 BA 00 00 00 8B F4 68 F0 15 41 00 B8 01 00
-
发现在答完1000道题之后仍然没有flag,找到
*
号修改为0即可int __thiscall sub_41ADE0(char *this) { unsigned int v1; // eax int v2; // eax int v3; // eax int v5; // [esp-8h] [ebp-158h] int v6; // [esp-4h] [ebp-154h] int v7; // [esp+0h] [ebp-150h] int v8; // [esp+0h] [ebp-150h] int v9; // [esp+0h] [ebp-150h] int v10; // [esp+4h] [ebp-14Ch] int v11; // [esp+4h] [ebp-14Ch] char v12[36]; // [esp+1Ch] [ebp-134h] BYREF char v13[39]; // [esp+40h] [ebp-110h] BYREF bool v14; // [esp+67h] [ebp-E9h] unsigned int i; // [esp+130h] [ebp-20h] char *v16; // [esp+13Ch] [ebp-14h] int v17; // [esp+14Ch] [ebp-4h] v16 = this; __CheckForDebuggerJustMyCode(&unk_42F035); SetConsoleCursorPosition(*((HANDLE *)v16 + 64), *(COORD *)(v16 + 272)); for ( i = 0; ; ++i ) { sub_41146F(v13); v1 = sub_41118B(v7, v10); v14 = i < v1; sub_411528(v8, v11); if ( !v14 ) break; sub_411474(std::cout, "*"); } sub_41146F(v12); v17 = 0; v5 = sub_41118B(sub_4115F0, v7); v2 = sub_411474(std::cout, " "); v3 = std::ostream::operator<<(v2, v5, v6); std::ostream::operator<<(v3); v17 = -1; return sub_411528(v9, v10); }
对
sub_411474(std::cout, "*");
对应的硬编码进行修正:
.rdata:00428DD4 ; const char Str[] .rdata:00428DD4 2A 00 Str db '*',0 ; DATA XREF: sub_41ADE0+E1↑o .rdata:00428DD6 00 unk_428DD6 db 0
-
最终输入1000行随机字符得到flag:
输入方法:在notepad里输入任意字符复制粘贴1000行,然后粘贴到控制台里就行
-
flag{YOU_ar3_The_k1ng_Of_pig_bra1n!}
作者发布、转载的任何文章中所涉及的技术、思路、工具仅供以安全目的的学习交流,并严格遵守《中华人民共和国网络安全法》、《中华人民共和国数据安全法》等网络安全法律法规。
任何人不得将技术用于非法用途、盈利用途。否则作者不对未许可的用途承担任何后果。
本文遵守CC BY-NC-SA 3.0协议,您可以在任何媒介以任何形式复制、发行本作品,或者修改、转换或以本作品为基础进行创作
您必须给出适当的署名,提供指向本文的链接,同时标明是否(对原文)作了修改。您可以用任何合理的方式来署名,但是不得以任何方式暗示作者为您或您的使用背书。
同时,本文不得用于商业目的。混合、转换、基于本作品进行创作,必须基于同一协议(CC BY-NC-SA 3.0)分发。
如有问题, 可发送邮件咨询.