Re几道入门题

逆向目前我还是刚开始专门学,现在只懂点c语言。有错误 | 更好的方法就请各位师傅多多指教了orz。第一篇文章有一些过程会写的很细,因为我第一次(用ai)打逆向是在去年10月的pctf,当时ai还只是deepseek,还是要自己懂点操作的,当时我还是跟着别人手把手教的写了几个题,这里也是想回报一下吧。目前ai很强了,不过为了线下我觉得还是要学学,下面就正式开始吧。题目在这里PCTF2025 - Review::CTF

PCTF2025——flag

放ida里看看
FY9OXL{_%TFS~YE{$A$S

这里直接shift+f12搜一下字符串就找到了
9XWA62K8I@S2}__8MVJTQX

PCTF2025——xor

下好附件解压后放ida里
H$PVSUTKH`15O3NV02DLNXO

这里可以按f5反编译看伪c代码。
BCJ@A4HP58}$V88)MZ52DY

这里就是c语言代码,整体逻辑就是先进行flag的解密,然后比较我们输入的flag和他的flag是不是一样,先看看他怎么解密的。
P56WI1ZLS{B$NNNY5GI$XH

对着变量按n可以重命名变量,整体逻辑就是把encrypted_flag里的每个字符对着密钥进行异或,并且把异或后结果放进s2里。因为异或是可逆的,这里有两种解法,第一种是动态调试。不过他是elf文件,可能要配一下远程linux调试,或者直接gdb调,远程可以看看这篇文章由一道逆向题而引发,IDA调试ELF文件 - DorinXL - 博客园,这里是re就不讲gdb了吧。总之配好了之后我们点一下strcmp这行伪代码按f2下断点,不过我的环境有点问题,要在汇编下断点不然断不下来。在汇编上下也是一样,点strcmp这行伪代码按tab切换汇编,也可以再按空格好看一点。
L(@CGTK4YEK}QTG)J0)AU3B

_RM5EC48EQPWHS{T9GEM$C

然后直接f9调试,这里要输入一个数据,直接在虚拟机上输入数据即可,右上角就是flag
4}$LTSTJ5MAOMT$%XCCVX0F

还有第二种方法就是自己写一个python脚本去解密,这里不能只看注释的字符串,因为有不可打印的字符,要点两下encrypted_flag去看他的原始数据,这里他有一部分是16进制数据有一部分是字符串,我们直接对着字符串按d就可以也转化成16进制了,然后选中后按shift+e导出
PA}0SP@%F(RR7`M}FK8EX{9

这样直接复制就可以在python里写列表了,简单写个python脚本解决
4SVAO70{UUWV(Z~7M`Y1Q1

脚本如下:

a=[0x3E,0x5C,0x33,0x38,0x28,0x36,0x2A,0x3F,0x35,0x38,0x3A,0x14,0x3D,0x36,0x2A,0x6F,0x37,0x31,0x30,0x37,0x3A,0x22,0x31,0x3D,0x30,0x25,0x1A,0x30,0x2B,0x6F,0x25,0x3A,0x32,0x2E,0x3E]
key=b'X0R_SECRET_KEY'
flag=""
for i in range(len(a)):
    flag+=chr(a[i]^key[i%len(key)])
print(flag)

PCTF2025——debugme

依然是拿到附件先放ida看看
SONGK0M%92P67HT6Y_(69

这里逻辑函数先输入数据,如果输入的数据长度是32就会解密出flag,最后让输入的数据与flag进行比较。这里的解密函数我们如果双击点进去看会发现
MQSW9Y5OYA0PGBW7YBPE8

上面的ida的注释也告诉了我们,这就是一种混淆的办法:控制流扁平化。简单来说就是写程序的人不想让我们这么简单就逆向出他的程序,所以就加混淆/壳。当然有混淆就有去混淆。目前就先不去混淆了,这题名字就是提升我们动态调试,我们去那个比较flag的地方下断点f9动态调试就可以。这题是exe程序,可以在windows本地运行。
73W4B`)M1R6HYU3R1MZDTG9

右上角就是flag

PCTF2025——upx

这里如果我们还是拿到附件就放ida看,就发现怎么奇奇怪怪的,这里就遇到了刚才所讲的壳了。这里我们就需要查壳工具DIE了,我们把附件放进DIE看看
5ZL%UG@$9I41F46EGRG%WT

可以看见这里告诉我们壳是upx壳,upx是有脱壳工具的。各位可以下载一下,然后运行这个命令
38{FY`U1AA@L84IBZ_LFA$Q

这样就把壳脱出来了,此时再在DIE看也是没看见壳了
8(XII@YD`4$WDR9JQ$89

然后我们放ida看看
KPO{R)R$DRKV`CZYEI@Q88P

这里程序就不带着逆了,因为跟之前的差不多,多点点几个函数即可。还是一个异或,这题也可以动态调试。直接解密脚本如下:

a=[0x3E,0x5C,0x33,0x38,0x28,0x36,0x2A,0x3F,0x35,0x38,0x3A,0x14,0x30,0x29,0x20,0x6F,0x37,0x31,0x30,0x37,0x3A,0x22,0x31,0x3D,0x30,0x25,0x1A,0x30,0x2B,0x6F,0x25,0x3A,0x32,0x2E,0x3E]
key=b'X0R_SECRET_KEY'
flag=""
for i in range(len(a)):
    flag+=chr(a[i]^key[i%len(key)])
print(flag)

Base64编码的原理

base64其实还是很简单的,他的左右结束传输一些文件,因为文件内可能有不可打印字符,这个编码就可以把不可打印字符变成可打印字符。原理很简单,我们知道一个字符其实是以ascii码的值储存在计算机中,也就是8个bit。而base64就是只用6个bit,并且0-63用可打印的字符表进行编码。标准的表是ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/。编码的过程就是对我们要发送的字节按3个为一组(因为6和8的最小公倍数是24,3*8=24,6 *4=24)。3个字节就有了24个二进制位,前6个二进制位就是一个索引,然后去表上找。如果不满足3字节怎么办呢?就会自动补0,并且在0的时候不会进行索引,而是在后面加=。加=因为base64编码后必须为4的倍数(这是规定,其实是为了解码器更好还原)

我就以flag为例子人工编码一下f的ascii码是0x66(16进制更好转2进制),l的ascii码是0x6c,a的ascii码是0x61,g的ascii码是0x67他们的二进制就是

		f 				l  				a 				g
	01100110		01101100		01100001		01100111
	按6给bit划分就是011001 100110 110001 100001 011001 110000(这里后面就没有二进制位了自动补0)
	这6个bit的10进制就是25		38     49	33		25		48

根据索引找表我就用python的列表演示了。
VTW3EE%S2(16W@TT54{3PW

a='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
c=a[25]+a[38]+a[49]+a[33]+a[25]+a[48]
print(c)

结果ZmxhZw补上=号就是ZmxhZw==解码后就是flag。所以流程大概就是这样,这里加解密的python脚本我也写好了,可以大概看看,总之能用就行,也不是来追求速度的。

while True:
    choice=input("输入你想加密(1)或解密(2)输入0退出")
    if int(choice)==1:
        word=input("输入想加密的字符串")
        table='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
        resul=[]
        for i in range(0,len(word),3):
            buf=word[i:i+3]
            c=0
            for j in buf:
                c=(c<<8)+ord(j)
            if len(buf)==3:
                index=[(c>>18)&0x3f,(c>>12)&0x3f,(c>>6)&0x3f,c&0x3f]
                resul.extend(table[i] for i in index)
            if len(buf) == 2:
                c<<=8
                index = [(c >> 18) & 0x3f, (c >> 12) & 0x3f, (c >> 6) & 0x3f]
                resul.extend(table[i] for i in index)
                resul.append('=')
            if len(buf) == 1:
                c<<=16
                index = [(c >> 18) & 0x3f, (c >> 12) & 0x3f]
                resul.extend(table[i] for i in index)
                resul.append('=')
                resul.append('=')
        en=''.join(resul)
        print(en)
    if int(choice)==2:
        word=input("输入想解密的字符串")
        table='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
        refle={c:i for i,c in enumerate(table)}
        resul=bytearray()
        for i in range(0,len(word),4):
            buf=word[i:i+4]
            c=0
            long=0
            for j in buf:
                if j=='=':
                    break
                c=(c<<6) | refle[j]
                long+=1
            if long==4:
                resul.append((c>>16)&0xff)
                resul.append((c>>8) & 0xff)
                resul.append(c & 0xff)
            if long==3:
                resul.append((c>>10)&0xff)
                resul.append((c>>2) & 0xff)
            if long==2:
                resul.append((c>>4)&0xff)
        print(resul.decode())
    if int(choice)==0:
        break

知道了原理,那写题就随便写了,无非就是换了个语言实现了这个原理/改了点东西。我们看看题

Pctf2025——base64

附件先放DIE,没看见壳。然后放ida看看前面就不看了,直接看加密函数
_R%$$JZLLHKCTO8HDFUM@D

整体逻辑就是输入字符串,加密后跟已编码的字符串是不是一样。这个实现可以看见跟上面原理是一样的,用int类型存储3个byte的二进制位,用>>和&取6个二进制位,查表用索引,写回字符串用指针。就是标准的base64。因为base64编码可逆,我们把编码的字符串解码就可以了,也不一定要用我那个脚本,用cyberchef或者随便找个网站解码一样的。
38S7Q81WK3@`Z3O(~O8

PCTF2025——base64_pro

这题就不是标准的base64了,die没看见壳,放ida看看
@SOY2_0R5VNZM{6$%_LN6E

main函数前面逻辑很简单就不看了,整体逻辑就是输入字符串,进行加密跟已加密的字符串比较。这里可以看见流程还是base64,但是加密的表换了。换表也一样解,我们用cyberchef或者用我那个脚本把表换了一样解。如果直接换表解会发现居然错了。不管是cyberchef还是我的脚本都解不出来,我的脚本可以错cyberchef总不可能错吧。所以这题肯定有什么奇奇怪怪的地方,但是我们跟着main函数看也没看出来什么东西阿?这里在左边列表我们可以看见一个函数,他没有出现在main函数里,但他是不是就不会被调用呢?我们看看
@(W0}XAJAGHT0S{MTY8OZJ

可以看见他对这个表进行了各种操作,我们可以ctrl+x看看哪里调用了他
E}6Q_HBGP(G5VU%A2425%XQ

可以看见他在初始化的数组上,所以这其实是个预主函数。也就是在main函数之前就已经调用了他了,也就是说我们现在看见的base64的表跟程序实际运行main函数时的表其实是不一样的。这里如果我们想对这个函数进行分析也可以,但这有点太复杂了,这里虽然有个随机数,但没有以时间为种子(其实也不可能,如果表会变,那密文应该也要跟着动态加载,不然flag就解不出来了)所以我们可以动态调试,直接把表拿到再解密。这个文件是elf文件,需要配置一下,在他取表的地方下个断点
P43H_@C1H{6AO0M~%MIL368

然后f9动调一下
J5LQ`X{W_JIQB5S%2DHS5M

就可以看见表了,我们用cyberchef/我写的脚本把表换了就能解出来了
7TL`ZEH67TJ@VI$@XN22X

change_base64

这题在这里下网络空间安全执法技术实战 - SDPC::CTF,主逻辑还是挺简单就不看了,我们看加密过程
6(O9N_GGRNT

可以看见,首先这个表换了,然后从表取值的索引,他这里^了0x15,如果只是换表,那用网站还是能写的,不用写脚本。这里改了一下就肯定要写脚本了,当然理解了逻辑就很简单,因为异或可逆,我们取索引的时候再异或一下就可以了,换了表我们解密也把表换了就可以了。
(}@ZV%TH05A(CA)CISMD7U5

所以逆向还是挺开心的,当然现在其实还没怎么逆,还是在写写套路题。后面慢慢来吧,Re:0


原文地址: https://www.cveoy.top/t/topic/qGND 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录