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

和去年那篇相比,本文實現了更加細粒度的內存寫監控。去年那個是函數級別的,本文這個是則是指令級別的,從上面的代碼和執行效果上,可以一目瞭然!

當然了,經理會認爲這些不值得一提。


浙江溫州皮鞋溼,下雨進水不會胖!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章