当前位置: 首页 > 工具软件 > dropbear > 使用案例 >

编译内核+busybox+dropbear,ssh登录

花高爽
2023-12-01

以下是学习过程记录:

学习环境使用VMware虚拟机,宿主机使用centos6.10,内核源码linux-3.0.1,busybox-1.22.0,dropbear-2020.81。

1、目标硬盘分区与挂载:

我新建了5G的磁盘,其实很小就可以。使用fdisk分区1+4G过程略。两个分区分别挂载至宿主机。

mount /dev/sdb1 /mnt/boot;mount /dev/sdb2 /mnt/root

2、BootLoader(grub):

grub-install --root-directory=/mnt /dev/sdb

vim /mnt/boot/grub/grub.conf

        default=0
        timeout=2
        title Mini Linux
            root (hd0,0)
            kernel /bzImage ro root=/dev/sda2 init=/sbin/init

待会儿我的内核就编译为bzImage非模块化方式。

3、编译内核:

很多文章都说内核源码放置/usr/src,这只是沿用了系统默认的文件部署形式。其实无所谓的,进入源码根目录。

make allnoconfig(初始化最小配置。)

lscpu;lspci(查看当前系统硬件情况,因为是虚拟机,虚拟的硬件环境一样,参考用。)

make menuconfig是tui界面,会根据内核版本不同而有区别。我总结了几个我认为主要的选项。主要是针对:架构,模块,处理器,pci总线,执行文件,设备驱动(磁盘、键盘、鼠标、/dev、network),fs。
        [*] Enable loadable module support  --->
            [*]   Module unloading
        Processor type and features  --->
            [*] Symmetric multi-processing support
            [*] Multi-core scheduler support
        Bus options (PCI etc.)  --->
            [*] PCI support
        Executable file formats / Emulations  --->
            [*] Kernel support for ELF binaries  
            [*] Write ELF core dumps with partial segments
        -*- Networking support  --->
            Networking options  --->[*] TCP/IP networking
        Device Drivers  --->
            Generic Driver Options  --->
                [*] Maintain a devtmpfs filesystem to mount at /dev
                [*]   Automount devtmpfs at /dev, after the kernel mounted the rootfs
            SCSI device support  --->
                <*> SCSI device support
                <*> SCSI disk support
                [*] SCSI low-level drivers  --->
            [*] Fusion MPT device support  --->
                <*>   Fusion MPT ScsiHost drivers for SPI
                <*>   Fusion MPT ScsiHost drivers for FC
                <*>   Fusion MPT ScsiHost drivers for SAS
                <*>   Fusion MPT misc device (ioctl) driver
            [*] Network device support  --->
                [*]   Ethernet (1000 Mbit)  ---><M>   Intel(R) PRO/1000 Gigabit Ethernet support
                (网卡选择为<M>稍后编译成模块)
            Input device support  --->
                Keyboards  --->
                [*]   Mice  --->
            [*] USB support  --->
        File systems  --->
            <*> Second extended fs support
            <*> Ext3 journalling file system support
            <*> The Extended 4 (ext4) filesystem
        网卡驱动非模块化方式:
            直接编译进内核,不需要后期加载驱动模块。
        网卡驱动模块化方式:
            modinfo e1000 (查看有无depend项,有的话一并复制)
    编译内核:        
        make -j 4 bzImage:非模块化式编译,不含网卡。编译完成会提示生成位置arch/x86/boot/bzImage 
        cp arch/x86_64/boot/bzImage /mnt/boot (符号链接x86_64-->x86)
        chmod +x /mnt/boot/bzImage
    编译网卡驱动:
        make M=drivers/net/e1000 (编译单个模块:make M=path/to/dir)          
        mkdir /mnt/root/lib/modules
        cp drivers/net/e1000/e1000.ko /mnt/root/lib/modules
        驱动的具体位置需要从源码目录中找到,可以参考宿主机的/lib/modules,
        理论上安装位置可以任意指定,加载模块时指定即可。系统原有路径很长,这里就简化处理。

4、busybox编译:

    tar -xf busybox-1.22.0.tar.bz2(试过1.35版本编译出错,也许是版本不兼容)
    cd busybox-1.22.0
    使用静态编译,不依赖动态库文件,把库编译进可执行文件,依赖于glibc-static包
    make menuconfig (其中有重要选项,用于设置为静态模式,如下列出)
            --- Build Options
                [*] Build static binary (no shared libs)
            --- Installation Options ("make install" behavior) 
                (./_install) Destination path for 'make install' (NEW)
    make -j 4 && make install
    cp -a _install/* /mnt/root
    mkdir -p boot root home usr var tmp etc bin sbin lib lib64 mnt media dev proc sys(16个常用目录补全)

另外我写了一个脚本用于移植文件:(其实也可以写得很简洁,我习惯这样写)

#!/bin/bash

#sDestDir="/root/mytest/tmp"
sDestDir="/mnt/root"
sCmdName=""
sFunction=""
case $1 in
        "")#install
                sFunction="install"
                ;;
        e)#erase
                sFunction="remove"
                ;;
        *)
                echo "The arguments must be e|none."
                exit 2
                ;;
esac

f_chkInput(){
        #read input
        read -p "Enter a name of command:" sCmdName
        sCmdName=${sCmdName//[[:space:]]}
        if [ -z $sCmdName ];then
                return 1 #input null
        elif [[ $sCmdName == "quit" || $sCmdName == "exit" ]];then
                return 2 #input 'quit' or 'exit'
        elif (! which $sCmdName &>/dev/null);then
                echo "Command not found,or it is a shell builtin."
                return 3 #command wrong
        #else

        fi
        echo $sCmdName
}

f_getCmdPath(){
        echo $(which $1 | egrep -o '(/[^/]+)+$')
}

f_getDependList(){
        echo $(ldd $1 | egrep -o '(/[^/]+)+[[:space:]]')
}

f_InstallOrRemove(){
        #Create tmp directory
        install -d $sDestDir

        #copy files
        arrFile=($@)
        sNewFilesList=""
        iCount=0
        for ((i=0;i<${#arrFile[*]};i++));do
                sBaseName=${arrFile[$i]##*/}
                sDirName=${arrFile[$i]%/*}
                sNewDir="${sDestDir}${sDirName}"
                if [ $sFunction == "install" ];then
                        install -d $sNewDir
                        #if (install ${arrFile[$i]} $sNewDir);then
                        if ([ -f ${sNewDir}/${sBaseName} ] || cp ${arrFile[$i]} $sNewDir);then
                                if ((i>0));then
                                        sNewFilesList+="\n"
                                fi
                                sNewFilesList+="${sFunction} ${sNewDir}/${sBaseName}"
                                let iCount++
                        fi
                else
                        if ([ -f ${sNewDir}/${sBaseName} ] && rm -f $sNewDir/${sBaseName});then
                                if ((i>0));then
                                        sNewFilesList+="\n"
                                fi
                                sNewFilesList+="${sFunction} ${sNewDir}/${sBaseName}"
                                let iCount++
                        fi
                fi
        done
        sNewFilesList="-------------------------------------\n"${sNewFilesList}
        echo -e $sNewFilesList >> "${sDestDir}/myinstall.log"
        echo "$sNewFilesList\n$iCount files done."
}

while true;do
        sInputResult=$(f_chkInput)
        case $? in
        1)#input null
                continue;;
        2)#input quit
                exit 0;;
        3)#command wrong
                echo $sInputResult
                continue;;
        esac
        sCmdName=$sInputResult
        sCmdPath=$(f_getCmdPath $sCmdName)
        sDependList=$(f_getDependList $sCmdPath)
        declare -a arrFile
        arrFile=($sCmdPath $sDependList)
        echo -e $(f_InstallOrRemove ${arrFile[*]})
done

使用的时候可以在代码中指定目标目录,也可以给参数“e”,就表示卸载。我是给自己用的,没想那么多,就是用ldd判断依赖关系而已,卸载的时候比较暴力,有些共享的库可能会被删除,不过我不在乎,哪个程序有问题,再移植一下就行了。以后再完善这个脚本。

我使用这个脚本移植了bash过去。

bash myinstall.sh

在提示符下输入bash就可以自动移植完成。

5、etc/inittab:

格式:id:runlevel:action:program 

    ::sysinit:/etc/rc.d/rc.sysinit
    ::respawn:/sbin/getty 9600 tty1
    ::respawn:/sbin/getty 9600 tty2
    ::respawn:/sbin/getty 9600 tty3
    ::ctrlaltdel:/sbin/reboot
    ::shutdown:/bin/umount -a -r

6、etc/rc.d/rc.sysinit:

cd /mnt/root;mkdir etc/rc.d;vim etc/rc.d/rc.sysinit

	#!/bin/sh
	echo -e "Welcome to \033[33mMini\033[0m Linux"
	
	echo "scan /sys to /dev..."
	mdev -s
	
	echo "make dir..."
	mkdir var/run dev/pts
	
	echo "mount filesystem..."
	mount -a #mount from fstab
	mount -o remount,rw /
	
	echo "Load driver ..."
	insmod /lib/modules/e1000.ko #(需要在内核源码中编译网卡驱动)
	
	echo "Initializing ethernet card..."
	ifconfig eth0 192.168.0.61 up
	ifconfig lo 127.0.0.1 up
	
	[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network
	[ -z $HOSTNAME -o $HOSTNAME == "(none)" ] && HOSTNAME="localhost"
	hostname $HOSTNAME
	
	chmod +x etc/rc.d/rc.sysinit

7、etc/fstab:

	/dev/sda1	/boot		ext4	defaults	0	0
	/dev/sda2	/		    ext4	defaults    0	0
	devpts		/dev/pts	devpts	mode=620	0	0
	sysfs		/sys		sysfs	defaults	0	0
	proc		/proc		proc	defaults	0	0

8、用户验证:

head -1 /etc/passwd > etc/passwd;head -1 /etc/group > etc/group;head -1 /etc/shadow > etc/shadow(我这是比较懒的做法,把宿主机的root信息复制一份过去)

其中shadow里面密码的加密串很长,minilinux可能不支持,实测,本地登录可以,使用ssh不行。解决方法很简单,chroot或者进入minilinux,更改一下密码就可以了。因为它使用自己支持的格式再生成的密码串,当然没问题。

9、dropbear:

我虽然下载了源码,但没有编译使用,只是看了一下其中的说明问题,就是要那几个key文件就行了。因为随后要使用我写的脚本向目标位置移植dropbear,dropbearkey,dbclient三个程序,所以我使用yum安装的epel源当中的dropbear。

cd /mnt/root		
mkdir etc/dropbear
cd etc/dropbear
dropbearkey -t rsa -s 2048 -f dropbear_rsa_host_key
dropbearkey -t dss -f dropbear_dss_host_key
dropbearkey -t ecdsa -f dropbear_ecdsa_host_key
dropbearkey -t ed25519 -f dropbear_ed25519_host_key

最后一个ed25519它不支持,也就不考虑了,可以不要这个。

10、几个文件:

新建etc/issue,登录提示文本,内容如下:
        kernel \r

新建etc/shells,内容如下:
         /bin/sh
        /bin/ash
        /bin/hush
        /bin/bash
        /sbin/nologin.

新建etc/nsswitch.conf,用于解析用户名到id,内容如下:

        passwd:files
        group:files
        shadow:files
        hosts:files dns

        mkdir -p usr/lib64
        cp -d /lib64/libnss_file* lib64/
        cp -d /usr/lib64/libnss3.so usr/lib64/
        cp -d /usr/lib64/libnssutil3.so usr/lib64/
        cp -d /usr/lib64/libnss_file* usr/lib64/

新建etc/sysconfig/network,用于指定主机名,内容如下:

        HOSTNAME=nxMINI

新建root/.bash_profile,内容如下:
        export PS1='[\u@\h \W]\$ '  #(命令行提示符)
        export PATH=$PATH:/usr/local/bin:/usr/local/sbin #(dropbear程序所在目录加入环境变量)
新建etc/profile,内容如下:
         [ $UID -eq 0 ] && export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

11、测试:

启动dropbear:

dropbear -FE

使用ssh登录成功即可。

本文完。

 类似资料: