-
-
[原创]DEFCON33-Quals nfuncs angr➕unicorn 快速自动化逆向
-
发表于: 2025-5-9 10:09 2391
-
这道题给了3g的附件,超出了PE大小上限
[64 bit - what is the maximum size of a PE file on 64-bit Windows? - Stack Overflow]
程序不能运行,程序存在大量的smc操作,需要输入正确的输入(8字节),然后计算出key参与到smc的运算中,然后call到smc之后的代码,如此循环往复。
同一个附件分为三关:
第一关将所有的解拼出来PNG,flag在PNG里。
采用angr+unicorn的方案,angr求解输入,unicorn去跑smc
经过我的不断优化,跑出第一关的图片用时间:
从5.5h→1.5h→26min
, 速度实现质的飞跃
一共有三种约束:
LUT[input[i]] == num
LUT[index] = (index + 13) % 256
位运算
直接判断
其中2、3使用angr都可以秒解
LUT我开了unicorn, 在explore使用指定avoid地址,把求解的函数切片,指定backend 为 blob , 避免每次都load 3Gb的文件。在我的i7-14650HX , 主频为2.2GHz上,求解需要20s。这个速度在求解第一关还行,倒是到了第二关就捉襟见肘了。因此还需要继续优化。
于是对LUT的情况添加静态求解的部分:
这样对99%的LUT的都可以秒解,并没有处理存在AND的情况,处理AND的情况需要模拟一个简单的污点传播,有点小麻烦,再加上这种情况很少,索性就退回到angr求解。
angr部分代码:
几个注意的点:
只load一次,完成section映射。
只hook一次,测试表明不重载uc, 代码会越跑越慢。
这样的好处是快了,但是代码段大小很大,跑着跑着代码就崩了,报memory unmap的错误,这里我觉得就是申请空间太大了,实际上没有申请到这段内存。
但是可以大力出奇迹, 写个bat脚本重新运行,程序就可以照常运行。
unicorn部分的代码:
flag{kitty_kitty_on_the_wall_439xb8q@}
第二关将所有的解拼出来MP4,flag在MP4里。
第二关主要考察速度,前面我们已经优化的足够好了。
第二关相较于第一关,添加了rc4加密,只需要添加求解部分就可以了
read(0, DstBuf, 1u);
read(0, &DstBuf[1], 1u);
read(0, &DstBuf[2], 1u);
read(0, &DstBuf[3], 1u);
read(0, &DstBuf[4], 1u);
read(0, &DstBuf[5], 1u);
read(0, &DstBuf[6], 1u);
read(0, &DstBuf[7], 1u);
v0 = 32 * (DstBuf[0] & 1);
if
( (DstBuf[0] & 2) != 0 )
v0 = (32 * (DstBuf[0] & 1)) | 0x40;
if
( (DstBuf[0] & 4) != 0 )
v0 |= 0x80u;
if
( (DstBuf[0] & 8) != 0 )
v0 |= 0x10u;
if
( (DstBuf[0] & 0x10) != 0 )
v0 |= 1u;
if
( (DstBuf[0] & 0x20) != 0 )
v0 |= 2u;
if
( (DstBuf[0] & 0x40) != 0 )
v0 |= 8u;
if
( DstBuf[0] < 0 )
v0 |= 4u;
v1 = v0 & 0xDF;
if
( (DstBuf[1] & 1) != 0 )
v1 = v0 | 0x20;
v2 = v1 | 0x40;
v3 = v1 & 0xBF;
if
( (DstBuf[1] & 2) != 0 )
v3 = v2;
v4 = v3 | 0x80;
v5 = v3 & 0x7F;
if
( (DstBuf[1] & 4) != 0 )
v5 = v4;
v6 = v5 | 0x10;
v7 = v5 & 0xEF;
if
( (DstBuf[1] & 8) != 0 )
v7 = v6;
v8 = v7 | 1;
v9 = v7 & 0xFE;
if
( (DstBuf[1] & 0x10) != 0 )
v9 = v8;
v10 = v9 | 2;
v11 = v9 & 0xFD;
if
( (DstBuf[1] & 0x20) != 0 )
v11 = v10;
v12 = v11 | 8;
v13 = v11 & 0xF7;
if
( (DstBuf[1] & 0x40) != 0 )
v13 = v12;
v14 = v13 | 4;
v15 = v13 & 0xFB;
if
( DstBuf[1] < 0 )
v15 = v14;
v16 = v15 & 0xDF;
if
( (DstBuf[2] & 1) != 0 )
v16 = v15 | 0x20;
v17 = v16 | 0x40;
v18 = v16 & 0xBF;
if
( (DstBuf[2] & 2) != 0 )
v18 = v17;
v19 = v18 | 0x80;
v20 = v18 & 0x7F;
if
( (DstBuf[2] & 4) != 0 )
v20 = v19;
v21 = v20 | 0x10;
v22 = v20 & 0xEF;
if
( (DstBuf[2] & 8) != 0 )
v22 = v21;
v23 = v22 | 1;
v24 = v22 & 0xFE;
if
( (DstBuf[2] & 0x10) != 0 )
v24 = v23;
v25 = v24 | 2;
v26 = v24 & 0xFD;
if
( (DstBuf[2] & 0x20) != 0 )
v26 = v25;
v27 = v26 | 8;
v28 = v26 & 0xF7;
if
( (DstBuf[2] & 0x40) != 0 )
v28 = v27;
v29 = v28 | 4;
v30 = v28 & 0xFB;
if
( DstBuf[2] < 0 )
v30 = v29;
v31 = v30 & 0xDF;
if
( (DstBuf[3] & 1) != 0 )
v31 = v30 | 0x20;
v32 = v31 | 0x40;
v33 = v31 & 0xBF;
if
( (DstBuf[3] & 2) != 0 )
v33 = v32;
v34 = v33 | 0x80;
v35 = v33 & 0x7F;
if
( (DstBuf[3] & 4) != 0 )
v35 = v34;
v36 = v35 | 0x10;
v37 = v35 & 0xEF;
if
( (DstBuf[3] & 8) != 0 )
v37 = v36;
v38 = v37 | 1;
v39 = v37 & 0xFE;
if
( (DstBuf[3] & 0x10) != 0 )
v39 = v38;
v40 = v39 | 2;
v41 = v39 & 0xFD;
if
( (DstBuf[3] & 0x20) != 0 )
v41 = v40;
v42 = v41 | 8;
v43 = v41 & 0xF7;
if
( (DstBuf[3] & 0x40) != 0 )
v43 = v42;
v44 = v43 | 4;
v45 = v43 & 0xFB;
if
( DstBuf[3] < 0 )
v45 = v44;
v46 = v45 & 0xDF;
if
( (DstBuf[4] & 1) != 0 )
v46 = v45 | 0x20;
v47 = v46 | 0x40;
v48 = v46 & 0xBF;
if
( (DstBuf[4] & 2) != 0 )
v48 = v47;
v49 = v48 | 0x80;
v50 = v48 & 0x7F;
if
( (DstBuf[4] & 4) != 0 )
v50 = v49;
v51 = v50 | 0x10;
v52 = v50 & 0xEF;
if
( (DstBuf[4] & 8) != 0 )
v52 = v51;
v53 = v52 | 1;
v54 = v52 & 0xFE;
if
( (DstBuf[4] & 0x10) != 0 )
v54 = v53;
v55 = v54 | 2;
v56 = v54 & 0xFD;
if
( (DstBuf[4] & 0x20) != 0 )
v56 = v55;
v57 = v56 | 8;
v58 = v56 & 0xF7;
if
( (DstBuf[4] & 0x40) != 0 )
v58 = v57;
v59 = v58 | 4;
v60 = v58 & 0xFB;
if
( DstBuf[4] < 0 )
v60 = v59;
v61 = v60 & 0xDF;
if
( (DstBuf[5] & 1) != 0 )
v61 = v60 | 0x20;
v62 = v61 | 0x40;
v63 = v61 & 0xBF;
if
( (DstBuf[5] & 2) != 0 )
v63 = v62;
v64 = v63 | 0x80;
v65 = v63 & 0x7F;
if
( (DstBuf[5] & 4) != 0 )
v65 = v64;
v66 = v65 | 0x10;
v67 = v65 & 0xEF;
if
( (DstBuf[5] & 8) != 0 )
v67 = v66;
v68 = v67 | 1;
v69 = v67 & 0xFE;
if
( (DstBuf[5] & 0x10) != 0 )
v69 = v68;
v70 = v69 | 2;
v71 = v69 & 0xFD;
if
( (DstBuf[5] & 0x20) != 0 )
v71 = v70;
v72 = v71 | 8;
v73 = v71 & 0xF7;
if
( (DstBuf[5] & 0x40) != 0 )
v73 = v72;
v74 = v73 | 4;
v75 = v73 & 0xFB;
if
( DstBuf[5] < 0 )
v75 = v74;
v76 = v75 & 0xDF;
if
( (DstBuf[6] & 1) != 0 )
v76 = v75 | 0x20;
v77 = v76 | 0x40;
v78 = v76 & 0xBF;
if
( (DstBuf[6] & 2) != 0 )
v78 = v77;
v79 = v78 | 0x80;
v80 = v78 & 0x7F;
if
( (DstBuf[6] & 4) != 0 )
v80 = v79;
v81 = v80 | 0x10;
v82 = v80 & 0xEF;
if
( (DstBuf[6] & 8) != 0 )
v82 = v81;
v83 = v82 | 1;
v84 = v82 & 0xFE;
if
( (DstBuf[6] & 0x10) != 0 )
v84 = v83;
v85 = v84 | 2;
v86 = v84 & 0xFD;
if
( (DstBuf[6] & 0x20) != 0 )
v86 = v85;
v87 = v86 | 8;
v88 = v86 & 0xF7;
if
( (DstBuf[6] & 0x40) != 0 )
v88 = v87;
v89 = v88 | 4;
v90 = v88 & 0xFB;
if
( DstBuf[6] < 0 )
v90 = v89;
v91 = v90 & 0xDF;
if
( (DstBuf[7] & 1) != 0 )
v91 = v90 | 0x20;
v92 = v91 | 0x40;
v93 = v91 & 0xBF;
if
( (DstBuf[7] & 2) != 0 )
v93 = v92;
v94 = v93 | 0x80;
v95 = v93 & 0x7F;
if
( (DstBuf[7] & 4) != 0 )
v95 = v94;
v96 = v95 | 0x10;
v97 = v95 & 0xEF;
if
( (DstBuf[7] & 8) != 0 )
v97 = v96;
v98 = v97 | 1;
v99 = v97 & 0xFE;
if
( (DstBuf[7] & 0x10) != 0 )
v99 = v98;
v100 = v99 | 2;
v101 = v99 & 0xFD;
if
( (DstBuf[7] & 0x20) != 0 )
v101 = v100;
v102 = v101 | 8;
v103 = v101 & 0xF7;
if
( (DstBuf[7] & 0x40) != 0 )
v103 = v102;
v104 = v103 | 4;
v105 = v103 & 0xFB;
if
( DstBuf[7] < 0 )
v105 = v104;
if
( v0 == -77 && !(v45 | (unsigned
__int8
)(v30 | v15)) && v60 == 32 && v75 == 107 && v90 == 73 && v105 == -24 )
{
strcpy
(v108,
":)"
);
puts
(v108);
v110[0] = 0LL;
v110[1] = 0LL;
sub_14003A1C0(v110, *(_QWORD *)DstBuf + 2815032436LL);
VirtualProtect(sub_140055A50, 0x17960uLL, 0x40u, &v109);
for
( i = 0LL; i != 96608; ++i )
*(_BYTE *)(i + 0x140055A50LL) ^= *((_BYTE *)v110 + (i & 0xF));
VirtualProtect(sub_140055A50, 0x17960uLL, v109, 0LL);
return
sub_140055A50();
}
else
{
strcpy
(Buffer,
":("
);
return
puts
(Buffer);
}
}
read(0, DstBuf, 1u);
read(0, &DstBuf[1], 1u);
read(0, &DstBuf[2], 1u);
read(0, &DstBuf[3], 1u);
read(0, &DstBuf[4], 1u);
read(0, &DstBuf[5], 1u);
read(0, &DstBuf[6], 1u);
read(0, &DstBuf[7], 1u);
v0 = 32 * (DstBuf[0] & 1);
if
( (DstBuf[0] & 2) != 0 )
v0 = (32 * (DstBuf[0] & 1)) | 0x40;
if
( (DstBuf[0] & 4) != 0 )
v0 |= 0x80u;
if
( (DstBuf[0] & 8) != 0 )
v0 |= 0x10u;
if
( (DstBuf[0] & 0x10) != 0 )
v0 |= 1u;
if
( (DstBuf[0] & 0x20) != 0 )
v0 |= 2u;
if
( (DstBuf[0] & 0x40) != 0 )
v0 |= 8u;
if
( DstBuf[0] < 0 )
v0 |= 4u;
v1 = v0 & 0xDF;
if
( (DstBuf[1] & 1) != 0 )
v1 = v0 | 0x20;
v2 = v1 | 0x40;
v3 = v1 & 0xBF;
if
( (DstBuf[1] & 2) != 0 )
v3 = v2;
v4 = v3 | 0x80;
v5 = v3 & 0x7F;
if
( (DstBuf[1] & 4) != 0 )
v5 = v4;
v6 = v5 | 0x10;
v7 = v5 & 0xEF;
if
( (DstBuf[1] & 8) != 0 )
v7 = v6;
v8 = v7 | 1;
v9 = v7 & 0xFE;
if
( (DstBuf[1] & 0x10) != 0 )
v9 = v8;
v10 = v9 | 2;
v11 = v9 & 0xFD;
if
( (DstBuf[1] & 0x20) != 0 )
v11 = v10;
v12 = v11 | 8;
v13 = v11 & 0xF7;
if
( (DstBuf[1] & 0x40) != 0 )
v13 = v12;
v14 = v13 | 4;
v15 = v13 & 0xFB;
if
( DstBuf[1] < 0 )
v15 = v14;
v16 = v15 & 0xDF;
if
( (DstBuf[2] & 1) != 0 )
v16 = v15 | 0x20;
v17 = v16 | 0x40;
v18 = v16 & 0xBF;
if
( (DstBuf[2] & 2) != 0 )
v18 = v17;
v19 = v18 | 0x80;
v20 = v18 & 0x7F;
if
( (DstBuf[2] & 4) != 0 )
v20 = v19;
v21 = v20 | 0x10;
v22 = v20 & 0xEF;
if
( (DstBuf[2] & 8) != 0 )
v22 = v21;
v23 = v22 | 1;
v24 = v22 & 0xFE;
if
( (DstBuf[2] & 0x10) != 0 )
v24 = v23;
v25 = v24 | 2;
v26 = v24 & 0xFD;
if
( (DstBuf[2] & 0x20) != 0 )
v26 = v25;
v27 = v26 | 8;
v28 = v26 & 0xF7;
if
( (DstBuf[2] & 0x40) != 0 )
v28 = v27;
v29 = v28 | 4;
v30 = v28 & 0xFB;
if
( DstBuf[2] < 0 )
v30 = v29;
v31 = v30 & 0xDF;
if
( (DstBuf[3] & 1) != 0 )
v31 = v30 | 0x20;
v32 = v31 | 0x40;
v33 = v31 & 0xBF;
if
( (DstBuf[3] & 2) != 0 )
v33 = v32;
v34 = v33 | 0x80;
v35 = v33 & 0x7F;
if
( (DstBuf[3] & 4) != 0 )
v35 = v34;
v36 = v35 | 0x10;
v37 = v35 & 0xEF;
if
( (DstBuf[3] & 8) != 0 )
v37 = v36;
v38 = v37 | 1;
v39 = v37 & 0xFE;
if
( (DstBuf[3] & 0x10) != 0 )
v39 = v38;
v40 = v39 | 2;
v41 = v39 & 0xFD;
if
( (DstBuf[3] & 0x20) != 0 )
v41 = v40;
v42 = v41 | 8;
v43 = v41 & 0xF7;
if
( (DstBuf[3] & 0x40) != 0 )
v43 = v42;
v44 = v43 | 4;
v45 = v43 & 0xFB;
if
( DstBuf[3] < 0 )
v45 = v44;
v46 = v45 & 0xDF;
if
( (DstBuf[4] & 1) != 0 )
v46 = v45 | 0x20;
v47 = v46 | 0x40;
v48 = v46 & 0xBF;
if
( (DstBuf[4] & 2) != 0 )
v48 = v47;
v49 = v48 | 0x80;
v50 = v48 & 0x7F;
if
( (DstBuf[4] & 4) != 0 )
v50 = v49;
v51 = v50 | 0x10;
v52 = v50 & 0xEF;
if
( (DstBuf[4] & 8) != 0 )
v52 = v51;
v53 = v52 | 1;
v54 = v52 & 0xFE;
if
( (DstBuf[4] & 0x10) != 0 )
v54 = v53;
v55 = v54 | 2;
v56 = v54 & 0xFD;
if
( (DstBuf[4] & 0x20) != 0 )
v56 = v55;
v57 = v56 | 8;
v58 = v56 & 0xF7;
if
( (DstBuf[4] & 0x40) != 0 )
v58 = v57;
v59 = v58 | 4;
v60 = v58 & 0xFB;
if
( DstBuf[4] < 0 )
v60 = v59;
v61 = v60 & 0xDF;
if
( (DstBuf[5] & 1) != 0 )
v61 = v60 | 0x20;
v62 = v61 | 0x40;
v63 = v61 & 0xBF;
if
( (DstBuf[5] & 2) != 0 )
v63 = v62;
v64 = v63 | 0x80;
v65 = v63 & 0x7F;
if
( (DstBuf[5] & 4) != 0 )
v65 = v64;
v66 = v65 | 0x10;
v67 = v65 & 0xEF;
if
( (DstBuf[5] & 8) != 0 )
v67 = v66;
v68 = v67 | 1;
v69 = v67 & 0xFE;
if
( (DstBuf[5] & 0x10) != 0 )
v69 = v68;
v70 = v69 | 2;
v71 = v69 & 0xFD;
if
( (DstBuf[5] & 0x20) != 0 )
v71 = v70;
v72 = v71 | 8;
v73 = v71 & 0xF7;
if
( (DstBuf[5] & 0x40) != 0 )
v73 = v72;
v74 = v73 | 4;
v75 = v73 & 0xFB;
if
( DstBuf[5] < 0 )
v75 = v74;
v76 = v75 & 0xDF;
if
( (DstBuf[6] & 1) != 0 )
v76 = v75 | 0x20;
v77 = v76 | 0x40;
v78 = v76 & 0xBF;
if
( (DstBuf[6] & 2) != 0 )
v78 = v77;
v79 = v78 | 0x80;
v80 = v78 & 0x7F;
if
( (DstBuf[6] & 4) != 0 )
v80 = v79;
v81 = v80 | 0x10;
v82 = v80 & 0xEF;
if
( (DstBuf[6] & 8) != 0 )
v82 = v81;
v83 = v82 | 1;
v84 = v82 & 0xFE;
if
( (DstBuf[6] & 0x10) != 0 )
v84 = v83;
v85 = v84 | 2;
v86 = v84 & 0xFD;
if
( (DstBuf[6] & 0x20) != 0 )
v86 = v85;
v87 = v86 | 8;
v88 = v86 & 0xF7;
if
( (DstBuf[6] & 0x40) != 0 )
v88 = v87;
v89 = v88 | 4;
v90 = v88 & 0xFB;
if
( DstBuf[6] < 0 )
v90 = v89;
v91 = v90 & 0xDF;
if
( (DstBuf[7] & 1) != 0 )
v91 = v90 | 0x20;
v92 = v91 | 0x40;
v93 = v91 & 0xBF;
if
( (DstBuf[7] & 2) != 0 )
v93 = v92;
v94 = v93 | 0x80;
v95 = v93 & 0x7F;
if
( (DstBuf[7] & 4) != 0 )
v95 = v94;
v96 = v95 | 0x10;
v97 = v95 & 0xEF;
if
( (DstBuf[7] & 8) != 0 )
v97 = v96;
v98 = v97 | 1;
v99 = v97 & 0xFE;
if
( (DstBuf[7] & 0x10) != 0 )
v99 = v98;
v100 = v99 | 2;
v101 = v99 & 0xFD;
if
( (DstBuf[7] & 0x20) != 0 )
v101 = v100;
v102 = v101 | 8;
v103 = v101 & 0xF7;
if
( (DstBuf[7] & 0x40) != 0 )
v103 = v102;
v104 = v103 | 4;
v105 = v103 & 0xFB;
if
( DstBuf[7] < 0 )
v105 = v104;
if
( v0 == -77 && !(v45 | (unsigned
__int8
)(v30 | v15)) && v60 == 32 && v75 == 107 && v90 == 73 && v105 == -24 )
{
strcpy
(v108,
":)"
);
puts
(v108);
v110[0] = 0LL;
v110[1] = 0LL;
sub_14003A1C0(v110, *(_QWORD *)DstBuf + 2815032436LL);
VirtualProtect(sub_140055A50, 0x17960uLL, 0x40u, &v109);
for
( i = 0LL; i != 96608; ++i )
*(_BYTE *)(i + 0x140055A50LL) ^= *((_BYTE *)v110 + (i & 0xF));
VirtualProtect(sub_140055A50, 0x17960uLL, v109, 0LL);
return
sub_140055A50();
}
else
{
strcpy
(Buffer,
":("
);
return
puts
(Buffer);
}
}
def collect_cmp_value(base_addr):
md = Cs(CS_ARCH_X86, CS_MODE_64)
md.detail = True
cmps = []
for
i in md.disasm(func_code, base_addr):
if
i.mnemonic ==
'cmp'
:
# print(f"0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}")
op2 = i.op_str.split(
','
)[1].strip()
if
i.operands[1].type == X86_OP_IMM :
op2 =
int
(op2, 16)
if
op2 < 0x100:
# print(f"op2: {op2}")
cmps.append(op2)
if
i.mnemonic ==
'test'
:
cmps.append(0)
if
len(cmps) == 8:
break
def collect_cmp_value(base_addr):
md = Cs(CS_ARCH_X86, CS_MODE_64)
md.detail = True
cmps = []
for
i in md.disasm(func_code, base_addr):
if
i.mnemonic ==
'cmp'
:
# print(f"0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}")
op2 = i.op_str.split(
','
)[1].strip()
if
i.operands[1].type == X86_OP_IMM :
op2 =
int
(op2, 16)
if
op2 < 0x100:
# print(f"op2: {op2}")
cmps.append(op2)
if
i.mnemonic ==
'test'
:
cmps.append(0)
if
len(cmps) == 8:
break
import
angr
import
claripy
import
io
from
angr.calling_conventions
import
SimCCMicrosoftAMD64
from
angr.errors
import
SimProcedureError
from
capstone
import
*
import
archinfo
from
capstone.x86_const
import
*
def
rva_to_foa(addr):
return
addr
-
0x140001000
+
0x400
def
get_file_slice(file_path, start, size):
start
=
rva_to_foa(start)
with
open
(file_path,
'rb'
) as f:
f.seek(start)
return
f.read(size)
def
store_ans(ans):
with
open
(
"all-ans.bin"
,
'a+b'
) as f1:
# print("write all-ans")
print
(ans)
f1.write(ans)
f1.flush()
with
open
(
'last-ans.bin'
,
'wb'
) as f:
f.write(ans)
# last_read_return_address = None
is_lut
=
False
def
find_ans(FUN_VA, file_path
=
'nfuncs1.exe'
):
global
is_lut
input_bytes
=
[]
class
ReadHook(angr.SimProcedure):
def
run(
self
, fd, buf, cnt):
global
last_read_return_address
fd
=
self
.state.solver.
eval
(fd)
cnt
=
self
.state.solver.
eval
(cnt)
target_addr
=
self
.state.solver.
eval
(buf)
if
fd !
=
0
or
cnt !
=
1
:
print
(f
'[!] Unexpected read: fd {fd}, count {cnt}'
)
# if len(input_bytes) == 0:
# for i in range(256):
# self.state.memory.store(target_addr-0x108 + i , (i+13) % 256, 8, endness=archinfo.Endness.LE)
sym
=
claripy.BVS(f
"input_{len(input_bytes)}"
,
8
)
input_bytes.append(sym)
self
.state.memory.store(target_addr, sym)
# print(f"[+] Hooked: wrote symbolic byte to {hex(target_addr)}")
# rip = self.state.solver.eval(self.state.memory.load(self.state.regs.rsp,8,endness=archinfo.Endness.LE))
# last_read_return_address = rip
# print(f"[+] Hooked: rip {hex(rip)}")
value
=
self
.state.solver.
eval
(
self
.state.memory.load(target_addr
-
0x108
,
1
),cast_to
=
int
)
if
value
=
=
13
+
len
(input_bytes)
-
1
:
is_lut
=
True
else
:
is_lut
=
False
# print(f"[+] Hooked: value {hex(value)}")
if
len
(input_bytes)
=
=
8
and
is_lut:
# print("is_lut")
cmps
=
collect_cmp_value(FUN_VA)
if
len
(cmps)
=
=
8
:
# nothing i can do
for
i, target
in
enumerate
(cmps):
# v12_expr = (index + 13) % 256
# print(hex(target))
self
.state.solver.add(input_bytes[i]
=
=
target
-
13
)
# state.solver.add((input_bytes[i] + 13) % 256 == target)
class
VirtualProtectHook(angr.SimProcedure):
def
run(
self
, lpAddress, dwSize, flNewProtect, lpflOldProtect):
addr
=
self
.state.solver.
eval
(lpAddress)
size
=
self
.state.solver.
eval
(dwSize)
prot
=
self
.state.solver.
eval
(flNewProtect)
print
(f
"[+] Hooked VirtualProtect:"
)
print
(f
" -> Address: {hex(addr)}"
)
print
(f
" -> Size : {hex(size)}"
)
print
(f
" -> NewProt: {hex(prot)}"
)
return
claripy.BVV(
1
,
self
.state.arch.bits)
class
PutsHook(angr.SimProcedure):
def
run(
self
,buf):
str_address
=
self
.state.solver.
eval
(buf)
s
=
self
.state.solver.
eval
(
self
.state.memory.load(str_address,
3
),cast_to
=
bytes)
print
(
"input:"
,s)
# b':)\x00' or b':(\x00'
if
s
=
=
b
':(\x00'
:
print
(
"[!] Detected bad output ':(', killing path."
)
return
claripy.BVV(
1
,
self
.state.arch.bits)
# FUN_VA = 0x14000F000
func_code
=
get_file_slice(file_path, FUN_VA,
0x1000
)
def
find_avoid_address(base_addr):
md
=
Cs(CS_ARCH_X86, CS_MODE_64)
find_address
=
None
avoid_address
=
None
for
i
in
md.disasm(func_code, base_addr):
# print(f"0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}")
if
i.mnemonic
=
=
'mov'
and
'0x283a'
in
i.op_str:
# print(f"0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}")
avoid_address
=
i.address
if
i.mnemonic
=
=
'mov'
and
'0x293a'
in
i.op_str:
# print(f"0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}")
find_address
=
i.address
if
find_address
and
avoid_address:
break
return
(find_address,avoid_address)
def
collect_cmp_value(base_addr):
md
=
Cs(CS_ARCH_X86, CS_MODE_64)
md.detail
=
True
cmps
=
[]
for
i
in
md.disasm(func_code, base_addr):
if
i.mnemonic
=
=
'cmp'
:
# print(f"0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}")
op2
=
i.op_str.split(
','
)[
1
].strip()
if
i.operands[
1
].
type
=
=
X86_OP_IMM :
op2
=
int
(op2,
16
)
if
op2 <
0x100
:
# print(f"op2: {op2}")
cmps.append(op2)
if
i.mnemonic
=
=
'test'
:
cmps.append(
0
)
if
len
(cmps)
=
=
8
:
break
# assert len(cmps) == 8, f"[-] cmps length is not 8!"
return
cmps
# exit()
# print(f"0x{i.address:x}:\t{i.mnemonic}\t{i.op_str}")
find_address,avoid_address
=
find_avoid_address(FUN_VA)
# assert avoid_address != None, f"[-] Can't find avoid address!"
proj
=
angr.Project(io.BytesIO(func_code), auto_load_libs
=
False
, main_opts
=
{
'base_addr'
: FUN_VA,
'backend'
:
'blob'
,
'arch'
:
'X86_64'
,
'entry_point'
:
0
,
# just avoid warnings
}, )
#handle IAT
cc
=
SimCCMicrosoftAMD64(proj.arch)
proj.hook(
0x1A703AA78
, ReadHook(cc
=
cc))
proj.hook(
0xDEADBEFF00
, VirtualProtectHook(cc
=
cc))
proj.hook(
0x1A703AA50
, angr.SIM_PROCEDURES[
'libc'
][
'puts'
]())
state
=
proj.factory.blank_state(addr
=
FUN_VA, add_options
=
{
angr.options.UNICORN,
angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY,
angr.options.ZERO_FILL_UNCONSTRAINED_REGISTERS,
})
# faster
#manually process relocations
#read(0)
state.regs.rsp
=
claripy.BVV(
0x7fffffffffe000
,
64
)
# 设个高地址
state.regs.rdx
=
claripy.BVV(
0x7fffffffffdfe8
,
64
)
# state.memory.store(0x7fffffffffdfe8 - 0x108, claripy.BVV(0, 64))
# 手动在栈顶写入一个“假的返回地址”,防止后面ret或call出问题
state.memory.store(
0x7fffffffffe000
, claripy.BVV(
0xdeadbeefdeadbeef
,
64
))
state.memory.store(
0x1A707D330
,
int
.to_bytes(
0x1A703AA78
,
16
,
'little'
))
#put()
state.memory.store(
0x1A707D320
,
int
.to_bytes(
0x1A703AA50
,
16
,
'little'
))
#virtualprotect()
state.memory.store(
0x1A71B2210
,
int
.to_bytes(
0xDEADBEFF00
,
16
,
'little'
))
simgr
=
proj.factory.simulation_manager(state)
# simgr.use_technique(angr.exploration_techniques.Veritesting())
simgr.explore(find
=
find_address,avoid_address
=
avoid_address)
# print("start explore")
# print(simgr)
# print(simgr.errored)
if
simgr.found:
found
=
simgr.found[
0
]
# print("[+] Found a solution!")
ans
=
found.solver.
eval
(claripy.Concat(
*
input_bytes),cast_to
=
bytes)
print
(ans)
# print(found.step().regs.rip)
# store_ans(ans)
return
ans
# find_ans(0x140001510, file_path='nfuncs_fast.exe')
import
angr
import
claripy
import
io
from
angr.calling_conventions
import
SimCCMicrosoftAMD64
from
angr.errors
import
SimProcedureError
from
capstone
import
*
import
archinfo
from
capstone.x86_const
import
*
def
rva_to_foa(addr):
return
addr
-
0x140001000
+
0x400
def
get_file_slice(file_path, start, size):
start
=
rva_to_foa(start)
with
open
(file_path,
'rb'
) as f:
f.seek(start)
return
f.read(size)
def
store_ans(ans):
with
open
(
"all-ans.bin"
,
'a+b'
) as f1:
# print("write all-ans")
print
(ans)
f1.write(ans)
f1.flush()
with
open
(
'last-ans.bin'
,
'wb'
) as f:
f.write(ans)
# last_read_return_address = None
is_lut
=
False
def
find_ans(FUN_VA, file_path
=
'nfuncs1.exe'
):
global
is_lut
input_bytes
=
[]
class
ReadHook(angr.SimProcedure):
def
run(
self
, fd, buf, cnt):
global
last_read_return_address
fd
=
self
.state.solver.
eval
(fd)
cnt
=
self
.state.solver.
eval
(cnt)
target_addr
=
self
.state.solver.
eval
(buf)
if
fd !
=
0
or
cnt !
=
1
:
print
(f
'[!] Unexpected read: fd {fd}, count {cnt}'
)
# if len(input_bytes) == 0:
# for i in range(256):
# self.state.memory.store(target_addr-0x108 + i , (i+13) % 256, 8, endness=archinfo.Endness.LE)
sym
=
claripy.BVS(f
"input_{len(input_bytes)}"
,
8
)
input_bytes.append(sym)
self
.state.memory.store(target_addr, sym)
# print(f"[+] Hooked: wrote symbolic byte to {hex(target_addr)}")
# rip = self.state.solver.eval(self.state.memory.load(self.state.regs.rsp,8,endness=archinfo.Endness.LE))
# last_read_return_address = rip
# print(f"[+] Hooked: rip {hex(rip)}")
value
=
self
.state.solver.
eval
(
self
.state.memory.load(target_addr
-
0x108
,
1
),cast_to
=
int
)
if
value
=
=
13
+
len
(input_bytes)
-
1
:
is_lut
=
True
else
:
is_lut
=
False
# print(f"[+] Hooked: value {hex(value)}")
if
len
(input_bytes)
=
=
8
and
is_lut:
# print("is_lut")
cmps
=
collect_cmp_value(FUN_VA)
if
len
(cmps)
=
=
8
:
# nothing i can do
for
i, target
in
enumerate
(cmps):
# v12_expr = (index + 13) % 256
# print(hex(target))
self
.state.solver.add(input_bytes[i]
=
=
target
-
13
)
# state.solver.add((input_bytes[i] + 13) % 256 == target)
class
VirtualProtectHook(angr.SimProcedure):
def
run(
self
, lpAddress, dwSize, flNewProtect, lpflOldProtect):
addr
=
self
.state.solver.
eval
(lpAddress)
size
=
self
.state.solver.
eval
(dwSize)
prot
=
self
.state.solver.
eval
(flNewProtect)
print
(f
"[+] Hooked VirtualProtect:"
)
print
(f
" -> Address: {hex(addr)}"
)
print
(f
" -> Size : {hex(size)}"
)
print
(f
" -> NewProt: {hex(prot)}"
)
return
claripy.BVV(
1
,
self
.state.arch.bits)
class
PutsHook(angr.SimProcedure):
def
run(
self
,buf):
str_address
=
self
.state.solver.
eval
(buf)
s
=
self
.state.solver.
eval
(
self
.state.memory.load(str_address,
3
),cast_to
=
bytes)
print
(
"input:"
,s)
# b':)\x00' or b':(\x00'
if
s
=
=
b
':(\x00'
:
print
(
"[!] Detected bad output ':(', killing path."
)
return
claripy.BVV(
1
,
self
.state.arch.bits)
# FUN_VA = 0x14000F000
func_code
=
get_file_slice(file_path, FUN_VA,
0x1000
)
def
find_avoid_address(base_addr):
md
=
Cs(CS_ARCH_X86, CS_MODE_64)
find_address
=
None
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课