-
-
[原创]DEFCON33-Quals nfuncs angr➕unicorn 快速自动化逆向
-
发表于: 2025-5-9 10:09 4471
-
这道题给了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: breakdef 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: breakimport angr import claripyimport iofrom angr.calling_conventions import SimCCMicrosoftAMD64from angr.errors import SimProcedureErrorfrom capstone import *import archinfofrom capstone.x86_const import *def rva_to_foa(addr): return addr - 0x140001000 + 0x400def 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 = Noneis_lut = Falsedef 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 claripyimport iofrom angr.calling_conventions import SimCCMicrosoftAMD64from angr.errors import SimProcedureErrorfrom capstone import *import archinfofrom capstone.x86_const import *def rva_to_foa(addr): return addr - 0x140001000 + 0x400def 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 = Noneis_lut = Falsedef 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[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!