如何查找不同linux内核版本下的内核函数

如何查找不同linux内核版本下的内核函数,第1张

BOOT目录下的文件,

其中几个核心的如下:

Systemmap、vmlinuz、initrd-247-10img

这几个文件是怎么产生的又有什么作用呢本文对此做些介绍。

一、vmlinuz

vmlinuz是可引导的、压缩的内核。“vm”代表“Virtual Memory”。Linux 支持虚拟内存,不像老的 *** 作系统比如DOS有640KB内存的限制。Linux能够使用硬盘空间作为虚拟内存,因此得名“vm”。vmlinuz是可执行的Linux内核,它位于/boot/vmlinuz,它一般是一个软链接,比如图中是vmlinuz-247-10的软链接。

vmlinuz的建立有两种方式。一是编译内核时通过“make zImage”创建,然后通过:“cp /usr/src/linux-24/arch/i386/linux/boot/zImage/boot/vmlinuz”产生。zImage适用于小内核的情况,它的存在是为了向后的兼容性。

二是内核编译时通过命令make bzImage创建,然后通过:“cp/usr/src/linux-24/arch/i386/linux/boot/bzImage /boot/vmlinuz”产生。bzImage是压缩的内核映像,需要注意,bzImage不是用bzip2压缩的,bzImage中的bz容易引起误解,bz表示“big zImage”。 bzImage中的b是“big”意思。 zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip压缩的。它们不仅是一个压缩文件,而且在这两个文件的开头部分内嵌有gzip解压缩代码。所以你不能用gunzip 或 gzip –dc解包vmlinuz。

内核文件中包含一个微型的gzip用于解压缩内核并引导它。两者的不同之处在于,老的zImage解压缩内核到低端内存(第一个640K),bzImage解压缩内核到高端内存(1M以上)。如果内核比较小,那么可以采用zImage或bzImage之一,两种方式引导的系统运行时是相同的。大的内核采用bzImage,不能采用zImage。vmlinux是未压缩的内核,vmlinuz是vmlinux的压缩文件。

二、initrd-xxximg

initrd是“initial ramdisk”的简写。initrd一般被用来临时的引导硬件到实际内核vmlinuz能够接管并继续引导的状态。图中的initrd-247-10img主要是用于加载ext3等文件系统及scsi设备的驱动。

比如,使用的是scsi硬盘,而内核vmlinuz中并没有这个scsi硬件的驱动,那么在装入scsi模块之前,内核不能加载根文件系统,但scsi模块存储在根文件系统的/lib/modules下。为了解决这个问题,可以引导一个能够读实际内核的initrd内核并用initrd修正scsi引导问题。initrd-247-10img是用gzip压缩的文件,initrd实现加载一些模块和安装文件系统等功能。

initrd映象文件是使用mkinitrd创建的。mkinitrd实用程序能够创建initrd映象文件。这个命令是RedHat专有的。其它Linux发行版或许有相应的命令。这是个很方便的实用程序。具体情况请看帮助:man mkinitrd下面的命令创建initrd映象文件。

三、Systemmap

Systemmap是一个特定内核的内核符号表。它是你当前运行的内核的Systemmap的链接。

内核符号表是怎么创建的呢 Systemmap是由“nm vmlinux”产生并且不相关的符号被滤出。

对于本文中的例子,编译内核时,Systemmap创建在/usr/src/linux-24/Systemmap。像下面这样:

nm /boot/vmlinux-247-10 > Systemmap

下面几行来自/usr/src/linux-24/Makefile:

nm vmlinux | grep -v '\(compiled\)\|\(\o$$\)\|\( [aUw] \)\|\(\\ng$$\)\|\(LASH[RL]DI\)' | sort > Systemmap

然后复制到/boot:

cp /usr/src/linux/Systemmap /boot/Systemmap-247-10

下图是Systemmap文件的一部分:

在进行程序设计时,会命名一些变量名或函数名之类的符号。Linux内核是一个很复杂的代码块,有许许多多的全局符号。

Linux内核不使用符号名,而是通过变量或函数的地址来识别变量或函数名。比如不是使用size_t BytesRead这样的符号,而是像c0343f20这样引用这个变量。

对于使用计算机的人来说,更喜欢使用那些像size_t BytesRead这样的名字,而不喜欢像c0343f20这样的名字。内核主要是用c写的,所以编译器/连接器允许我们编码时使用符号名,当内核运行时使用地址。

然而,在有的情况下,我们需要知道符号的地址,或者需要知道地址对应的符号。这由符号表来完成,符号表是所有符号连同它们的地址的列表。上图就是一个内核符号表,由上图可知变量名checkCPUtype在内核地址c01000a5。

Linux 符号表使用到2个文件:

/proc/ksyms

Systemmap

/proc/ksyms是一个“proc file”,在内核引导时创建。实际上,它并不真正的是一个文件,它只不过是内核数据的表示,却给人们是一个磁盘文件的假象,这从它的文件大小是0可以看出来。然而,Systemmap是存在于你的文件系统上的实际文件。

当你编译一个新内核时,各个符号名的地址要发生变化,你的老的Systemmap具有的是错误的符号信息。每次内核编译时产生一个新的Systemmap,你应当用新的Systemmap来取代老的Systemmap。

虽然内核本身并不真正使用Systemmap,但其它程序比如klogd,lsof和ps等软件需要一个正确的Systemmap。如果你使用错误的或没有Systemmap,klogd的输出将是不可靠的,这对于排除程序故障会带来困难。没有Systemmap,你可能会面临一些令人烦恼的提示信息。

另外少数驱动需要Systemmap来解析符号,没有为你当前运行的特定内核创建的Systemmap它们就不能正常工作。

Linux的内核日志守护进程klogd为了执行名称-地址解析,klogd需要使用Systemmap。Systemmap应当放在使用它的软件能够找到它的地方。执行:man klogd可知,如果没有将Systemmap作为一个变量的位置给klogd,那么它将按照下面的顺序,在三个地方查找Systemmap:

/boot/Systemmap

/Systemmap

/usr/src/linux/Systemmap

Systemmap也有版本信息,klogd能够智能地查找正确的映象(map)文件。

注意看这个文件

sysdeps/unix/sysv/linux/syscallslist

里面记录着系统调用的名字和一些属性,具体我也没有研究过,不懂。

再看select的实现,很让人惊讶,一旦使用,结果就是“报错“。

int

__select (nfds, readfds, writefds, exceptfds, timeout)

int nfds;

fd_set readfds;

fd_set writefds;

fd_set exceptfds;

struct timeval timeout;

{

__set_errno (ENOSYS);

return -1;

}

libc_hidden_def (__select)

stub_warning (select)

weak_alias (__select, select)

这是因为glibc并没有实现系统调用,而是调用系统调用,

更进一步,连调用系统调用都没有一个个实现,而是使用了通用的办法,

理由很简单,所有的系统调用在linux内核头文件里都能找到,

所有的系统调用参数类型就那么几种,参数个数也是有限的,

因此没有必要针对所有的系统调用一一封装,

于是就有了这个list文件,自动生成调用系统调用的函数,

如果生成失败,也就是你看到的“报错”。

符号是有强弱的,当自动生成成功的时候,“报错”的弱符号就被忽略了。

当你在glibc中找到一个系统调用的封装源码,是以下原因,

1 编译的目标系统不支持这个系统调用,所以自己用另一种方式实现了。

2 这个系统调用无法使用通用的自动生成方式生成,用特化的方式覆盖。

3 针对这个系统调用做了特别的优化。

4 其它可能的原因。

具体可以留意

SYSCALL, PSEUDO, DO_CALL, INLINE_CALL 等名字

这两个文件是重点所在

sysdeps/unix/i386/sysdeph

sysdeps/unix/i386/sysdepS

要搞清楚具体的自动生成过程,恐怕得研究glibc自身的编译过程了

编译qt-desktop版,关键发版linuxx-server否显卡驱,并支持opengl才重要, x-server驱framebuffer使用opengl加速 编译qt-embeded版,看显卡提供qt所用opengl加速插件没

这种问题你在问问上问不会有很好的结果的,我简单给你说说思路和原理 NtReadVirtualMemory这个函数在RING3下由NTDLLDLL导出,对应的系统服务函数地址保存在SSDT里。不知道你问的是应用层还是内核层,我分别和你说一下。 RING3下可以编写DLL注入每个进程,然后在每个进程内修改系统动态链接库的导出表,即IAT HOOK。要想得到原始函数地址,首先要打开磁盘上的NTDLLDLL文件,解析该文件的导出表(EAT),根据NTDLLDLL的内存基址以及磁盘文件里记录的RVA手动计算出NtReadVirtualMemory函数地址。 RING0下直接修改SSDT表即可挂钩NtReadVirtualMemory系统服务,要想获取SSDT里各例程的原始地址,同样需要自己解析磁盘文件(ntoskrnlexe)。关于SSDT HOOK的内容网上很多,我在看雪找到了一个不错的贴你可以参考下: >

看系统调用,还有库函数,以前一直不明白,总是以为 系统调用跟库函数是一样的,但是今天才知道是不一样的。

库函数也就是我们通常所说的应用编程接口API,它其实就是一个函数定义,比如常见read()、write()等函数说明了如何获得一个给定的服务,但是系统调用是通过软中断向内核发出一个明确的请求,再者系统调用是在内核完成的,而用户态的函数是在函数库完成的。

系统调用发生在内核空间,因此如果在用户空间的一般应用程序中使用系统调用来进行文件 *** 作,会有用户空间到内核空间切换的开销。事实上,即使在用户空间使用库函数来对文件进行 *** 作,因为文件总是存在于存储介质上,因此不管是读写 *** 作,都是对硬件(存储器)的 *** 作,都必然会引起系统调用。也就是说,库函数对文件的 *** 作实际上是通过系统调用来实现的。例如C库函数fwrite()就是通过write()系统调用来实现的。

这样的话,使用库函数也有系统调用的开销,为什么不直接使用系统调用呢?这是因为,读写文件通常是大量的数据(这种大量是相对于底层驱动的系统调用所实现的数据 *** 作单位而言),这时,使用库函数就可以大大减少系统调用的次数。这一结果又缘于缓冲区技术。在用户空间和内核空间,对文件 *** 作都使用了缓冲区,例如用fwrite写文件,都是先将内容写到用户空间缓冲区,当用户空间缓冲区满或者写 *** 作结束时,才将用户缓冲区的内容写到内核缓冲区,同样的道理,当内核缓冲区满或写结束时才将内核缓冲区内容写到文件对应的硬件媒介。

系统调用与系统命令:系统命令相对API更高一层,每个系统命令都是一个可执行程序,比如常用的系统命令ls、hostname等,比如strace ls就会发现他们调用了诸如open(),brk(),fstat(),ioctl()等系统调用。

系统调用是用户进程进入内核的接口层,它本身并非内核函数,但他是由内核函数实现的,进入系统内核后,不同的系统调用会找到各自对应的内核函数,这写内核函数被称为系统调用的“服务例程”。也可以说系统调用是服务例程的封装例程。

使用32位的IDA加载zImage时, Processer Type 选择 ARM ,勾选 Manual load , 点击Ok

在ROM start address和Loading address填写0xc0008000,这个是内核text段的起始地址,通常都为0xc0008000,点击OK等待IDA加载完成。

如果你不确定是不是这个地址, 你可以使用如下命令直接从手机中获取

往上查看dmesg的输出信息可以找到

在小米内核源码中搜索,直接在github中搜索的ptmx_fops

由上图可以看到ptmx_fops仅在ptyc文件中被引用了两次,随便选一处引用

再次搜索tty_default_fops发现就只有一处调用该函数,那就用这个tty_default_fops函数去找到ptmx_fops吧

IDA跳转到地址c03fb21c(按g,输入地址,即可跳转到指定地址),把c03fb21c重命名为tty_default_fops(按n, 输入名称,即可修改别名)

IDA查找tty_default_fops的引用(按x,可以找到所有引用该函数的地址),由于从源码知道只有一次引用该函数,就直接跳转到应用tty_default_fops的地方

那么就找到了 ptmx_fops 的地址为 0xC12D5298

源码中搜索sidtab,找到很多处引用,发现在servicesc 中有个静态的结构体变量,

进入servicesc中,找引用sidtab的地方,找啊找啊找朋友~~~,找到一个好朋友

什么是好朋友呢,就是参数越少的函数,引用越少的函数,这种函数方便分析,

sidtab 的地址为 0xC12BC530

policydb 地址 0xC12BC420

selinux_enabled 地址 0xC0F5332C

selinux_enforcing 地址 0xC12BA9D0

以上就是关于如何查找不同linux内核版本下的内核函数全部的内容,包括:如何查找不同linux内核版本下的内核函数、如何调用Linux内核函数、在linux2.6内核中为什么找不到地址转换函数inet等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/9541120.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-29
下一篇 2023-04-29

发表评论

登录后才能评论

评论列表(0条)

保存