ctf php黑魔法,社团的CTF逆向题WriteUp

最近社团弄了CTF比赛,然后我就帮忙写了逆向的题目,这里写一下WriteUp,题目和源码在附件中给出

一个简单的逆向:one_jmp_to_flag.exe

这题算是签到题,直接OD智能搜索就完事了,flag{Welcome_to_GeekFZCTF}

7f9d151811b08bff43f571ec424e4393.png

一个简单的对比:check.exe

这一道也算是送分题,可以用IDA直接分析可以看出来,这里就是读取输入的字符串,然后逐个进行对比,这里可以直接用IDA转化为char型就可以看出。flag{sAdf_fDfkl_Fdf}

7b1692451ae21d93a475c56c400702d8.png

c76e75769134396608bb4f2147901ccd.png

猜猜那个是flag:whichisflag.exe

首先加载进IDA,先看一下基本逻辑,输入的flag首先要小于25,然后进行判断进行判断,如果flag[5]=Y,且flag[8] = flag[11],flag[16] = flag[18],上面的都实现了就执行which_is_flag这个函数,我们跟进去看一下。

28d78e9543ae60e3977c6bccbb0834e2.png

可以看到这是通过flag[5]进行switch跳转,然后我们之前有个判断条件flag[5]=Y,所以这里的跳转就是到89处

97a471ab48bda0096ba8baafcaa986b7.png

4683a4b4f7ce992e3104bb9b33b58c53.png

但是我们可以看到,这个flag的长度是大于25的,然后仔细观察一下flag里的内容,可以看出是base64编码过的,我们找个网站进行解码就可以,这里的flag是用python随机出来的,代码也在附件里。flag{YkEj_djkf3_jEj_eUn}

82367e95664bd55dedbcb7a73a10debc.png

简单的反调试:fts.exe

其实这道题目就只是用OD调试时会遇到一点反调试,如果用IDA直接分析逻辑就可以了,这里首先用IDA分析先。

6cfa972387fe36c79b9f9a8bb30a577f.png

可以看到一个可疑的循环并printf出来字符 ,我们看到逻辑就是用flag_2这个数组的数据与0x11进行异或,我们手动计算一下得出字符串(这里注意的是0x76707D77是小端序,我们要从77开始异或):flag{

d4b62b278cac141e5aed9268ea72c667.png

然后我们可以继续往下面找关键循环,函数CheckDebug、fts_Rdtsc、the_end里都有循环输出,然后都解密出来就是:congratulations_for_you}

09dae4ff0a3ee788d7216a4a5754509b.png

72f0990da0bca162b8184d8e88fcf095.png

6ef746e463d217f55eb59c3ee4bd5e0d.png

716bc8d448083bbbacb2d044631f86a8.png

所以flag就是:flag{congratulations_for_you}

然后用OD动态调试一下,一开始就是先进行进程的检索,判断是否存在IDA或者OD,然后我们可以通过je直接跳过进行判断的地方。

1ede980fd838af8f1a9ab83039510d1f.png

跳过第一个反调试的地方后就得看一下我们的main函数入口在哪里(为什么不先找main函数,因为你不跳过第一个反调试即使找到main函数入口也没用,尝试一下就发现跳过了第一个反调试就很容易去到main函数了),我们这里先智能搜索一下可以看到一些字符串,你可以每个都进去看一下,然后发现main函数就在走过八十一难哪里(用IDA可以直接找到)

29fe83885c40b88072fc4f6f0253ca3e.png

找到main函数后下断点,然后F9跳过去就可以单步跟踪了,我们可以发现会自己打印出了第一个解密循环

fc42e35dbf4b0d744d1c7182f852c29d.png

下面继续跟会发现有用到FindWindow函数去查找有没有IDA和OD,然后我们只要不让下面两个je进行跳转就可以,就会再打印出一段flag出来

cea67e5fd149dd54f5964259171a19b1.png

99dd00e9740f110b8b661598292f079e.png

跟进去函数里面,可以发现用了ZwQueryInformationProcess进行检测调试端口的,我们不让它跳转就会打印出字符串来

af60f6ef663924e3144353e75928c38a.png

bc6345ef4bf4ad6e9ac49ac94f77cf55.png

314c39415de3b8a3e037c7c89e463108.png

再进入下一个函数中,在里面可以看到rdtsc命令,这个用于把时间保存的指令,这里是基于时间的反调试,我们可以直接在下面的popad下断点然后F9直接跳过,然后就找到了解密循环。

c4a0876642f518f1db3dcaa8537ba163.png

df210a9b7e52e0078321a88a6a2c393d.png

e6630b3560baa856bcafdca79118ad54.png

最后进入函数,我们可以看到有一个get函数并且下面的跳转是关键,可以先随机输入一些东西,然后可以看到下面的跳转跳过了我们的printf函数,所以我们让它不跳转,然后就跑出最后的flag出来。

42636d20a433abf41ea48467de88a37d.png

c33b834ccd9bdd1e594f23726cfe75ab.png

bb933cc3518bc396bb652f7bfa3ea636.png

a99dc152a128321258f25b6e57e8163f.png

简单的算法:suafa.exe

这是一个算法,然后这里要道个歉是出题不够严谨,在跑flag的时候会出现多解的情况。正向的核心算法是输入的字符串减去key之后对4求余,然后在key1到key4之间选择字符,最后与我们给定的字符进行对比

1 char key1[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";2 char key2[65] = "+/abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";3 char key3[65] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/";4 char key4[65] = "0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";5

6 char key[27] = "QASWZXDECVFRBNGTHYJUMKIOLP";7 int len =strlen(flag);8 for(int i=0; i= 33)11 {12 if(flag[i]-key[i] > 0)13 {14 int the_key = (flag[i]-key[i]) % 4;15 switch(the_key)16 {17 case 0:18 flag[i] = key1[flag[i]-key[i]];19 continue;20 case 1:21 flag[i] = key2[flag[i]-key[i]];22 continue;23 case 2:24 flag[i] = key3[flag[i]-key[i]];25 continue;26 case 3:27 flag[i] = key4[flag[i]-key[i]];28 continue;29 default:30 continue;31 }32 }33 else

34 {35 printf("flag is wrong");36 ExitProcess(0);37 }38 }39 }

然后在逆向的时候我们用IDA打开基本都能编译出来,然后有一点小问题就是v5 = v4 - v1[key-flag]这里,反编译后与原来的代码int the_key = (flag[i]-key[i])有点差别,不过如果看汇编的代码可以更好的理解

d4ef9153fb58c1b7b4a7cc0b0e32d69b.png

其中sub eax, flag就是我们的v4 - v1[key-flag],而v4=flag[i],所以理论上flag = v1[key-flag],而我们汇编中flag的值为byte ptr [ebx+edx],这里的ebx可以从前面查看就是key,而edx就相当于索引。不懂得可以自己仔细看一下。

28ee368928ca973e70b29563caaceba5.png

然后分析完就可以写个脚本自己跑出来:flag{this_is_a_easy_suanfa}

1 #include "stdio.h"

2 #include "Windows.h"

3

4 intmain()5 {6 char key1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";7 char key2[] = "+/abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";8 char key3[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/";9 char key4[] = "0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";10

11 char key[] = "QASWZXDECVFRBNGTHYJUMKIOLP";12

13 char flag_1[] = "tfoQ5ckkwhX51HYpxAjkMQYTAp5";14

15 int yushu = 0;16

17 for(int m=0; m<=26; m++)18 {19 for(int n=33; n<=126; n++)20 {21 yushu = n - int(key[m]);22 yushu %= 4;23 switch(yushu)24 {25 case 0:26 if(key1[n - int(key[m])] ==flag_1[m])27 {28 printf("%c", n);29 }30 continue;31 case 1:32 if(key2[n - int(key[m])] ==flag_1[m])33 {34 printf("%c", n);35 }36 continue;37 case 2:38 if(key3[n - int(key[m])] ==flag_1[m])39 {40 printf("%c", n);41 }42 continue;43 case 3:44 if(key4[n - int(key[m])] ==flag_1[m])45 {46 printf("%c", n);47 }48 continue;49 default:50 continue;51 }52 }53 printf("\n");54 }55 }

因为存在多解,所以跑出来得结果是这样子的

8fedfcdfd2ad4a01b4c50d1783a6b8d0.png

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值