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实际是被这样执行的????真的假的???