1.查壳
无壳,获取到信息64位,而且AMD x86-64
后面的信息平时没怎么关注,但是在这题里面有着关键指向作用
X86平台属于小端序,ARM平台属于大端序
涉及到字符串的储存问题
2.审题
题目很简单,分析清楚之后爆破就行(%的逆我暂时不清楚如何实现)
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; //转化之后为 *(_QWORD *)src = 'SLCDN';
v7 = 0LL;
v8 = 0;
v9 = 512969957736LL; //转化之后为 v9 = 'wodah';
v10 = 0LL;
v11 = 0;
text = (char *)join(key3, &v9); //拼接函数 key3='kills' key3='kills'+v9
strcpy(key, key1); //key1='ADSFK'
strcat(key, src); //拼接 key='ADSFK'+scr
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;
}
就是一条核心算法,较为简单
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;
但是重要的点在于字符串的储存方式(大小端
3.大小端储存
大端(存储)模式:是指一个数据的低位字节序的内容放在高地址处,高位字节序存的内容放在低地址处。
小端(存储)模式:是指一个数据的低位字节序内容存放在低地址处,高位字节序的内容存放在高地址处。(可以总结为“小小小”即低位、低地址、小端)
在计算机系统中,我们是以字节为单位存放数据的,每个地址单元都对应着一个字节,一个字节为8bit。但在C语言中存在不同的数据类型,占用的字节数也各不相同,那么就存在怎样存放多个字节的问题,因此就出现了大端存储模式和小端存储模式。
高低地址
C程序映射中内存的空间布局大致如下:
|最高内存地址 0xFFFFFFFF
|栈区(从高内存地址,往 低内存地址发展。即栈底在高地址,栈顶在低地址)
|堆区(从低内存地址 ,往 高内存地址发展。即栈底在低地址,栈顶在高地址)
|全局区(常量和全局变量)
|代码区
|最低内存地址 0x00000000
高低字节
在十进制中靠左边的是高位,靠右边的是低位,在其他进制也是如此。例如 0x12345678,从高位到低位的字节依次是0x12、0x34、0x56和0x78。
网络字节序 就是 大端字节序:4个字节的32 bit值以下面的次序传输,首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit
主机字节序 就是 小端字节序,现代PC大多采用小端字节序。
对于数据 0x12345678,假设从地址0x4000开始存放,在大端和小端模式下,存放的位置分别为:
内存地址 | 小端储存 | 大端储存 |
---|---|---|
0x4003 | 0x12 | 0x78 |
0x4002 | 0x34 | 0x56 |
0x4001 | 0x56 | 0x34 |
0x4000 | 0x78 | 0x12 |
小端存储后:0x78563412 大端存储后:0x12345678
4.解题
由于我们查到 AMD x86-64 这个信息,并且查到是小端序,那我们上面的字符串就要逆着读
key3='kills'+v9=killshadow
key='ADSFK'+scr=ADSFKNDCLS
#include <stdio.h>
#include <string.h>
int main()
{
int i=0;int c=0;
char a[11]="killshadow";
char b[11]="adsfkndcls";
for(i=0;i<10;i++){
for(c=32;c<127;c++){
if((c-39-b[i]+97)%26+97==a[i]){
if((c>=65&&c<=90)||(c>=97&&c<=122)){
printf("%c",c);break;
}
}
}
}
return 0;
}
得出flag;
参考博客:
https://blog.csdn.net/sifanchao/article/details/79999219
https://blog.csdn.net/sunflower_della/article/details/90439935