2023年第三届陕西省大学生网络安全技能大赛--本科高校组 Reverse题解

news2024/12/25 19:51:23

文章目录

  • 一. 我的upx -d怎么坏了
    • 1. 查看节区信息
    • 2. 动态调试脱壳
    • 3.输出迷宫图
    • 4.走迷宫
  • 二. babypython
    • 1.字节码简单分析
    • 2. gpt分析
    • 3. 程序逻辑
    • 4.解题脚本
  • 三. BadCoffee
    • 1. 相关文章
    • 2.解混淆
    • 3.解题脚本
  • 四. Web&Assembly(暂时没复现出来,提供一些相关文章)
  • 总结

这次比赛做出来三道题,Web&Assembly找到了工具和相关文章,但是时间不太够了hhh,收获还是不少的

一. 我的upx -d怎么坏了

1. 查看节区信息

可以看到节区被修改了,本来应该是UPX被改成了HOEY,试着修改了一下还是不能upx -d,遂选择动调
在这里插入图片描述

2. 动态调试脱壳

这里推荐使用吾爱破解专用OD打开,可以很快找到popad这个关键码,x32dbg和ollydbg都不行(不知道是不是指令集的问题或者是什么插件的问题)
打开程序后向上翻大概四五行就可以看到popad,而且这个下面有个调整栈的循环,还有个jmp 0x004012D0的远跳转,所以很可能是oep
请添加图片描述

f7跟进4012D0后,使用插件里的OllyDump脱壳
请添加图片描述

脱壳后的文件打开分析,shift+f12查看字符串,可以看到第一行有一串可疑字符串,然后跟进,再对函数按x交叉引用往上面找就可以找到主函数,可以看到是迷宫,并且能看出迷宫是每行15个元素
在这里插入图片描述

3.输出迷宫图

#include <stdio.h>
#include <string.h>
int main() {
    char maze[] = "****************S000*0000000***0**000*****0***0*00*0*000*0***000**0*0*0*0***0***00*0*0*00**0***0**0*0**0**000*0*00*00*0****0*0******0#****0*00000000***000********0***0***00000*00***0*0*****0**0***0000000*00000****************";
    for (int i = 0; i < strlen(maze); i++)
    {
        if (i  % 15 == 0)
            printf("\n");
        printf("%c", maze[i]);

    }
    return 0;
}

得到迷宫图:

***************
*S000*0000000**
*0**000*****0**
*0*00*0*000*0**
*000**0*0*0*0**
*0***00*0*0*00*
*0***0**0*0**0*
*000*0*00*00*0*
***0*0******0#*
***0*00000000**
*000********0**
*0***00000*00**
*0*0*****0**0**
*0000000*00000*
***************

4.走迷宫

我以前写过一个走迷宫脚本,稍微修改一下就可以解这题的路径了
C语言实现自动走迷宫 自动输出迷宫路径
修改后:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <Windows.h>
// 枚举一些关键常量,可以根据迷宫的不同而修改
enum state
{
	start = 'S', end = '#', road = '0', wall = '*', visited = '1', successPath = '%', currentPosition = '@'
}State;
//路径操作符枚举
enum operate {
	up = 'U', right = 'R', down = 'D', left = 'L'
}Operate;
//保存路径
struct
{
	int len;
	unsigned char arr[1000];
}Path;
//输入路径
void inputPath(unsigned char op)
{
	Path.arr[Path.len] = op;
	Path.len++;
}
//输出路径
void printPath()
{
	printf("\nPath:");
	while (Path.len > 0)
	{
		Path.len--;
		putchar(Path.arr[Path.len]);
	}
	printf("\n");
}
//判断是否在迷宫范围内以及是否可以走这一步
bool isLegal(int x, int y, int row, int col, unsigned char* p)
{
	if (x >= 0 && y >= 0)
		if (x < row && y < col)
			return (p[x * col + y] == road || p[x * col + y] == end);
	return false;
}
//输入迷宫图
//支持以矩阵形式输入,也可以输入一整行,自动处理换行符,直到读取到整个迷宫图为止
void inputMaze(unsigned char* p, int row, int col)
{
	unsigned char ch;
	printf("请输入迷宫图:\n");
	for (int i = 0; i < row * col; i++)
	{
		if ((ch = getchar()) != '\n')
			p[i] = ch;
		else
			--i;
	}

}
//打印迷宫图
void printMaze(unsigned char* p, int row, int col) {
	printf("\n迷宫图如下:\n");
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
			printf("%c", p[i * col + j]);
		printf("\n");
	}

}
//走迷宫
//递归查询,这里由于递归是倒序输出路径,所以需要一个倒序操作
bool walkMaze(int row, int col, unsigned char* p, int x, int y)
{
	int pos = x * col + y;	//当前位置
	if (p[pos] == end)		//到达终点
		return true;
	if (isLegal(x - 1, y, row, col, p))	//上
	{
		//printMaze(p,row,col); //如果需要可以逐步输出迷宫图
		p[pos] = visited;	//设置访问标识,防止无限递归
		if (walkMaze(row, col, p, x - 1, y))	//该路径可行,输出操作符
		{
			inputPath(up);
			p[pos] = successPath;			//用于显示该路径
			return true;
		}
	}
	if (isLegal(x, y + 1, row, col, p))	//右
	{
		//printMaze(p,row,col);
		p[pos] = visited;
		if (walkMaze(row, col, p, x, y + 1))
		{
			inputPath(right);
			p[pos] = successPath;
			return  true;
		}
	}
	if (isLegal(x + 1, y, row, col, p))	//下
	{
		//printMaze(p,row,col);
		p[pos] = visited;
		if (walkMaze(row, col, p, x + 1, y))
		{
			inputPath(down);
			p[x * col + y] = successPath;
			return true;
		}
	}
	if (isLegal(x, y - 1, row, col, p))	//左
	{
		//printMaze(p,row,col);
		p[pos] = visited;
		if (walkMaze(row, col, p, x, y - 1))
		{
			inputPath(left);
			p[pos] = successPath;
			return  true;
		}
	}
	p[pos] = visited;
	return false;	//无路可走,该条路径不行
}

//自动寻找起点,可以自行选择是否调用
void findStart(unsigned char* p, int row, int col, int* x, int* y)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			if (p[i * col + j] == start)
			{
				*x = i;
				*y = j;
				return;
			}
		}
	}
}

int main()
{
	int row = 15, col = 15, x = 1, y = 1;	//行和列,起点坐标
	unsigned char* Maze = (unsigned char*)malloc(row * col);	//分配空间
	inputMaze(Maze, row, col);		//输入迷宫
	printMaze(Maze, row, col);		//打印迷宫
	walkMaze(row, col, Maze, x, y);		//走迷宫
	Maze[x * col + y] = start;		//矫正起点字符
	printMaze(Maze, row, col);		//打印迷宫
	printPath();					//打印路径
	free(Maze);						//释放空间
	system("pause");
	return 0;
}


运行结果:
在这里插入图片描述

得到路径:RRRDRRURRRRRRDDDDRDDD,32位小写md5后得到flag
flag{ae2de0be8285f69db701d4dba8721a40}

二. babypython

这题一开始想着能不能将txt里的字节码转成pyc文件的二进制字节码,询问gpt得到的脚本并不行,只能老老实实生啃字节码了(还好有gpt)
使用gpt辅助分析,但是要注意有一部分混淆代码没有实际作用,可以跳过,保留关键代码然后让gpt整合分析

1.字节码简单分析

可以搜索flag快速定位关键代码,关键代码上方有一些初始化操作
在这里插入图片描述
遍历flag,元素异或8保存到value数组
在这里插入图片描述
垃圾代码,后面还提示了"This line will never be executed"
在这里插入图片描述
遍历value数组,元素+3
在这里插入图片描述
后面还有一些垃圾代码,是无用的操作和一些跳转,像这里是跳转到1362
在这里插入图片描述
跳转到最后有base64编码处理(处理完之后字符串还要倒序)
在这里插入图片描述
替换字符处理
在这里插入图片描述
文件末尾可以看到输出的值
在这里插入图片描述

2. gpt分析

这里将字节码中有用的部分截取出来给gpt分析,然后让他给出python代码,再将各个代码段整合就可以得到程序逻辑的结果了
在这里插入图片描述

3. 程序逻辑

总之,主要逻辑如下:

  1. 遍历flag,每个元素和8异或后保存到value中
  2. 遍历value,每个元素+3后保存到output中
  3. 对output进行base64编码,然后进行逆序得到obfuscated_output
  4. 对obfuscated_output中部分字符进行替换
    最后输出 =1nb0A3b7AUQwB3b84mQ/E0MvJUb+EXbx5TQwF3bt52bAZncsd9c
import base64

flag = '************************************'
value = ''
output = ''
i = 0
while i < len(flag):
    temp = ord(flag[i]) ^ 8
    value += chr(temp)
    i += 1
    
for j in range(len(flag)):
    temp = ord(value[j]) + 3
    output += chr(temp)
obfuscated_output = base64.b64encode(output.encode()).decode()[::-1]
obfuscated_output = obfuscated_output.replace('g', '1').replace('H', '3').replace('W', '9')
print(obfuscated_output)

4.解题脚本

import base64
Encoded= '=1nb0A3b7AUQwB3b84mQ/E0MvJUb+EXbx5TQwF3bt52bAZncsd9c'
Encoded= Encoded.replace('1', 'g').replace('3', 'H').replace('9', 'W')
decoded = base64.b64decode(Encoded[::-1])
for i in decoded:
    print(chr((i- 3)^8),end='')

flag{5dcbafe63fbf3b7d8647c1aee650ae9c}

三. BadCoffee

1. 相关文章

这题最开始也看不出是怎么做,然后就到网上查了下js逆向的混淆方法
找到几篇文章:

  1. 【JavaScript 逆向】AST 技术反混淆
  2. 使用javascript-obfuscator对js文件进行混淆
    不过文章只是简单介绍了一下,并没有给出反混淆的解决方法

2.解混淆

后来找到了工具:

  1. JS逆向 | ob混淆一键还原工具这个是本地工具,下载了但是还没使用
  2. 解混淆测试版这个在线工具非常好用
    只要将代码复制进去,然后选择模式1,选项全部勾选即可
    在这里插入图片描述
  3. 解混淆代码:
function xxx(_0x53b7bb, _0x590286) {
  return _0x53b7bb ^ _0x590286;
}

function enc(_0x4bda4c) {
  var _0x8ff1dd = [],
      _0x6aca75 = [233, 129, 127, 238, 145, 144, 11, 43, 87, 134, 243, 158, 197, 216, 111, 136, 152, 29, 204, 31, 26, 228, 39, 148, 215, 220, 90, 76, 251, 57, 183, 184, 150, 157, 156, 176, 13, 41, 30, 86, 244, 8];

  for (let _0x7bc200 = 0; _0x7bc200 < 42; _0x7bc200++) {
    _0x8ff1dd[_0x7bc200] = xxx(_0x6aca75['at'](_0x7bc200), _0x4bda4c["charAt"](_0x7bc200)['charCodeAt']());
  }

  for (let _0x4f674a = 0; _0x4f674a < 42; _0x4f674a++) {
    _0x8ff1dd[_0x4f674a] = xxx(_0x8ff1dd['at'](_0x4f674a), _0x6aca75['at'](41 - _0x4f674a));
  }

  console["log"](_0x8ff1dd);
  return _0x8ff1dd;
}

function fff() {
  var _0xe4960c = "flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}",
      _0x55dae6 = enc(_0xe4960c),
      _0xbb5ecd = [135, 25, 72, 151, 195, 212, 228, 212, 250, 101, 39, 77, 163, 77, 70, 167, 119, 184, 7, 77, 144, 154, 93, 10, 185, 48, 179, 77, 71, 163, 67, 61, 113, 156, 196, 136, 239, 241, 128, 93, 84, 156];

  for (let _0x37df9d = 0; _0x37df9d < 42; _0x37df9d++) {
    if (_0x55dae6['at'](_0x37df9d) != _0xbb5ecd['at'](_0x37df9d)) {
      console["log"]("Error");
      return;
    }
  }

  console["log"]("YES");
  return;
}

fff();

3.解题脚本

手动修改变量名和函数美化后的代码:

function xor(a, b) {
    return a ^ b;
  }
  function enc(data) {
    var result = [],
        buffer = [233, 129, 127, 238, 145, 144, 11, 43, 87, 134, 243, 158, 197, 216, 111, 136, 152, 29, 204, 31, 26, 228, 39, 148, 215, 220, 90, 76, 251, 57, 183, 184, 150, 157, 156, 176, 13, 41, 30, 86, 244, 8];
    for (let j = 0; j < 42; j++) {
      result[j] =xor(buffer['at'](j), data["charAt"](j)['charCodeAt']());
    }
    for (let k = 0; k < 42; k++) {
      result[k] =xor(result['at'](k), buffer['at'](41 - k));
    }
    console["log"](result);
    return result;
  }
  function main() {
    var flag = "flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}",
        encodeFlag = enc(flag),
        data = [135, 25, 72, 151, 195, 212, 228, 212, 250, 101, 39, 77, 163, 77, 70, 167, 119, 184, 7, 77, 144, 154, 93, 10, 185, 48, 179, 77, 71, 163, 67, 61, 113, 156, 196, 136, 239, 241, 128, 93, 84, 156];
    for (let i = 0; i < 42; i++) {
      if (encodeFlag['at'](i) != data['at'](i)) {
        console["log"]("Error");
        return;
      }
    }
    console["log"]("YES");
    return;
  }
  main();

很容易看出来是简单的异或和比较操作,解题脚本也很简单:

Encoded = [135, 25, 72, 151, 195, 212, 228, 212, 250, 101, 39, 77, 163, 77, 70, 167, 119, 184, 7, 77, 144, 154, 93, 10, 185, 48, 179, 77, 71, 163, 67, 61, 113, 156, 196, 136, 239, 241, 128, 93, 84, 156]
array = [233, 129, 127, 238, 145, 144, 11, 43, 87, 134, 243, 158, 197, 216, 111, 136, 152, 29, 204, 31, 26, 228, 39, 148, 215, 220, 90, 76, 251, 57, 183, 184, 150, 157, 156, 176, 13, 41, 30, 86, 244, 8]
for i in range(42):
    print(chr(Encoded[i]^array[41-i]^array[i]),end='')

flag{I_c0uld_neu3r_undeRstand_jvaVs3rIpt!}

四. Web&Assembly(暂时没复现出来,提供一些相关文章)

  1. 一步步学习Webassembly逆向分析方法
  2. WebAssembly/wabt
  3. WASM逆向分析
  4. WASM反编译,WASM逆向
  5. js遇到的wasm的加密
  6. 一种Wasm逆向静态分析方法
  7. 1.2.1 生成wasm

总结

  1. 这次比赛总体感觉很好,比前几天黑盾杯和国赛坐牢要好太多,虽然一些题目没见过,但是在网上查一下就能找到相关文章和工具
  2. 还要重视理论知识水平,不能做脚本小子,这些题目虽然有现成的工具做,但还是要了解一下相关原理,不然下次变一下就呆住了.例如这个的babypython,以前都是用工具或者脚本直接干pyc文件,这次只能生啃字节码(还好有gpt强大的分析能力),甚至还有很多混淆和跳转代码,也是锻炼到了啃字节码的能力
  3. 另一方面,个人的经验还是不足,还要继续多做题,多比赛,多复现,勤能补拙

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/606081.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

冈萨雷斯DIP第5章知识点

图像增强&#xff1a;主要是一种 主观处理&#xff0c;而图像复原很大程度上是一种 客观处理。 5.1 图像退化/复原处理的一个模型 如图5.1 本章把图像退化建模为一个算子 H \mathcal{H} H 该算子 与一个加性噪声项 η ( x , y ) η(x,y) η(x,y) 共同对输入图像 f ( x , y…

Rust每日一练(Leetday0013) 解数独、外观数列、组合总和

目录 37. 解数独 Sudoku Solver &#x1f31f;&#x1f31f;&#x1f31f; 38. 外观数列 Count and Say &#x1f31f;&#x1f31f; 39. 组合总和 Combination Sum &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Gola…

常微分方程(ODE)求解方法总结

常微分&#xff08;ODE&#xff09;方程求解方法总结 1 常微分方程&#xff08;ODE&#xff09;介绍1.1 微分方程介绍和分类1.2 常微分方程得计算方法1.3 线性微分方程求解的推导过程 2 一阶常微分方程&#xff08;ODE&#xff09;求解方法2.1 欧拉方法2.1.1 欧拉方法的改进思路…

逻辑推理——弟弟的编程课

前言 这篇文章不写代码&#xff0c;不科普知识。而是推理&#xff01; 这是我弟弟编程课上的一个同学&#xff1b;不是我的同学&#xff0c;我都成年了&#xff0c;这还是个小毛孩&#xff01; 这是他们学的&#xff1a; 乍一看这没任何问题&#xff0c;还有人会说&#xff…

谷歌地图模型自动下载

本工具是收费软件&#xff0c;学生党勿扰&#xff0c;闹眼子党勿扰 本工具收费1000元 视频教程 1 概述 记得去年写过一篇关于谷歌地图模型提取的博客&#xff0c;得到了广泛好评。有很多同学提出&#xff0c;能不能自动下载谷歌地图模型&#xff0c;由于提出此需求的人太多了…

【起点到终点 走哪条路径使得(路径长度排序从大到小后) 第k+1条边最小】通信线路

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

单片机GD32F303RCT6 (Macos环境)开发 (三十四)—— 数字加速度计 (ADXL345)

数字加速度计 &#xff08;ADXL345&#xff09;- 计算xyz轴重力值 1、i2c总线读取 1、接线 上一节的软件模式i2c的方式&#xff0c;选择PB10(SCL) PB11(SDA)。 GD32 ADXL345PB10 --------------- SCLPB11 --------------- SDA3.3 --…

Eclipse 教程 完结

Eclipse 快捷键 关于快捷键 Eclipse 的很多操作都提供了快捷键功能&#xff0c;我们可以通过键盘就能很好的控制 Eclipse 各个功能&#xff1a; 使用快捷键关联菜单或菜单项使用快捷键关联对话窗口或视图或编辑器使用快捷键关联工具条上的功能按钮 Eclipse 快捷键列表可通过…

《crossfire》游戏分析

文章目录 一、 穿越火线简介和定位二、 游戏发行三、 用户基础四、 游戏玩法枪王排位团队竞技爆破模式歼灭模式突围模式幽灵模式生化模式个人竞技挑战模式跳跳乐地图工坊 五、 游戏竞技公平性cf竞技公平性 六、CF火热到现在的原因分析1.时代、空间背景2.用户基础3.丰富的游戏模…

【iOS】—— nil、Nil、NULL和NSNull学习

nil、Nil、NULL和NSNull 文章目录 nil、Nil、NULL和NSNullnilNSNullNilNULL总结&#xff1a; 我们先来看看这几个苹果官方文档的解释&#xff1a; nil&#xff1a;Defines the id of a null instance.&#xff08;定义空实例的id&#xff09;Nil&#xff1a;Defines the id of…

给编程初学者的一封信

提醒&#xff1a;以下内容仅做参考&#xff0c;具体请自行设计。 随着信息技术的快速发展&#xff0c;编程已经成为一个越来越重要的技能。那么&#xff0c;我们该如何入门编程呢&#xff1f;欢迎大家积极讨论 一、自学编程需要注意什么&#xff1f; 要有足够的时间、精力等…

大数据治理入门系列:数据目录

在元数据管理一文中&#xff0c;我们曾将数据比喻为一本本的书&#xff0c;将书的作者、出版时间等信息比喻为元数据。试想一下&#xff0c;假如你是一名新任的图书管理员&#xff0c;如何快速掌握图书馆的馆藏情况呢&#xff1f;假如你是一名读者&#xff0c;如何快速找到你需…

Redis GEO功能详细介绍与实战

一、概述 Redis的Geo功能主要用于存储地理位置信息&#xff0c;并对其进行操作。该功能在Redis 3.2版本新增。Redis Geo操作方法包括&#xff1a; geoadd&#xff1a;添加地理位置的坐标&#xff1b;geopos&#xff1a;获取地理位置的坐标&#xff1b;geodist&#xff1a;计算…

第五届湖北省大学生程序设计竞赛(HBCPC 2023)vp赛后补题

Problem - B - Codeforces 思路&#xff1a; 数位dp&#xff0c;如果我们暴力的计算的状态的话&#xff0c;显然就是记录每个数字出现几次。但是显然这样难以发挥数位dp的记忆化功效&#xff0c;因为只有出现次数相同&#xff0c;你是什么数字&#xff0c;实际是无所谓的。所…

I2C学习笔记——I2C协议学习

1、I2C简介&#xff1a;一种简单、双线双向的同步串行总线&#xff0c;利用串行时钟线(SCL)和串行数据线(SDA)在连接总线的两个器件之间进行信息传递&#xff1b; 数据传输是通过对SCL和SDA线高低电平时序的控制&#xff0c;来产生I2C总线协议所需要的信号。在总线空闲状态时&a…

【Linux C】基于树莓派/香橙派的蓝牙服务端——支持多蓝牙设备接入

一、需求 在树莓派/香橙派上利用开发板自带的蓝牙作为一个蓝牙服务端&#xff08;主机&#xff09;&#xff0c;允许外来设备&#xff08;从机&#xff09;通过蓝牙接入进行通信&#xff0c;通信格式为透传方式&#xff1b;采用的编程语言为Linux C 二、环境准备 bluez安装 …

三波混频下的相位失配原理

原理推导 在四波混频情况下&#xff0c;实现零相位失配是一件很困难的事情。因为在四波混频中&#xff0c;相位调制和增益都依赖于相同的参数&#xff0c;即克尔非线性 γ \gamma γ。这个问题可以用嵌入在传输线上的辅助共振元件的复杂色散工程来部分解决。 但是在三波混频中…

ceph集群监控

文章目录 Ceph Dashboard启用dashboard插件dashboard启用ssl Promethues监控ceph启用prometheus模块配置prometheus采集数据grafana数据展示 Ceph Dashboard ceph-dashboard官方介绍&#xff1a;https://docs.ceph.com/en/latest/mgr/dashboard/ Ceph Dashboard是一个内置的c…

数据库系统概论---选择题刷题实训

&#xff08;一&#xff09;选择题 1.下列选项中&#xff0c;不属于关系模型三要素的是&#xff08; C &#xff09; A&#xff0e;数据结构 B&#xff0e;数据操纵 C&#xff0e;数据安全 D&#xff0e;数据完整性规则 2.保证数据库…

【Spring】透过Spring源码查看Bean的命名转换规则

近期在写Spring项目的时候&#xff0c;需要通过注解的形式去替代之前直接将Bean存放在Spring容器这种方式&#xff0c;以此来简化对于Bean对象的操作&#xff0c;但是这样无法通过准确的Id去获取到相应的Bean对象了 测试观察 首先&#xff0c;如果要将指定的对象存放到Spring中…