easyre-xctf
题目
龟缩起来,保护自己
题解
扔进die里面看一下,UPX加壳程序,脱壳之后拉进IDA,可以找到后半截flag。
在字符串里面找不到前半截,看一眼是不是有其他函数在负责处理,可以找到part1函数。
这里用伪代码只能得到一部分flag,在汇编里面才能看见后面还拼接了_4n。
666
题解
先IDA发现是把输入串通过encode函数加密后与enflag的值对比。
encode函数每三个字符做一轮操作,直接反向即可解出flag,这里注意异或运算符优先级低于加减,要带括号。
enflag="izwhroz\"\"w\"v.K\".Ni"
realflag=""
for i in range (0,18,3):
realflag+=chr((18^ord(enflag[i]))-6)
realflag+=chr((18^ord(enflag[i+1]))+6)
realflag+=chr(18^ord(enflag[i+2])^6)
print(realflag)
easyRE1
题解
IDA一把唆,用flag{}包裹。

Reversing-x64Elf-100
题解
IDA发现关键函数是sub_4006FD。

__int64 __fastcall sub_4006FD(__int64 a1)
{
int i; // [rsp+14h] [rbp-24h]
__int64 v3[4]; // [rsp+18h] [rbp-20h]
v3[0] = (__int64)"Dufhbmf";
v3[1] = (__int64)"pG`imos";
v3[2] = (__int64)"ewUglpt";
for ( i = 0; i <= 11; ++i )
{
if ( *(char *)(v3[i % 3] + 2 * (i / 3)) - *(char *)(i + a1) != 1 )
return 1LL;
}
return 0LL;
}
可以看出函数逻辑是有一个3个元素的字符串数组,然后每个数组进行加减操作,然后与输入的字符作比较,反向编写代码得到flag。
str=["Dufhbmf","pG`imos","ewUglpt"]
flag=""
i=0
print(flag)
for i in range(0,12) :
print(i)
flag+=chr(ord(str[i%3][2*(int(i/3))])-1)
print(flag)
lucknum
题解
IDA直接可以看见flag。

1000Click
题解
打开程序,提示点击1000次或者逆向获得flag。
逆向试了一下,没找到线索,直接上CE。
找到内存,修改为999,然后再点击一次,获得flag。
xxxorrr
题解
IDA逆向,只能看见一个main函数,找不到逻辑,这里学到了一个知识点。
在 ELF (Executable and Linkable Format) 文件中,Initialization Function Table 是一种特殊的数据结构,用于存储在程序启动时(在 main 函数执行之前)需要调用的一系列初始化函数的地址。这个机制允许程序或库执行必要的初始化任务,例如设置全局变量的初始状态、注册回调函数、初始化硬件设备或执行其他任何启动前准备工作。
如果 sub_840 的地址被包含在 ELF 的 Initialization Function Table 中,那么它会在程序的主逻辑开始执行之前被自动调用。这种自动调用是由程序的启动代码(通常是由编译器和链接器自动生成的一部分)负责的,该代码会遍历 Initialization Function Table 中的所有条目,并按照它们出现的顺序调用每个函数。

可以看出会按顺序调用sub_840、sub_84A、sub_8C3、sub_800。
跟一下这几个函数,发现只有84A有一些操作,对s1进行了一轮异或运算,同时可以直接定位到s1的值。
unsigned __int64 sub_84A()
{
int i; // [rsp+Ch] [rbp-14h]
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u);
for ( i = 0; i <= 33; ++i )
s1[i] ^= 2 * i + 65;
return __readfsqword(0x28u) ^ v2;
}

回到main函数,发现注册了sub_916,跟进一下,发现这里是最终判断的函数
unsigned __int64 sub_916()
{
unsigned __int64 v1; // [rsp+8h] [rbp-8h]
v1 = __readfsqword(0x28u);
if ( !strcmp(s1, byte_201060) )
puts("Congratulations!");
else
puts("Wrong!");
return __readfsqword(0x28u) ^ v1;
}
在此之前,main函数里面又进行了一轮异或,是用s1和我们的输入值进行异或,然后进入sub_916,与byte_201060进行比较,可以读到这个串的值。

因此,我们的合理输入,就应该是s1先本身进行一轮异或,再与byte_201060进行一轮异或。
s1="qasxcytgsasxcvrefghnrfghnjedfgbhn"
s2=[ 0x56, 0x4E, 0x57, 0x58, 0x51, 0x51, 0x09, 0x46, 0x17, 0x46,
0x54, 0x5A, 0x59, 0x59, 0x1F, 0x48, 0x32, 0x5B, 0x6B, 0x7C,
0x75, 0x6E, 0x7E, 0x6E, 0x2F, 0x77, 0x4F, 0x7A, 0x71, 0x43,
0x2B, 0x26, 0x89, 0xFE, 0x00]
flag=""
for i in range (0,33):
flag+=chr(ord(s1[i])^(2*i)+65)
flag2=""
for i in range(0,33):
flag2+=chr(ord(flag[i])^s2[i])
print(flag2)
reverse_re3
题目
我从不走回头路,但你能找到我选择的路吗
题解
main函数很简单,直接调用了sub_940()
940点进去,有一些逻辑,并且最后提示flag是输入的md5值。
100、115、119、97对应的字符分别是d s w a,考虑是走迷宫的题。
每一个选项进去都是一个子函数,都使用了dword_202020这个变量,并且步进为15,那么迷宫应该是15个字符为一行,并且可以看出,字符为1的地方是路,那么字符为0就是墙,3是当前位置,4是迷宫出口。
进入dword_202020变量,是一个数组,通过shift+E对变量进行提取。
对提取的数据进行处理,15个字符一行,从3开始走到4
111110000000000
111110311000000
111110001000000
111110001000000
111110001111100
111110000000100
111110000000100
111110000000110
111110000000010
111110000000040
111111111111111
111111111111111
111111111111111
111111111111111
111111111111111
走法:ddsssddddsssdss
110000000000000
110311111000000
110110001000000
110000001000000
110110001111100
110110000000100
110110000000100
110110000011110
110110000010010
110110000010000
110111111010110
110111111111110
110000000000040
111111111111111
111111111111111
走法:dddddsssddddsssaassssddds
000000000000000
031100000000000
000101110000000
000111010000000
000010010000000
011010010000000
001110010000000
000000010000000
000000011110000
000000000010000
000000000010000
000000000010000
000000000011110
000000000000010
000000000000040
走法:ddssddwddssssssdddssssdddss
合理输入:ddsssddddsssdssdddddsssddddsssaassssdddsddssddwddssssssdddssssdddss
计算MD5:aeea66fcac7fa80ed8f79f38ad5bb953
happyctf
题解
这题给了pdb文件,用IDA分析的时候,如果加载了pdb文件,代码会变得非常乱,看不出来什么东西,不加载pdb反而会好一点。

输入一个flag,经过一些函数的处理,然后与目标串“rxusoCqxw{yqK{KZqag{r
i”进行比较。
看一下前面的几个函数,发现while内部的sub_403B70进行了一些操作。
int __thiscall sub_403B70(void *this, char a2)
{
char v3[65]; // [esp+Fh] [ebp-45h] BYREF
void *v4; // [esp+50h] [ebp-4h]
v4 = this;
v3[0] = a2 ^ 0x14;
sub_406170(v3);
return ++dword_4DD8F8;
}
看起来是把字符进行了一轮和0x14的异或,直接梭,得到flag。
s1="rxusoCqxw{yqK`{KZqag{r`i"
flag=""
for i in range(0,len(s1)):
flag+=chr(ord(s1[i])^0x14)
print(flag)
//flag{Welcome_to_Neusoft}
文章评论