REVERSE-PRACTICE-BUUCTF-17

  • [网鼎杯 2020 青龙组]jocker
  • [2019红帽杯]childRE
  • [MRCTF2020]PixelShooter
  • [ACTF新生赛2020]SoulLike

[网鼎杯 2020 青龙组]jocker

exe程序,运行后提示输入flag,无壳,用ida分析
main函数平衡栈后,F5反汇编
主要逻辑为
读取输入,检验输入长度是否为24,对输入进行变换,与已知数组比较,执行一段从encrypt函数起始地址开始的SMC,分析可知,finally函数也会完全被SMC,未经变换的输入作为参数,调用encrypt函数和finally函数

先写input经过wrong变换和omg验证的逆运算脚本,得到的是假flag

往下走,在ida中使用idapython脚本完成SMC自修改代码

from idaapi import *
from idautils import *
start_addr = 0x401500
key = 0x41
for i in range(start_addr,start_addr+187):PatchByte(i,Byte(i)^key)

SMC前,encrypt函数和finally函数各自包含了一大段数据

SMC后,encrypt函数和finally函数的指令间都有一些db指令,实际上为花指令
encrypt函数:

finally函数:

手动nop掉多余的db指令,让ida能够自动分析成代码
完成nop后,发现encrypt函数,在两端黑色代码中间插有一段红色代码

这时的处理方法是,在encrypt函数起始地址0x401500处,右键->undefine,变成黄色的数据,再按c转成代码,这时,encrypt函数起始地址与finally函数起始地址之间的代码全部为红色,再在encrypt函数起始地址0x401500处,右键->create function,平衡栈后,F5反汇编
这里encrypt函数反汇编后,好像没有用到未经变换的input,可能是patch代码的时候出错了,不过可以猜测为input和字符串“hahahaha_do_you_find_me?”异或,再与已知的unk_403040数组比较

写encrypt函数的逆运算脚本,得到部分flag,之所以是部分flag,是因为长度为24的unk_403040的最后5个元素为0,“d_me?”与0异或不变,或者v6=19说明了只异或了19次,而且提交失败

同encrypt函数的解析步骤,对finally函数,先nop掉多余的db指令,undefine掉黑色代码,转成数据,按c再转成代码,右键->create function,F5反汇编
没看懂这个函数,看了其他师傅的wp,说这里也是异或,能看到的5个值[37,116,112,38,58]是异或后要比较的值,由于input的最后一位一定是“}”,它异或一个值(“71”)后与58相等,而且它之前的四位也是和这个值(“71”)异或,结果是58之前的四个值

写finally函数的逆运算脚本得到后半部分的flag,替换掉“flag{d07abccf8a410cd_me?”的后5位,flag即为“flag{d07abccf8a410cb37a}”

[2019红帽杯]childRE

exe程序,运行后直接输入,无壳,ida分析
交叉引用字符串“flag{MD5(your input)}”来到sub_140001610函数
sub_140001610函数主要的逻辑为
读取输入,验证输入的长度是否为31,对输入进行位置变换处理,位置变换的结果放到v2(name),经调试可知,输入为abcdefghijklmnopqrstuvwxyz12345时,v2(name)的内容为pqhrsidtujvwkebxylz1mf23n45ogca
对v2(name)调用UnDecorateSymbolName函数处理,结果放到outputstring,验证outputstring的长度62及其内容

signed __int64 sub_7FF6DC281610()
{signed __int64 input_len; // rax_QWORD *v1; // raxconst CHAR *v2; // r11__int64 v3; // r10__int64 v4; // r9const CHAR *v5; // r10signed __int64 outputstring_len; // rcx__int64 v7; // raxsigned __int64 result; // raxunsigned int v9; // ecx__int64 v10; // r9int v11; // er10__int64 v12; // r8__int128 input; // [rsp+20h] [rbp-38h]__int128 v14; // [rsp+30h] [rbp-28h]input = 0i64;v14 = 0i64;sub_7FF6DC281080((__int64)"%s", &input);      // 读取输入input_len = -1i64;do++input_len;while ( *((_BYTE *)&input + input_len) );if ( input_len != 31 )                        // 输入的长度为31{while ( 1 )Sleep(0x3E8u);}v1 = sub_7FF6DC281280(&input);                // 对input的处理,通过调试可知,从31行到41行,是对input的位置变换,变换后的结果放入v2,也就是name// 例如,输入abcdefghijklmnopqrstuvwxyz12345,name=“pqhrsidtujvwkebxylz1mf23n45ogca”v2 = name;                                    // v2==nameif ( v1 ){sub_7FF6DC2815C0((unsigned __int8 *)v1[1]);sub_7FF6DC2815C0(*(unsigned __int8 **)(v3 + 16));v4 = dword_7FF6DC2857E0;v2[v4] = *v5;dword_7FF6DC2857E0 = v4 + 1;}UnDecorateSymbolName(v2, outputString, 0x100u, 0);// v2,也就是name,经过UnDecorateSymbolName函数处理,结果放到outputstring中outputstring_len = -1i64;do++outputstring_len;while ( outputString[outputstring_len] );if ( outputstring_len == 62 )                 // outputstring的长度为62{v9 = 0;v10 = 0i64;do                                          // do循环体在验证outputstring的内容{v11 = outputString[v10];v12 = v11 % 23;if ( table[v12] != *(_BYTE *)(v10 + 0x7FF6DC283478i64) )// (_@4620!08!6_0*0442!@186%%0@3=66!!974*3234=&0^3&1@=&0908!6_0*&_exit(v9);if ( table[v11 / 23] != *(_BYTE *)(v10 + 0x7FF6DC283438i64) )// 55565653255552225565565555243466334653663544426565555525555222_exit(v9 * v9);++v9;++v10;}while ( v9 < 0x3E );sub_7FF6DC281020("flag{MD5(your input)}\n", v11 / 23, v12, v10);result = 0i64;}else{v7 = sub_7FF6DC2818A0(std::cout);std::basic_ostream<char,std::char_traits<char>>::operator<<(v7, sub_7FF6DC281A60);result = 0xFFFFFFFFi64;}return result;
}

先写验证outputstring的长度62及其内容的逆运算脚本,得到outputstring,为一个未修饰的C++符号名

UnDecorateSymbolName函数反修饰指定已修饰的 C++ 符号名,参考:UnDecorateSymbolName
第1个参数为已修饰的 C++ 符号名,此名称能以始终为问号 (?) 的首字符鉴别,本题中为v2(name),第2个参数指向字符串缓冲区的指针,该缓冲区接收未修饰的名字,本题中为outputstring
可知需要对outputstring符号名修饰才能得到v2(name),参考:c/c++函数名修饰规则
或者通过写C++代码,调用__FUNCDNAME__宏(FUNCDNAME:只有在函数内部才有效,返回该函数经编译器修饰后的名字。如果编译器选项中设定了/EP或/P,则__FUNCDNAME__是未定义。)直接得到函数经编译器修饰后的符号名,需要注意的是函数所在的类,域,返回类型,函数名,参数类型都必须和已知完全相同

#include<iostream>
using namespace std;
class R0Pxx {//函数所在的类
public:R0Pxx() {//该类的构造函数unsigned char a;My_Aut0_PWN(&a);}private://函数属于私有域//函数的返回类型 函数名 以及参数类型char * My_Aut0_PWN(unsigned char*) {char * ret = NULL;//调用宏 输出该函数经编译器修饰后的符号名printf("%s", __FUNCDNAME__);return ret;}
};
int main() {new R0Pxx();getchar();return 0;
}

运行结果即为v2(name),注意是在x86架构下运行的结果

写逆位置变换脚本即可得到输入,对输入进行md5散列即可得到flag

[MRCTF2020]PixelShooter

apk文件,jadx-gui打开,什么都没发现
用Apktool Box反编译apk后,在PixelShooter->lib->armeabi-v7a目录下发现3个.so文件,依次分析,同样什么都没发现
突然想到这是个安卓unity游戏,而安卓unity游戏的核心逻辑一般位于assets\bin\Data\Managed\Assembly-CSharp.dll
用dnSpy打开,在类UIController的GameOver方法中找到flag

[ACTF新生赛2020]SoulLike

elf文件,无壳,ida分析
main函数,读取输入,验证输入的前5个字符是否为“actf{”,将输入{}内的字符放入v8,可知输入{}内的长度为12,调用sub_83A函数验证v8,且输入的最后一个字符为“}”

分析sub_83A函数,可以看到是对input{}内12个字符的超多异或运算

在sub_83A函数的最后,是input{}内的12个字符经过超多异或运算后的值与已知的v4到v15比较,因为会有类似input[3]^=input[2]的情况,所以不能通过调试得到每个字符最后等效的异或值是什么
不过当比较为不相同时,程序会打印输入是哪个位置的字符错了,于是可以写脚本爆破出flag

爆破脚本

#coding:utf-8
from itertools import *
import subprocessflag=""
t=""
for i in range(12):for j in range(32,126):flag ="actf{"+t+chr(j)+"}" p = subprocess.Popen(["./SoulLike"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)p.stdin.write(flag)p.stdin.close()out=p.stdout.read()p.stdout.close()if "#"+str(i) not in out:t+=chr(j)breakprint(flag)

运行结果

REVERSE-PRACTICE-BUUCTF-17相关推荐

  1. 恢复SQL Server被误删除的数据(再扩展)

    原文:恢复SQL Server被误删除的数据(再扩展) 恢复SQL Server被误删除的数据(再扩展) 大家对本人之前的文章<恢复SQL Server被误删除的数据> 反应非常热烈,但是 ...

  2. 恢复SQL Server被误删除的数据

    恢复SQL Server被误删除的数据 <恢复SQL Server被误删除的数据(再扩展)> 地址:http://www.cnblogs.com/lyhabc/p/4620764.html ...

  3. String 与StringBuilder

    相信大家对 String 和 StringBuffer 的区别也已经很了解了,但是估计还是会有很多同志对这两个类的工作原理有些不清楚的地方,今天我在这里重新把这个概念给大家复习一下,顺便牵出 J2SE ...

  4. 恢复SQLSERVER被误删除的数据

    曾经想实现Log Explorer for SQL Server的功能,利用ldf里面的日志来还原误删除的数据 这里有一篇文章做到了,不过似乎不是所有的数据类型都支持 以下为译文:http://rar ...

  5. Scala 入门2(数组、List、Set、Map、元组、Option、Iterator)

    文章目录 1. 数组 2. List 3. Set 4. Map 5. 元组 6. Option 7. 迭代器 学自 https://www.runoob.com/scala/scala-tutori ...

  6. c语言规范标准c99中文版下载,c99标准找到了,中文HTML页面

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 是网页格式, 不太方便全贴出来, 我就贴一部分吧,一个页面: 3 术语.定义和符号 该国际标准使用了如下定义.其他术语在其出现的位置以斜体显示,或放在语法 ...

  7. JavaScript复习笔记(三)数组及数组API

    一.数组 分为两种  关联数组:可以自己定义下标名称的数组 索引数组:自动生成下标的数组都是索引数组 1.创建.赋值和取值 ①创建:4种: 1. var 变量名=[];   创建一个空数组对象 2. ...

  8. ROSCon2018国际会议讲座录像和讲稿PPT

    连续第四年ROSCon门票完全售罄,参加人数超过500人.感谢47个赞助商6,数量再创新高, 为会议的发展提供资金支持! 此外,还发布了几乎所有讲座的幻灯片.因此,如果想获得链接或其他信息,现在也可以 ...

  9. 数学建模方法总结(matlab)

    1. 前言 在这篇文章中,我会把我所接触的数学建模的知识的代码分享给大家,有的是我自己写的,更多的是网上借鉴并修改为可执行可用的代码 需要说明的是,我不太了解其中的数学实现的具体方法和原理,我只分享源 ...

  10. 公司数据库使用的是sqlServer 以防万一留着 SQLsever误删数据恢复

    SQLsever误删数据恢复 ​ 创建存储过程 语句如下 -- Script Name: Recover_Deleted_Data_Proc – Script Type : Recovery Proc ...

最新文章

  1. Gut Microbes:中科院微生物所王军组在新冠病人肠道病毒组研究取得新进展
  2. 万物上链: 5G 起跑
  3. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(九)
  4. poj1769 线段树优化的dp
  5. Hazelcast入门
  6. LSTM 与 Bilstm介绍(包含代码实现、Python)
  7. [转载]Linux驱动-SPI驱动 之二:SPI通用接口层
  8. MS SQL入门基础:管理触发器
  9. 手把手教你在Windows环境下升级R
  10. python的设计哲学_Python的设计哲学
  11. 计算机驱动程序的安装过程,电脑常用的驱动程序的安装与管理
  12. 【毕设资料】 Web版RSS阅读器(一)——dom4j读取xml(opml)文件
  13. PTA - 数据库合集4
  14. JAVA常用数据结构
  15. HTML标签--换行标签与段落标签的区别对比
  16. JSON字符串的使用
  17. 三种方法获取公众号文章素材的永久链接
  18. 联想服务器显示系统初始化,[转载]联想服务器系统设置(一)
  19. python实现工具exe自动化
  20. 分块专题整理(分块+莫队)

热门文章

  1. 1 jquery对checkbox的简单操作
  2. 尚未注册 OLE DB 访问接口 SQLNCLI10 7043 错误
  3. learning to rank评价指标
  4. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol52]49.描述在IPsec和TLS后的基本想法
  5. [Leetcode][第1143题][JAVA][最长公共子序列][LCS][动态规划]
  6. Java虚拟机(JVM)面试题大集合
  7. HDU-5532Almost Sorted Array LIS问题
  8. java商城_java开源商城系统的优势是什么?
  9. 微信小程序怎么取mysql_微信小程序如何加载数据库真实数据?
  10. python生成表达式_说说 Python 的生成器表达式