逆向ctf-z3

博客介绍了如何通过分析64位的Z3.exe程序,使用ida进行反汇编,找出主函数中的数学方程式。接着利用Python的z3库建立约束并求解,得到一组数值,最后将这些数值转换为ASCII码,得到最终的flag。整个过程展示了逆向工程和代码解析的技术应用。
摘要由CSDN通过智能技术生成

一、z3.exe运行效果

二、使用exeinfope查壳工具看是否加壳:

结果显示为无壳,那就简单了。既然是64位,那就用IDA64位进行查看,找到主函数F5反汇编得到:


int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rdx@1
  __int64 v4; // rdx@1
  __int64 v5; // rdx@3
  int v7; // [sp+20h] [bp-60h]@1
  int v8; // [sp+24h] [bp-5Ch]@1
  int v9; // [sp+28h] [bp-58h]@1
  int v10; // [sp+2Ch] [bp-54h]@1
  int v11; // [sp+30h] [bp-50h]@1
  int v12; // [sp+34h] [bp-4Ch]@1
  int v13; // [sp+38h] [bp-48h]@1
  int v14; // [sp+3Ch] [bp-44h]@1
  int v15; // [sp+40h] [bp-40h]@1
  int v16; // [sp+44h] [bp-3Ch]@1
  int v17; // [sp+48h] [bp-38h]@1
  int v18; // [sp+4Ch] [bp-34h]@1
  int v19; // [sp+50h] [bp-30h]@1
  int v20; // [sp+54h] [bp-2Ch]@1
  int v21; // [sp+58h] [bp-28h]@1
  int v22; // [sp+5Ch] [bp-24h]@1
  int v23; // [sp+60h] [bp-20h]@1
  int v24; // [sp+64h] [bp-1Ch]@1
  int v25; // [sp+68h] [bp-18h]@1
  int v26; // [sp+6Ch] [bp-14h]@1
  int v27; // [sp+70h] [bp-10h]@1
  int v28; // [sp+74h] [bp-Ch]@1
  int v29; // [sp+78h] [bp-8h]@1
  int v30; // [sp+7Ch] [bp-4h]@1
  int v31; // [sp+80h] [bp+0h]@1
  int v32; // [sp+84h] [bp+4h]@1
  int v33; // [sp+88h] [bp+8h]@1
  int v34; // [sp+8Ch] [bp+Ch]@1
  int v35; // [sp+90h] [bp+10h]@1
  int v36; // [sp+94h] [bp+14h]@1
  int v37; // [sp+98h] [bp+18h]@1
  int v38; // [sp+9Ch] [bp+1Ch]@1
  int v39; // [sp+A0h] [bp+20h]@1
  int v40; // [sp+A4h] [bp+24h]@1
  int v41; // [sp+A8h] [bp+28h]@1
  int v42; // [sp+ACh] [bp+2Ch]@1
  int v43; // [sp+B0h] [bp+30h]@1
  int v44; // [sp+B4h] [bp+34h]@1
  int v45; // [sp+B8h] [bp+38h]@1
  int v46; // [sp+BCh] [bp+3Ch]@1
  int v47; // [sp+C0h] [bp+40h]@1
  int v48; // [sp+C4h] [bp+44h]@1
  unsigned __int8 v49; // [sp+D0h] [bp+50h]@1
  unsigned __int8 v50; // [sp+D1h] [bp+51h]@1
  unsigned __int8 v51; // [sp+D2h] [bp+52h]@1
  unsigned __int8 v52; // [sp+D3h] [bp+53h]@1
  unsigned __int8 v53; // [sp+D4h] [bp+54h]@1
  unsigned __int8 v54; // [sp+D5h] [bp+55h]@1
  unsigned __int8 v55; // [sp+D6h] [bp+56h]@1
  unsigned __int8 v56; // [sp+D7h] [bp+57h]@1
  unsigned __int8 v57; // [sp+D8h] [bp+58h]@1
  unsigned __int8 v58; // [sp+D9h] [bp+59h]@1
  unsigned __int8 v59; // [sp+DAh] [bp+5Ah]@1
  unsigned __int8 v60; // [sp+DBh] [bp+5Bh]@1
  unsigned __int8 v61; // [sp+DCh] [bp+5Ch]@1
  unsigned __int8 v62; // [sp+DDh] [bp+5Dh]@1
  unsigned __int8 v63; // [sp+DEh] [bp+5Eh]@1
  unsigned __int8 v64; // [sp+DFh] [bp+5Fh]@1
  unsigned __int8 v65; // [sp+E0h] [bp+60h]@1
  unsigned __int8 v66; // [sp+E1h] [bp+61h]@1
  unsigned __int8 v67; // [sp+E2h] [bp+62h]@1
  unsigned __int8 v68; // [sp+E3h] [bp+63h]@1
  unsigned __int8 v69; // [sp+E4h] [bp+64h]@1
  unsigned __int8 v70; // [sp+E5h] [bp+65h]@1
  unsigned __int8 v71; // [sp+E6h] [bp+66h]@1
  unsigned __int8 v72; // [sp+E7h] [bp+67h]@1
  unsigned __int8 v73; // [sp+E8h] [bp+68h]@1
  unsigned __int8 v74; // [sp+E9h] [bp+69h]@1
  unsigned __int8 v75; // [sp+EAh] [bp+6Ah]@1
  unsigned __int8 v76; // [sp+EBh] [bp+6Bh]@1
  unsigned __int8 v77; // [sp+ECh] [bp+6Ch]@1
  unsigned __int8 v78; // [sp+EDh] [bp+6Dh]@1
  unsigned __int8 v79; // [sp+EEh] [bp+6Eh]@1
  unsigned __int8 v80; // [sp+EFh] [bp+6Fh]@1
  unsigned __int8 v81; // [sp+F0h] [bp+70h]@1
  unsigned __int8 v82; // [sp+F1h] [bp+71h]@1
  unsigned __int8 v83; // [sp+F2h] [bp+72h]@1
  unsigned __int8 v84; // [sp+F3h] [bp+73h]@1
  unsigned __int8 v85; // [sp+F4h] [bp+74h]@1
  unsigned __int8 v86; // [sp+F5h] [bp+75h]@1
  unsigned __int8 v87; // [sp+F6h] [bp+76h]@1
  unsigned __int8 v88; // [sp+F7h] [bp+77h]@1
  unsigned __int8 v89; // [sp+F8h] [bp+78h]@1
  unsigned __int8 v90; // [sp+F9h] [bp+79h]@1
  int v91[43]; // [sp+110h] [bp+90h]@1
  int i; // [sp+1BCh] [bp+13Ch]@1

  _main(*(_QWORD *)&argc, argv, envp);
  memcpy(*(_QWORD *)&argc, argv, &unk_404020, v91, 168LL);
  printf(*(_QWORD *)&argc, argv, v3, "plz input your flag:");
  scanf(*(_QWORD *)&argc, argv, &v49, "%42s");
  v7 = 34 * v52 + 12 * v49 + 53 * v50 + 6 * v51 + 58 * v53 + 36 * v54 + v55;
  v8 = 27 * v53 + 73 * v52 + 12 * v51 + 83 * v49 + 85 * v50 + 96 * v54 + 52 * v55;
  v9 = 24 * v51 + 78 * v49 + 53 * v50 + 36 * v52 + 86 * v53 + 25 * v54 + 46 * v55;
  v10 = 78 * v50 + 39 * v49 + 52 * v51 + 9 * v52 + 62 * v53 + 37 * v54 + 84 * v55;
  v11 = 48 * v53 + 14 * v51 + 23 * v49 + 6 * v50 + 74 * v52 + 12 * v54 + 83 * v55;
  v12 = 15 * v54 + 48 * v53 + 92 * v51 + 85 * v50 + 27 * v49 + 42 * v52 + 72 * v55;
  v13 = 26 * v54 + 67 * v52 + 6 * v50 + 4 * v49 + 3 * v51 + 68 * v55;
  v14 = 34 * v59 + 12 * v56 + 53 * v57 + 6 * v58 + 58 * v60 + 36 * v61 + v62;
  v15 = 27 * v60 + 73 * v59 + 12 * v58 + 83 * v56 + 85 * v57 + 96 * v61 + 52 * v62;
  v16 = 24 * v58 + 78 * v56 + 53 * v57 + 36 * v59 + 86 * v60 + 25 * v61 + 46 * v62;
  v17 = 78 * v57 + 39 * v56 + 52 * v58 + 9 * v59 + 62 * v60 + 37 * v61 + 84 * v62;
  v18 = 48 * v60 + 14 * v58 + 23 * v56 + 6 * v57 + 74 * v59 + 12 * v61 + 83 * v62;
  v19 = 15 * v61 + 48 * v60 + 92 * v58 + 85 * v57 + 27 * v56 + 42 * v59 + 72 * v62;
  v20 = 26 * v61 + 67 * v59 + 6 * v57 + 4 * v56 + 3 * v58 + 68 * v62;
  v21 = 34 * v66 + 12 * v63 + 53 * v64 + 6 * v65 + 58 * v67 + 36 * v68 + v69;
  v22 = 27 * v67 + 73 * v66 + 12 * v65 + 83 * v63 + 85 * v64 + 96 * v68 + 52 * v69;
  v23 = 24 * v65 + 78 * v63 + 53 * v64 + 36 * v66 + 86 * v67 + 25 * v68 + 46 * v69;
  v24 = 78 * v64 + 39 * v63 + 52 * v65 + 9 * v66 + 62 * v67 + 37 * v68 + 84 * v69;
  v25 = 48 * v67 + 14 * v65 + 23 * v63 + 6 * v64 + 74 * v66 + 12 * v68 + 83 * v69;
  v26 = 15 * v68 + 48 * v67 + 92 * v65 + 85 * v64 + 27 * v63 + 42 * v66 + 72 * v69;
  v27 = 26 * v68 + 67 * v66 + 6 * v64 + 4 * v63 + 3 * v65 + 68 * v69;
  v28 = 34 * v73 + 12 * v70 + 53 * v71 + 6 * v72 + 58 * v74 + 36 * v75 + v76;
  v29 = 27 * v74 + 73 * v73 + 12 * v72 + 83 * v70 + 85 * v71 + 96 * v75 + 52 * v76;
  v30 = 24 * v72 + 78 * v70 + 53 * v71 + 36 * v73 + 86 * v74 + 25 * v75 + 46 * v76;
  v31 = 78 * v71 + 39 * v70 + 52 * v72 + 9 * v73 + 62 * v74 + 37 * v75 + 84 * v76;
  v32 = 48 * v74 + 14 * v72 + 23 * v70 + 6 * v71 + 74 * v73 + 12 * v75 + 83 * v76;
  v33 = 15 * v75 + 48 * v74 + 92 * v72 + 85 * v71 + 27 * v70 + 42 * v73 + 72 * v76;
  v34 = 26 * v75 + 67 * v73 + 6 * v71 + 4 * v70 + 3 * v72 + 68 * v76;
  v35 = 34 * v80 + 12 * v77 + 53 * v78 + 6 * v79 + 58 * v81 + 36 * v82 + v83;
  v36 = 27 * v81 + 73 * v80 + 12 * v79 + 83 * v77 + 85 * v78 + 96 * v82 + 52 * v83;
  v37 = 24 * v79 + 78 * v77 + 53 * v78 + 36 * v80 + 86 * v81 + 25 * v82 + 46 * v83;
  v38 = 78 * v78 + 39 * v77 + 52 * v79 + 9 * v80 + 62 * v81 + 37 * v82 + 84 * v83;
  v39 = 48 * v81 + 14 * v79 + 23 * v77 + 6 * v78 + 74 * v80 + 12 * v82 + 83 * v83;
  v40 = 15 * v82 + 48 * v81 + 92 * v79 + 85 * v78 + 27 * v77 + 42 * v80 + 72 * v83;
  v41 = 26 * v82 + 67 * v80 + 6 * v78 + 4 * v77 + 3 * v79 + 68 * v83;
  v42 = 34 * v87 + 12 * v84 + 53 * v85 + 6 * v86 + 58 * v88 + 36 * v89 + v90;
  v43 = 27 * v88 + 73 * v87 + 12 * v86 + 83 * v84 + 85 * v85 + 96 * v89 + 52 * v90;
  v44 = 24 * v86 + 78 * v84 + 53 * v85 + 36 * v87 + 86 * v88 + 25 * v89 + 46 * v90;
  v45 = 78 * v85 + 39 * v84 + 52 * v86 + 9 * v87 + 62 * v88 + 37 * v89 + 84 * v90;
  v46 = 48 * v88 + 14 * v86 + 23 * v84 + 6 * v85 + 74 * v87 + 12 * v89 + 83 * v90;
  v47 = 15 * v89 + 48 * v88 + 92 * v86 + 85 * v85 + 27 * v84 + 42 * v87 + 72 * v90;
  v4 = 26 * v89 + 67 * v87 + 6 * v85 + 4 * v84 + 3 * (unsigned int)v86;
  v48 = v4 + 68 * v90;
  for ( i = 0; i <= 41; ++i )
  {
    v4 = (unsigned int)*(&v7 + i);
    if ( (_DWORD)v4 != v91[i] )
    {
      printf(*(_QWORD *)&argc, argv, v4, "error");
      exit(*(_QWORD *)&argc, argv, v5, 0LL);
    }
  }
  printf(*(_QWORD *)&argc, argv, v4, "win");
  return 0;
}

这么一段代码,看着是不是很眼熟,没错很明显使用z3约束求解器。当然也可以使用angr(这个特别方便)。上面这一段大致意思就是说解出上述方程组的答案来与v91进行对比,相等就行了。那么v91是什么呢?大家看这里:

看到这个memcpy函数了吗?memcpy函数的原型是 :void *memcpy(void *str1, const void *str2, size_t n)

将str1指向的数据复制大小为n个字节到目标数组str2中。在上述代码中跟进&unk_404020,可以发现对应的v91中的值是:

没错,就是这些字符,这样看不舒服,我们换种方式:

这样就舒服多了,由于是64bit的可以明显看出来,可以分为0x4F17、0x9CF6、.....、0x3A1D这些数。接下来就简单了,上脚本代码:

from z3 import *

s = Solver()
v49, v50, v51, v52, v53, v54, v55 = Ints("v49 v50 v51 v52 v53 v54 v55")
v56, v57, v58, v59, v60, v61, v62 = Ints("v56 v57 v58 v59 v60 v61 v62")
v63, v64, v65, v66, v67, v68, v69 = Ints("v63 v64 v65 v66 v67 v68 v69")
v70, v71, v72, v73, v74, v75, v76 = Ints("v70 v71 v72 v73 v74 v75 v76")
v77, v78, v79, v80, v81, v82, v83 = Ints("v77 v78 v79 v80 v81 v82 v83")
v84, v85, v86, v87, v88, v89, v90 = Ints("v84 v85 v86 v87 v88 v89 v90")

s.add(0x4F17 == 34 * v52 + 12 * v49 + 53 * v50 + 6 * v51 + 58 * v53 + 36 * v54 + v55)
s.add(0x9CF6 == 27 * v53 + 73 * v52 + 12 * v51 + 83 * v49 + 85 * v50 + 96 * v54 + 52 * v55)
s.add(0x8DDB == 24 * v51 + 78 * v49 + 53 * v50 + 36 * v52 + 86 * v53 + 25 * v54 + 46 * v55)
s.add(0x8EA6 == 78 * v50 + 39 * v49 + 52 * v51 + 9 * v52 + 62 * v53 + 37 * v54 + 84 * v55)
s.add(0x6929 == 48 * v53 + 14 * v51 + 23 * v49 + 6 * v50 + 74 * v52 + 12 * v54 + 83 * v55)
s.add(0x9911 == 15 * v54 + 48 * v53 + 92 * v51 + 85 * v50 + 27 * v49 + 42 * v52 + 72 * v55)
s.add(0x40A2 == 26 * v54 + 67 * v52 + 6 * v50 + 4 * v49 + 3 * v51 + 68 * v55)
s.add(0x2F3E == 34 * v59 + 12 * v56 + 53 * v57 + 6 * v58 + 58 * v60 + 36 * v61 + v62)
s.add(0x62B6 == 27 * v60 + 73 * v59 + 12 * v58 + 83 * v56 + 85 * v57 + 96 * v61 + 52 * v62)
s.add(0x4B82 == 24 * v58 + 78 * v56 + 53 * v57 + 36 * v59 + 86 * v60 + 25 * v61 + 46 * v62)
s.add(0x486C == 78 * v57 + 39 * v56 + 52 * v58 + 9 * v59 + 62 * v60 + 37 * v61 + 84 * v62)
s.add(0x4002 == 48 * v60 + 14 * v58 + 23 * v56 + 6 * v57 + 74 * v59 + 12 * v61 + 83 * v62)
s.add(0x52D7 == 15 * v61 + 48 * v60 + 92 * v58 + 85 * v57 + 27 * v56 + 42 * v59 + 72 * v62)
s.add(0x2DEF == 26 * v61 + 67 * v59 + 6 * v57 + 4 * v56 + 3 * v58 + 68 * v62)
s.add(0x28DC == 34 * v66 + 12 * v63 + 53 * v64 + 6 * v65 + 58 * v67 + 36 * v68 + v69)
s.add(0x640D == 27 * v67 + 73 * v66 + 12 * v65 + 83 * v63 + 85 * v64 + 96 * v68 + 52 * v69)
s.add(0x528F == 24 * v65 + 78 * v63 + 53 * v64 + 36 * v66 + 86 * v67 + 25 * v68 + 46 * v69)
s.add(0x613B == 78 * v64 + 39 * v63 + 52 * v65 + 9 * v66 + 62 * v67 + 37 * v68 + 84 * v69)
s.add(0x4781 == 48 * v67 + 14 * v65 + 23 * v63 + 6 * v64 + 74 * v66 + 12 * v68 + 83 * v69)
s.add(0x6B17 == 15 * v68 + 48 * v67 + 92 * v65 + 85 * v64 + 27 * v63 + 42 * v66 + 72 * v69)
s.add(0x3237 == 26 * v68 + 67 * v66 + 6 * v64 + 4 * v63 + 3 * v65 + 68 * v69)
s.add(0x2A93 == 34 * v73 + 12 * v70 + 53 * v71 + 6 * v72 + 58 * v74 + 36 * v75 + v76)
s.add(0x615F == 27 * v74 + 73 * v73 + 12 * v72 + 83 * v70 + 85 * v71 + 96 * v75 + 52 * v76)
s.add(0x50BE == 24 * v72 + 78 * v70 + 53 * v71 + 36 * v73 + 86 * v74 + 25 * v75 + 46 * v76)
s.add(0x598E == 78 * v71 + 39 * v70 + 52 * v72 + 9 * v73 + 62 * v74 + 37 * v75 + 84 * v76)
s.add(0x4656 == 48 * v74 + 14 * v72 + 23 * v70 + 6 * v71 + 74 * v73 + 12 * v75 + 83 * v76)
s.add(0x5B31 == 15 * v75 + 48 * v74 + 92 * v72 + 85 * v71 + 27 * v70 + 42 * v73 + 72 * v76)
s.add(0x313A == 26 * v75 + 67 * v73 + 6 * v71 + 4 * v70 + 3 * v72 + 68 * v76)
s.add(0x3010 == 34 * v80 + 12 * v77 + 53 * v78 + 6 * v79 + 58 * v81 + 36 * v82 + v83)
s.add(0x67FE == 27 * v81 + 73 * v80 + 12 * v79 + 83 * v77 + 85 * v78 + 96 * v82 + 52 * v83)
s.add(0x4D5F == 24 * v79 + 78 * v77 + 53 * v78 + 36 * v80 + 86 * v81 + 25 * v82 + 46 * v83)
s.add(0x58DB == 78 * v78 + 39 * v77 + 52 * v79 + 9 * v80 + 62 * v81 + 37 * v82 + 84 * v83)
s.add(0x3799 == 48 * v81 + 14 * v79 + 23 * v77 + 6 * v78 + 74 * v80 + 12 * v82 + 83 * v83)
s.add(0x60A0 == 15 * v82 + 48 * v81 + 92 * v79 + 85 * v78 + 27 * v77 + 42 * v80 + 72 * v83)
s.add(0x2750 == 26 * v82 + 67 * v80 + 6 * v78 + 4 * v77 + 3 * v79 + 68 * v83)
s.add(0x3759 == 34 * v87 + 12 * v84 + 53 * v85 + 6 * v86 + 58 * v88 + 36 * v89 + v90)
s.add(0x8953 == 27 * v88 + 73 * v87 + 12 * v86 + 83 * v84 + 85 * v85 + 96 * v89 + 52 * v90)
s.add(0x7122 == 24 * v86 + 78 * v84 + 53 * v85 + 36 * v87 + 86 * v88 + 25 * v89 + 46 * v90)
s.add(0x81F9 == 78 * v85 + 39 * v84 + 52 * v86 + 9 * v87 + 62 * v88 + 37 * v89 + 84 * v90)
s.add(0x5524 == 48 * v88 + 14 * v86 + 23 * v84 + 6 * v85 + 74 * v87 + 12 * v89 + 83 * v90)
s.add(0x8971 == 15 * v89 + 48 * v88 + 92 * v86 + 85 * v85 + 27 * v84 + 42 * v87 + 72 * v90)
s.add(0x3A1D == 26 * v89 + 67 * v87 + 6 * v85 + 4 * v84 + 3 * v86 + 68 * v90)

flag = []

if s.check() == sat:
    ans = s.model()
    flag.append(ans[v49])
    flag.append(ans[v50])
    flag.append(ans[v51])
    flag.append(ans[v52])
    flag.append(ans[v53])
    flag.append(ans[v54])
    flag.append(ans[v55])
    flag.append(ans[v56])
    flag.append(ans[v57])
    flag.append(ans[v58])
    flag.append(ans[v59])
    flag.append(ans[v60])
    flag.append(ans[v61])
    flag.append(ans[v62])
    flag.append(ans[v63])
    flag.append(ans[v64])
    flag.append(ans[v65])
    flag.append(ans[v66])
    flag.append(ans[v67])
    flag.append(ans[v68])
    flag.append(ans[v69])
    flag.append(ans[v70])
    flag.append(ans[v71])
    flag.append(ans[v72])
    flag.append(ans[v73])
    flag.append(ans[v74])
    flag.append(ans[v75])
    flag.append(ans[v76])
    flag.append(ans[v77])
    flag.append(ans[v78])
    flag.append(ans[v79])
    flag.append(ans[v80])
    flag.append(ans[v81])
    flag.append(ans[v82])
    flag.append(ans[v83])
    flag.append(ans[v84])
    flag.append(ans[v85])
    flag.append(ans[v86])
    flag.append(ans[v87])
    flag.append(ans[v88])
    flag.append(ans[v89])
    flag.append(ans[v90])

for x in flag:
    print(x, end=",")

哇!!!!看到起都脑壳大。但是不要慌,解出来的还不是最终答案,它是对应的ascii码:

看不清楚是什么?没关系还有手动的:

102,108,97,103,123,55,101,49,55,49,100,52,51,45,54,51,98,57,45,52,101,49,56,45,57,57,48,101,45,54,101,49,52,99,50,97,102,101,54,52,56,125,

哟西!最紧张的时候到了,解ascii码,代码奉上:

s = [102, 108, 97, 103, 123, 55, 101, 49, 55, 49, 100, 52, 51, 45, 54, 51, 98, 57, 45, 52, 101,
     49, 56, 45, 57, 57, 48, 101, 45, 54, 101, 49, 52, 99, 50, 97, 102, 101, 54, 52, 56, 125]
for x in s:
    print(chr(x), end="")

多得也不说了flag也整上:

flag{7e171d43-63b9-4e18-990e-6e14c2afe648}

好了!好了!OVER!!!其实还是挺简单的哈。。。。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值