BUUCTF SimpleRev(涉及大小端序存储的问题)

**

逆向reverse小白一枚,欢迎各位师傅指出不足之处。

buuctf-SimpleRev

**

考点:大端序,小端序,分析伪代码

做这道题的时候遇到了一个新的知识点,大端序和小端序。
BUUCTF SimpleRev(涉及大小端序存储的问题)_第1张图片

用Exeinfo PE打开
BUUCTF SimpleRev(涉及大小端序存储的问题)_第2张图片
发现是64位的,无壳。然后用IDA pro64位打开

shift + F12 查看字符串窗口
BUUCTF SimpleRev(涉及大小端序存储的问题)_第3张图片
BUUCTF SimpleRev(涉及大小端序存储的问题)_第4张图片
BUUCTF SimpleRev(涉及大小端序存储的问题)_第5张图片
ctrl + X 交叉引用
BUUCTF SimpleRev(涉及大小端序存储的问题)_第6张图片
BUUCTF SimpleRev(涉及大小端序存储的问题)_第7张图片
F5反汇编。
BUUCTF SimpleRev(涉及大小端序存储的问题)_第8张图片
将100、68、113、83,R字符转换为ASCLL码。
BUUCTF SimpleRev(涉及大小端序存储的问题)_第9张图片
看到有一个Decry()函数。
打开之后,代码如下:
BUUCTF SimpleRev(涉及大小端序存储的问题)_第10张图片

unsigned __int64 Decry()
{
char v1; // [rsp+Fh] [rbp-51h]
int v2; // [rsp+10h] [rbp-50h]
int v3; // [rsp+14h] [rbp-4Ch]
int i; // [rsp+18h] [rbp-48h]
int v5; // [rsp+1Ch] [rbp-44h]
char src[8]; // [rsp+20h] [rbp-40h]
__int64 v7; // [rsp+28h] [rbp-38h]
int v8; // [rsp+30h] [rbp-30h]
__int64 v9; // [rsp+40h] [rbp-20h]
__int64 v10; // [rsp+48h] [rbp-18h]
int v11; // [rsp+50h] [rbp-10h]
unsigned __int64 v12; // [rsp+58h] [rbp-8h]

v12 = __readfsqword(0x28u);
*(_QWORD *)src = 357761762382LL;
v7 = 0LL;
v8 = 0;
v9 = 512969957736LL;
v10 = 0LL;
v11 = 0;
text = (char *)join(key3, &v9);
strcpy(key, key1);
strcat(key, src);
v2 = 0;
v3 = 0;
getchar();
v5 = strlen(key);
for ( i = 0; i < v5; ++i )
{
if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
key[i] = key[v3 % v5] + 32;
++v3;
}
printf(“Please input your flag:”, src);
while ( 1 )
{
v1 = getchar();
if ( v1 == 10 )
break;
if ( v1 == 32 )
{
++v2;
}
else
{
if ( v1 <= 96 || v1 > 122 )
{
if ( v1 > 64 && v1 <= 90 )
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;
}
else
{
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;
}
if ( !(v3 % v5) )
putchar(32);
++v2;
}
}
if ( !strcmp(text, str2) )
puts(“Congratulation!\n”);
else
puts(“Try again!\n”);
return __readfsqword(0x28u) ^ v12;
}
BUUCTF SimpleRev(涉及大小端序存储的问题)_第11张图片
将src 和 v9 的数据转为十六进制,快捷键H。
BUUCTF SimpleRev(涉及大小端序存储的问题)_第12张图片
可以看到这里的两个十六进制是大端序,但是数据在内存中都是小端序,所以要将其,反转一下。一般在CPU,x86都是小端序,但是IDA将之转换为了大端序。
BUUCTF SimpleRev(涉及大小端序存储的问题)_第13张图片
先快捷键R 将其转为字符。再反转,所以src = NDCLS , v9 = hadow 。
BUUCTF SimpleRev(涉及大小端序存储的问题)_第14张图片
key3已经告诉,key3 = kills 。
再看这有一个join函数,它的作用是以指定的字符连接成一个新的字符串。此处是将key3 和 v9 连接成一个新的字符串。
BUUCTF SimpleRev(涉及大小端序存储的问题)_第15张图片

即text = killshadow。
在这里插入图片描述
strcpy(key, key1); //复制函数,将key1的字符串复制给key,
BUUCTF SimpleRev(涉及大小端序存储的问题)_第16张图片
key1 = ADSFK, 所以key = ADSFK
strcat函数,是将key 和 src 拼接在一起的函数, 所以key = ADSFKNDCLS。
BUUCTF SimpleRev(涉及大小端序存储的问题)_第17张图片
看到v5 = strlen(key),strlen是计算字符串的长度,所以v5 = 10 。
再看这个for循环语句,先将64,90变为字符。为
BUUCTF SimpleRev(涉及大小端序存储的问题)_第18张图片
再对照ASCLL码表,
BUUCTF SimpleRev(涉及大小端序存储的问题)_第19张图片
如果key3【v3 % v5】是大写字母,则把它变为小写字母。大小写字母的ASCLL码,相差32。
BUUCTF SimpleRev(涉及大小端序存储的问题)_第20张图片
再将下面的数字变为ASCLL码字符。
BUUCTF SimpleRev(涉及大小端序存储的问题)_第21张图片
看到最下面的if语句,如果!strcmp(text ,str2),则正确,strcmp函数,是比较函数,如果两个字符串相同,则等于0,所以text = str2才成功。

而得到str2的关键就是:
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;

接下来,写脚本。

BUUCTF SimpleRev(涉及大小端序存储的问题)_第22张图片

#include
int main()
{
char key[] = “adsfkndcls”; //key字符串是adsfkndcls
char text[] = “killshadow”; //text字符串是killshadow
int i; //定义了变量 i
int v2 = 0;
int v3 = 10;//v3的长度为10 ,因为在大写字母变小写的时候,v3会++,而字符串变了10次。
int v5 = 10;
for (int i = 0; i < v5; i++)//开始循环
{
for (int j = 0; j < 123; j++)//开始第二重循环 j = v1;
{
if ((j < ‘A’ || j > ‘Z’) || (j < ‘z’ && j > ‘a’))//|| 和 && 交换 > 和 < 交换 ,让j不再那个范围之内
{
continue;//如果不在范围之内,就跳过本次循环。
}
if ((j - 39 - key[v3 % 10] + 97) % 26 + 97 == text[i])//执行这个算法,跟text字符串相比,如果相等就输出
//这个字符
{
printf("%c",j);
v3++;//注意算法里面 v3++,所以这里也要把v3++;
break;
}
}
}
}

总结:这个题目除了基本的IDA pro的一些小小的快捷键之外,还需要知道小端序和大端序的知识,怎么去判断是小端序和大端序,这个我也不知道(百度了一波,可以自己写一个小程序来判断),大概就是在做题的时候,如果碰到我们需要手动去转字符的,应该就是反转一下字符的位置,实在不行大端序和小端序都去试一下。然后并是分析伪代码,知道它是在干什么,我们需要什么,还差了什么。然后写脚本,来运行得出flag。目前这一点,自己还不是很会,还需多多练习啊。

继续学习!!!

你可能感兴趣的:(CTF逆向reverse新手,wp)