OD加载程序,F9运行,提示输入flag。随便输入一个字符串,提示“you shall not pass!”
这道题是输入验证类型,验证的字符串是固定的,因此相对容易分析。验证可分为6个阶段:
① 验证长度
② 验证前6个字符
③ 验证第24位、第13位、第19位
④ 验证7~12位
⑤ 验证14~18位
⑥ 验证20~23位
具体分析步骤如下:
1.验证长度
重新加载,右键“查找”->"所有参考文本字串"。显示字符串(图 2.1), 发现很多“you shall not pass”,在汇编中从“you shall not pass ”往回找跳转句,在附近的比较函数(cmp)或test下断,F9运行,提示输入时输入一个字符串“12345”,回车,程序断在004011EB处,此句将堆栈 ss:[0012FE60]的内容和0x19(25)进行比较,大于等于跳转到提示错误,为零也提示错误。数据窗口中查看[0012FE60] 内存(图2.3),很明显此内存+8的地方存放了我们输入的flag,那这个内存存放的是什么呢?数据窗口中此处的值为5,可以联想到是输入flag的长度,可以调试前面的代码得证,换几个不同长度字符串输入也可以验证这一点。
往前可以找到“Give me the flag:”后面可以验证。F8单步,后面的jz和jnz都跳到了00401224,说明此段放行了长度满足0<n<25的输入字符串。
图 2.1
图 2.2
图 2.3
图 2.4
2.验证前6个字符
F8继续单步运行,下面的代码将输入的前6个字符和“XDCTF{”比较,相等则跳到0040130F处。(代码2.1)
;代码2.1004012AC 8B8D D0FEFFFF mov ecx,dword ptr ss:[ebp-0x130] 004012B2 83C1 01 add ecx,0x1 004012B5 898D D0FEFFFF mov dword ptr ss:[ebp-0x130],ecx 004012BB 8B95 E0FEFFFF mov edx,dword ptr ss:[ebp-0x120] 004012C1 83EA 01 sub edx,0x1 004012C4 3995 D0FEFFFF cmp dword ptr ss:[ebp-0x130],edx ; 控制比较次数为6次 004012CA 7F 3C jg Xctf2.00401308 004012CC 8B85 D0FEFFFF mov eax,dword ptr ss:[ebp-0x130] 004012D2 0FBE8C05 70FFFF>movsx ecx,byte ptr ss:[ebp+eax-0x90] 004012DA 8B95 D0FEFFFF mov edx,dword ptr ss:[ebp-0x130] 004012E0 0FBE8415 F0FEFF>movsx eax,byte ptr ss:[ebp+edx-0x110] 004012E8 3BC8 cmp ecx,eax ;将输入的前六个字符和”XDCTF_”比较 004012EA 74 1A je Xctf2.00401306 004012EC 68 7CCA4000 push ctf2.0040CA7C ; ASCII "You shall not pass!" 004012F1 E8 0B070000 call ctf2.00401A01 004012F6 83C4 04 add esp,0x4 004012F9 E8 CD070000 call ctf2.00401ACB 004012FE 83C8 FF or eax,0xFFFFFFFF 00401301 E9 72030000 jmp ctf2.00401678 00401306 ^ EB A4 jmp Xctf2.004012AC
3.验证第24位、第13位、第19位
分析到这里我们不妨换一个字符串输入,就取它最大允许的长度24,输入“XDCTF{123456789ABCDEFGH}”,果然程序跳到0040130F处(代码3.1)。这段代码发现将第24位和“}”比较,第13位和“_”比较,第19位和“$”比较,相等跳到0040136B。至此我们可以修改输入字符为“XDCTF{123456_ABCDE$abcd}”。
;代码3.10040130F 83F9 7D cmp ecx,0x7D ; 第24位和“}”比较 00401312 74 1A je Xctf2.0040132E 00401314 68 7CCA4000 push ctf2.0040CA7C ; ASCII "You shall not pass!" 00401319 E8 E3060000 call ctf2.00401A01 0040131E 83C4 04 add esp,0x4 00401321 E8 A5070000 call ctf2.00401ACB 00401326 83C8 FF or eax,0xFFFFFFFF 00401329 E9 4A030000 jmp ctf2.00401678 0040132E 0FBE95 FCFEFFFF movsx edx,byte ptr ss:[ebp-0x104] 00401335 83FA 5F cmp edx,0x5F ; 第13位和“_”比较 00401338 75 0C jnz Xctf2.00401346 0040133A 0FBE85 02FFFFFF movsx eax,byte ptr ss:[ebp-0xFE] 00401341 83F8 24 cmp eax,0x24 ; 第19位和“$”比较 00401344 74 1A je Xctf2.00401360 00401346 68 7CCA4000 push ctf2.0040CA7C ; ASCII "You shall not pass!" 0040134B E8 B1060000 call ctf2.00401A01 00401350 83C4 04 add esp,0x4 00401353 E8 73070000 call ctf2.00401ACB 00401358 83C8 FF or eax,0xFFFFFFFF 0040135B E9 18030000 jmp ctf2.00401678 00401360 74 09 je Xctf2.0040136B ; 通过 00401362 75 12 jnz Xctf2.00401376 ; 不通过
4.验证7~12位
重新运行程序,输入“XDCTF{123456_ABCDE$abcd}”,程序如预期跳到0040136B,再跳到00401376(代码4.1),F8到0040145C处,程序将”XDCTF_”放入内存0040CA90。
继续往下分析,从00401090开始,进入第四阶段的验证(代码 4.2)。代码中标注了三行关键代码,004010AA处第一次验证指向的地址为0040CA90,此处的内存存放了“XDCTF_”(图 4.1);004010B3处第一次验证指向的地址为004010B3,存放了“123456”。004010B6处将“XDCTF_”和“123456”对应依次相减(ascii码),得到的结果在004010BE处与ds:[edx+ecx*4+0x8]中存储的数据比较,相等则通过验证。通过强制跳转分析,每一次相减得到的正确数值应为:
堆栈 ds:[0012FEF8]=00000015
堆栈 ds:[0012FEFC]=FFFFFFD5
堆栈 ds:[0012FF00]=FFFFFFD5
堆栈 ds:[0012FF04]=FFFFFFED
堆栈 ds:[0012FF08]=FFFFFFD4
堆栈 ds:[0012FF0C]=FFFFFFFE
即:7~12位正确的输入应为(需转换类型):
“X” - 0x00000015 = “C”
“D” - 0xFFFFFFD5 = “o”
“C” - 0xFFFFFFD5 = “n”
“T” - 0xFFFFFFED = “g”
“F” - 0xFFFFFFD4 = “r”
“_” - 0xFFFFFFFE = “a”
;代码4.10040145C C785 ECFEFFFF 9>mov dword ptr ss:[ebp-0x114],ctf2.0040CA>; ASCII "XDCTF_" 00401466 6A 06 push 0x6 00401468 E8 12020000 call ctf2.0040167F
;代码4.2 00401090 8B45 F8 mov eax,dword ptr ss:[ebp-0x8] 00401093 83C0 01 add eax,0x1 00401096 8945 F8 mov dword ptr ss:[ebp-0x8],eax 00401099 8B4D FC mov ecx,dword ptr ss:[ebp-0x4] 0040109C 83E9 01 sub ecx,0x1 0040109F 394D F8 cmp dword ptr ss:[ebp-0x8],ecx 004010A2 7F 26 jg Xctf2.004010CA 004010A4 8B55 08 mov edx,dword ptr ss:[ebp+0x8] 004010A7 0355 F8 add edx,dword ptr ss:[ebp-0x8] 004010AA 0FBE02 movsx eax,byte ptr ds:[edx] ; [0040CA90]-->”XDCTF_” 004010AD 8B4D 0C mov ecx,dword ptr ss:[ebp+0xC] 004010B0 034D F8 add ecx,dword ptr ss:[ebp-0x8] 004010B3 0FBE11 movsx edx,byte ptr ds:[ecx] ; [004010B3]-->”123456” 004010B6 2BC2 sub eax,edx ;对应依次相减-->eax 004010B8 8B4D F8 mov ecx,dword ptr ss:[ebp-0x8] 004010BB 8B55 10 mov edx,dword ptr ss:[ebp+0x10] 004010BE 3B448A 08 cmp eax,dword ptr ds:[edx+ecx*4+0x8] ;eax是否与ds:[edx+ecx*4+0x8]中存储的数据是否相等 004010C2 74 04 je Xctf2.004010C8 004010C4 32C0 xor al,al 004010C6 EB 04 jmp Xctf2.004010CC 004010C8 ^ EB C6 jmp Xctf2.00401090
图 4.1
图 4.2
5.验证14~18位
F8继续往下,来到004010F1处(代码5.1),从这里开始将第14~18位依次与“t”“U”、“l”、“a”、“t”比较,相等则验证通过。
;代码5.1 004010F1 8955 F4 mov dword ptr ss:[ebp-0xC],edx 004010F4 8B45 08 mov eax,dword ptr ss:[ebp+0x8] 004010F7 8945 F0 mov dword ptr ss:[ebp-0x10],eax 004010FA 8B4D F0 mov ecx,dword ptr ss:[ebp-0x10] 004010FD 8A11 mov dl,byte ptr ds:[ecx] 004010FF 8855 EF mov byte ptr ss:[ebp-0x11],dl 00401102 8B45 F4 mov eax,dword ptr ss:[ebp-0xC] 00401105 3A10 cmp dl,byte ptr ds:[eax] 00401107 75 2E jnz Xctf2.00401137 00401109 807D EF 00 cmp byte ptr ss:[ebp-0x11],0x0 0040110D 74 1F je Xctf2.0040112E 0040110F 8B4D F0 mov ecx,dword ptr ss:[ebp-0x10] 00401112 8A51 01 mov dl,byte ptr ds:[ecx+0x1] 00401115 8855 EE mov byte ptr ss:[ebp-0x12],dl 00401118 8B45 F4 mov eax,dword ptr ss:[ebp-0xC] 0040111B 3A50 01 cmp dl,byte ptr ds:[eax+0x1] 0040111E 75 17 jnz Xctf2.00401137 00401120 8345 F0 02 add dword ptr ss:[ebp-0x10],0x2 00401124 8345 F4 02 add dword ptr ss:[ebp-0xC],0x2 00401128 807D EE 00 cmp byte ptr ss:[ebp-0x12],0x0 0040112C ^ 75 CC jnz Xctf2.004010FA
6.验证20~23位
继续往下跟踪,到004015D1处进入第6阶段验证。(代码 6.1)
“T”与第20个字符异或结果为0x31,该字符为“e”;
“C”与第21个字符异或结果为0x3A,该字符为“y”;
“D”与第22个字符异或结果为0xB,该字符为“W”
“X”与第23个字符异或结果为0x2D,该字符为“u”
;代码6.1 004015D1 0FBE8D DCFEFFFF movsx ecx,byte ptr ss:[ebp-0x124] ; “e” 004015D8 0FBE95 F3FEFFFF movsx edx,byte ptr ss:[ebp-0x10D] ;“T” 004015DF 33CA xor ecx,edx 004015E1 83F9 31 cmp ecx,0x31 ;ecx=“e”⊕ “T”=0x31 004015E4 75 3F jnz Xctf2.00401625 004015E6 0FBE85 DDFEFFFF movsx eax,byte ptr ss:[ebp-0x123] ; ”y” 004015ED 0FBE8D F2FEFFFF movsx ecx,byte ptr ss:[ebp-0x10E] ;”C” 004015F4 33C1 xor eax,ecx 004015F6 83F8 3A cmp eax,0x3A ;eax=“y”⊕ “C”=0x3A 004015F9 75 2A jnz Xctf2.00401625 004015FB 0FBE95 DEFEFFFF movsx edx,byte ptr ss:[ebp-0x122] 00401602 0FBE85 F1FEFFFF movsx eax,byte ptr ss:[ebp-0x10F] 00401609 33D0 xor edx,eax 0040160B 83FA 0B cmp edx,0xB ; edx=“O”⊕ “D”=0xB 0040160E 75 15 jnz Xctf2.00401625 00401610 0FBE8D DFFEFFFF movsx ecx,byte ptr ss:[ebp-0x121] 00401617 0FBE95 F0FEFFFF movsx edx,byte ptr ss:[ebp-0x110] 0040161E 33CA xor ecx,edx 00401620 83F9 2D cmp ecx,0x2D ;ecx=“u”⊕ “X”=0x2D 00401623 74 12 je Xctf2.00401637 00401625 68 98CA4000 push ctf2.0040CA98 ; ASCII "You shall not pass!\n" 0040162A E8 D2030000 call ctf2.00401A01 0040162F 83C4 04 add esp,0x4 00401632 E8 94040000 call ctf2.00401ACB 00401637 68 B0CA4000 push ctf2.0040CAB0 ; ASCII "You do it!" 0040163C E8 C0030000 call ctf2.00401A01
到这里,flag已浮出水面,赶紧输入一下,”you do it!”~~
Flag: XDCTF{Congra_tUlat$eyOu}
Ps: 欢迎大家指正~
By. Vi