高铁北京回杭州的路上,想到一个简单的话题。
在一个复杂的程序中,发生踩内存是一件非常恶心的事情,很难通过什么线索直到谁在哪个函数中往哪个地址写了什么,比方说数组越界写什么的。
去年,我曾经长篇大论了一篇:
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
和去年那篇相比,本文实现了更加细粒度的内存写监控。去年那个是函数级别的,本文这个是则是指令级别的,从上面的代码和执行效果上,可以一目了然!
当然了,经理会认为这些不值得一提。
浙江温州皮鞋湿,下雨进水不会胖!
转载:https://blog.csdn.net/dog250/article/details/106670543
查看评论