XCTF-攻防世界CTF平台-Reverse逆向类——57、re5-packed-movement(linux32位ELF文件、movfuscator代码混淆)
目录标题
- 方法一:搜索字节序列
- 方法二:IDC脚本
- 方法三:Python脚本:
- 方法四:bgrep工具
先查看文件信息:
是linux下的32位ELF文件,且被加了UPX的壳
下载最新版的UPX脱壳,UPX脱壳的Githup地址:https://github.com/upx/upx/releases/tag/v3.91
之后脱壳,指定加壳文件57,输出脱壳文件57move
upx -d 57 -o 57move
赋执行权限运行程序:
用IDA打开57move,找到字符串“Guess a flag:”
有两个位置使用了这个字符串:
同样地,我们查看“Wrong Flag!”字符串:
发现有70个引用的地方。
但是我们可以看到程序的汇编代码全都是mov,肯定是被混淆过了,这里是用了movfuscator来混淆,。
剑桥大学的Stephen Dolan证明了x86的mov指令是图灵完全的(论文《mov is Turing-complete》)。这意味着从理论上来讲,x86只要有mov这一条指令就可以完成几乎所有功能了(可能还需要jmp),其他指令都是“多余的”。受此启发,有个大牛做了一个虚拟机加密编译器。它是一个修改版的LCC编译器,输入是C语言代码,输出的obj里面直接包含了虚拟机加密后的代码。如它的名字,函数的所有代码只有mov指令,没有其他任何指令。对,完全没有,连call,jz,ret之类的都没有。
开源项目地址:https://github.com/xoreaxeaxeax/movfuscator
M/o/Vfuscator(简称“o”,听起来像“mobfuscator”)将程序编译成“mov”指令,并且只编译“mov”指令。算术、比较、跳转、函数调用,以及程序需要的一切,都是通过mov操作完成的;没有自修改代码,没有传输触发的计算,也没有其他形式的非 mov 作弊。
继续直接分析原程序:
这类movfuscator 混淆后的程序,MOV混淆是不会混淆函数的逻辑的,因此函数的逻辑还是不变的。大多都是通过逐个比较输入后的字符串的每个字符的方式,比较结果不对就输出“Wrong Flag!”,所以在程序当中就会出现单个的字符,例如:
.text:080493DB C7 05 68 20 06 08 41 00 00 00 mov R2, 41h ; 'A'
movfuscator 混淆后的程序都是通过R2寄存器来存储常量字符,
方法一:搜索字节序列
直接在IDA中搜索字节序列:字符串C7 05 68 20 06 08(“mov R2,”对应字节码)
得到程序中所有使用的常量字符:
连起来就是程序的flag:ALEXCTF{M0Vfusc4t0r_w0rk5_l1ke_m4g1c}
输入到程序验证:
Well Done,这就是正确的flag。
方法二:IDC脚本
也可以用IDA中的IDC脚本和Python脚本来提取代码段中的常量字符:
#include<idc.idc>
static isAscii(p) //判断符合条件的字符
{if(Byte(p)<='9' && Byte(p)>='0')return 1;if(Byte(p)<='z' && Byte(p)>='a')return 1;if(Byte(p)<='Z' && Byte(p)>='A')return 1;if(Byte(p)=='}' || Byte(p)=='{' || Byte(p)=='_' || Byte(p)=='@' || Byte(p)=='!' || Byte(p)=='#' || Byte(p)=='&' || Byte(p)=='*')return 1;return 0;
}
static main()
{auto start=0x0804829C,end=0x08060B32; //代码段起止地址auto point=start;auto str="";while(point<=end){if(isAscii(point) && Byte(point+1)==0 && Byte(point+2)==0 && Byte(point+3)==0) { //汇编中立即数一般都是DWORDMessage("%X %c\n",point,Byte(point));str=str+Byte(point);}point=point+1;}Message("%s\n",str); //可能是flag
}
运行结果:
得到flag:ALEXCTF{M0Vfusc4t0r_w0rk5_l1ke_m4g1c}
方法三:Python脚本:
start=0x0804829C
end=0x08060B32
flag = ""
while start<end:if (Byte(start) <= ord('9') and Byte(start)>=ord('0')) or (Byte(start)<=ord('z') and Byte(start)>=ord('a')) or (Byte(start)<=ord('Z') and Byte(start)>=ord('A')) or (Byte(start) == ord('}')) or (Byte(start) == ord('{')) or (Byte(start) == ord('_')) or (Byte(start) == ord('@')) or (Byte(start) == ord('!')) or (Byte(start) == ord('#')) or (Byte(start) == ord('&')) or (Byte(start) == ord('*')):if Byte(start) and (Byte(start+1)==0) and (Byte(start+2)==0) and (Byte(start+3)==0):print(chr(Byte(start)))flag += chr(Byte(start))start += 1
print(flag)
运行结果:
脚本找到的运行结果flag中都出现了字符2,这是因为脚本在判断的时候的逻辑是:从代码段.text起止地址0x0804829C到0x08060B32,只要字符的ASCII值在数字、大小写字母和几个特殊字符中,即可认为是flag中的一个字符,所以这中判断逻辑是可能出现误判的:
得到flag:ALEXCTF{M0Vfusc4t0r_w0rk5_l1ke_m4g1c}
方法四:bgrep工具
我们从前面的IDA中知道.text:080493DB上的字节序列:字符串C7 05 68 20 06 08(“mov R2,”对应字节码),表明标志的字符是硬编码在二进制文件中的:
bgrep工具:
用法:
bgrep [-B 字节] [-A 字节] [-C 字节] [ […]]
-B:bytes_before
-A:bytes_after
-C:bytes_before 和 bytes_after
先安装:
bgrep "C70568200608" ./57move
查找程序当中字节序列:C70568200608
得到的是所有出现的字节序列C70568200608的文件偏移地址,之后+6是字节序列C70568200608的长度是6,再从当前的文件读取指针位置读取一个字节的字符,拼接起来所有的字符就是flag。
Python脚本:
#!/usr/bin/env python2offsets = [0x000013db, 0x00001dde, 0x000027e1, 0x000031e4, 0x00003b9c, 0x0000459f, 0x00004fa2, 0x000059a5, 0x00006357, 0x00006d5a, 0x0000775d, 0x00008160, 0x00008b0c, 0x0000950f, 0x00009f12, 0x0000a915, 0x0000b2bb, 0x0000bcbe, 0x0000c6c1, 0x0000d0c4, 0x0000da64, 0x0000e467, 0x0000ee6a, 0x0000f86d, 0x00010207, 0x00010c0a, 0x0001160d, 0x00012010, 0x000129a4, 0x000133a7, 0x00013daa, 0x000147ad, 0x0001513b, 0x00015b3e, 0x00016541, 0x00016f44, 0x000178cc]with open('./57move') as f:flag = ''for offset in offsets:# "mov R2, 41h" is "C70568200608"+"41000000" (the immediate starts after the 6th byte)# 移动文件读取指针到指定位置f.seek(offset + 0x6)#从当前的文件读取指针位置读取一个字节的字符,+6是字节序列C70568200608的长度是6flag += f.read(1)
print flag
运行结果:
得到flag:ALEXCTF{M0Vfusc4t0r_w0rk5_l1ke_m4g1c}
XCTF-攻防世界CTF平台-Reverse逆向类——57、re5-packed-movement(linux32位ELF文件、movfuscator代码混淆)相关推荐
- XCTF-攻防世界CTF平台-Reverse逆向类——52、handcrafted-pyc(Python的pyc文件逆向)
下载题目附件之后,查看附件52: 发现它就是一个Python代码文件 #!/usr/bin/env python # -*- coding: utf-8 -*-import marshal, zlib ...
- XCTF-攻防世界CTF平台-Reverse逆向类——56、tar-tar-binks(Mac平台下的64位动态链接共享库.dylib逆向)
目录标题 一.解压缩 二.查看文件 三.分析程序 四.程序主要逻辑: 五.逆向思路: 步骤一: 步骤二: 六.解密代码: 题目提供了两个文件flag.tar和libarchive.dylib 一.解压 ...
- 【ics-05 | mfw】攻防世界CTF题WP
攻防世界CTF题WP ics-05 所需知识 解题步骤 学习知识 php伪协议(文件包含漏洞中使用) preg_place函数 mfw 所需知识 解题步骤 学习知识 Dirserach工具 GitHa ...
- XCTF攻防世界 Normal_RSA
XCTF攻防世界 Normal_RSA 实验环境: windows 10 实验所需工具: python工具: yafu (可以在https://github.com/DarkenCode/yafu上下 ...
- XCTF攻防世界Web新手入门题大全
XCTF攻防世界Web之WriteUp无图版 (Tips:有图版本,请移步我的资源,自行下载doc文档) 0x00 准备 [内容] 在xctf官网注册账号,即可食用. [目录] 目录 0x01 vie ...
- XCTF攻防世界Web之WriteUp
XCTF攻防世界Web之WriteUp 0x00 准备 [内容] 在xctf官网注册账号,即可食用. [目录] 目录 0x01 view-source2 0x02 get post3 0x03 rob ...
- XCTF攻防世界练习区-web题(新手)
XCTF攻防世界练习区-web题(新手) https://adworld.xctf.org.cn/task?now_checked_num=3&name=web 001 view_source ...
- XCTF攻防世界BABYRE逆向
攻防世界BABYRE逆向 拿到题目,查壳如下: 拖拽IDA Pro7.5打开,查看main函数,代码如下: 可以看到: (*(unsigned int (__fastcall **)(char *)) ...
- xctf攻防世界 crypto 新手练习区--write up(持续更新中)
文章目录 base64 Caesar Morse Railfence 不仅仅是Morse easy RSA RSA算法 简介 RSA计算公钥和私钥 混合编码 转轮机加密 回转轮加密 base64 题目 ...
最新文章
- AttributeError: Cant get attribute SPPF on module models
- 阿里算法,浙大博士带你写项目经历!
- 网站推广的三大基本方式
- java path设置错误_linux下环境变量PATH设置错误的补救
- C/C++之 C++ String(字符串)
- C++实现二分查找(附完整源码)
- linux下屏幕太靠右了,怎么消除linux下的屏幕偏移现象和调整屏幕刷新率?
- Qt中的TableWidget初始化表头、行高、选中、自动扩展和接受修改
- b站测试岗怎么样_情商测试《大家一起察言观色》,一款适合作为B站测试题的游戏...
- “网页上有错误”的解决方法
- 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,
- 物流配送信息管理系统java_基于jsp的物流配送管理系统-JavaEE实现物流配送管理系统 - java项目源码...
- android mp3 lrc歌词文件utf-8歌词显示为乱码,Android访问Tomcat错误以及mp3player项目乱码问题解决...
- 【Oracle】IF EXISTS用法
- 阿里云服务器如何购买?三种购买阿里云服务器方式教程分享
- 如何给PDF加水印,PDF加水印的快速方法
- mov格式如何转换成mp4?详细步骤教程
- 他一年写了200篇原创笔记,帮助你快速入门Python与机器学习
- MySQL8 免安装版安装
- 思科光纤模块兼容性解决