Linux用户态进程监控内存写排查踩内存

高铁北京回杭州的路上,想到一个简单的话题。

在一个复杂的程序中,发生踩内存是一件非常恶心的事情,很难通过什么线索直到谁在哪个函数中往哪个地址写了什么,比方说数组越界写什么的。

去年,我曾经长篇大论了一篇:
https://blog.csdn.net/dog250/article/details/90690292

现在看来,我又忍不住怼一波了…那篇文章里的方法纯粹就是为了炫技,搞什么又是纯汇编又是内联汇编,简直太复杂了。

本文给出一个清新版的,试试看下面的代码:

// mem_monitor.c
#include <sys/mman.h>
#include <stdio.h>
#include <signal.h>
#include <asm/processor-flags.h>

char *buff = NULL;

void new_func(int index)
{
	buff[index] = 'c'; // write memory!
	buff[index + 1] = 'd'; // write memory!
}

void main_func()
{
	buff[0] = 'a'; // write memory!
	buff[1] = 'b'; // write memory!
	new_func(2);
	buff[4] = 'e'; // write memory!
}

#define F_OFFSET		200
#define PC_OFFSET		192
#define BP_OFFSET		144
#define CR2_OFFSET		240

// 单步信号处理函数
void resume_trap()
{
	unsigned long *p;

	p = (unsigned long*)((unsigned char *)&p + F_OFFSET);

	mprotect(buff, 1024, PROT_READ);
	*p &= ~X86_EFLAGS_TF;

}

// 写保护信号处理函数
void wp_trap(int signo)
{
	unsigned long *p;

	p = (unsigned long*)((unsigned char *)&p + PC_OFFSET);
	printf("---RIP:[%lx]----", *p); // 打印指令地址
	p = (unsigned long*)((unsigned char *)&p + BP_OFFSET);
	printf("STACK:[%lx]----", *p);  // 打印堆栈地址
	p = (unsigned long*)((unsigned char *)&p + CR2_OFFSET);
	printf("at Address:[%lx]----\n", *p); // 打印写入的位置

	p = (unsigned long*)((unsigned char *)&p + F_OFFSET);
	*p |= X86_EFLAGS_TF;

	mprotect(buff, 1024, PROT_READ|PROT_WRITE);

	return;
}

int main()
{
	int i;

	buff = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
	printf("buffer base at[%lx]\n", buff);
	mprotect(buff, 1024, PROT_READ);

	signal(SIGSEGV, wp_trap);
	signal(SIGTRAP, resume_trap);

	main_func();
	buff[5] = 'f'; // write memory!

	for (i = 0; i < 6; i++) {
		printf("%c ", buff[i]);
	}
	printf("\n");

	return 0;
}

来,看下效果:

[root@localhost checker]# gcc mem_monitor.c
[root@localhost checker]# ./a.out
buffer base at[7f0f8c72e000]
---RIP:[40067a]----STACK:[7fffb98ec3c0]----at Address:[7f0f8c72e000]----
---RIP:[400688]----STACK:[7fffb98ec3c0]----at Address:[7f0f8c72e001]----
---RIP:[400653]----STACK:[7fffb98ec3b0]----at Address:[7f0f8c72e002]----
---RIP:[40066a]----STACK:[7fffb98ec3b0]----at Address:[7f0f8c72e003]----
---RIP:[4006a0]----STACK:[7fffb98ec3c0]----at Address:[7f0f8c72e004]----
---RIP:[40083b]----STACK:[7fffb98ec3e0]----at Address:[7f0f8c72e005]----
a b c d e f

和去年那篇相比,本文实现了更加细粒度的内存写监控。去年那个是函数级别的,本文这个是则是指令级别的,从上面的代码和执行效果上,可以一目了然!

当然了,经理会认为这些不值得一提。


浙江温州皮鞋湿,下雨进水不会胖!

展开阅读全文
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值