前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Re:从零开始的逆向生活_buu篇(8.25更)

Re:从零开始的逆向生活_buu篇(8.25更)

作者头像
回天
发布2023-04-25 15:18:22
2620
发布2023-04-25 15:18:22
举报
文章被收录于专栏:Ga1@xy's W0r1dGa1@xy's W0r1d

xor

将程序拖进ida,找到flag相关字样,F5进去,直接可以看到主函数内容

image-20200605200411834
image-20200605200411834

其中代码大概意思为数组前后位异或后,与global对应字符串比较前33位,即ord('!'),如果相同则返回Success,也就是得到了flag

双击global可以找到其对应的一系列字符

image-20200605200703089
image-20200605200703089

将其提取出来按照主函数意思编写代码,还原flag

代码语言:javascript
复制
s = ['f',0xA,'k',0xC,'w&O.@',0x11,'x',0xD,'Z;U',0x11,'p',0x19,'F',0x1F,'v"M#D',0xE,'g',6,'h',0xF,'G2O',0]
for i in range(len(s)):
    if(isinstance(s[i],int)):
        s[i] = chr(s[i])
s = "".join(s)
flag = 'f'
for i in range(1,len(s)):
    flag += chr(ord(s[i]) ^ ord(s[i-1]))
print(flag)

得到flag:flag{QianQiuWanDai_YiTongJiangHu}

reverse3

程序拖进ida,可以先看到Str2,在之后会用到,再f5到主函数里

image-20200609194719831
image-20200609194719831

可以看到在Dest[]数组经过一番操作后与Str2比较,如果相同则为flag,而现在有了Str2,所以我们需要找出Dest,先对for循环进行逆操作

代码语言:javascript
复制
str2 = 'e3nifIH9b_C@n@dH'
dest = ''
for i in range(len(str2)):
    dest += chr(ord(str2[i]) - i)

print dest

得到dest后,再看上面的操作,先对v1进行一番操作,再将v1赋值给dest,所以再看v1的操作

image-20200609203912180
image-20200609203912180

看到这里多次出现的aAbcdefghijklmn,点进去可以看到很熟悉的base64编码表

image-20200609204500996
image-20200609204500996

于是尝试对dest进行base64解码,即可得到flag:flag{i_l0ve_you}

不一样的flag

程序拖进ida,可以看到一长串的01

代码语言:javascript
复制
*11110100001010000101111#

f5到主函数,可以看到里面有上下左右,推测是一个走迷宫游戏

image-20200609184214370
image-20200609184214370

01序列长度为25,从这可以看出是一个5*5的迷宫

代码语言:javascript
复制
*1111
01000
01010
00010
1111#

而且只要遇到1就退出,遇到#则返回

代码语言:javascript
复制
ok, the order you enter is the flag!

句意为:输入的顺序为flag

所以从*出发走0最后到#,得到flag:flag{222441144222}

SimpleRev

file命令查看,发现是64位程序,拖进ida找到关键函数

代码语言:javascript
复制
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;  // 数据在内存中是小端存储,所以转换成字符串的时候要逆序,实际是'NDCLS'
  v7 = 0LL;
  v8 = 0;
  v9 = 512969957736LL;  // 此处也同理,得到'hadow'
  v10 = 0LL;
  v11 = 0;
  text = join(key3, (const char *)&v9);  // 进一步分析可知join()函数起到衔接两个字符串的作用,key3='kills',连接在一起就是'killshadow'
  strcpy(key, key1);  // key1='ADSFK'
  strcat(key, src);  // 连接两个字符串后,key='ADSFKNDCLS'
  v2 = 0;
  v3 = 0;
  getchar();
  v5 = strlen(key);  // v5=10
  for ( i = 0; i < v5; ++i )
  {
    if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )  // 将key的大写字母转换成小写,此时key='adsfkndcls'
      key[i] = key[v3 % v5] + 32;
    ++v3;
  }
  printf("Please input your flag:", src);
  while ( 1 )  // 通过这里开始的while循环得到最终的flag
  {
    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; // key='adsfkndcls'
      }
      else // ( v1 > 96 && v1 <= 122 ) 对小写字母进行操作
      {
        str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;
      }
      if ( !(v3 % v5) )
        putchar(32);
      ++v2;
    }
  }
  if ( !strcmp(text, str2) )  // 最后将str2与text进行比对,如果相同,输入的值即为flag,text='killshadow'
    puts("Congratulation!\n");
  else
    puts("Try again!\n");
  return __readfsqword(0x28u) ^ v12;
}

我们现在已知最后对比时的字符串为killshadow,而且只对大小写字母进行操作,所以直接写脚本用所有大小写字母试一下即可

代码语言:javascript
复制
key = 'adsfkndcls'
text = 'killshadow'
dic = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
flag = ''
for i in range(10):
    for x in dic:
        if chr((ord(x) - 39 - ord(key[i]) + 97) % 26 + 97) == text[i]:
            flag += x

print flag

可以发现最后输出flag的时候既有大写字母,也有小写字母,而且恰好是交替出现,说明其实有两种答案,但是本题flag只考虑了大写字母的情况,所以将其中的大写字母挑出来即可,flag:flag{KLDQCUDFZO}

刮开有奖

32位程序,用ida打开后,可以看到WinMain主函数,点进去,找到关键函数

image-20200727171602050
image-20200727171602050

反编译成C,其中比较关键的代码在下图

image-20200727172735411
image-20200727172735411

题干提示输入即为flag,上图中也提到了flag有8位,其中赋值了v7~v17,然后通过sub_4010F0函数对v7~v17进行了操作

代码语言:javascript
复制
int __cdecl sub_4010F0(int a1, int a2, int a3)
{
  int result; // eax
  int i; // esi
  int v5; // ecx
  int v6; // edx

  result = a3;
  for ( i = a2; i <= a3; a2 = i )
  {
    v5 = 4 * i;
    v6 = *(_DWORD *)(4 * i + a1);
    if ( a2 < result && i < result )
    {
      do
      {
        if ( v6 > *(_DWORD *)(a1 + 4 * result) )
        {
          if ( i >= result )
            break;
          ++i;
          *(_DWORD *)(v5 + a1) = *(_DWORD *)(a1 + 4 * result);
          if ( i >= result )
            break;
          while ( *(_DWORD *)(a1 + 4 * i) <= v6 )
          {
            if ( ++i >= result )
              goto LABEL_13;
          }
          if ( i >= result )
            break;
          v5 = 4 * i;
          *(_DWORD *)(a1 + 4 * result) = *(_DWORD *)(4 * i + a1);
        }
        --result;
      }
      while ( i < result );
    }
LABEL_13:
    *(_DWORD *)(a1 + 4 * result) = v6;
    sub_4010F0(a1, a2, i - 1);
    result = a3;
    ++i;
  }
  return result;
}

把这段函数改成可以执行的C代码,把v7~v17代入后执行

代码语言:javascript
复制
#include<stdio.h>

int __cdecl sub_4010F0(char *a1, int a2, int a3)
{
  int result; // eax
  int i; // esi
  int v5; // ecx
  int v6; // edx

  result = a3;
  for ( i = a2; i <= a3; a2 = i )
  {
    v5 = i;
    v6 = a1[i];
    if ( a2 < result && i < result )
    {
          do
          {
            if ( v6 > a1[result] )
            {
                  if ( i >= result )
                    break;
                  ++i;
                  a1[v5] = a1[result];
                  if ( i >= result )
                    break;
                  while ( a1[i] <= v6 )
                  {
                    if ( ++i >= result )
                          goto LABEL_13;
                  }
                  if ( i >= result )
                    break;
                  v5 = i;
                  a1[result] = a1[i];
            }
            --result;
          }
          while ( i < result );
    }
    LABEL_13:
        a1[result] = v6;
        sub_4010F0(a1, a2, i - 1);
        result = a3;
        ++i;
      }
      return result;
} 

int main()
{
    char a[20] = {90,74,83,69,67,97,78,72,51,110,103};
    sub_4010F0(a, 0, 10);
    for(int i = 0; i < 11 ; i++)
        printf("%d ",a[i]);
    return 0;
}

执行完可以发现v7~v17对应的数字发生了改变,变成了:51 67 69 72 74 78 83 90 97 103 110

再看最后得到flag的部分

代码语言:javascript
复制
if ( String == v7 + 34      // v7经过操作后变为51,51+34=85,即'U'
        && v19 == v11       // v11经过操作后变为74,即'J'
        && 4 * v20 - 141 == 3 * v9
        && v21 / 4 == 2 * (v14 / 9)
        && !strcmp(v4, "ak1w")
        && !strcmp(v5, "V1Ax") )
      {
        MessageBoxA(hDlg, "U g3t 1T!", "@_@", 0);
      }

其中v4和v5在之前被执行了sub_401000函数,进函数看到byte_407830这个类似数组一样的东西,点进去跳转到汇编中

可以看到熟悉的base64编码字符集,推测ak1wV1Ax是两个经过base64编码的字符串,拼接在一起解码后恰好可以得到WP1jMp(有个顺序上的前后关系,先是v23,后是v20,所以要颠倒一下),再加上开头的两位UJ恰好一共八位,即为flag:flag{UJWP1jMp}

Java逆向解密

将class文件拖入jd-gui即可完成反编译,得到源码

代码语言:javascript
复制
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Scanner;

public class Reverse
{
  public static void main(String[] args)
  {
    Scanner s = new Scanner(System.in);
    System.out.println("Please input the flag :");
    String str = s.next();
    System.out.println("Your input is :");
    System.out.println(str);
    char[] stringArr = str.toCharArray();
    Encrypt(stringArr);
  }
  
  public static void Encrypt(char[] arr)
  {
    ArrayList<Integer> Resultlist = new ArrayList();
    for (int i = 0; i < arr.length; i++)
    {
      int result = arr[i] + '@' ^ 0x20;
      Resultlist.add(Integer.valueOf(result));
    }
    int[] KEY = { 180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65 };
    ArrayList<Integer> KEYList = new ArrayList();
    for (int j = 0; j < KEY.length; j++) {
      KEYList.add(Integer.valueOf(KEY[j]));
    }
    System.out.println("Result:");
    if (Resultlist.equals(KEYList)) {
      System.out.println("Congratulations!");
    } else {
      System.err.println("Error!");
    }
  }
}

源码中给出了KEY数组,我们需要按照其加密方式来逆向解密,即KEY[i] -= '@' ^ 0x20,python实现即可

代码语言:javascript
复制
key = [180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65]
flag = ''
for i in key:
    flag += chr( i - ord('@') ^ 0x20 )

print flag

得到flag:flag{This_is_the_flag_!}

findit

需要逆向apk文件,直接拖进JEB进行反编译:行为 → 解析,得到关键源码

image-20200730201755559
image-20200730201755559

可以看到其中有类似flag的字样:pvkq{m164675262033l4m49lnp7p9mnk28k75},而qvkq与flag恰好差10,想到凯撒加密,直接得到flag

代码语言:javascript
复制
flag{c164675262033b4c49bdf7f9cda28a75}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-06-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • xor
  • reverse3
  • 不一样的flag
  • SimpleRev
  • 刮开有奖
  • Java逆向解密
  • findit
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档