修改任意Linux进程地址空间实施代码注入(linux修改地址命令)

修改任意Linux进程地址空间实施代码注入# 代码就不展示了,很简单,就是把75 c7改成75 00即可。
[rootlocalhost test]# ./a.out 5446 4006a3 # base(0x4

# 代码不显示。只需将75 c7 更改为75 00 即可。

[root@localhost test]# ./a.out 5446 4006a3 # 基址(0x400000) + 偏移量(0x6a2+1)

我们用psss来看看情况。

值:5446 地址:0x7ffd4943cf18 pid:5446

值:5446 地址:0x7ffd4943cf18 pid:5446

值:5446 地址:0x7ffd4943cf18 pid:5446

让我们打破循环吧!

成功逃离无限循环!

接下来,尝试简单的进程注入来调用僵尸函数。

请参阅原始程序代码。

//pokestack.c

#include stdio.h

#包括stdlib.h

void Say\\_hi()

{

printf(\’皮鞋\\n\’);

结束(0);

}

int main(int argc, char \\*\\*argv)

{

int tf=atoi(argv[1]);

长a=0x1122334455667788;

而(tf){

printf(\’value:%lx 地址:%p pid:%d\\n\’, a, a, getpid());

sleep(120); //120秒内完成手动操作。您还可以使用getchar。

}

printf(\’请中断循环!\\n\’);

}

请注意,我们没有在任何地方调用Say_hi 函数。接下来,修改mem文件,以便该程序可以调用Say_hi。

让我们从运行开始:

[root@localhost 测试]# ./pokestack 1

值:1122334455667788 地址:0x7fff75a4ba80 pid:5553

与往常一样,这次的目标是在堆栈中找到推送的唤醒地址并更改它。

如果你不想每次都检查堆栈位置,你可以像这样关闭ASLR 保护:

sysctl -w kernel.randomize_va_space=0

然而,这里并没有使用这个技巧,以使事情变得更加真实。在现实环境中,ASLR 很少被关闭。

毕竟堆栈位置是随机的,而且每次都不同,所以需要检查一下。

[root@localhost test]# cat /proc/5553/smaps |grep -E \\\\[stack\\\\]

7fff75a2c000-7fff75a4d000 rw-p 00000000 00:00 0 [堆栈]

[root@localhost test]# dd if=/proc/5553/mem of=./pokestack.dd Skip=140735166988288 bs=1 count=557056

记录135168+0次读取

记录135168+0次写入

135168 字节(135 KB) 副本,0.165683 秒,816 KB/秒

[root@localhost 测试]# hexdump ./pokestack.dd ./pokestack.hex

我开始在pokestack.hex中寻找sleep的返回地址,发现了这一行:

001fa60 bb70 75a4 7fff 0000 06ff 0040 0000 0000

这就是4006ff 的全部内容。

如何找到它们超出了本文的范围,只需按照以下模式进行匹配即可:

返回main函数应该是400000左右.

我们将其更改为say_hi 的地址:

#0x7FFF75A4BA68是堆栈基地址与0x001fa60+0x8之和。

#0x000000000040067d 是say\\_hi 的地址。

# 将位置0x7FFF75A4BA68的值更改为0x000000000040067d

[root@localhost 测试]# ./a.out 55530x7FFF75A4BA680x000000000040067d

等待它重新进入睡眠状态,然后检查效果。

值:1122334455667788 地址:0x7fff75a4ba80 pid:5553

皮鞋

[root@localhost 测试]#

效果不错。

现在让我们将另一个代码注入到已经运行的进程中。

//pokestack.c

#include stdio.h

#包括stdlib.h

int main(int argc, char \\*\\*argv)

{

\\_\\_asm(\’mov $123, %rdi\\n\’); //该语句导出退出系统调用参数123 的命令代码。

另一方面(1) {

printf(\’pid:%d\\n\’, getpid());

睡眠(120);

}

}

导出堆栈信息。

[root@localhost test]# cat /proc/6033/smaps |grep -E -A2 \\\\[stack\\\\]

7ffe66868000-7ffe66889000 rw-p 00000000 00:00 0 [堆栈]

大小: 136KB

RSS: 16kB

请注意,堆栈没有执行权限,因此必须将其插入二进制文件的文本部分。

如果堆栈是可执行的,您所需要做的就是用注入代码覆盖堆栈的开头,堆栈将处于运行状态(堆栈从上到下增长,因此通常不会增长那么远) )。这并不难。只需使用以下命令编译它:

[root@localhost test]# gcc -O0 -z execstack pokestack.c -o pokestack

然而,为了让事情更现实,没有使用这个技巧,因为在真实环境中使堆栈可执行的方法很少。

现在我们来看一下二进制文本段信息。

[root@localhost test]# cat /proc/6033/smaps |grep -A2 r-xp.\\*pokestack

00400000-00401000 r-xp 00000000 fd:00 75346995 /usr/test/pokestack

大小: 4kB

Rss: 4kB

实现注入的代码如下:

#include sys/types.h

#include sys/stat.h

#包括fcntl.h

#include stdio.h

#包括stdlib.h

int main(int argc, char \\*\\*argv)

{

角色名称[32];

int fd;

PID;

无符号长caddr、raddr;

无符号长ret_addr;

//代码只是一个exit(123) 系统调用

字符代码[14]={0x48,0xc7,0xc7,0x7b,0x00,0x00,0x00,0xb8,0x3c,0x00,0x00,0x00,0x0f,0x05};

pid=atoi(argv[1]);

caddr=strtoul(argv[2], NULL, 16);

raddr=strtoul(argv[3], NULL, 16);

sprintf(名称, \’/proc/%d/mem\’, pid);

fd=open(名称, O_RDWR);

lseek(fd, caddr, SEEK\\_SET);

写(fd,代码,sizeof(代码));

lseek(fd, raddr, SEEK\\_SET);

写(fd,caddr,sizeof(caddr));

}

代码不再解释,直接看效果。

#0x7FFE66887998 仍然是dd 方法导出的堆栈中找到的返回地址地址。

[root@localhost 测试]# ./a.out 60330x004000000x7FFE66887998

查看进程号6033 的末尾。

[root@localhost 测试]# ./pokestack

pid:6033

[root@localhost 测试]# echo $?

一二三

最终以123分顺利结束。

下次为什么不尝试打印呢?大量印刷。

您需要插入对printf 的调用,但该调用通常使用相对偏移量进行调用,因此使用以下方法:

推送printf@GLIBC

但是printf 在哪里呢?让我们先快速解释一下。直接调用write 系统调用。

我们先看一下原来的代码。

#include stdio.h

#包括stdlib.h

int main(int argc, char \\*\\*argv)

{

另一方面(1) {

printf(\’pid:%d\\n\’, getpid());

getchar();

}

}

开始运行:

[root@localhost 测试]# ./pokestack

pid:14917

pid:14917

. # 按住任意键仍然执行getchar。这是一个无限循环。

一步步获取信息。

[root@localhost test]# cat /proc/14917/smaps |grep -E \\\\[stack\\\\]

7ffc08ac1000-7ffc08ae2000 rw-p 00000000 00:00 0 [堆栈]

[root@localhost test]# dd if=/proc/14917/mem of=./pokestack.dd Skip=140720453980160 bs=1 count=557056

[root@localhost 测试]# hexdump ./pokestack.dd ./pokestack.hex

.

我在pokestack.hex 中找到了以下行:

001f4a0 0000 0000 0000 0000 05dc 0040 0000 0000

拼接偏移:

0x7ffc08ac1000 +0x001f4a0 +0x08=0x7FFDF4F9E818

编写注入代码并实现注入的代码如下:

#include sys/types.h

#include sys/stat.h

#包括fcntl.h

#include stdio.h

#包括stdlib.h

int main(int argc, char \\*\\*argv)

{

角色名称[32];

int fd;

PID;

无符号长caddr、raddr;

无符号长ret_addr;

字符代码[58]={/\\*0x00\\*/0x61,0x61,0x61,0x0a,

/*0x04\\*/0x00,0x00,0x00,0x00,

/*0x08\\*/0x00,0x00,0x00,0x00,

/*0x0c*/0x00,0x00,0x00,0x00,

/*0x10\\*/0x48,0xc7,0xc7,0x01,0x00,0x00,0x00, //移动1, rdi

0x48,0xc7,0xc6,0x00,0x00,0x40,0x00, //移动400000, rsi

0x48,0xc7,0xc2,0x04,0x00,0x00,0x00, //移动4, rdx

0xb8,0x01,0x00,0x00,0x00, //移动1, eax

0x0f,0x05,//写入系统调用

0x48,0xc7,0xc7,0x7b,0x00,0x00,0x00, //移动123, rdi

0xb8,0x3c,0x00,0x00,0x00, //移动60, eax

0x0f,0x05}; //完成系统调用。

pid=atoi(argv[1]);

caddr=strtoul(argv[2], NULL, 16);

raddr=strtoul(argv[3], NULL, 16);

sprintf(名称, \’/proc/%d/mem\’, pid);

fd=open(名称, O_RDWR);

lseek(fd, caddr, SEEK\\_SET);

写(fd,代码[0],sizeof(代码));

caddr +=0x10; //从mov 1,rdi开始执行。

lseek(fd, raddr, SEEK\\_SET);

写(fd,caddr,sizeof(caddr));

}

实现注入:

[root@localhost 测试]# ./a.out 149170x004000000x7FFC08AE04A8

检查效果:

[root@localhost 测试]# ./pokestack

pid:14917

pid:14917

[root@localhost 测试]# echo $?

一二三

[root@localhost 测试]#

是的,我摆脱了无限循环,最终得到了123。

是不是比ptrace更好玩?

……

我们希望直接调用GLIBC库函数,而不是直接调用系统调用。其实,这并不难。

首先看一下下面的代码。

#include stdio.h

char abc1[]=\’aaaa\\n\’;

int main()

{

printf(\’\\n\\n\’); //加载程序时解析printf 函数

\\_\\_asm(\’mov $0x000000000060102c, %rdi\’); //abc1 的地址作为rdi 寄存器的参数给出

\\_\\_asm(\’push $0x40053d\’) //主函数之后的位置\\_asm(\’ret\’)

\\_\\_asm(\’push $0x0000000000400400\’); //printf 位置

\\_\\_asm(\’ret\’);

}

所有数字都可以从objdump 手动找到。

运行并检查是否输出aaaa。

使用该方法来实现注入。这仍然是一个原始程序。

#include stdio.h

#包括stdlib.h

int main(int argc, char \\*\\*argv)

{

另一方面(1) {

printf(\’pid:%d\\n\’, getpid());

getchar();

}

}

开始运行:

[root@localhost 测试]# ./pokestack

![](https://img-blog.csdnimg.cn/img_convert/9a8cb5f8c0ec69e6499adead0da6e95b.png)

适合Linux 初学者和专家的最全面的Linux 教程。

=====================

1. **Linux从初学者到专家(第二版)**

2. **移植Linux系统**

3. **Linux驱动开发介绍与实践**

4. **LINUX系统移植第二版**

5. **详细讲解Linux开源网络全栈,从DPDK到OpenFlow**

!【华为18级工程师苦心编写3000页Linux学习笔记本教程】(https://img-blog.csdnimg.cn/img_convert/59742364bb1338737fe2d315a9e2ec54.png)

第一版《Linux从入门到精通》 466 页

===================

简单的介绍

====

这是经典Linux畅销书**《Linux从入门到精通》**的第二版,受到了众多读者的好评。本书第一版自出版以来已多次印刷,并荣获51CTO读书频道“最受读者喜爱的原创IT技术图书奖”。书号?本书采用最新的Ubuntu 12.04版本,循序渐进地向读者介绍Linux基本应用、系统管理、网络应用、娱乐办公、程序开发、服务器配置、系统安全等。本书附带一张CD,其中包含支持本书的多媒体教育视频。另外,本书还为读者提供了大量的Linux学习资料和Ubuntu安装镜像文件供读者免费下载。

!【华为18年级工程师苦心编写3000页Linux学习笔记本教程】(https://img-blog.csdnimg.cn/img_convert/9d4aefb6a92edea27b825e59aa1f2c54.png)

**本书适合初、中级Linux用户、开源软件爱好者、大学生。它还适合准备进行Linux 平台开发的各类人员。 **

需要《Linux入门到精通》、《linux系统移植》、《Linux驱动开发入门实战》、《Linux开源网络全栈》电子书和教程的工程师朋友请转发评论。

# 以上修改Linux进程地址空间实现代码注入的相关内容摘自网络,仅供参考。相关信息请参见官方公告。

原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92133.html

(0)
CSDN的头像CSDN
上一篇 2024年6月25日
下一篇 2024年6月25日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注