当前位置: 首页 > news >正文

BUUCTF逆向刷题笔记(13-?)持续更新

[BJDCTF2020]JustRE

shitf+f12看到可疑字符串,查看他的交叉引用。

 查看后发现一个格式化输出的东西,如实填写即可。

 应该是点击1999次按钮就会出flag吧也许。

刮开有奖

这是个赌博程序?有点意思呀。点开说是刮开有奖,但是没什么反应。

先他妈不写了,没有音乐写不进去。

OK,我们拖进IDA看看,根据经验跟进此函数进行分析。

由于string长度=8才会进行此if判断,因此大胆推测string就是flag。其中前四位在末尾的if判断已经给出,所以我们只需要看后四位就行(实际上前四位一会也需要看)。看后面的几位,很明显看到v18被string所赋值,点进函数看看究竟发生了什么事。 

函数内有一数组内容如下所示,怀疑是base64加密(上面的41h代表A),在chef里面解密以下v4和v5的数据就拿到了原本的了应该。 最后得到v4=jMp,v5是WP1。

根据此,string的678位是jMp,第345是WP1,但是真的很容易看到12位吗?请看开头部分的代码。

这部分其实点进去函数,推测是一个排序的(我也没看出来,参考网络WP所写的)根据高手思路,直接复制伪C代码是最快的写题方法。汇编中寻址是i*4,因为一个int占4空间,我们修改一下就可以了,直接用i寻址!以下是参考的WP所写的代码:

#include <stdio.h>
#include <string.h>

int  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(void)
{
    char str[] = "ZJSECaNH3ng";
    sub_4010F0(str,0,10);
    printf("%s", str);
	return 0;
}


然后运行,就是新的v7,这样才可以在if判断句里面进行计算。

刚开始想到了base64,没想到v7也进行了排序操作。现在粗略瞄一眼这个函数,实现了递归调用和对数组值的修改,确实可能是排序。具体算法:

 斗胆写了个快速排序的python实现,方便以后复习:

a = [1, 4, 5, 2, 3]


 

def quick(arr):

    if(len(arr)<=1):

        return arr

    b=arr[0]

    left=[x for x in arr[1:] if x<b]

    right=[x for x in arr[1:] if x>b]

    return quick(left)+[b]+quick(right)

print(quick(a))

参考WP:

BUUCTF 刮开有奖(特别详细了,尽自己全力理解所写)-CSDN博客

[BUUCTF]Reverse-刮开有奖 - 玉石听 - 博客园

破解BUUCTF_刮开有奖-CSDN博客

[BUUCTF]REVERSE——刮开有奖_buuctf reverse 刮开有奖-CSDN博客

[ACTF新生赛2020]easyre1

先用UPX脱壳,看到了主要的判断条件,但是目前看不出来v5的值,陷入僵局。看了WP才知道咋写了。

观察发现关键的(char *)操作,即强制转换为char指针,v5本来占3*4=12字节,转换后相当于储存字符串的一个数组,这点格外注意,那么_data_start后面中括号就是v5的索引的意思?非也,最前面的*表示解引用,那就是说其实就是v5的字符。find()函数可以快速查询特定字符的索引。

我们只要满足if的判断条件即可。那么v4我们已经知道是什么了,为了方便代码的开展,我们把它转换为ASCII数组。具体实现看脚本。。

#转换a的ASCII码到b
a='''*F'\"N,\"(I?+@'''
b=[]
c=[]
flag=''
for i in a:
    b.append(ord(i))
print(b)
#开始写脚本破解
index='''~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$# !"'''
for i in b:
    c.append(index.find(chr(i))+1)#+1不可以忘记,原代码中的索引v5进行-1才是=v4
for i in c:
    flag+=chr(i)
print(flag)

还有一个坑点,这里的27h没有识别出来,我们需要将他转换为10进制自己再查ASCII表添加进脚本。

参考题解:

BUUCTF之[ACTF新生赛2020]easyre 1(RE) - Eip的浪漫 - 博客园

BUUCTF逆向wp [ACTF新生赛2020]easyre_buuctf [actf新生赛2020]easyre-CSDN博客

 简单注册器

说实话这也是我学逆向的一大乐趣,破解软件的感觉还是很爽的。

居然是APK格式。先进模拟器看看里面内容,然后直接用jadx分析就可以了。原来看大佬们破解玄奥周易这样的小软件应该也是这种思路了,不过他们的算法估计更厉害。

进去是这样,不惯着他,直接进jadx分析。锁定关键代码。通过第一个if判断句,我们应该可以得到其实flag长度估计是32位。而且第二个和最后一个值都已经知道。

然后对x进行操作,咱们把这个代码copy到java代码运行一下看看。

出来了59acc538825054c7de4b26440c0999dd这一串

public class Main {
    public static void main(String[] args) {
        char[] x = "dd2940c04462b4dd7c450528835cca15".toCharArray();
        x[2] = (char) ((x[2] + x[3]) - 50);
        x[4] = (char) ((x[2] + x[5]) - 48);
        x[30] = (char) ((x[31] + x[9]) - 48);
        x[14] = (char) ((x[27] + x[28]) - 97);
        for (int i = 0; i < 16; i++) {
            char a = x[31 - i];
            x[31 - i] = x[i];
            x[i] = a;
        }
        for (int j = 0; j < x.length; j++) {
            System.out.println(x[j]);
        }
    }
}

其实这个就是flag。但是我们亲自输入进去软件让他自己出flag成就感满满呀,接着看吧。一共是32位。按照第一个判断句的要求给他修改了。其中最后一个相加=104,我们知道肯定是两个数字,因为字母都是ASCII码比较大,无法满足条件。得到下面的字符串:

2b6cc538825054c7de4b26440c0999da

直接输进入软件就行,出来flag。

[GWCTF 2019]pyre

看名字像是python逆向!不出意料是pyc文件,掏出工具反编译PYC。

关键代码如上图所示。

首先第一个for循环看样子就是通过input1计算出了一个数字。在下面的循环中,对code进行了一次反复异或操作。code首先要被第一个for循环操作一次,再自己反复异或。又遇到我最反感的有%的题目。首先我揣测这是不是某个没见过的算法,于是我问问豆包吧。

看到这里恍然大悟,code其实是储存了所有的num后的并且经过第二个for循环的列表了,所以我们应该先将code转换为异或之前,才有可能找到原来的num!然后我们用爆破的思路做。有思路了,咱们开始行动吧。

但是这样的思路按照我的实力暂时还做不出来,而且是复杂的思路。看看别人的wp:

[GWCTF 2019]pyre - 原来是甘文川同学 - 博客园

学到了新知识;

 先看对code的异或,是0和1,1和2.由于两次异或就是不异或,所以我们考虑倒着异或。务必理解这个脚本,举个例子,本来是0=0^1,3=3^4(数字代表索引)。现在我们倒着计算3,就是3=3^4,所以必须是i+1才可以。因为最终的长度的最后一位自己没有被后面的异或,从len-2开始计算即可。range中间的-1代表最后i会走到0这个值,刚好就是第一个。

随后, 看这个代码:

我们可以改写为:

code=(flag+i) %128。ASCII不超过128的,对着以后还要敏感点。但是%128并不是无用,因为里面还有负数,如-1%5还余4,(在python里面)这个需要注意。

code =['\x1f','\x12','\x1d','(','0','4','\x01','\x06','\x14','4',',','\x1b','U','?','o','6','*',':','\x01', 'D', ';','%', '\x13']
code1=[]
for i in code:
    code1.append(ord(i))

#还原code
for i in range(len(code1)-2,-1,-1):
     code1[i]=code1[i]^code1[i+1]
print(code1)
flag=''
for i in range(len(code1)):
      flag+=chr((code1[i]-i)%128)
print(flag)

为什么不可以爆破,因为很容易重复,可能1和129结果就一样。原来一个simpleRev可以爆破就是因为不会重复。(我猜)

findit

还是一个apk,看样子flag就是wifi'密码。

粗略扫一眼,先定义了a和b,然后经过特定运算得到X和Y,必须X和输入的东西一样,才会输出Y。所以Y是flag没跑了,X是获得Y的密钥。老规矩,复制到编译器运行一下便知。 

public class Main {
    public static void main(String[] args) {
        char[] a = { 'T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e' };
        char[] b = { 'p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4',
                'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}' };
        char[] x = new char[17];
        char[] y = new char[38];

        // 处理数组 a
        for (int i = 0; i < 17; i++) {
            if ((a[i] < 'I' && a[i] >= 'A') || (a[i] < 'i' && a[i] >= 'a')) {
                x[i] = (char) (a[i] + 18);
            } else if ((a[i] >= 'A' && a[i] <= 'Z') || (a[i] >= 'a' && a[i] <= 'z')) {
                x[i] = (char) (a[i] - '\b');
            } else {
                x[i] = a[i];
            }
        }

        // 处理数组 b
        for (int i2 = 0; i2 < 38; i2++) {
            if ((b[i2] >= 'A' && b[i2] <= 'Z') || (b[i2] >= 'a' && b[i2] <= 'z')) {
                y[i2] = (char) (b[i2] + 16);
                if ((y[i2] > 'Z' && y[i2] < 'a') || y[i2] >= 'z') {
                    y[i2] = (char) (y[i2] - 26);
                }
            } else {
                y[i2] = b[i2];
            }
        }

        // 输出处理后的数组 x
        for (int i = 0; i < 17; i++) {
            System.out.print(x[i]);
        }
        System.out.println();

        // 输出处理后的数组 y
        for (int i = 0; i < 38; i++) {
            System.out.print(y[i]);
        }
    }
}

x就是我们应该要输入的,y直接就是flag。

[ACTF新生赛2020]rome

 看样子也是实现了一个简单的字符变换加密。接下来细细分析代码。

相关文章:

  • 【leetcode hot 100 24】两两交换链表中的节点
  • vulnhub-DC-9 SQL注入、“ssh端口敲门”、hydra爆破
  • 题解:AT_arc093_b [ABC092D] Grid Components
  • Python规则引擎DIY:从零开始构建规则引擎
  • Linux》》Ubuntu22.04下Docker的安装 Docker
  • 【VS】vs生成前事件,复制脚本文件至运行目录
  • Python Numpy面试题及参考答案 草
  • Prompt 工程
  • MySQL中IN关键字与EXIST关键字的比较
  • JAVA:利用 Jsoup 轻松解析和操作 HTML 的技术指南
  • 展望 AIGC 前景:通义万相 2.1 与蓝耘智算平台共筑 AI 生产力高地
  • 如何在Android中实现SQLite数据库操作
  • 【设计模式】设计模式介绍
  • 力扣热门100题【525,1314】
  • 数字隔离器,如何提升储能系统的安全与效能?
  • Python - 爬虫;爬虫-网页抓取数据-工具curl
  • Python精进系列:filter 模块
  • leetcode 142. 环形链表 II
  • STM第三天点亮LED
  • 修改nginx配置,同一台服务器部署多个前端项目
  • 千亿市值光储龙头董事长向母校合肥工业大学捐赠1亿元
  • 为何未来的福利国家必须绿色且公平
  • 洛阳原副市长收礼品消费卡,河南通报6起违反八项规定典型问题
  • 我国核电总体规模首次跃居世界第一,发电量持续增长
  • 第二十届华表奖提名名单公布,张译、王一博、马丽、郭帆等入围
  • 伤者升至80人,伊朗港口爆炸源头或为“危险品和化学品仓库”