解压vmlinux+linux如何进入内核+部分内联汇编+std缓冲区和fflush

vmlinuz解压为vmlinux并还原符号

测试用的是ubuntu 16.04的vmlinuz

1.将vmlinuz解压成vmlinux

dd if=/boot/vmlinuz-4.10.0-28-generic skip=`grep -a -b -o -m 1 -e $'\x1f\x8b\x08' /boot/vmlinuz-4.10.0-28-generic | cut -d: -f 1` bs=1 | zcat > /tmp/vmlinux
# dd 读取vmlinuz的内容
# skip跳到gzip的头
# grep查找gzip标志 “1f 8b” + 压缩标志 8 == \x1f\x8b\x08 并利用cat获取该位置所处的行
# 将dd的输出利用zcat读取压缩数据并重定向为vmlinx文件

2.用ida打开解压后的vmlinux

​ 此时发现ida中打开的vmlinux没有符号信息,可以利用System.map将符号信息还原

​ 从/boot/目录下将System.map拷贝出来

3.将System.map-4.10.0-28-generic复制到vmlinux同一个目录,然后执行python脚本,利用idapython还原符号信息

import idaapi
import idautils
import idc

def do_rename(funfile):
    with open(funfile, 'r') as f:
        for line in f:
            line = line.strip()
            items = line.split()
            if len(items) >= 3:
                    print(items[0], items[2])
                    if items[2].startswith("sub_") or items[2].startswith("byte_") or items[2] == "af":
                        # 处理ida不能重命名特殊情况
                        # sub_这种函数的开头
                        # 数据类型开头,这里只处理了byte_
                        # 符号名与寄存器重名,这里处理了af
                        # 需要根据运行脚本弹出的提示进行相应的添加
                        items[2] = "a_"+items[2]# 重命名追加一个a_
                        print(items[2])
                    idc.set_name(int(items[0], 16), items[2])
                    # System.map中存在不同地址两个函数同名的情况,这种暂时没有处理

if __name__ == "__main__":
    funfile = 'System.map-4.10.0-28-generic'
    do_rename(funfile)

linux调用syscall命令之后如何进入内核

// 首先讲一下syscall初始化的过程
start_kernel->trap_init->cpu_init->syscall_init;
// 主要是进行中断初始化和系统调用初始化

// 在syscall_init过程中
syscall_init->entry_syscall_64->swapgs;
entry_SYSCALL_64_after_swapgs->entry_syscall64_slow_path->do_syscall_64->ds:sys_call_table;

正常的触发系统调用时,应该是直接进入到entry_syscall_64,然后swapgs切换到内核的gs。gs.base存储了中断stack的地址

关于内联汇编的一些笔记

// 内联汇编格式
// asm ("asm code" [: "=x" (output) ][: "x" (inuput)]  [:"x"  (alter)])。
//其中%0...n-1,代表第几个参数,参数数量为:max(10,xxx)
// movq $1f , %0 1: 这个1f中的1代表“1:”的1,“f”代表向前,
// 1:代表标号,类似于汇编中的"_start:",只是一个标记
#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
#define get_sp(sp) asm("movq %%rsp, %0" : "=r" (sp) :)
#define get_ip(ip) asm("movq $1f, %0\n\t"\
                    "1:": "=r" (ip) :)

关于printf缓冲区和fflush

// printf scanf等函数在获取输入后不添加"\n",则不会将缓冲区写回,导致函数达不到预期效果
// 举例1
	printf("%d",1);// 在不执行exit或者其他的缓冲区函数时,printf的内容并不会打印回缓冲区
// 举例2
	int buf,c;
	scanf("%d",buf);
	c = getchar();// scanf不添加"\n"会导致这个getchar不会获取用户输入,仿佛函数没有执行
	printf("%d\n",c);// 打印结果为10,即"\n"的ascii码

// 百度举例2的解决方案时,发现有提示使用fflush(stdin)的方式刷新缓冲区,但是实际上没有解决问题
// 后找其原因,有说法是vc支持fflush而gcc不支持
/**
	gcc 标准没有定义fflush(stdin)
	fflush on input stream is an extension to the c standard(fflush操作输入流是对c标准的扩充)
*/
// 解决方案
// 1:
	setbuf();// 不推荐
// 2:
	int c;
	while((c=getchar())!='\n');

// 在研究printf的过程中,发现了关于exit的有趣事情
_exit(); // 直接结束进程进入到内核中
exit(); // 清理i/o缓冲区后在退出进程
// 但是,如果你在一个c程序中
int a=1;
printf("aaa\n");  // stdio.h
printf("bbb");// 这里没有"\n",不会立即将缓冲区的数据写入到stdout
_exit(0); // 此处退出,没有对缓冲区数据写回,故只打印了aaa // unistd.h
// return 0; // 打印 aaa bbb
// exit(0);  // 打印 aaa bbb // stdlib.h
// 如果用exit肯定会打印两行,因为清理缓冲区的操作会将缓冲区的数据写回
// 直接return依旧会打印两行?,我在一本书上看到,main函数实质是exit函数的一个回调
// 即:
	exit(main(argc, argv));// main实际是被这样执行的????真的假的???
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值