buu—Re(5)

本文详细介绍了网鼎杯2020青龙组singal题目的逆向工程过程,包括IDA Pro的使用、虚拟机指令分析、加密算法逆向及解密脚本编写等关键技术环节。

[网鼎杯 2020 青龙组]singal


进入ida看主函数:v4被赋值unk_403040数组,然后有个操作函数vm_operad
在这里插入图片描述
进入操作函数:这是以v4数组里面的值为操作的函数,只需跟进v4数组的下标并进行相应的操作即可

switch ( a1[v10] )
    {
      case 1:
        v4[v7] = v5;
        ++v10;
        ++v7;
        ++v9;
        break;
      case 2:
        v5 = a1[v10 + 1] + flag[v9];
        v10 += 2;
        break;
      case 3:
        v5 = flag[v9] - LOBYTE(a1[v10 + 1]);
        v10 += 2;
        break;
      case 4:
        v5 = a1[v10 + 1] ^ flag[v9];
        v10 += 2;
        break;
      case 5:
        v5 = a1[v10 + 1] * flag[v9];
        v10 += 2;
        break;
      case 6:
        ++v10;
        break;
      case 7:
        if ( v4[v8] != a1[v10 + 1] )//a1[v10+1]也就是数组的下一位,而下一位不参与switch,且Str有15位,这就可以把Str给找出来
        {
          printf("what a shame...");
          exit(0);
        }
        ++v8;
        v10 += 2;
        break;
      case 8:
        flag[v6] = v5;
        ++v10;
        ++v6;
        break;
      case 10:
        read(flag);
        ++v10;
        break;
      case 11:
        v5 = flag[v9] - 1;
        ++v10;
        break;
      case 12:
        v5 = flag[v9] + 1;
        ++v10;
        break;
      default:
        continue;

v4数组:因为是小端存储,所以前面三个0x00去掉,留下后面的

10, 4, 16, 8, 3, 5, 1, 4, 32, 8, 5, 3, 1, 3, 2, 8, 11, 1, 12, 8, 4, 4, 1, 5, 3, 8, 3, 33, 1, 11, 8, 11, 1, 4, 9, 8, 3, 32, 1,2, 81, 8, 4, 36, 1, 12, 8, 11, 1, 5, 2, 8, 2, 37, 1, 2, 54, 8, 4, 65, 1, 2, 32, 8,5, 1, 1, 5, 3, 8, 2, 37, 1, 4, 9, 8, 3, 32,1, 2, 65, 8, 12, 1, 7, 34, 7, 63, 7, 52, 7, 50, 7, 114, 7, 51, 7, 24, 7, 167,255, 255, 255, 7, 49, 7, 241, 255, 255, 255, 7,40, 7, 132, 255, 255, 255, 7, 193, 255, 255, 255, 7, 30, 7, 122

我们从第一个数字7开始,得到Str数组的值:34, 63, 52, 50, 114, 51, 24, 167, 49, 241, 40, 132, 193, 30, 122(至于为什么在7这里就是下一位,因为我数了,在7之前的任何一个数字你都不能说:它会不会参与操作,因为有+1也有+2,但是在7这里确确实实是下一位,因为7是+2,当时我还有点迷惑,数过就不迷了)

case 1 :唯一一个给v4赋值的
case 2 , 3 , 4 ,5 :都是给v5赋值的
case 7 :相当于continue
case 10 :输入

分析case:
里面的case1,操作了15次,说明v4跟flag有关,且v5是给v4赋值的,在操作期间进行了许多的变化,猜测v5是个中间变量,相当于进行加密。而v4则是最终的加密结果。

我整理了一下操作的case:
4,8,3,1,4,8,5,1,3,8,11,1,12,8,4,1,5,8,3,1,11,8,11,1,4,8,3,1,2,8,4,1,12,8,11,1,5,8,2,1,2,8,4,1,2,8,5,1,5,8,2,1,4,8,3,1,2,12,1
想着去逆一下,不过还是失败了
参考了大佬博客
大佬博客
记录一下虚拟机逆向脚本吧:

a1=[]
v4=[10, 4, 16, 8, 3, 5, 1, 4, 32, 8, 5, 3, 1, 3, 2, 8, 11, 1, 12, 8, 4, 4, 1, 5, 3, 8, 3, 33, 1, 11, 8, 11, 1, 4, 9, 8, 3, 32, 1, 2, 81, 8, 4, 36, 1, 12, 8, 11, 1, 5, 2, 8, 2, 37, 1, 2, 54, 8, 4, 65, 1, 2, 32, 8, 5, 1, 1, 5, 3, 8, 2, 37, 1, 4, 9, 8, 3, 32, 1, 2, 65, 8, 12, 1, 7, 34, 7, 63, 7, 52, 7, 50, 7, 114, 7, 51, 7, 24, 7, 167, 255, 255, 255, 7, 49, 7, 241, 255, 255, 255, 7, 40, 7, 132, 255, 255, 255, 7, 193, 255, 255, 255, 7, 30, 7, 122]
for i in range(0,len(v4)):
          if v4[i]==7:
                    a1.append(v4[i+1])
a1 = [34, 63, 52, 50, 114, 51, 24, 167, 49, 241, 40, 132, 193, 30, 122]
a1.reverse()
v4.reverse()

v9 = 0
us = 0
v5 = 0
flag = []
for i in range(0, len(v4)):
    if i == len(v4) - 1:
        flag.append(us)
#这里因为是逆着来的,所以倒数第1个才是最开始输入的,所以到时候要赋值
    if v4[i] == 1 and v4[i - 1] != 1:
        v5 = a1[v9]
        v9 += 1
        flag.append(us)
#防止重复进行case1的操作
    if v4[i] == 2:
        if (v4[i + 1] != 3 and v4[i + 1] != 4 and v4[i + 1] != 5):
            us = v5 - v4[i - 1]
#2,3,4,5case都是会+2的,如果前一位是3、4、5,那么会导致跳过本case,产生矛盾,所以会判断一下
    if v4[i] == 3:
        if (v4[i + 1] != 2 and v4[i + 1] != 4 and v4[i + 1] != 5):
            us = v5 + v4[i - 1]

    if v4[i] == 4:
        if (v4[i + 1] != 3 and v4[i + 1] != 2 and v4[i + 1] != 5):
            us = v5 ^ v4[i - 1]

    if v4[i] == 5:
        if (v4[i + 1] != 3 and v4[i + 1] != 4 and v4[i + 1] != 2):
            us = int(v5 / v4[i - 1])
    if v4[i] == 8:
        v5 = us

    if v4[i] == 11:
        us = v5 + 1

    if v4[i] == 12:
        us = v5 - 1
flag.reverse()
out = ''
for j in flag:
    out += chr(j)
print("flag{" + out + "}")

reverse1

进入ida看主函数:
在这里插入图片描述
找到关键函数,如果Str里面有o,转化为0
在这里插入图片描述
找到Str2,所以flag就是hell0_w0rld
在这里插入图片描述

reverse2

进入ida看主函数
在这里插入图片描述
找到关键部分
在这里插入图片描述

在这里插入图片描述

内涵的软件

直接字符串查找得到flag
在这里插入图片描述

新年快乐

检查到upx
在这里插入图片描述
题目上说flag就是一串字符串,考察眼力,所以我查找字符串,猜一个:
flag还真猜对了
在这里插入图片描述

xor

进入ida看主函数,一个异或,然后对比
在这里插入图片描述
写脚本:

#include <stdio.h>
#include <stdlib.h>

int main(){
    char a[] =
{
  0x66, 0x0A, 0x6B, 0x0C, 0x77, 0x26, 0x4F, 0x2E, 0x40, 0x11,
  0x78, 0x0D, 0x5A, 0x3B, 0x55, 0x11, 0x70, 0x19, 0x46, 0x1F,
  0x76, 0x22, 0x4D, 0x23, 0x44, 0x0E, 0x67, 0x06, 0x68, 0x0F,
  0x47, 0x32, 0x4F,0x00
};
    for(int i=1;i<33;i++){
        a[i-1] = a[i]^a[i-1];
    }
    printf("%s",a);
    return 0;
}


helloword

进入jdax,没想到随手一翻找到了😓
在这里插入图片描述

reverse3

看主函数,从后往前逆:Str2就是Destination进行for循环后的,所以通过Str2可以得到Destination。
在这里插入图片描述
进入sub_4110BE函数,发现是个base64加密(其实通过查找字符串能看出有个base64表,从而猜出有个base64加密)
v4就是base64加密后跟Destination对比的,所以得到Destination进行解密即可
在这里插入图片描述
脚本:

#include <stdio.h>
#include <stdlib.h>

int main(){
    char a[] ="e3nifIH9b_C@n@dH";
    int b = 16;
    char c[]="e2lfbDB2ZV95b3V9";

    for(int i=1;i<b;i++){
        a[i] = a[i]-i;
    }
    printf("%s",a);
    return 0;
}


解密:
在这里插入图片描述

提供的引用内容未涉及“buu”和“snake”相关的IT信息。一般来说,“buu”可能指“BUUCTF”,这是一个在线CTF(Capture The Flag)平台,为网络安全爱好者提供了各种类型的安全挑战题目,涵盖Web安全、逆向工程、密码学等多个领域。“snake”在IT领域常代表“Snake Case”(蛇形命名法),它是一种命名规范,单词之间用下划线分隔,如`variable_name`,常用于Python等编程语言中变量和函数的命名。此外,“snake”也可能指经典的贪吃蛇游戏,在编程学习中,实现贪吃蛇游戏是一个常见的实践项目,可以使用Python、Java等多种编程语言完成。 ```python # 一个简单的Python贪吃蛇游戏示例框架 import pygame import time import random snake_block = 10 snake_speed = 15 # 初始化pygame pygame.init() # 设置显示窗口 dis_width = 800 dis_height = 600 dis = pygame.display.set_mode((dis_width, dis_height)) pygame.display.set_caption('Snake Game') clock = pygame.time.Clock() # 定义颜色 white = (255, 255, 255) yellow = (255, 255, 102) black = (0, 0, 0) red = (213, 50, 80) green = (0, 255, 0) blue = (50, 153, 213) font_style = pygame.font.SysFont("bahnschrift", 25) score_font = pygame.font.SysFont("comicsansms", 35) def Your_score(score): value = score_font.render("Your Score: " + str(score), True, yellow) dis.blit(value, [0, 0]) def our_snake(snake_block, snake_list): for x in snake_list: pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block]) def message(msg, color): mesg = font_style.render(msg, True, color) dis.blit(mesg, [dis_width / 6, dis_height / 3]) def gameLoop(): game_over = False game_close = False x1 = dis_width / 2 y1 = dis_height / 2 x1_change = 0 y1_change = 0 snake_List = [] Length_of_snake = 1 foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0 foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0 while not game_over: while game_close == True: dis.fill(blue) message("You Lost! Press C-Play Again or Q-Quit", red) Your_score(Length_of_snake - 1) pygame.display.update() for event in pygame.event.get(): if event.type == pygame.KEYDOWN: if event.key == pygame.K_q: game_over = True game_close = False if event.key == pygame.K_c: gameLoop() for event in pygame.event.get(): if event.type == pygame.QUIT: game_over = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: x1_change = -snake_block y1_change = 0 elif event.key == pygame.K_RIGHT: x1_change = snake_block y1_change = 0 elif event.key == pygame.K_UP: y1_change = -snake_block x1_change = 0 elif event.key == pygame.K_DOWN: y1_change = snake_block x1_change = 0 if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0: game_close = True x1 += x1_change y1 += y1_change dis.fill(blue) pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block]) snake_Head = [] snake_Head.append(x1) snake_Head.append(y1) snake_List.append(snake_Head) if len(snake_List) > Length_of_snake: del snake_List[0] for x in snake_List[:-1]: if x == snake_Head: game_close = True our_snake(snake_block, snake_List) Your_score(Length_of_snake - 1) pygame.display.update() if x1 == foodx and y1 == foody: foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0 foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0 Length_of_snake += 1 clock.tick(snake_speed) pygame.quit() quit() gameLoop() ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值