一.目录
1.喵喵喵的flag碎了一地
2.聪明的信使
3.你是真的大学生吗
4.DebugMe
5.砸核桃
6.ez_cube
7.baby unity
二.题解
1.喵喵喵的flag碎了一地
例行查壳,没有壳,64bit的,直接丢到ida-64里分析,分析结束,直接在函数窗口找到main函数,
三个提示,第一部分flag在字符串界面里,shift+F12就可以看到,第二部分在函数窗口里找,在最上面,
第三部分就是在函数里找,这里提到了Xref,就是交叉引用,CTRL+x,
就可以找到剩下这部分flag,拼接在一起就是完整的flag,签到题
2.聪明的信使
例行查壳,没有壳,32bit的,直接丢到ida-32里分析
分析结束,找到main函数,
很清晰,就是加密,然后比对,直接拿着密文解密就好了
enc = "oujp{H0d_TwXf_Lahyc0_14_e3ah_Rvy0ac@wc!}"
flag = ''
for i in range(len(enc)):
if 96 < ord(enc[i]) <= 122:
for j in range(97, 123):
if (j + 9 - 97) % 26 + 97 == ord(enc[i]):
flag += chr(j)
break
elif 64 < ord(enc[i]) <= 90:
for k in range(65, 91):
if (k + 9 - 65) % 26 + 65 == ord(enc[i]):
flag += chr(k)
break
else:
flag += enc[i]
print(flag)
3.你是真的大学生吗
这个题一查壳,没有壳,但是显示8bit,就猜这应该是直接分析汇编的题了,那么就随便那ida-32或者ida-64分析了。丢入ida-32,然后按空格,这样好看点,
dseg:0000 ; Segment type: Pure data
dseg:0000 dseg segment para stack 'DATA' use16
dseg:0000 assume cs:dseg
dseg:0000 unk_10000 db 0Dh ; DATA XREF: start+5↓o
dseg:0001 db 0Ah
dseg:0002 db 69h ; i
dseg:0003 db 6Eh ; n
dseg:0004 db 70h ; p
dseg:0005 db 75h ; u
dseg:0006 db 74h ; t
dseg:0007 db 20h
dseg:0008 db 73h ; s
dseg:0009 db 74h ; t
dseg:000A db 72h ; r
dseg:000B db 69h ; i
dseg:000C db 6Eh ; n
dseg:000D db 67h ; g
dseg:000E db 3Ah ; :
dseg:000F db 24h ; $
dseg:0010 unk_10010 db 0Dh ; DATA XREF: start+15↓o
dseg:0011 db 0Ah
dseg:0012 db 24h ; $
dseg:0013 unk_10013 db 0Dh ; DATA XREF: start+52↓o
dseg:0014 db 0Ah
dseg:0015 db 59h ; Y
dseg:0016 db 65h ; e
dseg:0017 db 73h ; s
dseg:0018 db 24h ; $
dseg:0019 unk_10019 db 76h ; v ; DATA XREF: start+3D↓o
dseg:001A db 0Eh
dseg:001B db 77h ; w
dseg:001C db 14h
dseg:001D db 60h ; `
dseg:001E db 6
dseg:001F db 7Dh ; }
dseg:0020 db 4
dseg:0021 db 6Bh ; k
dseg:0022 db 1Eh
dseg:0023 db 41h ; A
dseg:0024 db 2Ah ; *
dseg:0025 db 44h ; D
dseg:0026 db 2Bh ; +
dseg:0027 db 5Ch ; \
dseg:0028 db 3
dseg:0029 db 3Bh ; ;
dseg:002A db 0Bh
dseg:002B db 33h ; 3
dseg:002C db 5
dseg:002D unk_1002D db 15h ; DATA XREF: start+D↓o
dseg:002E byte_1002E db 0 ; DATA XREF: start+21↓r
dseg:002F unk_1002F db 0 ; DATA XREF: start+39↓o
dseg:0030 db 0
dseg:0031 db 0
dseg:0032 db 0
dseg:0033 db 0
dseg:0034 db 0
dseg:0035 db 0
dseg:0036 db 0
dseg:0037 db 0
dseg:0038 db 0
dseg:0039 db 0
dseg:003A db 0
dseg:003B db 0
dseg:003C db 0
dseg:003D db 0
dseg:003E db 0
dseg:003F db 0
dseg:0040 db 0
dseg:0041 db 0
dseg:0042 db 0
dseg:0043 db 0
dseg:0044 db 0
dseg:0045 db 0
dseg:0046 db 0
dseg:0047 db 0
dseg:0048 db 0
dseg:0049 db 0
dseg:004A db 0
dseg:004B db 0
dseg:004C db 0
dseg:004D db 0
dseg:004E db 0
dseg:004F db 0
dseg:004F dseg ends
dseg:004F
seg001:0000 ; ===========================================================================
seg001:0000
seg001:0000 ; Segment type: Pure code
seg001:0000 seg001 segment byte public 'CODE' use16
seg001:0000 assume cs:seg001
seg001:0000 assume es:nothing, ss:dseg, ds:nothing, fs:nothing, gs:nothing
seg001:0000
seg001:0000 ; =============== S U B R O U T I N E =======================================
seg001:0000
seg001:0000 ; Attributes: noreturn
seg001:0000
seg001:0000 public start
seg001:0000 start proc near
seg001:0000 mov ax, seg dseg
seg001:0003 mov ds, ax
seg001:0005 assume ds:dseg
seg001:0005 lea dx, unk_10000
seg001:0009 mov ah, 9
seg001:000B int 21h ; DOS - PRINT STRING
seg001:000B ; DS:DX -> string terminated by "$"
seg001:000D lea dx, unk_1002D
seg001:0011 mov ah, 0Ah
seg001:0013 int 21h ; DOS - BUFFERED KEYBOARD INPUT
seg001:0013 ; DS:DX -> buffer
seg001:0015 lea dx, unk_10010
seg001:0019 mov ah, 9
seg001:001B int 21h ; DOS - PRINT STRING
seg001:001B ; DS:DX -> string terminated by "$"
seg001:001D xor cx, cx
seg001:001F xor ax, ax
seg001:0021 mov cl, byte_1002E
seg001:0025 mov si, 2Fh ; '/'
seg001:0028 mov al, [si]
seg001:002A add si, cx
seg001:002C
seg001:002C loc_1007C: ; CODE XREF: start+37↓j
seg001:002C sub si, 1
seg001:002F xor [si], al
seg001:0031 mov al, [si]
seg001:0033 dec cx
seg001:0034 cmp cx, 0
seg001:0037 jnz short loc_1007C
seg001:0039 lea si, unk_1002F
seg001:003D lea di, unk_10019
seg001:0041
seg001:0041 loc_10091: ; CODE XREF: start+50↓j
seg001:0041 mov al, [si]
seg001:0043 mov bl, [di]
seg001:0045 add si, 1
seg001:0048 inc di
seg001:0049 cmp al, bl
seg001:004B jnz short loc_100AA
seg001:004D cmp cx, 0
seg001:0050 jnz short loc_10091
seg001:0052 lea dx, unk_10013
seg001:0056 mov ah, 9
seg001:0058 int 21h ; DOS - PRINT STRING
seg001:0058 ; DS:DX -> string terminated by "$"
seg001:005A
seg001:005A loc_100AA: ; CODE XREF: start+4B↑j
seg001:005A mov ah, 4Ch
seg001:005C int 21h ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT)
seg001:005C start endp ; AL = exit code
seg001:005C
seg001:005C seg001 ends
seg001:005C
seg001:005C
seg001:005C end start
这个还是很好看的,就是一个异或,不过是级联异或,那么我们就可以直接用厨子梭一下就好了
xyctf{you_know_8086}
4.DebugMe
这道题在题目提示就已经给了,就是去动态调试这个.apk文件。那么动态调试,就需要用到虚拟器,我这里是用到雷电模拟器,然后调试的工具是jadx,但是这里要记住,可能需要把雷电模拟器自带的adb.exe给换掉,当时弄了好久,发现是这玩意出了问题,以及模拟器要调成手机模式
那么就开始吧
1.先用MT管理器查看其是否具备可调式的属性,如果没有得加上去,在application那一个<>里加入,android:debuggable="true",因为这个.apk文件本身没有这个属性,所以得加,如果有,但现实的是false,就改成true,然后得记得,加完之后,点击保存,然后记得加上签名,点击自动签名,
2.打开模拟器,安装这个修改了的.apk文件,然后打开设置,进入开发者模式,如果没有进,就多点几次版本号,就好了,
打开USB调试,然后再选择调试应用,现在我们要调试的应用,如果在之前,没有把它的可调式属性改成true,这里就无法选择。
3.打开cmd,然后运行adb.exe,这里要记得去用户的环境变量里添加,但是文件地址只到bin,
如果这里记得要检查端口是否连接上,以及设备连的是否是要使用的设备或者模拟器,可以用
adb devices -l查看连接的设备
adb shell ps查看线程状态
连接上以后,就可以进行动调了
4.用jadx打开
点击这个和甲虫一样的图标,
如果前面的步骤正确,就可以到这里,可能第一个选项没有,但不影响,
然后在模拟器里点击应用,就会显示这个,此时,jadx那边也会显示线程
点击线程
就到了这里,然后点击运行,直到模拟器那边显示
再点击那个按钮,就出flag了
5.砸核桃
下载好附件,是.exe文件,先查壳吧,
32bit的,同时我们可以看到是UPX壳,换了名的,那么我就用010editor修改一下,
这样,我们修改完成之后,保存一下,再用工具脱壳,
很遗憾,没有脱壳成功,那么我们就只能手动脱壳了,刚哈这又是32bit的可执行文件,那么就用吾爱破解打开,
恰好我们在这里看到了pushad,我们先按两次F8,
看到旁边寄存器,除了EIP,只有ESP变红了,那么我们就可以利用ESP定律进行脱壳,然后我们光标来到ESP寄存器上,右键,选择HD break [ESP],下个断点,然后F9运行,
此时我们可以看到程序跑到了popfd这一行,我们继续F8单步,通过第一个jmp跳转,可以看到,
如果没有看到汇编代码,只看到了十六进制数,可以右键,然后在分析选项中,找到,从模块中删除分析,就好了,这里我们仔细阅读代码,就可以看到这里有一个函数的开头,push ebp,mov ebp,esp,然后光标来到这里,右键,用吾爱破解的插件进行脱壳,点击用OllyDump脱壳调试进程,
点击获取EIP作为OEP,然后点击脱壳,再将文件取名保存即可,
此时我们再去查壳,显示壳还在,因为我们只是更改了程序的入口点,壳的特征还在。接下来我们就可以进行正常分析了,
直接用ida-32打开分析,找到main函数,就可以得到伪代码了,就是一个简单的异或,脚本如下,
不过得动调一下才能得正确的数据,
key = "this_is_not_flag"
enc = [0x12, 0x04, 0x08, 0x14, 0x24, 0x5C, 0x4A, 0x3D, 0x56, 0x0A, 0x10,
0x67, 0x00, 0x41, 0x00, 0x01, 0x46, 0x5A, 0x44, 0x42, 0x6E,
0x0C, 0x44, 0x72, 0x0C, 0x0D, 0x40, 0x3E, 0x4B, 0x5F, 0x02,
0x01, 0x4C, 0x5E, 0x5B, 0x17, 0x6E, 0x0C, 0x16, 0x68, 0x5B,
0x12, 0x48]
flag = ''
for i in range(42):
flag += chr(ord(key[i % 16]) ^ enc[i])
print(flag)
得到flag:flag{59b8ed8f-af22-11e7-bb4a-3cf862d1ee75}
6.ez_cube
下载好附件,是一个.exe文件,依旧现查壳,
没有壳,64bit,直接丢到ida64里分析,分析结束,在函数窗口找到main函数,然后就得到伪代码了,
int __fastcall main_0(int argc, const char **argv, const char **envp)
{
int i; // [rsp+44h] [rbp+24h]
char v5; // [rsp+64h] [rbp+44h]
int v6; // [rsp+84h] [rbp+64h]
j___CheckForDebuggerJustMyCode(&unk_1400240A2, argv, envp);
for ( i = 0; i < 9; ++i )
{
qword_14001FB60[i] = &unk_14001CC24;
qword_14001FB00[i] = "Blue";
qword_14001FAA0[i] = "Green";
qword_14001FA40[i] = "Orange";
qword_14001F9E0[i] = "Yellow";
qword_14001F980[i] = "White";
}
qword_14001FB00[1] = &unk_14001CC24;
qword_14001FB60[1] = "Green";
qword_14001FAA0[1] = "Blue";
while ( 1 )
{
do
v5 = getchar();
while ( v5 == 10 );
switch ( v5 )
{
case 'R':
sub_140011375();
break;
case 'U':
sub_1400113BB();
break;
case 'r':
sub_140011366();
break;
case 'u':
sub_14001115E();
break;
}
++dword_14001F1C0;
v6 = sub_140011389();
if ( v6 == 1 )
break;
if ( v6 == 2 )
goto LABEL_19;
}
sub_14001119F(&unk_14001CCA0);
LABEL_19:
system("pause");
return 0;
}
第一个for循环就是将魔方进行初始化,后面的三行代码就是将某三个面的最上面那一行的中间的那个换成了其他颜色。然后就是读入我们的输入,怎么操作,把魔方进行还原,具体R U r u的所带来的影响进入每个函数查看即可。
R:右侧面进行顺时针转一圈;r相反
U:上面这层进行顺时针转一圈;u相反
来玩魔方肯定是不可能的啦,去网上一搜三阶魔方三面凹字还原,教程一堆,不过只有一种才是正确答案,控制步数在12步以内,那么flag就是 flag{RuRURURuruRR}
7.baby unity
这道题是根据题目的hint所提供的工具完成的
GitHub - Perfare/Il2CppDumper: Unity il2cpp reverse engineer
用这个工具对文件的符号进行修复。
先查壳,.exe文件和.dll文件(GameAssembly.dll)都有壳,都脱下吧。
我们通过链接所下载的是Il2CppDumper-win-v6.7.40.zip。
然后我点击运行Il2CppDumper.exe,再依次选择GameAssembly.dll,global-metadata.dat(在文件夹里,找找),然后就可以看到
我们先用ILSpy打开Assembly-CSharp看看有没有什么有用的信息,
果不其然,这里有加密函数,可是我们却看不到完整的,这也就是我们为什么要使用这个工具的原因,记下这个函数名,待会有用
然后将GameAssembly.dll用ida-64分析,这是一个漫长的过程,分析结束,我们就可以利用Il2CppDumper自带的恢复符号的idapython脚本进行复原,在File选项中找到Script flie,然后依次选中这三个文件,ida_with_struct_py3.py-->script.json-->il2cpp.h,然后静等ida自己跑,结束后,我们在函数窗口搜索Check....,
就可以找到加密函数了,分析代码下来,就是先进行base64加密,然后再进行一个简单的异或,但是加密结果在ida里是找不到的,要在stringliteral.json里找,我当时在做的时候,是通过flag的格式的开头XYCTF反推找到的加密结果,然后进行完整的逆向,得到flag,
8.今夕是何年
这道题,就真的是跑一下就出了,但是我们需要支持龙芯架构的系统来跑,然后我用的是qemu,在Ubuntu上下载了这玩意,然后跑一下,