NKCTF2024 re VM?VM!WP

news2025/1/14 18:19:45

逻辑似乎很简单(个鬼啊)

这个函数是把输入的字符转化为二进制并倒序存储

sub_1570太大了加载不出来,应该是加密的主逻辑,目的是需要输出1

可以通过删除栈的方法强行转化伪代码

首先删掉这部分

9A0改小点

这个也是

栈这里U一下再P

像是虚拟机的分发器,unk_4018是类似opcode的大坨数据

好像有几十万

实际上是一个2324*2324的像素图,在上面进行染色

cable management | /den/face0xff/writeupsicon-default.png?t=N7T8https://ctf.0xff.re/2022/dicectf_2022/cable_management

【游戏框架系列】Wireworld元胞自动机 - 知乎【多图预警】本文含有大量图片写在前面这次实现的是Wireworld元胞自动机,相关资料如下: 维基:Wireworld - Wikipedia 介绍:WireworldFlash模拟:Wireworld Player (Flash) 如何实现简单的计算机:The Wireworld…icon-default.png?t=N7T8https://zhuanlan.zhihu.com/p/25593938

根据资料我才知道,这其实是在模拟Wireworld元胞自动机

组成:

  1. 导体
  2. 电子头
  3. 电子尾

每代变化:

  1. 空→空
  2. 电子头→电子尾
  3. 电子尾→导体
  4. 当仅有一个或仅有两个电子头的邻居是导体时,导体→电子头

对应着理解,0xCD就是导线

0xEA就是电子尾,0xEC是电子头

0x11是数据注入点

0x80相当于空/消除信号

1就是终点,到达就返回1

由此根据数据绘图分析,这实际上是利用wireworld高度抽象的虚拟机

数据量太大,这里用脚本提取

#data_extract
import idaapi  
import idautils  
  
# 设置你要读取数据的起始和结束地址  
START_ADDR = 0x4018  # 替换为你的起始地址  
END_ADDR = 0x535D93  # 替换为你的结束地址  
BYTES_PER_LINE = 16  # 每行显示的字节数  
  
# 打开一个文件用于写入,如果文件不存在则创建它  
with open('output.txt', 'w') as f:  
    # 用于记录当前行已经写入了多少字节  
    bytes_written = 0  
    # 遍历指定地址范围内的每个地址  
    for ea in range(START_ADDR, END_ADDR + 1):  
        # 读取当前地址的一个字节  
        byte_value = idaapi.get_byte(ea)  
        # 将字节转换为十六进制字符串  
        hex_string = '0x{:02X}'.format(byte_value)  
        # 写入文件,并在需要时添加逗号  
        if bytes_written > 0 and bytes_written % BYTES_PER_LINE != 0:  
            f.write(',')  
        f.write(hex_string)  
        bytes_written += 1  
        # 如果当前行已经写入了足够的字节数,则换行  
        if bytes_written % BYTES_PER_LINE == 0:  
            f.write(',\n')  
  
# 文件会在脚本执行完毕后自动关闭  
print("Data has been written to output.txt")

然后绘图(来自孤恒师傅的脚本)

from PIL import Image
s = [...]
img = Image.new('RGB', (0x914, 0x914), (255, 255, 255))
pixels = img.load()
for i in range(len(s)):
    if s[i] == 0x1:
        i_row = i // 0x914
        i_col = i % 0x914
        #print("0x01_row:"+f"{i_row:X}" + "  0x01_col:"+f"{i_col:X}")
        pixels[i_row, i_col] = (255, 0, 0)

    elif s[i] == 0xEC:
        i_row = i // 0x914
        i_col = i % 0x914
        #print("0xEC_row:"+f"{i_row:X}" + "  0xEC_col:"+f"{i_col:X}")
        pixels[i_row, i_col] = (0, 0, 255)

    elif s[i] == 0x11:
        i_row = i // 0x914
        i_col = i % 0x914
        #print("0x11_row:"+f"{i_row:X}" + "  0x11_col:"+f"{i_col:X}"
        pixels[i_row, i_col] = (0, 255, 0)

    elif s[i] == 0xCD:
        i_row = i // 0x914
        i_col = i % 0x914
        #print("0xCD:"+f"{i:X}")
        pixels[i_row, i_col] = (0, 0, 0)

    elif s[i] == 0x80:
        i_row = i // 0x914
        i_col = i % 0x914
        #print("0xCD:"+f"{i:X}")
        pixels[i_row, i_col] = (255, 255, 0)
		
    elif s[i] == 0xEA:
        i_row = i // 0x914
        i_col = i % 0x914
        #print("0xCD:"+f"{i:X}")
        pixels[i_row, i_col] = (0, 255, 255)

img.save('D:\\下载\\CTF附件\\nk\\image.png')

有大量重复的图案,我们放大进行分析

乍一看难以理解,结合wireworld的规则,我们可以分析出图案蕴藏的含义

最上面就是一条畅通无阻的电线

下面很复杂,先看重复度最高的这部分,注意到不断重复的这个模块

我们用网站模拟

Wireworld Simulatoricon-default.png?t=N7T8https://danprince.github.io/wireworld/

只有一侧输入信号(即一侧1,一侧0)时,电子头会正常向下传导

但如果两边都有

信号就会消失

所以这其实是在模拟异或(逻辑门),原理是在这里

箭头所指的导线周围有三个电子头,但我们的规则是当仅有一个或仅有两个电子头的邻居是导体时,导体→电子头

因此就达到了异或的效果

图中除了大量的异或,还有别的图形

可以用相同的方法分析出这个是与

这个是或

这个则是一个二极管,像神经突触一样,只会从“突触前模”向“突触后膜”单向传导

我们可以根据这些特征把整个图分割开,由于每个输入的字符都转化为8位二进制注入(绿色就是注入点),所以我每八个循环分割一次,最后得到29块,对应29个输入的字符

输入的字符究竟是如何处理的呢?可以看到,每个绿色注入点激活的电子头会向左右两边传导,经过一个异或(输入的字符转化为倒序二进制数,这个数的每相邻两位异或)之后,与蓝色点激活的电子头再次异或,之后得到的信号就会输入下面的向右的二极管结构

也就是说,只要有一个异或结果是1(有电),电子头就会向右传导到失败点。所以我们的目标就是消除所有产生的电子头,使得上面那一条完整的电线上的电子头平安到达左侧的终点

可以看到,蓝色电子头总是在循环结构相同的位置上,代表着这个位置上电信号的1和0,将他们连接在一起就相当于组成了一个由0、1组成的key(可以脚本取key,我嫌麻烦就直接手敲了)

我们要求的flag是上面一排注入点的0/1状态,加密过程就是我之前说的一系列异或,我们期望得到的结果就是全0

由此我们可以写出解密的函数,将key与全0序列异或逆序转化成字符串

def decode(key):
    key_string = long_to_bytes(int("".join([str(i) for i in key]), 2))
    #print(key_string)
    res = [0]
    for i in range(len(key)-1):
        tmp = res[i]^key[i]
        res.append(tmp)
    #print(res)
    flag = long_to_bytes(int("".join([str(i) for i in res]), 2))
    print(flag)

但我们并不能把整段key直接放进去解密,因为整个wireworld结构被中段分割成了两半,右边(相当于前面一半)是插入了与的部分

左边是插入了或的部分

先看前半部分,与的前面有四个注入点,key第四位相当于缺失的

但反正就0和1两种情况,拿出前八位二进制试一下就会发现这一位为1的时候可以得到n(就是nkctf的开头),否则会得到a

然后第9位一直到断点前面都是连续的,可以得到第二段flag

中间这个位置比较尴尬,这四位右边是断开的,左边是个或,只要有一个满足1就能激活

中间四位排列组合一下就能凑出有意义字符

剩下的直接输入

就可以得到完整的flag了

#VM?VM!
from Crypto.Util.number import long_to_bytes
key0 = [1, 0, 1, 1, 0, 0, 1, 0]

key1 = [1, 0, 1, 1, 1, 1, 0, 1, 
1, 0, 1, 0, 0, 1, 0, 1,
1, 0, 0, 1, 1, 1, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0, 
1, 0, 0, 0, 1, 1, 0, 1, 
1, 0, 0, 1, 1, 0, 0, 1, 
1, 0, 1, 1, 1, 0, 1, 1, 
1, 1, 1, 1, 0, 1, 1, 0, 
1, 0, 1, 0, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 0, 0, 1, 
1, 0, 1, 1, 0, 0, 0, 1]

key2 = [0, 1, 1, 1, 0, 1, 
1, 1, 
1, 0, 
1, 1, 0, 1, 0, 0]

key3 = [1, 0, 1, 0, 1, 1, 0, 0, 
1, 1, 1, 0, 0, 0, 0, 1, 
0, 1, 0, 1, 0, 0, 1, 1, 
1, 0, 0, 1, 0, 1, 0, 1, 
1, 1, 1, 0, 0, 0, 0, 1, 
1, 0, 1, 1, 0, 0, 1, 0, 
0, 1, 0, 1, 0, 0, 0, 0, 
1, 0, 0, 1, 1, 1, 0, 0, 
1, 1, 1, 0, 0, 0, 0, 1, 
1, 0, 1, 0, 1, 0, 0, 1, 
1, 0, 1, 1, 0, 0, 0, 1, 
1, 1, 0, 1, 0, 0, 0, 1, 
1, 1, 0, 0, 1, 1, 0, 0, 
0, 1, 1, 0, 0, 0, 1, 1, 
1, 0, 0, 0, 0, 1, 1, 0]
def decode(key):
    key_string = long_to_bytes(int("".join([str(i) for i in key]), 2))
    #print(key_string)
    res = [0]
    for i in range(len(key)-1):
        tmp = res[i]^key[i]
        res.append(tmp)
    #print(res)
    flag = long_to_bytes(int("".join([str(i) for i in res]), 2))
    print(flag)
decode(key0)
decode(key1)
decode(key2)
decode(key3)

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

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

相关文章

docker部署在线流程图

下载镜像 docker pull registry.cn-beijing.aliyuncs.com/wuxingge123/drawio:latestdocker-compose部署 vim docker-compose.yml version: 3 services:drawio:container_name: drawioimage: registry.cn-beijing.aliyuncs.com/wuxingge123/drawio:latestports:- 8083:8080v…

【MATLAB源码-第25期】基于matlab的8QAM调制解调仿真,手动实现未调用内置函数,星座图展示。

操作环境: MATLAB 2022a 1、算法描述 8QAM调制(8 Quadrature Amplitude Modulation)是一种数字调制技术,它可以在有限带宽内传输更多的信息比特。在8QAM调制中,每个符号可以携带3个比特的信息。QAM调制是将数字信号…

【数据分析面试】6.计算对话总数(SQL)

题目:计算对话总数 给定了名为 messenger_sends 的消息发送表格,找出总共有多少个唯一的对话。 注:在某些记录中,receiver_id 和 sender_id 从初始消息中互换了。这些记录应视为同一个对话。 示例: 输入&#xff1…

ubuntu更换国内镜像源,下载增速

方法一:通过脚本更换源 1.备份原来的源 sudo cp /etc/apt/sources.list /etc/apt/sources_init.list 将原来的源保留一下,以后想用还可以继续用 2.更换源 sudo gedit /etc/apt/sources.list 使用gedit打开文档,将下面的阿里源复制进去&am…

微信小程序纯CSS实现好看的加载动画

进入下面小程序可以体验效果&#xff1a; WXML: <wxs module"img" src"./loading.wxs"></wxs> <view class"loading-container {{show?:loading-container-hide}}"><view class"loading-mask" wx:if"{{ma…

分享:搭建企微知识库简单易学步骤

说起企微知识库&#xff0c;可能有些人还不太清楚&#xff0c;为什么现在很懂企业选择搭建企微知识库&#xff1f;其实&#xff0c;企微知识库就是一个装满了企业的各种知识、经验和资料的载体。目的是为了方便员工随时查找和学习、有助于知识的传承和共享、加强团队协作和沟通…

《机器学习算法实战宝典》正式发布!

大家好&#xff0c;我是城哥&#xff0c;最近写了两本资料&#xff0c;一本是&#xff1a;《机器学习算法面试宝典》正式发布&#xff01;&#xff0c;内容是面试技巧、面试真题、常考题等。 今天分享的《机器学习算法实战宝典》&#xff08;以下简称《算法实战宝典》&#xf…

element-ui avatar 组件源码分享

今日简单分享 avatar 组件的源码实现&#xff0c;主要从以下四个方面&#xff1a; 1、avatar 组件页面结构 2、avatar 组件属性 3、avatar 组件事件 4、avatar 组件 slot 一、avatar 组件页面结构 二、avatar 组件属性 2.1 icon 属性&#xff0c;设置头像的图标类型&…

【Redis】分布式锁及其他常见问题

分布式锁及其他常见问题 1. 我看你的项目都用到了 Redis&#xff0c;你在最近的项目的哪些场景下用到了 Redis 呢&#xff1f; 一定要结合业务场景来回答问题&#xff01;要是没有不要硬讲&#xff0c;除非面试官问&#xff1b; 接下来面试官将深入发问。 你没用到的也可能会…

VS Code 配置 cmake

手动添加 CMake 编译器的搜索路径 如果没有设置上面的路径&#xff0c;有些编译器是找不到的

基于SpringBoot和Vue的校园周边美食探索以及分享系统

今天要和大家聊的是基于SpringBoot和Vue的校园周边美食探索以及分享系统 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同学 &#x1f495;&#x1f…

kali 渗透工具 - mestaploit

永恒之蓝漏洞的小知识&#xff1a; 黑客通过改造 永恒之蓝 制作 wannacry 制作病毒入侵高校内网。 mestaploit 攻击永恒之蓝流程&#xff1a; 使用模块 msfconsole配置required 模块参数运行&#xff0c;开始监听主机 msfconsole 主要模块 - 选择使用模块 search ms17_01…

工业组态 物联网组态 组态编辑器 web组态 组态插件 编辑器

体验地址&#xff1a;by组态[web组态插件] BY组态是一款非常优秀的纯前端的【web组态插件工具】&#xff0c;可无缝嵌入到vue项目&#xff0c;react项目等&#xff0c;由于是原生js开发&#xff0c;对于前端的集成没有框架的限制。同时由于BY组态只是一个插件&#xff0c;不能独…

大转盘抽奖小程序源码

源码介绍 大转盘抽奖小程序源码&#xff0c;测试依旧可用&#xff0c;无BUG&#xff0c;跑马灯旋转效果&#xff0c;非常酷炫。 小程序核心代码参考 //index.js //获取应用实例 var app getApp() Page({data: {circleList: [],//圆点数组awardList: [],//奖品数组colorCirc…

SCI一区 | Matlab实现NGO-TCN-BiGRU-Attention北方苍鹰算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测

SCI一区 | Matlab实现NGO-TCN-BiGRU-Attention北方苍鹰算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测 目录 SCI一区 | Matlab实现NGO-TCN-BiGRU-Attention北方苍鹰算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测预测效果基本介绍模型…

设计模式总结-面向对象设计原则

面向对象设计原则 面向对象设计原则简介单一职责原则单一职责原则定义单一职责原则分析单一职责原则实例 开闭原则开闭原则定义开闭原则分析开闭原则实例 里氏代换原则里氏代换原则定义里氏代换原则分析 依赖倒转原则依赖倒转原则定义依赖倒转原则分析依赖倒转原则实例 接口隔离…

配置 施耐德 modbusTCP 分布式IO子站 RPA0100

1. 总体步骤 2. 软件组态&#xff1a;在 Unity Pro 软件中创建编辑 PRA 模块工程 2.1 新建项目 模块箱硬件型号如下 点击 Unity Pro 软件左上方【新建】按钮&#xff0c;选择正确的 DIO 模块型号、背板型号 2.2 模块组态 2.2.1 拖拽添加模块 双击【配置】菜单下的【0&…

糟糕,Oracle归档满RMAN进不去,CPU98%了!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

【QT+QGIS跨平台编译】056:【pdal_lepcc+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、pdal_lepcc介绍二、pdal下载三、文件分析四、pro文件五、编译实践一、pdal_lepcc介绍 pdal_lepcc 是 PDAL(Point Data Abstraction Library)的一个插件,用于点云数据的压缩。它基于 EPCC(Entwine Point Cloud Compression)算法,提供了对点…

72小时内报告!美国发布关键基础设施网络攻击通报新规草案

美国网络安全和基础设施安全局(CISA)本周四发布了关键基础设施企业如何向政府报告网络攻击的规定草案。 新规基于拜登2022年3月15日签署的美国《关键基础设施网络事件报告法案》(简称CIRCIA)。这是美国联邦政府首次提出一套跨关键基础设施部门的全面网络安全规则。CISA正在就规…