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

台州ctf市赛reverse(easy_choice)超详细复现

一,题目链接

easy_choice的附件

(市赛题目,涉侵权联系删)


二,题目分析

(一)查壳

查壳带upx壳,32位

用工具脱壳,发现脱不了,说明upx的壳特征被魔改

特征被修改,把它们改成正常的upx特征

改会正常特征后保存,再用工具脱壳

成功脱壳

(二)ida分析

拖入32位ida进行分析,自动定位到main函数,然后进行漫长的代码审计,在这个过程中按N键对显眼的函数、变量等修改名字,以助于后续理解

大致的逻辑是这样的:输入key->对key进行检查->输入flag->对flag进行两次加密(两个do_while循环)->检查加密后的密文是否与cipher一致

(1)check_key()分析,得到密钥

check_key()是我改的函数名,助于理解,双击函数查看代码

看到下面的代码是不是直接懵逼了……

按tab键+空格看看汇编吧……丸辣,是我们最爱的花指令!如果你连花指令是什么意思都不知道,那也没必要来看这题的wp了,后面的水还深着呢……

下图红框框起来的部分是本处花指令的构成,这个花指令是通过call+esp+retn的组合,扰乱ida的反汇编

花指令原理:

原文来源->花指令总结-安全客 - 安全资讯平台

去这个花最简单粗暴的办法,全部nop,因为它们对代码正常的逻辑没有影响,可以全部视为垃圾字节(包括jmp     short loc_4011DB,jmp过去的int 3只是断点指令罢了,nop掉也不影响),把垃圾字节全部nop掉,ida才能正常反汇编

选中这部分然后按U键转为数据,这样方便我们确认要nop的范围

然后把这部分字节全部改成nop的字节码(0x90)

然后从函数头开始,选到下面的retn

按U键转成数据后,回到函数头按P创建函数

成功去花,可以F5了!

F5看到C代码,这个逻辑其实不难,读者仔细阅读一下,这里a2刚开始是0,看传参就知道

所以把a2=0代入进去,你模拟一下就知道key是什么了,主要注意LABEL_17那里递归调用enc_key(),a2的值是在变的

注意递归调用时a1+1的意思是让按顺序访问key的每位,所以最后模拟出来的key就是正常顺序,不用去考虑要不要转大端小端之类的

模拟:

a2_arr = []
a2 = 0  # a2初始是0
for i in range(8):  # 递归7次调用enc_key,a2的表达式是(8*a2+8)%11a2_arr.append(a2)a2 = (8 * a2 + 8) % 11  # 计算下一个a2
print(a2_arr)# 从case 0-case9,给key赋的值,注意题目没有case2和case3,用0占位置,实在不理解就搓个分支赋值吧
cipher = [84, 65, 0, 0, 67, 83, 68, 84, 79, 70]
for i in range(8):print(chr(cipher[a2_arr[i]]), end='')  # 按递归过程中a2的值的顺序去获取每位key

结果:

TODASCTF,这么标志,可以肯定是正确的key了!不确定的话就运行题目测一下能不能过check_key()

(2)enc()分析,搞清楚如何对输入进行加密

enc()也是我改的函数名,现在还不清楚它的具体加密,先在main函数里观察一下它的调用流程吧

输入input之后,把input分别用ins1和ins2做了备份,然后各进行4次do...while循环,每次循环传入input和固定整数2调用enc()

重点要注意的是第二次循环时,key = &key + 3,意思很明显,第二次循环过程中用的key是向后偏移3位的

完整key:              TODASCTF

第一次调用的key:TODA

第二次调用的key:ASCT

双击enc()函数查看代码……应该轻车熟路了,又是花指令

tab+空格

这题唯一良心的地方就是两个函数插入的是同一个花指令,去除方式和上面check_key()是一样的,不再赘述

又可以F5了

终于是见到了加密函数的庐山真面目,十分标志的xxtea(又名btea),当然如果你没学过的话,就不觉得标志了(废话

做这种套路加密,首先一定要改好关键参数的名字,包括类型识别错的,按Y键给它改一下(比如这里的key),方便对照脚本

改的差不多就好了,有些参数不是很重要的就懒得管了,

这里要注意一点,

sum -= 0x61C88647

sum += 0x9E3779B9

这两在tea系列算法中是完全等价的,所以如果你预留的脚本里面用的delta是0x9E3779B9,不要认为和题目不一致,但注意是要sum+=0x9E3779B9

(3)总结

分析到这里终于可以写逆向脚本了

我们先把cipher提取出来

然后或是脚本,或是手搓,反正把密文处理成你脚本适配的格式,注意一下大小端序的问题

key这里还要注意,正向加密时,是

第一次调用的key:TODA

第二次调用的key:ASCT

而逆向解密时要反过来,先用"ASCT",后用"TODA"

 

然后做两个循环,各循环4次,每次传入v中的两个uint32_t(这里传入的-2是xxtea脚本的特性,负数是解密,正数是加密)

 

解完密后用经典算法循环&0xFF取末尾字节打印,不理解无所谓,反正是固定的输出算法

至于xxtea的解密逻辑,本题没有对其进行魔改(要是出题人还丧心病狂地魔改,这题放re第一题是真的逆了个大天),所以直接套用标准的即可


三,完整解题脚本

注:可能你觉得看wp写的脚本很简单,但这些都是一步步分析题目,不断修改和尝试出来的(比如密文密钥格式,循环设置,解密函数调用等等),所以千万不要认为看懂了wp就是学会了,一定要思考为什么是这样(比如为什么密文密钥是这个格式,为什么循环要这样设置)

exp

#include <stdint.h>
#include <stdio.h>
#define DELTA 0x9e3779b9  // 0x9e3779b9对应sum+=DELTA,而0x61C88647对应sum-=DELTA,它们是等价的#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)))
void btea(uint32_t* v, int n, uint32_t const key[4]) {uint32_t y, z, sum;unsigned p, rounds, e;if (n > 1) /* Coding Part */{rounds = 6 + 52 / n;sum = 0;z = v[n - 1];do {sum += DELTA;e = (sum >> 2) & 3;for (p = 0; p < n - 1; p++) {y = v[p + 1];z = v[p] += MX;}y = v[0];z = v[n - 1] += MX;} while (--rounds);} else if (n < -1) {n = -n;rounds = 6 + 52 / n;sum = rounds * DELTA;y = v[0];do {e = (sum >> 2) & 3;for (p = n - 1; p > 0; p--) {z = v[p - 1];y = v[p] -= MX;}z = v[n - 1];y = v[0] -= MX;sum -= DELTA;} while (--rounds);}
}int main() {uint32_t v[8] = {0xac3a28fd, 0x2331590c, 0x329f681b, 0xa6cf62db, 0x8738a413, 0x44d27414, 0xdef3a4cd, 0x5b22ba91,};                                                // v是要加解密的数据,传入任意个32位无符号整数(一个uint32_t == 4字节)uint32_t const k1[4] = {'A', 'S', 'C', 'T'};  // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位uint32_t const k2[4] = {'T', 'O', 'D', 'A'};int n = sizeof(v) / sizeof(v[0]);  // n的绝对值表示v的长度,for(int i = 0; i < 4; i++){btea(v + 2 * i, -2, k1);}for(int i = 0; i < 4; i++){btea(v + 2 * i, -2, k2);}// tea输出字符的固定算法,外层循环n次依次处理n个v中的元素// 内层循环4次是因为一个字符占1个字节即8位,每次&0xff可以摘下最后1字节打印出对应ASCII字符,然后>>8准备下一字节for (int i = 0; i < n; i++) {for (int j = 0; j < sizeof(uint32_t) / sizeof(uint8_t); j++) {printf("%c", (v[i] >> (j * 8)) & 0xFF);}}return 0;
}

运行结果


http://www.mrgr.cn/news/62707.html

相关文章:

  • 基于SSM+微信小程序的汽车维修管理系统(汽车5)
  • Windows Qt 6安装Oracle QOCI SQL Driver插件
  • 中小企业设备资源优化:Spring Boot系统实现
  • 排序算法汇总
  • python 使用进程池并发执行 SQL 语句
  • node升级package.json中的版本
  • 什么是决策树桩
  • 因特网的概述和三种交换方式
  • C++笔记---可变参数模板
  • XHCI 1.2b 规范摘要(八)
  • 从零实现数据结构:二叉搜索树
  • 【HTML5标准】深度解析HTML5:前端开发的基石
  • 【深度学习】VITS语音合成原理解析
  • 向量库Milvus异常挂了,重新启动
  • 有没有优质的公司可以提供高质量大模型数据?
  • Vue.js(2) 基础:指令与功能概览
  • C++对象模型:Function 语意学
  • 九泰智库 | 医械周刊- Vol.65 | 广州发布首批创新药械产品目录
  • 【产品经理】工业互联网企业上市之路
  • 【2024.10.31练习】123
  • 二分查找题目:搜索插入位置
  • 沈阳工业大学《2021年+2020年827自动控制原理真题》 (完整版)
  • Java - 手写识别; 如何用spring ai和大模型做手写识别教程
  • 监控pod日志
  • 集成学习(2)
  • Ethernet 系列(5)-- 物理层测试::PMA Test::MDI