【网络安全】Linux内核部分文件分析
前言
對于操作系統的分析,是一個復雜且枯燥的過程,其中包括中斷、調用等一系列的問題,需要從原理和代碼兩層的角度進行分析,包含匯編、C語言等較為難理解的知識,以及算法的思維。
【學習資料】
啟動流程
setup模塊扇區長度為4個扇區,各個模塊存放在內存的地址。
這里的ROOT_DEV=0x306表示第二個硬盤的第一個扇區。
基礎
設備號 = 主設備號 * 256 + 次設備號
主設備號是定義好的:
1-內存
2-磁盤
3-硬盤
PC機的BIOS把bootsect的一個固定地址拿到了內存中某個固定地址(0x90000),
并且進行硬件初始化和參數設置。
bootsect中的代碼首先移動到0X7C00,之后又轉移到0X90000。
代碼分析
bootsect模塊移入內存
start: mov ax,#BOOTSEG mov ds,ax mov ax,#INITSEG mov es,ax mov cx,#256 sub si,si sub di,di rep movw jmpi go,INITSEG把bootsect中代碼移動到內存中0X90000中,
可以看到此時的ds 存儲0x07c0 地址:es 0x90000。
利用寄存器從ds:si到es:di
jmpi go,INITSEGINITSEG是段地址,go是偏移地址,跳轉到程序執行的地方(0x90000)。
bootsect.s作用
1.首先加載bootsect的代碼(磁盤引導塊程序,在磁盤中第一個扇區的程序)
2.將setup.s中代碼加載到bootsect.s中代碼之后
3.將system模塊加載到0x10000地方,最后跳轉到setup.s中運行
棧的位置
對棧的設置 es:sp =0x90000:0xff00
setup模塊移入內存
load_setup: mov dx,#0x0000 ! drive 0, head 0 //驅動器號0;磁頭號0 mov cx,#0x0002 ! sector 2, track 0 //起始扇區2;磁道0 mov bx,#0x0200 ! address = 512, in INITSEG mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors int 0x13 ! read it jnc ok_load_setup ! ok - continue mov dx,#0x0000 mov ax,#0x0000 ! reset the diskette int 0x13 j load_setupsetup模塊加載到0x90200中。
setup.s作用
- 解析BIOS傳遞過來的參數;
- 設置系統內核運行的局部描述符,中斷描述寄存器,全局描述符;
- 設置中斷控制芯片,進入保護模式;
- 跳轉到system模塊中head.s中代碼執行。
system模塊移入內存
! we want to load the system (at 0x10000) mov ax,#SYSSEG mov es,ax ! segment of 0x010000 call read_it call kill_motor把system模塊加載0x10000處,
關閉驅動器。
【學習資料】
head.s作用
- 加載內核運行時的各種數據段寄存器,重新設置中斷描述表;
- 開啟內核正常運行時的協處理器;
- 設置內存管理的分頁機制;
- 跳轉到main.c開始運行。
中斷調用:
有出錯號、無出錯號
中斷范圍:
int0 ~ int255。
int0 ~ int31 : 軟件中斷,由Intel固定設置的。
int32 ~ int255: 可由用戶自己設置。其中int32 ~ int47 對應8259A的IRQ0 ~ IRQ15中斷。
特殊的一個:int128 為系統調用中斷(system_call)。
#int7 – 設備不存在。
#int14 – 頁錯誤。
#int16 – 協處理器錯誤。
#int 0x20 – 時鐘中斷。
#int 0x80 – 系統調用。
asm.s分析
寄存器入棧:
no_error_code:xchgl %eax,(%esp)pushl %ebxpushl %ecxpushl %edxpushl %edipushl %esipushl %ebppush %dspush %espush %fs
異常碼入棧:
pushl $0 # “error code”
函數返回值入棧:
lea 44(%esp),%edx //把中斷的地方壓棧pushl %edxmovl $0x10,%edxmov %dx,%dsmov %dx,%esmov %dx,%fs
調用中斷服務函數:
call *%eax //調用中斷打印函數
出棧函數返回值:
addl $8,%esp //函數參數出棧pop %fspop %espop %dspopl %ebppopl %esipopl %edipopl %edxpopl %ecxpopl %ebxpopl %eaxiret
error_code:
xchgl %eax,4(%esp) # error code <-> %eax //中斷錯誤碼xchgl %ebx,(%esp) # &function <-> %ebx //中斷函數pushl %ecxpushl %edxpushl %edipushl %esipushl %ebppush %dspush %espush %fspushl %eax # error code //出錯號入棧lea 44(%esp),%eax # offsetpushl %eaxmovl 0x10,8,%esp pop %fspop %espop %dspopl %ebppopl %esipopl %edipopl %edxpopl %ecxpopl %ebxpopl %eaxiret
trap.c分析
本程序用來處理硬件陷阱和故障。
asm.s和traps.c 兩個程序文件的關系:
asm.s 是匯編文件,主要實現大部分硬件中斷(異常)引起的中斷處理過程;trap.c
是C語言源文件,內部是各種中斷處理的C函數,這些函數在asm.s中進行調用。
GCC編譯過程:
1.預處理階段
2.編譯階段
3.匯編階段
4.鏈接階段
內聯匯編格式:
asm(“匯編語句” :輸出寄存器 :輸入寄存器 :會被修改的寄存器)
#define get_seg_byte(seg, addr) \ /*宏定義:取段seg中地址addr處的一個字節*/ ({ \ register char __res; \ //定義一個寄存器 __asm__("push %%fs; //保存fs寄存器的原值 mov %%ax, %%fs; //將seg設置到fs movb %%fs:%2, %%a1; //將seg:addr處的一個字節放置到a1寄存器中 pop %%fs "\ : "=a" (__res) \ //輸出寄存器列表 :"0" (seg), "m"(*(addr)));\ //輸入寄存器列表 __res;}) /*輸入:_res;輸出:seg 內存地址* : "=a" (__res) \ //輸出寄存器列表 輸出寄存器,a代表eax,運行結束后把eax的值放入res中 :"0" (seg), "m"(*(addr)));\ //輸入寄存器列表 輸入寄存器,0代表eax(與上面相同),m代表內存地址取seg段addr處的一個字節。
取seg段addr處的四個字節。
取fs段寄存器的值。
str字符串 esp_ptr 棧指針 nr段號(在哪里出錯)。
static void die(char * str,long esp_ptr,long nr) { long * esp = (long *) esp_ptr; int i; printk("%s: %04x\n\r",str,nr&0xffff); printk("EIP:\t%04x:%p\nEFLAGS:\t%p\nESP:\t%04x:%p\n", esp[1],esp[0],esp[2],esp[4],esp[3]); //打印棧中的一些寄存器 printk("fs: %04x\n",_fs()); printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17)); if (esp[4] == 0x17) { printk("Stack: "); for (i=0;i<4;i++) printk("%p ",get_seg_long(0x17,i+(long *)esp[3])); printk("\n"); } str(i); printk("Pid: %d, process nr: %d\n\r",current->pid,0xffff & i); for(i=0;i<10;i++) printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0]))); printk("\n\r"); do_exit(11); /* play segment exception */ } //打印當前棧中的內容trap_init分析
set_trap_gate:優先級為0 ,設置權限較高,只能由用戶程序調用。
set_system_gate :
設置權限較低,用戶和系統所有進程調用。
system_call.s分析
操作系統的進程管理
系統時間:CPU內部有一個RTC(定時器),運行時調用mktime函數,算出時間差。
給MKTIME函數傳來的時間結構體賦值是由初始化時間從RTC中讀出的:
#include <time.h> /* * This isn't the library routine, it is only used in the kernel. * as such, we don't care about years<1970 etc, but assume everything * is ok. Similarly, TZ etc is happily ignored. We just do everything * as easily as possible. Let's find something public for the library * routines (although I think minix times is public). */ /* * PS. I hate whoever though up the year 1970 - couldn't they have gotten * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy. */ #define MINUTE 60 #define HOUR (60*MINUTE) #define DAY (24*HOUR) #define YEAR (365*DAY) /* interestingly, we assume leap-years */ static int month[12] = { 0, DAY*(31), DAY*(31+29), DAY*(31+29+31), DAY*(31+29+31+30), DAY*(31+29+31+30+31), DAY*(31+29+31+30+31+30), DAY*(31+29+31+30+31+30+31), DAY*(31+29+31+30+31+30+31+31), DAY*(31+29+31+30+31+30+31+31+30), DAY*(31+29+31+30+31+30+31+31+30+31), DAY*(31+29+31+30+31+30+31+31+30+31+30) }; long kernel_mktime(struct tm * tm) { long res; int year; year = tm->tm_year - 70; /* magic offsets (y+1) needed to get leapyears right.*/ res = YEAR*year + DAY*((year+1)/4); res += month[tm->tm_mon]; /* and (y+2) here. If it wasn't a leap-year, we have to adjust */ if (tm->tm_mon>1 && ((year+2)%4)) res -= DAY; res += DAY*(tm->tm_mday-1); res += HOUR*tm->tm_hour; res += MINUTE*tm->tm_min; res += tm->tm_sec; return res; }main.c中time_init
static void time_init(void) { struct tm time; do { time.tm_sec = CMOS_READ(0); time.tm_min = CMOS_READ(2); time.tm_hour = CMOS_READ(4); time.tm_mday = CMOS_READ(7); time.tm_mon = CMOS_READ(8); time.tm_year = CMOS_READ(9); } while (time.tm_sec != CMOS_READ(0)); BCD_TO_BIN(time.tm_sec); BCD_TO_BIN(time.tm_min); BCD_TO_BIN(time.tm_hour); BCD_TO_BIN(time.tm_mday); BCD_TO_BIN(time.tm_mon); BCD_TO_BIN(time.tm_year); time.tm_mon--; startup_time = kernel_mktime(&time); }小結
內核源碼的時間片設計是很精妙的,對操作系統的分析同時也需要計算機組成原理的知識,硬件的理解以及利用算法如何更好的為用戶和上層軟件服務。
最后
點擊查看【網絡安全學習資料·攻略】獲取相關書籍與工具
總結
以上是生活随笔為你收集整理的【网络安全】Linux内核部分文件分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用WebStor快速检查你组织网络中的
- 下一篇: 某设备产品漏洞挖掘-从JS文件挖掘RCE