SimpleRev学习

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

原文地址:https://www.cnblogs.com/LLeaves/p/12879172.html