[ACTF新生赛2020]Splendid_MineCraft
本文最后更新于 375 天前,其中的信息可能已经过时,如有错误可以直接在文章下留言

虽说是新生赛的题,但是这题要手撕汇编,学到还是蛮多的。

直接 IDA 打开题目给的可执行文件.exe,很轻易的找到了主函数,如图

第一个关键信息是第一个 if 语句的判断

if ( &Str1[strlen(Str1) + 1] - v11 == 26 && !strncmp(Str1, "ACTF{", 5u) && v12 == 125 )
#Ascii值为125的字符为125,即v12=="}"

所以我们输入的 flag 形式为 ACTF {XXXXX},再看第一条判断 Str1 [strlen (Str1) + 1] – v11 == 26,v11 前面没有定义值,我们进入动态调试之后,这个 v11 就变了,如图

点进去确实存的是我们的输入,看上面 v11 的定义也变成了 char Str1 [25]。那是不是说明 flag 的长度为 25 呢?Str1 [1] 的为 C,其 Ascii 值为 99,而我们注意到 125-99 的值刚好为 26,而 Ascii 值为 125 的字符刚好就是 flag 的最后一个字符’}’。讲了这么多,好像也判断不了,好吧,其实 flag 的长度应该是 26,我们可以动态调试,发现只有长度为 26 的时候可以进入 if 判断里面执行的语句。

当我们动态调试输入 ACTF {12345678901234567890} 的时候,执行 if 代码块里面的语句时,出现了以下报错,

报错的原因是这里的 strtok 函数,这里运用三个这个函数,我们去搜索一下该函数的用途,发现 strtok 函数是 C 语言中用于分割字符串的函数,它可以将一个字符串按照指定的分隔符进行分割。它要求输入两个参数,第一个参数是要被分割的字符串,第二个参数是分隔符字符串,用于指定分割的分隔符,题目这里就是’_’,返回分割后的第一个子字符串的指针。如果无法继续分割,则返回 NULL。

但是我在 Visual Studio 2022 使用不了这个函数,只能用 strtok_s,和 scanf 一样的毛病,我也不知道为啥,strtok_s 需要传入三个参数,前两个和 strtok 一样,第三个参数具体是干啥的,说是指向一个字符指针的指针,用于保存当前分割位置的上下文信息,它的用法是第一次调用时,传入要分割的字符串 str 和分隔符 delim,同时将 context 设置为 NULL,之后每次调用 strtok_s 函数,传入 NULL 作为第一个参数,并将 context 设置为上一次调用返回的子字符串指针。用了一下,如图

很多 Writeup 都是直接推测将 flag 用分隔符分成了三个部分,每个部分的长度为 6,但是怎么看出来的?靠猜吗?有的 Writeup 说根据 + 5 和 + 9 差 4 个,再加上 + 9 强转为 WORD,得到每组字符是 4+2=6 个,DWORD 是 4 个字节,WORD 是 2 个字节,加起来刚好 6 个字节,是这个意思吗?我也不太清楚。

然后看第二个 if 语句判断有个 unk_4051D8,后面有个括号传入了参数 v17,大概是 flag 的第一部分,这应该是一个函数,猜测是经过了 SMC 处理,不能直接反汇编成伪代码。听说题目的标题也暗示了是 SMC,我们直接动态调试到函数快结束处打断点,然后对 unk_4051D8 处的数据 U+C+P,然后反编译成伪代码,成功得到了原函数,如图。

脚本代码如下

a="3@1b;b"
b="elcome "
flag=''
for i in range(len(a)):
flag+=chr((ord(a[i])^ord(b[i]))+35)
#这里必须要多加个括号确保先进行异或运算,不然ord(b[i])会先加35,再进行异或
print(flag)
#输出结果为yOu0y*

然后再看后面

后面又有个 for 循环,数字很大,估计又是一个 SMC,和 v9 异或,而这个 v9 明显来源于第一部分的 flag。

在 String Windows 里面找到了一个长度为 6 的字符 5mcsM<。

再跟踪,来到汇编处

这里是直接 strncmp,简单的比较,说明这个是 flag 的一部分,而且我们注意到这里有个 Congratulations,应该是另外一个函数,但是反汇编还是回到主函数,不知道是怎么回事,怎么有个 You win,猜测这个应该是 flag 的最后一部分。

最后只要找到 flag 的第二部分,第二部分的 flag 有点复炸,最好是用 OD 来跑程序,要手撕汇编。

我们注意到主函数中有一段内联汇编 jmp eax,我们直接用 OllyDbg 打开,然后右键,查找命令 jmp eax,来到此处汇编,打上断点,使程序运行

输入 ACTF {yOu0y*_abcdef_5mcsM<} 来分析,F7 步入

汇编分析,注意标红的汇编代码

001D511A 33FF xor edi,edi
#xor edi,edi可以清空edi的数据,这个我也是刚知道,手撕汇编太少了,没有这样的感知,清空edi是为了在for循环当中计数。
001D511C 51 push ecx
001D511D 53 push ebx
001D511E 83FF 06 cmp edi,0x6
#for循环开始的标志,用cmp,操作数一般是循环的次数,这里进行了6次循环,应该flag的第二部分刚好长度为6.但这里不知道为什么识别成0x6
001D5121 7D 20 jge short Splendid.001D5143
001D5123 33C9 xor ecx,ecx
001D5125 8A0C3E mov cl,byte ptr ds:[esi+edi]
#这里跟踪右边寄存器发现,每次循环都往ecx寄存器里面存入一个我们flag第二部分的输入
001D5128 EB 0C jmp short Splendid.001D5136
001D512A 123456 adc dh,byte ptr ds:[esi+edx*2]
001D512D ^ 78 9A js short Splendid.001D50C9
001D512F 05 61626364 add eax,0x64636261
001D5134 65:66:33db xor bx,bx
001D5138 8A5C38 12 mov bl,byte ptr ds:[eax+edi+0x12]
001D513C 884C38 18 mov byte ptr ds:[eax+edi+0x18],cl
#在此处跟踪数据窗口会发现我们的输入被放入了内存当中,图片上有。
001D5140 47 inc edi
#每执行一次循环,edi的值会自增1,直到6就跳出循环

所以这一部分汇编应该就是将 flag 的第二部分放入内存当中。后面又有一段相同作用的汇编指令,如图

不管它,往下走,进入最关键的一段加密指令.

指令如下

001D5156 33FF xor edi,edi
001D5158 83FF 06 cmp edi,0x6
001D515B 7D 3B jge short Splendid.001D5198
001D515D 33C9 xor ecx,ecx
001D515F 8A0C3E mov cl,byte ptr ds:[esi+edi]
#跑到这OD的中间窗口会显示该地址处的内容,是0x61,也就是a,是我们第二部分的输入
001D5162 80E1 FF and cl,0xFF
#这里的运算不影响cl的值,ecx存着我们的输入的第二部分
001D5165 2D 00010000 sub eax,0x100
001D516A 33DB xor ebx,ebx
#清空ebx寄存器的值
001D516C 8AD9 mov bl,cl
#将我们的输入放入ebx寄存器
001D516E 8BCF mov ecx,edi
#edi的值是循环执行的次数,也就是我们常写代码的i
001D5170 81C1 83000000 add ecx,0x83
#ecx的值为0x83+i,
001D5176 33D9 xor ebx,ecx
#进行input2[i]^(0x83+i)
001D5178 8A1C18 mov bl,byte ptr ds:[eax+ebx]
#让上面的结果作为一个数组的下标,赋值该数组对于下标的值给ebx寄存器,类似于bl=data[input2[i]^(0x83+i)]
001D517B EB 08 jmp short Splendid.001D5185

我跟着最后的跳转指令。

这里将某内存地址的值取出来放到 cl 里面,然后让 bl 和 cl 对比,这里应该就是最后的 flag 对比,bl 是我们要的 flag 的第二部分加密后的值,然后不对的话,就会跳出程序了。

我们进入这里的内存地址,取出 6 位的数据,

我们还需要的就是 bl 里面的值,上面分析指令说了,赋给 bl 的是从一个数组里面的值,flag 的第二部分处理后作为索引,而这个数组其实就在 eax 寄存器当中。

这里有个 sub eax,0x100 的指令其实就暗示了,这个数组在 eax 里面,后面对 bl 的赋值也是 [eax+ebx],并且长度为 0x100,我们取出里面的值。

整理一下思路,解题脚本如下

data=[ 0xF6, 0xA3, 0x5B, 0x9D, 0xE0, 0x95, 0x98, 0x68, 0x8C, 0x65, 0xBB, 0x76, 0x89, 0xD4, 0x09, 0xFD,
0xF3, 0x5C, 0x3C, 0x4C, 0x36, 0x8E, 0x4D, 0xC4, 0x80, 0x44, 0xD6, 0xA9, 0x01, 0x32, 0x77, 0x29,
0x90, 0xBC, 0xC0, 0xA8, 0xD8, 0xF9, 0xE1, 0x1D, 0xE4, 0x67, 0x7D, 0x2A, 0x2C, 0x59, 0x9E, 0x3D,
0x7A, 0x34, 0x11, 0x43, 0x74, 0xD1, 0x62, 0x60, 0x02, 0x4B, 0xAE, 0x99, 0x57, 0xC6, 0x73, 0xB0,
0x33, 0x18, 0x2B, 0xFE, 0xB9, 0x85, 0xB6, 0xD9, 0xDE, 0x7B, 0xCF, 0x4F, 0xB3, 0xD5, 0x08, 0x7C,
0x0A, 0x71, 0x12, 0x06, 0x37, 0xFF, 0x7F, 0xB7, 0x46, 0x42, 0x25, 0xC9, 0xD0, 0x50, 0x52, 0xCE,
0xBD, 0x6C, 0xE5, 0x6F, 0xA5, 0x15, 0xED, 0x64, 0xF0, 0x23, 0x35, 0xE7, 0x0C, 0x61, 0xA4, 0xD7,
0x51, 0x75, 0x9A, 0xF2, 0x1E, 0xEB, 0x58, 0xF1, 0x94, 0xC3, 0x2F, 0x56, 0xF7, 0xE6, 0x86, 0x47,
0xFB, 0x83, 0x5E, 0xCC, 0x21, 0x4A, 0x24, 0x07, 0x1C, 0x8A, 0x5A, 0x17, 0x1B, 0xDA, 0xEC, 0x38,
0x0E, 0x7E, 0xB4, 0x48, 0x88, 0xF4, 0xB8, 0x27, 0x91, 0x00, 0x13, 0x97, 0xBE, 0x53, 0xC2, 0xE8,
0xEA, 0x1A, 0xE9, 0x2D, 0x14, 0x0B, 0xBF, 0xB5, 0x40, 0x79, 0xD2, 0x3E, 0x19, 0x5D, 0xF8, 0x69,
0x39, 0x5F, 0xDB, 0xFA, 0xB2, 0x8B, 0x6E, 0xA2, 0xDF, 0x16, 0xE2, 0x63, 0xB1, 0x20, 0xCB, 0xBA,
0xEE, 0x8D, 0xAA, 0xC8, 0xC7, 0xC5, 0x05, 0x66, 0x6D, 0x3A, 0x45, 0x72, 0x0D, 0xCA, 0x84, 0x4E,
0xF5, 0x31, 0x6B, 0x92, 0xDC, 0xDD, 0x9C, 0x3F, 0x55, 0x96, 0xA1, 0x9F, 0xCD, 0x9B, 0xE3, 0xA0,
0xA7, 0xFC, 0xC1, 0x78, 0x10, 0x2E, 0x82, 0x8F, 0x30, 0x54, 0x04, 0xAC, 0x41, 0x93, 0xD3, 0x3B,
0xEF, 0x03, 0x81, 0x70, 0xA6, 0x1F, 0x22, 0x26, 0x28, 0x6A, 0xAB, 0x87, 0xAD, 0x49, 0x0F, 0xAF]
part2=[0x30, 4, 4, 3, 0x30, 0x63]
for i in range(0,6):
for j in range(len(data)):
if part2[i]==data[j]:
part2[i]=j^(i+0x83)
result = ''.join(chr(h) for h in part2)
print(result)
#输出knowo3

所以 flag 就是 ACTF {yOu0y*_knowo3_5mcsM<}

这题学到蛮多的,对汇编又有了更深的理解。

后面一大部分内容都是跟着这个视频做的

【BUUCTF】ACTF 新生赛 2020-Splendid_MineCraft 手把手带你跟汇编!_哔哩哔哩_bilibili

偶然发现的一个宝藏 up 主,但是更新频率不高,看他的博客,应该是一个大佬。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇