reverse方向入门过程

声明:因为懒,所以懒得从头开始做,基本都是看着wp复现的,其中大部分的wp都来源于
https://blog.csdn.net/palmer9/category_9607326.html

话不多说,直接从ctf-wiki上和做题开始

reverse方向入门过程_第1张图片
我们这里可以看到要求
熟悉操作系统(靠学校教的操作系统)
汇编语言(我看了王爽那本然后自己上网学了一点)
加解密(密码学)
具有丰富的多种高级语言编程经验(。。。。。多丰富?)
较强的程序理解和逆向分析能力(太主观了)

带着上述的基础,我们来进行逆向的学习

reverse方向入门过程_第2张图片

1.使用各种工具(对我来说主要是IDA)进行静态分析,收集信息
2.研究程序的保护方法,比如代码混淆,保护壳以及反调试等技术,并设法破除或者绕过保护。
3.反汇编目标软件,能够快速定位到关键代码进行分析
4.结合动态调试,验证自己的初期猜想,在分析的过程中理清程序功能
5.针对程序功能,写出对应脚本,求解出flag

代码混淆
reverse方向入门过程_第3张图片
reverse方向入门过程_第4张图片

reverse方向入门过程_第5张图片

然后直接开始做题

BUU部分

最简单的题目(直接搜索字符串就能看到flag的)
1.[BJDCTF 2nd]guessgame
打开IDA,F12搜索字符串就能看到
reverse方向入门过程_第6张图片

xor

一个64位的文件,直接F5看main函数
reverse方向入门过程_第7张图片
其中重要的语句为
if ( strlen(v6) != 33 ) //判断v6的长度是否为33(从上面的程序中可以看出,v6就是我们的输入)
for ( i = 1; i < 33; ++i ) //进行循环异或,从v6的第二位开始将v6的每一位与前一位异或
v6[i] ^= v6[i - 1];

if ( !strncmp(v6, global, 0x21uLL) ) //比较v6与global段处存放的前33位(也就是0x21)是否相同,是如果相同的话输出success,

大致地看完代码之后我们发现进入global段里面写了什么很重要,我们要做的就是将异或后的v6与global段中的数据进行比对,比对完之后相同就能拿到flag(这里的sucess应该是提示你通过了这道题,并且前面有提示input your flag,也就是要我们输入一串字符(就是v6变量)做为答案。)那么我们只要进入global看到的global的内容就是异或后的v6,也就是异或后的flag

双击进入global看到内容。

reverse方向入门过程_第8张图片


```python
str1 = ['f', 0x0A, 'k', 0x0C, 'w', '&', 'O', '.', '@', 0x11, 'x', 0x0D, 'Z', ';', 'U', 0x11, 'p', 0x19, 'F', 0x1F, 'v',
        '"', 'M', '#', 'D', 0x0E, 'g', 6, 'h', 0x0F, 'G', '2', 'O']

x = 'f'

for i in range(1, len(str1)):
    if (isinstance(str1[i], str)):
        if (isinstance(str1[i - 1], str)):
            x += chr(ord(str1[i]) ^ ord(str1[i - 1]))
        else:
            x += chr(ord(str1[i]) ^ str1[i - 1])
    else:
        x += chr(str1[i] ^ ord(str1[i - 1]))

print(x)

新年快乐(最简单的脱壳)
发现放进IDA里有错误报告,应该是加壳了
先用PE查壳(步骤省略)
直接用万能工具查壳,然后点击脱壳就好了

reverse方向入门过程_第9张图片
reverse方向入门过程_第10张图片
然后得到一个这样的文件,然后就可以放进IDA了,然后看main函数,里面的程序还是相当简单的
reverse方向入门过程_第11张图片
输入一个v5,与v4相等即可拿到flag(v4是HappyNewYear!,在上面可以看到)
v5来源于上面的scanf,也就是我们得到输入
在这里插入图片描述
emmmmm,其实也就是HappyNewYear!做为flag
所以flag是flag{HappyNewYear!}

SimpleRev
点进去看main函数,发现没什么关键的,下面代码的大致意思就是输入的不为d或者D就退出这次循环
和如果输入的为Q或者q就退出,然后看到有一个Decry函数,点进去

reverse方向入门过程_第12张图片
点进Decry函数
reverse方向入门过程_第13张图片

reverse方向入门过程_第14张图片
其中v9注意按R转换成字符串格式
在这里插入图片描述

同时发现有一个join函数,内容如下,大致意思为,
reverse方向入门过程_第15张图片

大致意思为将a1的长度赋值给v2
将a2的长度赋值给v3,然后malloc动态分配空间dest给a1和a2 (大小为a1+a2+1)
然后将a1赋值给dest(strcpy函数),将a2拼接到dest后(strcat函数) (。。。。其实整个函数就是将a1和a2,也就是下面的key3和v9连接起来的意思)
在这里插入图片描述
在这里插入图片描述

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;						//(按R变成SLCDN)
  v7 = 0LL;
  v8 = 0;
  v9 = 512969957736LL;
  v10 = 0LL;
  v11 = 0;
  text = (char *)join(key3, &v9);					
  													//令text等于key3+v9
  													//key3="kills"(双击点进key3可知)
  													//v9="hadow"		//因为小端序存储
  													//则 text= killshadow
  strcpy(key, key1);								//将key1赋值给key	,key = "ADSFK"(同样双击可知)
  strcat(key, src);									//将src处的字符拼接到key后
  													//key = "ADSFKNDCLS"(小端序)
  v2 = 0;											
  v3 = 0;
  getchar();
  v5 = strlen(key);									// v5 = key的长度   v5 = 10
  for ( i = 0; i < v5; ++i )
  {
    if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )			//如果key中存在大写字母,将其变成小写(asc码加32)(这里的v5是10,对10取余等于个位数,而v3最大只到9,所以可以忽略v5)
      key[i] = key[v3 % v5] + 32;							//key = "adsfkndcls"
    ++v3;
  }
  printf("Please input your flag:", src);
  while ( 1 )
  {
    v1 = getchar();								//接受用户的输入赋值给v1
    if ( v1 == 10 )								// 如果输入的为换行符,则退出(都可以按R转换看到是\n,以下省略省略)
      break;
    if ( v1 == 32 )											// 如果输入的为空格,则v2加一
    {
      ++v2;
    }
    else
    {
      if ( v1 <= 96 || v1 > 122 )									// 如果输入的v1不为小写字母
      {
        if ( v1 > 64 && v1 <= 90 )									// 如果v1为大写字母
          str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;			// 将v1减去39再减去key中下表为[v3++]位置的字母然后加上97之后求除以26的余数再加上97,然后赋值给str2
          																// str1[v2] = (v1-key[v3]+58)%26 + 97	
     																    // 变换后str1[v2]存放小写字母
      }			
      else
      {
        str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;			//如果v1为小写,则同样处理
      }
      if ( !(v3 % v5) )													//如果循环到key的最后一位	
        putchar(32);												//打印一个空格
      ++v2;
    }
  }
  if ( !strcmp(text, str2) )								// 如果text和str2存储的相同,则成功
    puts("Congratulation!\n");											// text = "killshadow"
  else
    puts("Try again!\n");
  return __readfsqword(0x28u) ^ v12;
}

所以我们的目标就是像str2中存入killshadow,其中要满足输入的每个字符减去39再减去key中下标为[v3++]位置的字母然后加上97对26取余然后再加上97,变为killshadow
根据这个要求,我们来编写脚本,首先赋值出一个代表killshadow的变量和一个代表adsfkndcls的变量,然后从大写字母(因为我们的只有我们的大写字母在经过一系列运算之后加上97还能得到的答案是字母的,虽然在字母表中把小写字母写上也没事)中找到一个字母减去39再减去key中下标为v3的字母的asc值再加上97后对26取余再加上97会得到killshadow
(其中97就是a)

key = "adsfkndcls"									//赋值给key
text = "killshadow"											//赋值给text
flag = ""
_dict = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"				//做字母表
v5 = len(text)											//赋值给v5 text的长度
for i in range(v5):
    for v1 in _dict:
        if ord(text[i]) == (ord(v1) - 39 - ord(key[i % v5]) + 97) % 26 + 97:				//例:
            flag += v1
print(flag)


//例:将text中的第一个k取出并且转换成asc值107,然后判断是否等于大写字母表中的一个值减去39和字母a的asc码值(也就是97),然后加上97,再对26取余,再加上97那么就是flag,我们时候诸葛亮的知道第一个正确字母是K,也就是75,减去39再减去97再加上97,得36,对26取余得到10,然后再加上97=107(后续答案同样如此得来)
答案KLDQCUDFZO
//ord,返回其asc码值

[ACTF新生赛2020]easyre

事先脱壳(UPX脱壳,用之前的万能脱壳工具即可)
reverse方向入门过程_第16张图片

前面都是一些定义变量的东西,然后到scanf,输入变量给v19,并且v19如果不等于ACTF{}这些字符,那么return 0
然后定义v16 17 18(?意义不明)
然后解题的重点就在这个循环,那就是判断*(&v4+i)是否等于byte_402000这个数组中下标为的&v16+i-1的数
在这里插入图片描述
我们点进去看到了byte_402000有这些,并且在上面的在这里插入图片描述
循环中我们可以知道flag大概是12位

并且*(&v4+i),意为每次v4的地址加1,也就是v4,v5,v6…这样子,直到v15然后判断是否等于byte-402000
所以如果写脚本的话我们要这样写
先将byte-402000中的值赋值给一个变量,然后将v4到v15的值赋值给另外一个变量,
然后将v4中的值用chr转换成字符,然后检索在byte_402000中的位置,然后把这个位置转换成字符添加到flag变量里

这里要介绍两个函数方法,一个叫做append,作用是将对象添加到末尾
例如
aList = [123, ‘xyz’, ‘zara’, ‘abc’];
aList.append( 2009 );
print "Updated List : ", aList;
结果将会输出Updated List : [123, ‘xyz’, ‘zara’, ‘abc’, 2009],2009被添加到了列表的末尾。
一个叫做find ,作用是检索一个字符串在指定字符串中的位置
例如
str1 = “this is string example…wow!!!”;
str2 = “exam”;

print str1.find(str2);
将会输出15,意为exam这个str2在 str1中的第15个位置开始

其实下面这张图里的这句话这样看,我们会顺眼很多
v4[i]!=byte_402000[flag[i]-1]
在这里插入图片描述

# -*- coding:utf-8 -*-
 
v4 = [42,70,39,34,78,44,34,40,73,63,43,64]
 
model = "}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(" + chr(0x27) + r'&%$# !"'
 
pos = []
 
for i in v4:
    pos.append(model.find(chr(i))+1)					//意为将v4中的数字转换成字符+1然后检索在model中的位置,并且把这个位置+1,然后把这个位置(一个数字)添加到pos后面
s = [chr(x + 1) for x in pos]							//然后将pos中的每个数字+1转换成字符,然后一个个组成flag
flag = ''.join(s)
print ('flag{'+flag+'}')

举个例子大概就是这样,先从v4中取出第一个字符42,然后将转换成字符,也就是*(星号),然后,然后检索*在model中的位置,是83,加1是84,再加1是85,再转换成字符就是85转换成U

*********为什么要两次加1?
答:第一个chr(i)+1是因为位置加1才是下标(下标从0开始)
第二个chr(x+1)是因为原式子中byte_402000[&v16+i]-1,所以要加1补回去

攻防世界部分

insanity(直接搜索字符串就能得到flag)

Mysterious

reverse方向入门过程_第17张图片

reverse方向入门过程_第18张图片

满足v10=123,v12=120,v14=122,v13=121

你可能感兴趣的:(CTF,re)