吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8666|回复: 20
收起左侧

[CTF] 【CTF习题】HomuraVM

  [复制链接]
whklhh 发表于 2017-12-17 20:53
本帖最后由 whklhh 于 2017-12-17 21:05 编辑

南邮的Re师傅们真是热爱VM啊……OTZ

这一题比WxyVM的两个要难一点,却又比asm汇编级别的解释器简单许多,感谢南邮师傅们(吼姆拉酱?ww)恰到好处的难度控制

题目为ELF文件,需要运行在Linux系统下

拖入IDA,结构很清晰
将输入拷贝到一个数组中,然后初始化机器码
变换后进行check

很明显解释器就是sub_8DC,而sub_8AA则是反调试

对sub_8DC进行反编译,发现不完整
这里写图片描述
这里的JUMPOUT就是用来跳转至对应解释函数的语句
不过对机器码进行解析的部分都反编译出来了,就是每个字符-67后去dword_1048中寻找偏移值,然后以dword_1048为基准进行跳转

jmp base[a[`i]-67] + base

回到汇编状态进行分析各个解释函数

这里写图片描述
可以看到有这么多,不过还好它们的核心语句基本上就只有一两行汇编,逐个记录即可

主要变量有两个计数器a和i,分别表示读取input和机器码的下标
两个寄存器qword_202080和qword_202088,下将其称为n1和n2

简单的函数如下

93c: a += 1
962: a -= 1

988: input[a] += 1
9aa: input[a] -= 1

9cc: n1 += 1
9ee: n1 -= 1

a10: n2 = n1
a36: n2 = n1 + input[a]
a67: n2 -= (n1&input[a])*2
aa6: n2 -= 1
ac8: n2 += 1

比较复杂的4个函数:

aea: if(input[a]!=0){b1d}else{af8}  
af8: i++;if(k[`i]==0x5d){c23}else{af8}
b1d: i++;

b31: if(input[a]!=0){b79}else{b3f}  
b3f: i--;if(k[`i]==0x5b){i++;c23}:else{b3f}
b79: i++;

b8d: if(n2!=0){bbd}else{b9b} 
b9b: i++;if(k[`i]==0x7d){c23}else{b9b}
bbd: i++;

bce: if(n2!=0){c13}else{bdc}  
bdc: i--;if(k[`i]==0x7b){i++;c23}else{bdc}  
c13: i++;

这4个函数是循环结构,通过input[a]和n2来进行判断,通过i来控制执行的语句
其中0x5d 0x5b 0x7d 0x7b这4个终止值让人比较在意,char分别是"[]{}"
看起来可能有点复杂,没关系,等会儿再继续解析

表示出现的机器码和解释函数对应关系:

# dword_1048处dump出来的偏移数组
n = [0xa67, 0xc23, 0xc23, 0xc23, 0xaa6, 0xc23, 0xc23, 0xc23, 0xc23, 0xc23, 0xa36, 0xc23, 0xc23, 0xc23, 0xc23, 0xc23, 0xc23, 0xac8, 0xc23, 0xc23, 0xc23, 0xc23, 0xc23, 0xc23, 0xaea, 0xc23, 0xb31, 0xc23, 0xc23, 0xc23, 0x9ee, 0xc23, 0xc23, 0xc23, 0xc23, 0xc23, 0xc23, 0x93c, 0xc23, 0xc23, 0xc23, 0xc23, 0x988, 0xc23, 0x962, 0xc23, 0xc23, 0x9cc, 0xc23, 0xc23, 0x9aa, 0xa10, 0xc23, 0xc23, 0xc23, 0xc23, 0xb8d, 0xc23, 0xbce]
s = "ahmoruvCMG[]{}"

for i in s:
    print(i, hex(n[ord(i)-67])[2:])

可以生成一份表(第三列代码部分是另加的对应字典)
这里写图片描述

这里可以看到,[]对应构成一个循环,{}对应构成一个循环
以'['和']'为例
当遇到'['时,判断input[a]是否==0,为0则直接跳到']'后,否则运行[]内的代码
当遇到']'时,判断input[a]是否==0,为0则继续运行后面的内容,否则返回到'['前

实际上就是一个while循环
这个思想挺像以前看到的BrainF@ck语言来着

观察机器码,发现只有三种循环:{aG}{mG}[ur]
这样可以针对性地翻译出它们的对应代码来降低理解难度:
(为了书写方便将input[a]简写为s[a],下同)

{mG}: s[a] += n2; n2=0
{aG}: n1 -= n2; n2=0
[ur]: n1 += s[a]; s[a]=0

(其实上一步可以省略)
分析机器码,发现大量的重复部分,区别只是中间的a和r
这里写图片描述
这样翻译起来就简单很多了
(感谢出题师傅手下留情)

尝试解析重复的部分,发现n2可以被消去
解析完以后发现h代表input下标+1,因此以它作为分界线更为合适
也就是说,将不同的a和r放在代码块的中间
通过正则表达式分组出如下代码:
这里写图片描述

虽然第一句长的不太一样,但是解析以后发现效果其实相同
每一行翻译出的伪代码为:

a += 1
n1 = 0
n2 = 0

n1 = s[a]

# n1根据a和r改变
...

# 计算
s[a] = n1+s[a-1] - (n1&s[a-1])*2

注意这里的s[a-1]是计算后的内容了
也就是说正向算法是

# x为不同行中的改变内容
f(计算前的s[a] + x,计算后的s[a-1]) = 计算后的s[a]

这样就得到了递推公式
虽然计算方法有点点复杂,无法逆运算
不过数据范围都在一个比特内,因此只有256种可能,穷举即可

# 有可能会出现多解情况,已验证皆为一解,因此可以直接return
def find(x, y):
    for z in range(256):
        if(y == x + z - (x & z) * 2):
            return z

于是根据递推公式可以逆求出所有的计算前的input


for i in range(1, 34):
    # 逆求值
    p = find(n[i-1], n[`i])
    # 修正对n1的改变
    offset = (o[`i].count('a')-1) - (o[`i].count('r')-1)
    print(chr(p + offset), end='')

得到flag

开头少了一位,是因为在赋值的时候

 *(_DWORD *)input_q = input[strlen(input) - 1];

将最后一位赋给了第一位(之后的操作全部都是从第二位开始的)
通过最后一位和第一位的值同样可以逆推出原值,直接根据格式猜也行233

另外check的地方有一个bug:

  for ( j = 0; j <= 33; ++j )
  {
    if ( *(&v5 + j) != v42[j + 1LL] )
    {
      puts("GG!");
      exit(0);
    }
  }
  puts("correct!");

意味着只要满足前34位值相同即可
而解释器的结束条件是机器码读取完毕,也就是说仅会对前34位进行变换
开始输入的地方也没有对长度进行校验

因此满足check的条件就是
正确flag + 任意位字符 (最后一位为'}')
这里写图片描述

不过flag显而易见所以无伤大雅啦~

PS:
静态分析被指针、内存等等搞乱了的时候,需要动态调试来观察内存中的变化
因此动态调试还是挺有必要滴:
这个反调试函数是通过比较是否Sessionid和ppid来判断的:

  v1 = getsid(v0);
  result = getppid();
  if ( v1 != result )
    exit(0);
  return result;

如果是调试器开启的程序则会导致ppid和sid不等,进而退出程序
最简单的方法就是直接patch,将0x8AA的首字节改为0x3c(retn)
不清楚gdb有没有附加调试功能,以及附加能不能过这个反调方法呢~



_(:з」∠)_[`i]会被误认为是斜体的标识符,于是我在代码中全部加上了反引号来破坏格式
版主大大们有空修正一下呗~

homuraVM.rar

3.03 KB, 下载次数: 14, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 4威望 +2 吾爱币 +12 热心值 +4 收起 理由
孟德兄 + 1 用心讨论,共获提升!
?﹏從此沉默 + 1 + 1 谢谢@Thanks!
曹大哥丶 + 1 + 1 用心讨论,共获提升!
Poner + 2 + 10 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

zbnysjwsnd8 发表于 2017-12-17 21:02
支持一下。
楼主太厉害了。。。动不动就逆VM
 楼主| whklhh 发表于 2018-1-3 14:55
wjbsyc 发表于 2018-1-3 00:16
emmmmm出题人来了,那啥 (a+b)-2(a&b) 这个公式是可逆的,而且其实是一个很简单的运算,你动态调试一波,观察每 ...

折腾了一下没想到怎么逆 求师傅指教
 楼主| whklhh 发表于 2017-12-17 21:06
zbnysjwsnd8 发表于 2017-12-17 21:02
支持一下。
楼主太厉害了。。。动不动就逆VM

dalao说笑了 这就入门级的VM 哪能入得了你的眼
zbnysjwsnd8 发表于 2017-12-17 21:06
whklhh 发表于 2017-12-17 21:06
dalao说笑了 这就入门级的VM 哪能入得了你的眼

不不不 你才是dalao
艾莉希雅 发表于 2017-12-17 21:36
楼上互吹中
kk1212 发表于 2017-12-17 21:43
很详细,感谢楼主,辛苦了
6767 发表于 2017-12-17 23:24
围观1。2楼互吹
小九i 发表于 2017-12-18 10:12
mark 学习了  VM
创始人123 发表于 2017-12-18 10:29
谢谢分享神文!!!
rendercc 发表于 2017-12-18 12:35
很详细,感谢楼主,辛苦了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 13:47

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表