码迷,mamicode.com
首页 > 编程语言 > 详细

CGCTF WxyVM1 WriteUp——IDA Python的使用

时间:2019-11-20 12:27:49      阅读:151      评论:0      收藏:0      [点我收藏+]

标签:c中   correct   replace   命令行   sem   地方   表示   switch   har   

CGCTF WxyVM1 WriteUp——IDA Python的使用

准备工作

  • 题目地址

  • 首先查看文件信息,可以看到,这是个64位elf文件
    技术图片

  • 在Linux上运行起来简单看一下,如果提示没有权限,可以使用sudo chmod +x ./WxyVM1来给予执行的权限
    技术图片

  • 然后拖到IDA-64bit中逆向

分析伪代码

  • 在main函数中,F5生成伪代码如下

技术图片

? 从上面可以看出,输入的flag应该是24长度的。byte_604B80用来表示输入的字符串,v4用来标记是否满足条件。第13-17行,就是用来判断byte_604B80dword_601060是否相同。

  • 再进入sub_4005B6()函数看一下
    技术图片

    byte_604B80还是我们刚才的输入,主体是一个switch-case语句,通过判断v0的值,来确定具体执行的内容,也可以算得上一道虚拟机的题目吧——通过找到虚表,来确定指令的具体操作。

  • 这里,循环的含义是byte_6010C0这段数据中每三字节一组:每组的第一个字节用来作为上述的指令,第二个字节和第三个字节用来对我们的输入(byte_604B80)进行变换,一共要循环5000次。看下byte_6010C0这段数据:
    技术图片

  • 再回到主函数中,我们就可以理清整个流程:

    我们输入的字符串,会被程序内部进行操作(sub_4005B6()函数),转化为新的字符串,只有新的字符串与dword_601060相同,才会输出correct

    那只需要逆向操作,将dword_601060放入sub_4005B6()中逆向操作,就可以得到原始应该输入的字符串,也就是flag

  • 这里面,有几个需要注意的地方:

    • dword_601060用到的,应该是Dword中的一个字节,而不是四字节。dword_601060数据如下:

      .data:0000000000601060 dword_601060    dd 0FFFFFFC4h           ; DATA XREF: main+6E↑r
      .data:0000000000601064                 dd 34h
      .data:0000000000601068                 dd 22h
      .data:000000000060106C                 dd 0FFFFFFB1h
      .data:0000000000601070                 dd 0FFFFFFD3h
      .data:0000000000601074                 dd 11h
      .data:0000000000601078                 dd 0FFFFFF97h
      .data:000000000060107C                 dd 7
      .data:0000000000601080                 dd 0FFFFFFDBh
      .data:0000000000601084                 dd 37h
      .data:0000000000601088                 dd 0FFFFFFC4h
      .data:000000000060108C                 dd 6
      .data:0000000000601090                 dd 1Dh
      .data:0000000000601094                 dd 0FFFFFFFCh
      .data:0000000000601098                 dd 5Bh
      .data:000000000060109C                 dd 0FFFFFFEDh
      .data:00000000006010A0                 dd 0FFFFFF98h
      .data:00000000006010A4                 dd 0FFFFFFDFh
      .data:00000000006010A8                 dd 0FFFFFF94h
      .data:00000000006010AC                 dd 0FFFFFFD8h
      .data:00000000006010B0                 dd 0FFFFFFB3h
      .data:00000000006010B4                 dd 0FFFFFF84h
      .data:00000000006010B8                 dd 0FFFFFFCCh
      .data:00000000006010BC                 dd 8
      .data:00000000006010C0 ; char byte_6010C0[15000]

      所以,以第一个dword为例,比较的应该是0xC4,而不是0x0FFFFFFC4

    • sub_4005B6()函数中,循环是正向的,一次一次对我们输入的数据进行更新迭代,而在我们逆向求解的过程中,循环也应该是逆向的,即byte_604B80应该从最后一组进行倒序遍历

  • 思路清楚了,就可以写脚本来输出了

脚本实现

Array_6010C0_0 = [] #用来存储byte_604B80中每一组的第一个元素
Array_6010C0_1 = [] #用来存储byte_604B80中每一组的第二个元素
Array_6010C0_2 = [] #用来存储byte_604B80中每一组的第三个元素
Array_601060 = [] ##用来存储dword_601060中每个dword里需要比较的元素
flag = ""

#将Hex中的字符转换为Dec中对应的数字
def Trans(NumHex):
    NumDec = 0
    if NumHex == 'a':
        NumDec = 10
    elif NumHex == 'b':
        NumDec = 11
    elif NumHex == 'c':
        NumDec = 12
    elif NumHex == 'd':
        NumDec = 13
    elif NumHex == 'e':
        NumDec = 14
    elif NumHex == 'f':
        NumDec =15
    else:
        NumDec = NumHex
    return NumDec

# 将byte_604B80中的数据分别存入下面三个数组中
for index in range(0x6010C0, 0x604B58, 3):
    Array_6010C0_0.append(Byte(index))
    Array_6010C0_1.append(Byte(index+1))
    Array_6010C0_2.append(Byte(index+2))


# 对dword_601060数据进行抽取,转化为需要比较的十进制
for index in range(0x601060, 0x6010BD, 4):
    Array_601060.append(int(Trans(('0' + (hex(Dword(index))).replace('0x', '').replace('L', '')[-2:])[-1])) + 16 * int(
        Trans(('0' + (hex(Dword(index))).replace('0x', '').replace('L', '')[-2:])[-2])))

# 逆向循环,复现sub_4005B6()函数中的VM
for index in range(4999, -1, -1):
    if Array_6010C0_0[index]==1:
        Array_601060[Array_6010C0_1[index]] = Array_601060[Array_6010C0_1[index]] - Array_6010C0_2[index]
    elif Array_6010C0_0[index]==2:
        Array_601060[Array_6010C0_1[index]] = Array_601060[Array_6010C0_1[index]] + Array_6010C0_2[index]
    elif Array_6010C0_0[index]==3:
        Array_601060[Array_6010C0_1[index]] = Array_601060[Array_6010C0_1[index]] ^ Array_6010C0_2[index]
    elif Array_6010C0_0[index]==4:
        Array_601060[Array_6010C0_1[index]] = Array_601060[Array_6010C0_1[index]] / Array_6010C0_2[index]
    elif Array_6010C0_0[index]==5:
        Array_601060[Array_6010C0_1[index]] = Array_601060[Array_6010C0_1[index]] ^ flag[Array_6010C0_2[index]]
    else:
        continue

for i in range(24):
  flag += chr(Array_601060[i]%256)

print flag

在IDA的输出中,有nctf{Embr4ce_Vm_j0in_R3}
技术图片

验证Flag

  • 在命令行中输入,有如下结果,证明结果正确
    技术图片

  • 有空再整理一下IDA python的内容,先挖个坑

CGCTF WxyVM1 WriteUp——IDA Python的使用

标签:c中   correct   replace   命令行   sem   地方   表示   switch   har   

原文地址:https://www.cnblogs.com/xrblog/p/11896841.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!