# UIUCTF

做了一道题就摆烂了 (第二天考试) Win95 的主题挺有特色

# VMWHERE1

image-20230701112737549

给了两个文件一个 chal 是虚拟机程序 一个 program 是二进制文件 就是需要用虚拟机载入的程序

# chal

image-20230703143835828

IDA7.7 打开虚拟机程序,逻辑很清晰 while 循环和 switch-case 其中每一个 case 对应一个操作

可以用 x86 汇编指令近似理解

  • case 0: 返回指令(ret)
  • case 1: 加法指令(add)
  • case 2: 减法指令(sub)
  • case 3: 位与指令(and)
  • case 4: 位或指令(or)
  • case 5: 位异或指令(xor)
  • case 6: 左移指令(shl)
  • case 7: 右移指令(shr)
  • case 8: 获取输入指令(getchar)
  • case 9: 输出指令(putchar)
  • case 0xA: 赋值指令(push)
  • case 0xB: 条件跳转指令(jz)
  • case 0xC: 条件跳转指令(jnz)
  • case 0xD: 无条件跳转指令(jmp)
  • case 0xE: 减一指令(dec)
  • case 0xF: 复制
  • case 0x28: 调用子函数指令

这里注意一点是通过 getchar () 函数读取输入,而 C 语言的 getchar () 函数一次只读取一个,多余的都会忽略,可以猜测对 flag 的验证是一位一位的验证

# program

010Editor 打开

image-20230703144613400

可以看到文件开头和结尾则是程序运行和结束时会提示的字符串 中间就是需要分析的 code

# 动态调试

思路是在输入时候下断点 只分析后面的 code 就行了

image-20230703145015778

在 getchar () 这里下断点 (每个指令后面的 goto LABEL_31 不用管,就是验证指令是否合法以及栈是否溢出)

然后一直 F8 找到验证 flag 的逻辑 发现每当运行在这里 也就是程序 code 为 08 0F 0A 04 07 05 05 0F 0A XX 05 0C 00 03 0D 是一个固定的一串指令在 program 中是负责对 flag 的每一位进行检查 (v10 的前一位是否为 0) 通过即跳转 若错误则会进入 0xD 的跳转 然后就跳转到 program 末尾 输出错误字符串

image-20230701152849383

于是我们的目标就是让他通过验证就行了 而每一位的验证逻辑都一样 分析第一位就行了

这里我写了前三位的示例

(password[0]>>4) ^ password[0] ^ 0x72 ^ 0x00==0 password[0]=’u’

(password[1]>>4) ^ password[1] ^ 0x72 ^ 0x1d==0 password[1]= ‘i’

(password[2]>>4) ^ password[2] ^ 0x1d ^ 0x6f==0 password[2]=’u’

(password[i]>>4) ^ password[i] ^ 0xXX ^ 0xXX==0

08 0F 0A 04 07 05 05 0F 0A XX 05 0C 00 03 0D 的验证逻辑就是这样,其中除了第一位的第一个 0xXX 的值为 0x00 后面的 0xXX 的值都是 push 进去的值和前一次验证时 push 的值

QQ图片20230701164247

直接在 program 中找出 0xXX 再自己异或就行辣

for password_0 in range(256):
    if ((password_0 >> 4) ^ password_0 ^ 0x72^0x1d) == 0:
        print("password[0] =", password_0)
        break
......
类似这样解出所有位就行了
uiuctf{ar3_y0u_4_r3al_vm_wh3r3_(gpt _g3n3r4t3d _th1s _f14g)}

QQ图片20230703140220

# VMWHERE2

输入第一位变二进制 再 push ff

image-20230702115936644

前一位 0xff

image-20230702121556088

没做了 蹲 WP

更新于 阅读次数