详解pwn-内核相关知识(2) – 作者:星云博创科技有限公司

0x00:前言

本篇文章接着内核中断(1)来进行源码的分析,文章难度较大,需要一定的汇编基础。中断分为两种:有错误码中断和无错误码中断,接下来我们来看正文部分。

0x01:源码

/* linux/kernel/asm.s */
.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
.globl _double_fault,_coprocessor_segment_overrun
.globl _invalid_TSS,_segment_not_present,_stack_segment
.globl _general_protection,_coprocessor_error,_irq13,_reserved

_divide_error:
  pushl $_do_divide_error

no_error_code:
  xchgl %eax,(%esp)
  pushl %ebx
  pushl %ecx
  pushl %edx
  pushl %edi
  pushl %esi
  pushl %ebp
  push %ds
  push %es
  push %fs
  pushl $0    # "error code"
  lea 44(%esp),%edx
  pushl %edx
  movl $0x10,%edx
  mov %dx,%ds
  mov %dx,%es
  mov %dx,%fs
  call *%eax
  addl $8,%esp
  pop %fs
  pop %es
  pop %ds
  popl %ebp
  popl %esi
  popl %edi
  popl %edx
  popl %ecx
  popl %ebx
  popl %eax
  iret

_debug:
  pushl $_do_int3    # _do_debug
  jmp no_error_code

_nmi:
  pushl $_do_nmi
  jmp no_error_code

_int3:
  pushl $_do_int3
  jmp no_error_code

_overflow:
  pushl $_do_overflow
  jmp no_error_code

_bounds:
  pushl $_do_bounds
  jmp no_error_code

_invalid_op:
  pushl $_do_invalid_op
  jmp no_error_code

_coprocessor_segment_overrun:
  pushl $_do_coprocessor_segment_overrun
  jmp no_error_code

_reserved:
  pushl $_do_reserved
  jmp no_error_code

_irq13:
  pushl %eax
  xorb %al,%al
  outb %al,$0xF0
  movb $0x20,%al
  outb %al,$0x20
  jmp 1f
1:  jmp 1f
1:  outb %al,$0xA0
  popl %eax
  jmp _coprocessor_error

_double_fault:
  pushl $_do_double_fault

error_code:
  xchgl %eax,4(%esp)    # error code <-> %eax
  xchgl %ebx,(%esp)    # &function <-> %ebx
  pushl %ecx
  pushl %edx
  pushl %edi
  pushl %esi
  pushl %ebp
  push %ds
  push %es
  push %fs
  pushl %eax      # error code
  lea 44(%esp),%eax    # offset
  pushl %eax
  movl $0x10,%eax
  mov %ax,%ds
  mov %ax,%es
  mov %ax,%fs
  call *%ebx
  addl $8,%esp
  pop %fs
  pop %es
  pop %ds
  popl %ebp
  popl %esi
  popl %edi
  popl %edx
  popl %ecx
  popl %ebx
  popl %eax
  iret
_invalid_TSS:
  pushl $_do_invalid_TSS
  jmp error_code
_segment_not_present:
  pushl $_do_segment_not_present
  jmp error_code
_stack_segment:
  pushl $_do_stack_segment
  jmp error_code
_general_protection:
  pushl $_do_general_protection
  jmp error_code

0x02:分析

该文件主要是定义了CPU异常产生的中断函数的调用。

分成2类:

  • 带返回错误码的中断调用
  • 不带返回错误码的中断调用

v2-5cf8047241a2a2c13aa2863ffa3a6355_720w.png

v2-9a1c5dd357e24cb31a592ca014af8068_720w.png

将所有的寄存器值入栈

SS:存放栈顶的段地址
SP:存放栈顶的偏移地址

一个栈也就是一块内存区域,我们必须要有基地址(也就是段地址左移4位)和偏移地址。

要在一个栈中寻址的话,也需要段地址和偏移地址。

——————————————————————————————————————–

CS:代码段寄存器
IP:指令段寄存器

CS:IP 指向可执行程序的起始地址

此后CPU从这个起始地址开始读取内存中的指令,并且执行。

CS:IP指向

  1. 你想让 CPU 执行哪行指令,你就让 CS:IP 指向保存有指令的那块内存即可。
  2. 任何时候,CS:IP 指向的地址中的内容都是 CPU 当前执行的指令。

————————————————————————————————-

前四步:

v2-854cdd4985a1b91351243924de887403_720w.png

===================================================

xchgl %eax,(%esp)

将eax的值保存在栈上,将中断处理函数的地址保存在eax寄存器中

xchg 交换eax 和esp的值

ESP 专门用作堆栈指针,被形象地称为栈顶指针

EAX是累加器,AX是算术的主要寄存器

asm.s包含着CPU探测到故障异常的底层代码程序,与traps.c关系密切,调用traps.c的程序打印出错信息,并退出。

v2-24be3b8fde9d7123d39e4ce88aae4b34_720w.png

对于不带出错号的中断过程,堆栈指针位置变化情况请参照图(a)。

在开始执行相应中断服务程序之前,堆栈指针esp指在中断返回地址一栏(图中 esp0处)。

当把将要调用的C函数do_ _divide_ error()或其他C函数地址入栈后,指针位置是esp1处,此时程序使用交换指令把该函数的地址放入eax寄存器中,而原来eax的值则被保存到堆栈上。

此后程序在把一些寄存器入栈后,堆栈指针位置处于esp2处。

当正式调用do_ divide_ error()之前, 程序会将开始执行中断程序时的原eip 保存位置(即堆栈指针esp0值)压入堆栈,放到esp3位置处,并在中断返回弹出入栈的寄存器之前指针通过加上8又回到esp2处。

对于CPU会产生错误号的中断过程,堆栈指针位置变化情况请参照图(b)。

在刚开始执行中断服务程序之前,堆栈指针指向图中esp0处。

在把将要调用的C函数do_ double_ fault()或其 他C函数地址入栈后,栈指针位置是esp1处。

此时程序通过使用两个交换指令分别把eax、ebx寄存器的值保存在esp0、esp1位置处,而把出错号交换到eax寄存器中:函数地址交换到了ebx寄存器中。随后的处理过程则和无错误号一样。

—————————————————————————————-

  • 一般寄存器:AX、BX、CX、DX

AX:累积暂存器,BX:基底暂存器,CX:计数暂存器,DX:资料暂存器

  • 索引暂存器:SI、DI

SI:来源索引暂存器,DI:目的索引暂存器

  • 堆叠、基底暂存器:SP、BP

SP:堆叠指标暂存器,BP:基底指标暂存器

cs是代码段寄存器

ds是数据段寄存器

ss是堆栈段寄存器

es是扩展段寄存器

fs是标志段寄存器

gs是全局段寄存器

—————————————————————————————-

把这些寄存器入栈保护

pushl %ebx

pushl %ecx

pushl %edx

pushl %edi

pushl %esi

pushl %ebp

push %ds

push %es

push %fs

v2-698ed2aca088fe2fe0d381cccb314074_720w.png

———————————————————————————————–

无错误号的代码:

核心代码:xchg1  %eax,(%esp)  交换ax和sp
                  push  $0     0作为错误号压栈
                  lea 44(%esp), %edx  把中断的地方压栈
                  call  *%eax   调用中断打印函数
                  add1 $8  %esp   函数的参数出栈

v2-ece3dbd783b28fd75f0ae9278ea91837_720w.png

—————————————————————————————-

有错误号的代码:

error_code:

v2-c25c779ff43d8f383b88d4ae9ef7a6d3_720w.png

0x03:小结

此篇文章主要讲解了中断的工作原理,下篇文章我们一起来看8086 PC机的8259A中断原理。

来源:freebuf.com 2021-06-02 17:03:34 by: 星云博创科技有限公司

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论