一、难点:

• 控制流平坦化; 【相关资料请参考[利用符号执行去除控制流平坦化](https://security.tencent.com/index.php/blog/msg/112)】
• 用idapython去除虚假控制流程;
• CRC算法;

二、具体步骤:

1.控制流去平坦化:


装好angr,使用脚本deflat.py去除控制流平坦化,deflat.py所在目录下打开cmd命令行输入

python deflat.py attachment.exe 0x400620    #python版本 + 脚本名 + 文件名 + 起始地址”

运行几分钟即可得到去除控制流平坦化之后的程序。

2.去除虚假控制流

(1)原始伪代码:

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{signed __int64 v4; // [rsp+1E0h] [rbp-110h]int i; // [rsp+1E8h] [rbp-108h]int v6; // [rsp+1ECh] [rbp-104h]int v7; // [rsp+1ECh] [rbp-104h]char s1[48]; // [rsp+1F0h] [rbp-100h]char s[60]; // [rsp+220h] [rbp-D0h]unsigned int v10; // [rsp+25Ch] [rbp-94h]char *v11; // [rsp+260h] [rbp-90h]int v12; // [rsp+26Ch] [rbp-84h]bool v13; // [rsp+272h] [rbp-7Eh]unsigned __int8 v14; // [rsp+273h] [rbp-7Dh]int v15; // [rsp+274h] [rbp-7Ch]char *v16; // [rsp+278h] [rbp-78h]int v17; // [rsp+284h] [rbp-6Ch]int v18; // [rsp+288h] [rbp-68h]bool v19; // [rsp+28Fh] [rbp-61h]char *v20; // [rsp+290h] [rbp-60h]int v21; // [rsp+298h] [rbp-58h]bool v22; // [rsp+29Fh] [rbp-51h]__int64 v23; // [rsp+2A0h] [rbp-50h]bool v24; // [rsp+2AFh] [rbp-41h]__int64 v25; // [rsp+2B0h] [rbp-40h]__int64 v26; // [rsp+2B8h] [rbp-38h]__int64 v27; // [rsp+2C0h] [rbp-30h]__int64 v28; // [rsp+2C8h] [rbp-28h]int v29; // [rsp+2D0h] [rbp-20h]int v30; // [rsp+2D4h] [rbp-1Ch]char *v31; // [rsp+2D8h] [rbp-18h]int v32; // [rsp+2E0h] [rbp-10h]int v33; // [rsp+2E4h] [rbp-Ch]bool v34; // [rsp+2EBh] [rbp-5h]v10 = 0;memset(s, 0, 0x30uLL);memset(s1, 0, 0x30uLL);printf("Input:", 0LL);v11 = s;if ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 )goto LABEL_43;while ( 1 ){__isoc99_scanf("%s", v11);v6 = 0;if ( dword_603058 < 10 || (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) == 0 )break;
LABEL_43:__isoc99_scanf("%s", v11);}while ( 1 ){dov12 = v6;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );v13 = v12 < 64;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );if ( !v13 )break;v14 = s[v6];dov15 = v14;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );if ( v15 == 10 ){v16 = &s[v6];*v16 = 0;break;}v17 = v6 + 1;dov6 = v17;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );}for ( i = 0; ; ++i ){dov18 = i;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );dov19 = v18 < 6;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );if ( !v19 )break;dov20 = s;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );v4 = *(_QWORD *)&v20[8 * i];v7 = 0;while ( 1 ){v21 = v7;dov22 = v21 < 64;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );if ( !v22 )break;v23 = v4;v24 = v4 < 0;if ( v4 >= 0 ){v27 = v4;dov28 = 2 * v27;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );v4 = v28;}else{v25 = 2 * v4;dov26 = v25;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );v4 = v26 ^ 0xB0004B7679FA26B3LL;}v29 = v7;dov7 = v29 + 1;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );}v30 = 8 * i;v31 = &s1[8 * i];if ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 )
LABEL_55:*(_QWORD *)v31 = v4;*(_QWORD *)v31 = v4;if ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 )goto LABEL_55;v32 = i + 1;}dov33 = memcmp(s1, &unk_402170, 0x30uLL);while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );v34 = v33 != 0;while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 );if ( v34 )puts("Wrong!");elseputs("Correct!");return v10;
}

上面的" while ( dword_603058 >= 10 && (((_BYTE)dword_603054 - 1) * (_BYTE)dword_603054 & 1) != 0 ); "都是虚假控制流反调试,可以忽略

(2)idapython去除虚拟控制流:

官方idapython:

st = 0x0000000000401117
end = 0x0000000000402144def patch_nop(start,end):for i in range(start,end):PatchByte(i, 0x90)                 #修改指定地址处的指令  0x90是最简单的1字节nopdef next_instr(addr):return addr+ItemSize(addr)          #ItemSize获取指令或数据长度,这个函数的作用就是去往下一条指令addr = st
while(addr<end):next = next_instr(addr)if "ds:dword_603054" in GetDisasm(addr):   #GetDisasm(addr)得到addr的反汇编语句while(True):addr = nextnext = next_instr(addr)if "jnz" in GetDisasm(addr):dest = GetOperandValue(addr, 0)      #得到操作数,就是指令后的数PatchByte(addr, 0xe9)PatchByte(addr+5, 0x90) offset = dest - (addr + 5)PatchDword(addr + 1, offset)print("patch bcf: 0x%x"%addr)addr = nextbreakelse:addr = next

在script command里运行得到如下伪代码:

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{signed __int64 v4; // [rsp+1E0h] [rbp-110h]signed int j; // [rsp+1E8h] [rbp-108h]signed int i; // [rsp+1ECh] [rbp-104h]signed int k; // [rsp+1ECh] [rbp-104h]char s1[48]; // [rsp+1F0h] [rbp-100h]char s[60]; // [rsp+220h] [rbp-D0h]unsigned int v10; // [rsp+25Ch] [rbp-94h]char *v11; // [rsp+260h] [rbp-90h]int v12; // [rsp+26Ch] [rbp-84h]bool v13; // [rsp+272h] [rbp-7Eh]unsigned __int8 v14; // [rsp+273h] [rbp-7Dh]int v15; // [rsp+274h] [rbp-7Ch]char *v16; // [rsp+278h] [rbp-78h]int v17; // [rsp+284h] [rbp-6Ch]int v18; // [rsp+288h] [rbp-68h]bool v19; // [rsp+28Fh] [rbp-61h]char *v20; // [rsp+290h] [rbp-60h]int v21; // [rsp+298h] [rbp-58h]bool v22; // [rsp+29Fh] [rbp-51h]__int64 v23; // [rsp+2A0h] [rbp-50h]bool v24; // [rsp+2AFh] [rbp-41h]__int64 v25; // [rsp+2B0h] [rbp-40h]__int64 v26; // [rsp+2B8h] [rbp-38h]__int64 v27; // [rsp+2C0h] [rbp-30h]__int64 v28; // [rsp+2C8h] [rbp-28h]int v29; // [rsp+2D0h] [rbp-20h]int v30; // [rsp+2D4h] [rbp-1Ch]char *v31; // [rsp+2D8h] [rbp-18h]int v32; // [rsp+2E0h] [rbp-10h]int v33; // [rsp+2E4h] [rbp-Ch]bool v34; // [rsp+2EBh] [rbp-5h]v10 = 0;memset(s, 0, 0x30uLL);memset(s1, 0, 0x30uLL);printf("Input:", 0LL);v11 = s;__isoc99_scanf("%s", s, (dword_603054 - 1), 3788079310LL);for ( i = 0; ; ++i ){v12 = i;v13 = i < 64;if ( i >= 64 )break;v14 = s[i];v15 = v14;if ( v14 == 10 ){v16 = &s[i];*v16 = 0;break;}v17 = i + 1;}for ( j = 0; ; ++j ){v18 = j;v19 = j < 6;if ( j >= 6 )break;v20 = s;v4 = *&s[8 * j];for ( k = 0; ; ++k ){v21 = k;v22 = k < 64;if ( k >= 64 )break;v23 = v4;v24 = v4 < 0;if ( v4 >= 0 ){v27 = v4;v28 = 2 * v4;v4 *= 2LL;}else{v25 = 2 * v4;v26 = 2 * v4;v4 = 2 * v4 ^ 0xB0004B7679FA26B3LL;}v29 = k;}v30 = 8 * j;v31 = &s1[8 * j];*v31 = v4;v32 = j + 1;}v33 = memcmp(s1, &unk_402170, 0x30uLL);v34 = v33 != 0;if ( v33 != 0 )puts("Wrong!");elseputs("Correct!");return v10;
}

伪代码进一步简化如下:

_int64 __fastcall main(__int64 a1, char **a2, char **a3)
{signed __int64 v4; signed int j,i,k; char s1[48],s[60]; unsigned __int8 v14; char *v16; int v33; memset(s, 0, 0x30uLL);memset(s1, 0, 0x30uLL);printf("Input:", 0LL);scanf_s("%s", s);for (i = 0; ; ++i){if (i >= 64)break;v14 = s[i];if (v14 == '\n'){v16 = &s[i];*v16 = 0;break;                            //换行符换成 '/0 '}}for (j = 0; j < 6; ++j){v4 = *&s[8 * j];                       // 输入的每8个字节一组,组成1个64位的v4,小端序for (k = 0; k < 64 ; ++k)              // 循环64次{if (v4 >= 0)                      // 如果v4非负,v4*=2,相当于左移一位,结果必为偶数,如果左移一位后最高位为1,则v4变成了负数v4 *= 2LL;else                              // 如果v4为负,v4乘2后再异或0xB0004B7679FA26B3,相当于先左移一位再异或,结果必为奇数,注意这时最高位的1被移出了v4 = 2 * v4 ^ 0xB0004B7679FA26B3LL;}}v33 = memcmp(s, &unk_402170, 0x30uLL);     /*(冗余码)unk_402170=[0x96, 0x62, 0x53, 0x43, 0x6D, 0xF2, 0x8F, 0xBC, 0x16, 0xEE, 0x30, 0x05, 0x78, 0x00, 0x01, 0x52, 0xEC, 0x08, 0x5F, 0x93, 0xEA, 0xB5, 0xC0, 0x4D, 0x50, 0xF4, 0x53, 0xD8, 0xAF, 0x90, 0x2B, 0x34, 0x81, 0x36, 0x2C, 0xAA, 0xBC, 0x0E, 0x25, 0x8B,0xE4, 0x8A, 0xC6, 0xA2, 0x81, 0x9F, 0x75, 0x55]  */if (v33 != 0)puts("Wrong!");elseputs("Correct!");return 0;
}

3.可以辨认出是CRC32编码

0xB0004B7679FA26B3就是生成多项式对应的代码,上面的算法是根据信息段【即我们的输入】求对应冗余码(CRC码)并与正确冗余码【unk_402170】比较的过程。

Exp:

unk_402170=['96','62','53','43','6D','F2','8F','BC','16','EE','30','05','78','00','01','52','EC','08','5F','93','EA','B5','C0','4D','50','F4','53','D8','AF','90','2B','34','81','36','2C','AA','BC','0E','25','8B','E4','8A','C6','A2','81','9F','75','55']
a=0
flag=''
for i in range(6):v4='0x'+unk_402170[a+7]+unk_402170[a+6]+unk_402170[a+5]+unk_402170[a+4]+unk_402170[a+3]+unk_402170[a+2]+unk_402170[a+1]+unk_402170[a]s=int(v4,16)                                                                 #转化成int型for j in range(64):    if s&1==1:s=((s^int('0xB0004B7679FA26B3',16))>>1)|0x8000000000000000          #根据奇偶性判断是否需要异或。else:s=s>>1print(hex(s)[2:])flag+=hex(s)[2:]a=a+8j=0while j < 8:flag+= chr(s&0xFF)s >>= 8j += 1
print(flag)

[RoarCTF2019]polyre相关推荐

  1. REVERSE-PRACTICE-BUUCTF-19

    REVERSE-PRACTICE-BUUCTF-19 [RoarCTF2019]polyre [安洵杯 2019]game [SCTF2019]Strange apk [CFI-CTF 2018]In ...

  2. 7-3 学习打卡(12.5)

    昨日和自己小组总结完,昨日状态确实不好,不过做分享好像挺有趣的,好了这周五终于可以公费旅游了,准备录个vlog,虽然又又又是去武汉,不过也算是公费旅游. 今天要把逃避很久的平坦化干掉,自从给这题ban ...

  3. BUUCTF reverse题解汇总

    本文是BUUCTF平台reverse题解的汇总 题解均来自本人博客 目录 Page1 Page2 Page3 Page4 Page1 easyre reverse1 reverse2 内涵的软件 新年 ...

  4. 2021-08-09[RoarCTF2019]黄金6年、从娃娃抓起

    [RoarCTF2019]黄金6年 线索:一段视频,一帧一帧审 最后这一个差点没找到 看到几个二维码 key1:i key2:want key3:play key4:ctf iwantplayctf ...

  5. BUU-RSA [RoarCTF2019]babyRSA(威尔逊定理)

    [RoarCTF2019]babyRSA(威尔逊定理) 题目 import sympy import randomdef myGetPrime():A= getPrime(513)print(A)B= ...

  6. BUUCTF:[RoarCTF2019]黄金6年

    题目地址:https://buuoj.cn/challenges#[RoarCTF2019]%E9%BB%84%E9%87%916%E5%B9%B4 题目attachment.mp4 使用Kinove ...

  7. buu-[RoarCTF2019]polyre(控制流平坦化,虚假控制流程)

    这题一开始拿到人看麻了(不会),写篇wp记录新题型 这么一大大大串的函数图,是经过OLLVM 的控制流平坦化混肴. 控制流平坦化(Control Flow Flattening)的基本思想主要是通过一 ...

  8. BUUCTF misc 专题(78)[RoarCTF2019]黄金6年

    下载附件,是个mp4文件 用普通的播放器打开,放慢看,会发现视频中的一些书本上面有二维码 用Kinovea打开视频(比较方便,能保存视频中的图片内容) 扫描上面的二维码 拼出来是iwantplay,应 ...

  9. 2021-07-07

    [RoarCTF2019]RSA 题目 A=(((y%x)**5)%(x%y))**2019+y**316+(y+1)/x p=next_prime(z*x*y) q=next_prime(z) A ...

最新文章

  1. android手机数字取证,基于Android智能终端微信应用的数字取证分析模型的研究
  2. 算法笔记-图--bfs
  3. 红米note3android驱动,红米note3 mtp驱动
  4. python的优缺点-Python 有什么一般人不知道的缺点?
  5. python项目开发实战-给缺少Python项目实战经验的人
  6. Windows系统C语言获取文件夹来的所有文件名的方法
  7. Ambari 架构(三)Ambari Server 架构
  8. spring cloud config动态刷新_SpringCloud-Config
  9. 非库存采购的自动记帐
  10. linux桌面环境知乎,24 个值得尝试的 Linux 桌面环境 | Linux 中国
  11. 测试nb信号的软件_NB-IOT的OTA测试(功率、灵敏度测试)
  12. 联想Y 系列 四面壳展示
  13. Linux——VIM学习选取多行(转)
  14. Flutter Icons 与 CupertinoIcons 的不一样的体验
  15. Java Web实训项目:西蒙购物网(中)
  16. Vue.js 服务器端渲染指南
  17. php 辗转相除法,手撸golang 基本数据结构与算法 最大公约数 欧几里得算法/辗转相除法...
  18. Convert your single instance to 10g RAC by manual
  19. 阿里为什么推荐使用LongAdder?而不是AtomicLong?
  20. 远程读取mysql_远程获取数据库和文件的方法

热门文章

  1. python中占位符包括_python中占位符
  2. 宇视摄像机实况画面不清晰排查方法
  3. 社群运营和用户运营的区别
  4. 灰色系统预测模型GM(1,1),GM(1,n)及Matlab实现
  5. 华为数通HCIA学习笔记之OSI参考模型TCP/IP模型
  6. 【李佳辉_周报_2022.10.30】
  7. javaFX裁剪视频exe
  8. PHP正则表达式提取html超链接中的h…
  9. ItunesConnect:苹果内购项目元数据缺失
  10. 数据库复习 - PART2 - 建模设计与范式