BUUCTF Reverse 1-20 [toc]
1. easyre 64位程序,没有加壳
使用64位ida,shift+f12检索字符串,得flag
2. reverse1 64位程序
丢入ida,shift+f12查看字符串
双击,发现被sub_1400118C0调用
str2为{hello_world}
转为伪代码,判断输入的字符串和str2相等即可
str2是对{hello_world}
进行字符串替换得到的,o替换为0
最后的flag:{hell0_w0rld}
3. reverse2
ida64打开,check+f12查看字符串,跟进right flag
main函数调用,跟进
和上一个题目差不多,查看s2的生成过程,将flag中的i和r替换为1
1 2 3 4 5 for ( i = 0 ; i <= strlen (&flag); ++i ) { if ( *(&flag + i) == 'i' || *(&flag + i) == 'r' ) *(&flag + i) = '1' ; }
flag为{hacking_for_fun}
那么最后的flag为flag{hack1ng_fo1_fun}
4. 内涵的软件 32位
ida32打开,将DBAPP修改为flag提交
5. 新年快乐 32位,UPX加壳
手动脱壳
查看xdbg的断点
根据ESP定律找OEP(Original Entry Point),程序的入口点
F9运行到这里,往上可以看到一个popad的指令,该指令将寄存器的值进行还原。找到下面一个jmp指令所要跳转的位置,就是程序的OEP
F8
dump下来,使用Scylla插件
第一步,生成dump.exe
第二步,进行修复
Misc–>options
然后点击IAT Autosearch,点击Get Imports,而后fix dump
生成dump_SCY.exe
丢入ida,修复之后的文件
进行一个字符串比较,最后的flag为flag{HappyNewYear!}
6. xor
1 2 3 4 5 6 7 8 9 10 11 12 13 string = ['f' ,0x0A ,'k' ,0x0C ,'w' ,'&' ,'O' ,'.' ,'@' ,0x11 ,'x' ,0x0D ,'Z' ,';' ,'U' ,0x11 ,'p' ,0x19 ,'F' ,0x1F ,'v' ,'"' ,'M' ,'#' ,'D' ,0x0E ,'g' ,0x6 ,'h' ,0x0F ,'G' ,'2' ,'O' ,0x0 ] flag = 'f' for i in (range (len (string))): if (type (string[i]) == int ): string[i] = chr (string[i]) print (string)for i in range (1 ,len (string)): flag += chr (ord (string[i])^ord (string[i-1 ])) print (flag)
7. helloword apk文件,使用jadx打开
或者丢入ida,使用APK Android打开
shift+f12查看字符串
8. reverse3 32位
main函数,对输入的字符串调用sub_4110BE进行处理,然后进行移位处理
跟进sub_4110BE,跟进sub_411AB0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 while ( v11 > 0 ) { byte_41A144[2 ] = 0 ; byte_41A144[1 ] = 0 ; byte_41A144[0 ] = 0 ; for ( i = 0 ; i < 3 && v11 >= 1 ; ++i ) { byte_41A144[i] = *v13; --v11; ++v13; } if ( !i ) break ; switch ( i ) { case 1 : *((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int )(unsigned __int8)byte_41A144[0 ] >> 2 ]; v5 = v4 + 1 ; *((_BYTE *)v12 + v5) = aAbcdefghijklmn[((byte_41A144[1 ] & 0xF0 ) >> 4 ) | (16 * (byte_41A144[0 ] & 3 ))]; *((_BYTE *)v12 + ++v5) = aAbcdefghijklmn[64 ]; *((_BYTE *)v12 + ++v5) = aAbcdefghijklmn[64 ]; v4 = v5 + 1 ; break ; case 2 : *((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int )(unsigned __int8)byte_41A144[0 ] >> 2 ]; v6 = v4 + 1 ; *((_BYTE *)v12 + v6) = aAbcdefghijklmn[((byte_41A144[1 ] & 0xF0 ) >> 4 ) | (16 * (byte_41A144[0 ] & 3 ))]; *((_BYTE *)v12 + ++v6) = aAbcdefghijklmn[((byte_41A144[2 ] & 0xC0 ) >> 6 ) | (4 * (byte_41A144[1 ] & 0xF ))]; *((_BYTE *)v12 + ++v6) = aAbcdefghijklmn[64 ]; v4 = v6 + 1 ; break ; case 3 : *((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int )(unsigned __int8)byte_41A144[0 ] >> 2 ]; v7 = v4 + 1 ; *((_BYTE *)v12 + v7) = aAbcdefghijklmn[((byte_41A144[1 ] & 0xF0 ) >> 4 ) | (16 * (byte_41A144[0 ] & 3 ))]; *((_BYTE *)v12 + ++v7) = aAbcdefghijklmn[((byte_41A144[2 ] & 0xC0 ) >> 6 ) | (4 * (byte_41A144[1 ] & 0xF ))]; *((_BYTE *)v12 + ++v7) = aAbcdefghijklmn[byte_41A144[2 ] & 0x3F ]; v4 = v7 + 1 ; break ; } } *((_BYTE *)v12 + v4) = 0 ; return v12;
base64编码,3位变4位
所以先逆向移位,然后base64解码
1 2 3 4 5 6 7 8 9 import base64str2 = 'e3nifIH9b_C@n@dH' flag = '' for i in range (len (str2)): flag += chr (ord (str2[i])-i) print (flag)print (base64.b64decode(flag))
9. 不一样的flag 32位
shift+f12查看字符串
主逻辑在main函数中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 __main(); v3[26 ] = 0 ; *(_WORD *)&v3[27 ] = 0 ; v4 = 0 ; strcpy (v3, "*11110100001010000101111#" ); while ( 1 ) { puts ("you can choose one action to execute" ); puts ("1 up" ); puts ("2 down" ); puts ("3 left" ); printf ("4 right\n:" ); scanf ("%d" , &v5); if ( v5 == 2 ) { ++*(_DWORD *)&v3[25 ]; } else if ( v5 > 2 ) { if ( v5 == 3 ) { --v4; } else { if ( v5 != 4 ) LABEL_13: exit (1 ); ++v4; } } else { if ( v5 != 1 ) goto LABEL_13; --*(_DWORD *)&v3[25 ]; } for ( i = 0 ; i <= 1 ; ++i ) { if ( *(int *)&v3[4 * i + 25 ] < 0 || *(int *)&v3[4 * i + 25 ] > 4 ) exit (1 ); } if ( v7[5 * *(_DWORD *)&v3[25 ] - 41 + v4] == '1' ) exit (1 ); if ( v7[5 * *(_DWORD *)&v3[25 ] - 41 + v4] == '#' ) { puts ("\nok, the order you enter is the flag!" ); exit (0 ); } }
上面的*11110100001010000101111#
是迷宫的地图
对v4的操作相当于迷宫中的左移和右移
而对(_DWORD *)&v3[25]
的操作相当于上移和下移,而*5
表示是5行
迷宫地图为
1 2 3 4 5 *1111 01000 01010 00010 1111 #
走到#
成功,这个过程中不能走到1
所以应该是下下下右右上上右右下下下
,也就是222441144222
10. SimpleRev 64位
小端序和大端序问题
可以看到这里的两个十六进制是大端序,但是数据在内存中都是小端序,所以要将其,反转一下。一般在CPU,x86都是小端序,但是IDA将之转换为了大端序
主要逻辑
从65到91爆破一下
exp
1 2 3 4 5 6 7 8 9 10 11 12 text = 'killshadow' key = 'ADSFKNDCLS' print (key.lower())flag = '' for i in range (0 ,10 ): for j in range (65 ,91 ): if ((((j - 39 - ord (key.lower()[i]) + 97 )%26 )+97 ) == ord (text[i])): print (chr (j)) flag += chr (j) break print (flag)