C语言花式玩法之把函数拷贝到数组执行 (需要mprotect)

在阅读内核代码的时候,明白了内核是通过页表项中的标志位_PAGE_READ,_PAGE_WRITE,_PAGE_EXECUTE来区分页的权限的。

进程在内核中的地址空间代码段,数据段,堆,栈之间最大的区别也是权限的区别,而系统调用mprotect恰好是用来改变内存页的权限的。

是否可以通过mprotect可以把栈上的数组修改成可执行权限,然后把函数内容拷贝到数组执行呢?值得尝试一下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <sys/mman.h>
 4 #include <sys/types.h>
 5 #include <string.h>
 6 #include <errno.h>
 7 #include <unistd.h>
 8
 9 int m_add(int i)
10 {
11         return i+10;
12 }
13
14 int show_map()
15 {
16         char command[256];
17         sprintf(command, "cat /proc/%d/maps", getpid());
18         system(command);
19 }
20
21 int main()
22 {
23         int (*func_p)(int);
24         int size;
25         int ret;
26         char m[1000];
27         size = (char *)show_map - (char *)m_add;
28         printf("size = %d\n",size);
29         func_p = m;
30
31         ret = mprotect((void *)((long)func_p&(~0XFFFUL)), 4096, PROT_READ|PROT_WRITE|PROT_EXEC);
32         if(ret < 0){
33                 perror("mprotect: ");
34                 exit(ret);
35         }
36
37         memcpy(func_p,m_add,size);
38
39         printf("m_add(24) = %d\n",m_add(24));
40         printf("func_p(63) = %d\n",func_p(63));
41         printf("m_add = %p, func_p = %p\n", m_add, func_p);
42         show_map();
43         return 0;
44 }

执行结果:

size = 15
m_add(24) = 34
func_p(63) = 73
m_add = 0x561528db08c0, func_p = 0x7ffd4c19e300
561528db0000-561528db1000 r-xp 00000000 fe:01 477434                     /home/test/a.out
561528fb0000-561528fb1000 r--p 00000000 fe:01 477434                     /home/test/a.out
561528fb1000-561528fb2000 rw-p 00001000 fe:01 477434                     /home/test/a.out
5615298e7000-561529908000 rw-p 00000000 00:00 0                          [heap]
7fcc3280c000-7fcc329a1000 r-xp 00000000 fe:01 329984                     /lib/x86_64-linux-gnu/libc-2.24.so
7fcc329a1000-7fcc32ba1000 ---p 00195000 fe:01 329984                     /lib/x86_64-linux-gnu/libc-2.24.so
7fcc32ba1000-7fcc32ba5000 r--p 00195000 fe:01 329984                     /lib/x86_64-linux-gnu/libc-2.24.so
7fcc32ba5000-7fcc32ba7000 rw-p 00199000 fe:01 329984                     /lib/x86_64-linux-gnu/libc-2.24.so
7fcc32ba7000-7fcc32bab000 rw-p 00000000 00:00 0
7fcc32bab000-7fcc32bce000 r-xp 00000000 fe:01 329980                     /lib/x86_64-linux-gnu/ld-2.24.so
7fcc32dbc000-7fcc32dbe000 rw-p 00000000 00:00 0
7fcc32dcb000-7fcc32dce000 rw-p 00000000 00:00 0
7fcc32dce000-7fcc32dcf000 r--p 00023000 fe:01 329980                     /lib/x86_64-linux-gnu/ld-2.24.so
7fcc32dcf000-7fcc32dd0000 rw-p 00024000 fe:01 329980                     /lib/x86_64-linux-gnu/ld-2.24.so
7fcc32dd0000-7fcc32dd1000 rw-p 00000000 00:00 0
7ffd4c17e000-7ffd4c19e000 rw-p 00000000 00:00 0
7ffd4c19e000-7ffd4c19f000 rwxp 00000000 00:00 0                          [stack]
7ffd4c1e1000-7ffd4c1e3000 r--p 00000000 00:00 0                          [vvar]
7ffd4c1e3000-7ffd4c1e5000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

可以看到,函数指针func_p实际指向的是char数组m[1000]的地址,其值为0x7ffd4c19e300 确实位于栈7ffd4c19e000-7ffd4c19f000上面,而其成功的执行了+10的操作,返回了正确结果。

这个例子没有实际应用价值,一旦函数中存在库函数的调用,一般就会报错了。

不过它说明了从C语言往下看,栈,堆,数据段,代码段统统都是内存,只要配置相同,相互之间并无本质区别。

C语言是操作内存的语言,在经过操作系统的封装后,它所看到的是无差别的内存。所有的数据类型,你都可以把它们理解成语法糖。

那它和汇编有什么区别?汇编是操作CPU和寄存器的语言,可以访问CPU专有指令,可以访问特定的寄存器,而C语言的初衷,便是抹平体系结构之间的差异。

原文地址:https://www.cnblogs.com/yuanjianye/p/9301856.html

时间: 2024-08-02 11:33:35

C语言花式玩法之把函数拷贝到数组执行 (需要mprotect)的相关文章

C语言复习---矩形法求定积分函数

一:分析: 大一学习积分的时候,我们学习过,可以通过矩形法来求定积分. 思路就是将积分区间划分成n等份,然后将这n等份近似看成矩形(或梯形),然后对所有的矩形(或梯形)的面积进行求和. 二:简单的例子 求函数X^2在的定积分 矩形法: #include<iostream> #include<math.h> using namespace std; int main(){ float fun(float x); float a, b; cout << "请输入函

JavaScript的三种工业化玩法

JavaScript的三种工业化玩法 软件工程中任何的语言如果想要写出健壮的代码都需要锋利的工具,当然JavaScript也不例外,很多朋友刚入门的时候往往因为工具选的不对而事半功倍,JavaScript同样需要软件调试技术,希望本文总结的三种工具会对大家的学习有所帮助. 任何语言的学习都离不开实践,不写代码是永远学不会编程的,当然javascript也不例外,很多人推荐直接浏览器调试,个人觉得这个推荐应该是非常初级的,比如Chrome, Firefox确实提供了实用的前端调试工具,但是个人认为

openresty+lua在反向代理服务中的玩法

openresty+lua在反向代理服务中的玩法 phith0n · 2015/06/02 10:35 0x01 起因 几天前学弟给我介绍他用nginx搭建的反代,代理了谷歌和维基百科. 由此我想到了一些邪恶的东西:反代既然是所有流量走我的服务器,那我是不是能够在中途做些手脚,达到一些有趣的目的. openresty是一款结合了nginx和lua的全功能web服务器,我感觉其角色和tornado类似,既是一个中间件,也结合了一个后端解释器.所以,我们可以在nginx上用lua开发很多“有趣”的东

[C#] 软硬结合第二篇——酷我音乐盒的逆天玩法

1.灵感来源: LZ是纯宅男,一天从早上8:00起一直要呆在电脑旁到晚上12:00左右吧~平时也没人来闲聊几句,刷空间暑假也没啥动态,听音乐吧...~有些确实不好听,于是就不得不打断手头的工作去点击下一曲或是找个好听的歌来听...但是,[移动手锁定鼠标-->移动鼠标关闭当前页面选择音乐软件页面-->选择合适的音乐-->恢复原来的界面] 这一过程也会烦人不少,如果说软件的设计要在用户体验上做足功夫,感觉这一点是软件设计人员很难管住的方面,毕竟操作系统也就这样安排的嘛(当然,有些机智的开发人

js命名空间的玩法详解

1.首先为什么要用js命名空间          在我们的项目中,如果多个人为同一个页面写js的话,命名冲突就有可能发生,如果所有的函数都是全局的话,如下: a.js中 function com() {   ..... } b.js中 function com() {     ........ } 且一个页面同时引用了这两个js文件,这样我们调用的时候会出问题,可能老是调用到第一个文件里面的函数了,我之前在做一个项目的时候就碰到了这个问题,我自己b.js文件中ajax的响应函数的名字和a.js文

图解快三源码红黑玩法跨度等Python变量与赋值

图解快三源码红黑玩法跨度(企鹅:212303635)[阿酋联源码论坛-aqiulian.com]等Python变量与赋值 Python是一门独特的语言,与C语言有很大区别,初学Python很多萌新表示对变量与赋值不理解,学过C的都知道,给变量赋值时,需要先指定数据类型,同时会开辟一块内存区域,用于存储值,例如: int a = 1; a 就是内存空间中的一小块区域,就像是一个大房间里面的一个小盒子,赋值就是把整数1装载到盒子里面. 现在给变量a重新赋值 a = 2; 盒子依然是那个盒子,也就是说

PHP远程DoS漏洞深入分析快三红黑玩法及防护方案源码搭建

PHP远程DoS漏洞 PHP远程DoS漏洞深入分析快三红黑玩法(企鹅:212303635)及防护方案源码搭建(aqiulian.com) 4月3日,有人在PHP官网提交PHP 远程DoS漏洞(PHP Multipart/form-data remote dos Vulnerability),代号69364.由于该漏洞涉及PHP的所有版本,故其影响面较大,一经发布迅速引发多方面关注.14日,各种PoC已经在网络上流传.此次漏洞具备如下特性: 一旦被利用成功,可以在迅速消耗被***主机的CPU资源,

神经网络和深度学习之——前馈神经网络吉林快三带红黑玩法

前面一章我们详细讲解了神经网络的组成吉林快三带红黑玩法 话仙源码论坛下载地址 QQ2952777280,工作原理,信号在网络中如何流动,以及如何求解每一个输入信号赋予的权重等计算过程:同时我们还构建了一个逻辑回归网模型来解决鸢尾花分类问题,很明显,这种网络很"浅",但它对于分类鸢尾花数据还是非常有效的,而且不仅仅是鸢尾花,对于有需要的其他二分类问题,该模型也能表现得很好.由于这种模型太"浅"了,我们一般称这种模型为bp网络,而不直接称为神经网络,有些人甚至觉得这种网

轻量级高性能ORM框架:Dapper高级玩法

Dapper高级玩法1: 数据库中带下划线的表字段自动匹配无下划线的Model字段. Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; 备注: 这个对使用Mysql数据库的朋友最有帮助,因为Mysql默认都是小写,一般字段都带下划线,比如:user_name之类. 具体效果如下演示 1,首先创建一张表并插入数据 2,创建Model模型 public class User { public int UserID { get; set;