1. 介绍

因为某些原因, 笔者需要在android上开发,  使用adb比较麻烦, 于是想使用sshd.

推荐的软件是openssh, 其他选择有dropbear, mosh.
当然还有其他选择, 如termux, 这里不予讨论

2. 编译

在Android中已经有openssh包, 位于external/openssh;默认openssh没有编译进Android系统, 需要进行配置

2.1 openssh模块

首先我们要了解Android中程序都是以模块(PACKAGES)的形式唯一存在的
我们按照既定的规则在模块中添加Android.mk的文件, 通过LOCAL_MODULE来定义
对于openssh, 它包含了如下模块

scp, sftp, ssh, sshd, sshd_config, ssh-keygen, start-ssh

2.2 Android编译系统

其次就是需要我们将openssh模块添加到Android的编译系统中去
而所有需要编译进Android中的模块则通过PRODUCT_PACKAGES变量来定义

Android在编译时候通常通过lunch在制定target
以bpi为例, 使用的命令是lunch mars_a31s-eng
而mars_a31s-eng则在device/softwinner/mars-a31s/vendorsetup.sh中定义

add_lunch_combo mars_a31s-eng

而该target又制定了总Makefile, 位于device/softwinner/mars-a31s/AndroidProducts.mk

PRODUCT_MAKEFILES := \
    $(LOCAL_DIR)/mars_a31s.mk

mars_a31s.mk又包含了其他林林总总的Makefile, 其中就包含了device/softwinner/fiber-common/fiber-common.mk
我们就把openssh模块添加到fiber-common.mk文件中

在fiber-common.mk中新增如下内容

# Openssh
PRODUCT_PACKAGES += \
    scp \
    sftp \
    ssh \
    sshd \
    sshd_config \
    ssh-keygen \
    start-ssh

然后重新编译Android系统

2.3 openssh文件

编译完成后烧录或者刷机后, 可以看到文件系统中openssh的文件分别在如下位置(CM中有所不同)

/system/bin/ssh
/system/bin/ssh-keygen
/system/bin/sshd
/system/bin/start-ssh
/system/bin/scp
/system/bin/sftp
/system/etc/ssh/sshd_config


3. 配置

在Linux中使用ssh我们一般都是采用username/password的方式
但是在Android中是没有这一概念的, 当然可以通过修改源码或者添加伪用户的方式
笔者这里采用的是ssh的另一个使用方法即使用密钥登录登录

注意: 以下命令均在root下执行

3.1 创建目录结构

mkdir -p /data/ssh/empty
chmod 700 /data/ssh
chmod 700 /data/ssh/empty

其中, /data/ssh用来存放密钥文件和sshd配置文件

3.2 生成配置文件

cat /system/etc/ssh/sshd_config | \
sed 's/#PermitRootLogin yes$/PermitRootLogin without-password/' | \
sed 's/#RSAAuthentication yes/RSAAuthentication yes/' | \
sed 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' | \
sed 's/PasswordAuthentication no/#PasswordAuthentication no/' | \
sed 's/#PermitEmptyPasswords no/PermitEmptyPasswords yes/' | \
sed 's/#ChallengeResponseAuthentication yes/ChallengeResponseAuthentication yes/' | \
sed 's/#UsePrivilegeSeparation yes/UsePrivilegeSeparation no/' | \
sed 's;/usr/libexec/sftp-server;internal-sftp;' > \
/data/ssh/sshd_config
chmod 600 /data/ssh/sshd_config

这里需要说明的是我们需要配置为root使用, 同时又不需要密码.

另外, 需要注意配置文件中指定了AuthorizedKeysFile为/data/ssh/authorized_keys

3.3 生成密钥

在Windows/Linux上通过下面的命令来生成密钥

ssh-keygen -t rsa -C "your_email_address"

上面的命令会在主目录下生成.ssh目录, 目录包含id_rsa(私钥)和id_rsa.pub(公钥)两个文件

然后通过adb等命令将id_rsa.pub上传至Android中(!!!文件要对应于AuthorizedKeysFile!!!)

adb push id_rsa.pub /data/ssh/authorized_keys
chmod 600 /data/ssh/authorized_keys
chown root:root /data/ssh/authorized_keys

3.4 生成启动脚本

mkdir -p /data/local/userinit.d
cat /system/bin/start-ssh | \
    sed 's;/system/etc/ssh/sshd_config;/data/ssh/sshd_config;' > \
    /data/local/userinit.d/99sshd
chmod 755 /data/local/userinit.d/99sshd

通过上面的命令单独生成一个启动脚本
然后就可以通过执行下面的脚本来启动sshd

/data/local/userinit.d/99sshd

实际操作过程中如果出现问题也可以通过下面的命令以调试的方式来启动sshd

/system/bin/sshd -f /data/ssh/sshd_config -D -ddd

3.5 连接sshd

使用命令即可连接sshd

ssh root@ip

需要注意的是在Windows下使用ssh客户端时需要配置使用密钥登录选项, 并指定密钥文件
具体选项的位置则依据工具的不同而不同

同理SFTP和SCP登录也如此, 需要制定密钥文件

4. 自启动

现在sshd已经可以成功运行并登录, 接下来需要做的则是让sshd可以自启动

4.1 修改init.rc

这是最直接的办法, 问题在于init.rc是由boot.img动态生成的initramfs而产生
故而即使在已经运行的文件系统中修改了, 重启后还是会恢复原来的内容
那么就只能在源代码中修改后再行编译

找到system/core/rootdir/init.rc, 发现已经包含了sshd的内容, 只是默认被禁用了, 而且启动方式也不是我们期望的

service sshd /system/bin/start-ssh
    class main
    disable

将init.rc修改为

service sshd /system/bin/start-ssh
    class main
    user  root
    group root

NOTE:
测试发现, 修改后没有效果, 因为编译时Android使用设备自己提供的init.rc将其覆盖
实际需要修改的文件是device/softwinner/fiber-common/init.rc
而对于CM, 只要修改system/core/rootdir/init.rc即可

除了修改init.rc外, 为了让sshd能够正常自启动
另外需要修改的文件包括如下external/openssh/start-ssh和external/openssh/sshd_config.android

具体的修改内容可以参考前文描述

TIP: 上面的做法对于没有selinux的Android版本正常工作, 但是一旦有了selinux则发现如下错误

[  155.996453] c0 init: Warning!  Service sshd needs a SELinux domain defined; please fix!
[ 156.004202] c0 init: Starting service 'sshd'...
[ 156.008591] c0 init: cannot execve('/system/bin/start-ssh'): Permission denied
[ 156.014985] c0 type=1400 audit(1480673531.748:53): avc: denied { execute_no_trans } for pid=4073 comm="init" path="/system/bin/star
t-ssh" dev=mmcblk0p9 ino=402 scontext=u:r:init:s0 tcontext=u:object_r:system_file:s0 tclass=file permissive=0


需要添加为start-ssh添加sepolicy
方法为start-ssh声明一个独立的domain, 同时为该domain声明start-ssh拥有的权限
具体的做法可以参考sysinit
sysinit在vendor/cm/sepolicy/file_contexts文件中增加了如下行

/system/bin/sysinit       u:object_r:sysinit_exec:s0

然后创建vendor/cm/sepolicy/sysinit.te文件, 在该文件中声明相关权限

4.2 其他方式(不成功)

在笔者使用的CM系统中, 就出现了由于selinux导致的权限问题
这里介绍另一种方式让sshd正常自启动, 对CM是有效的, 其他Android版本是否有效则需要验证

查看启动log后发现CM在启动的时候会执行/system/bin/sysinit脚本
sysinit则会执行/system/etc/init.d/目录下所有脚本, 其中包含了90userinit
该脚本又执行另一个脚本/data/local/userinit.sh
关键在于userinit.sh位于/data下, 即我们有权限修改的地方, 那么我们就可以在这里做文章

创建/data/local/userinit.sh文件, 内容如下

#!/system/bin/sh
export PATH=/sbin:/system/sbin:/system/bin:/system/xbin
for i in /data/local/userinit.d/*; do
if [ -x $i ]; then
/system/bin/log -t userinit Running $i
$i
fi
done

修改userinit.sh的权限

chmod 755 /data/local/userinit.sh

然后按照3.4章节生成/data/local/userinit.d/99sshd作为sshd的启动脚本

因为userinit.sh需要读取目录和文件执行, 需要修改它的domain, 改为和sysinit一样
修改vendor/cm/sepolicy/file_contexts文件

/data/local/userinit.sh                 u:object_r:userinit_data_exec:s0
--->
/data/local/userinit.sh u:object_r:userinit_exec:s0

同时需要为/data/local/userinit.d目录下所有文件增加权限

/data/local/userinit.d(/.*)?            u:object_r:userinit_exec:s0

注: 上面的方法不成功, 一直提示如下错误

12-02 22:42:39.370     1     1 W init    : type=1400 audit(0.0:4): avc: denied { relabelto } for name="userinit.sh" dev=mmcblk0p10 ino=81928 scontext=u:r:init:s0 tcontext=u:object_r:userinit_exec:s0 tclass=file permissive=0

似乎sepolicy比较麻烦, 必须单独配置, 这里不再深究, 还是采用init.rc的方法简单明了

配置sepolicy的方法可参考<Android下添加自启动应用Android下添加自启动应用>

5. 其他配置

5.1 shell

通过ssh登录后, 发现当前shell与系统的shell是有一些不同的, 同时如果我们需要配置一些环境变量的话又不知从何入手
笔者当前使用的shell是Android的默认mksh, 查阅后找到shell的配置方法(只针对拥有bash的Android起作用, 如CM)

创建HOME目录

mkdir /data/home
chmod 755 /data/home
chown root:root /data/home

然后在HOME目录下创建一个脚本/data/home/login, 内容如下

#!/system/xbin/bash

HOME='/data/home'
cd
exec bash --login

修改该脚本的权限

chmod 755 /data/home/login

然后每次登陆后执行执行下面这条命令

exec /data/home/login

同时在/data/home/目录下创建.bash_profile, 内容如下

if [ -f /etc/bash/bashrc ]; then
. /etc/bash/bashrc
fi
unset HOME
HOME=/data/home
LD_LIBRARY_PATH=.:/vendor/lib:/system/lib
PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
ANDROID_DATA=/data
ANDROID_ROOT=/system
export PS1 HOME HOSTNAME LD_LIBRARY_PATH PATH ANDROID_DATA ANDROID_ROOT

其中, bash默认会导入~/.bash_profile作为环境变量, 这里另外导入了/etc/bash/bashrc
是为了一些通用环境变量, 如PS1, 主要是为了避免登录后出现-bash-3.1#这样的提示符

-------------------------------------------------------------------------------------------
笔者使用的另一款Android系统中, 由于没有bash, 只有Android默认的mksh

了解发现, mksh会导入全局文件/profile作为环境变量
然后对于非root用户还会导入$HOME/.profile个文件作为环境变量
另外, 对于非root用户还可通过-i来导入$HOME/.mkshrc这个文件

显然这些我们都无法使用, 笔者的方案是自行导入一个文件作为环境变量
通过在login脚本的最后加上一句source .shrc
.shrc内容如下
HOME=/data/home
LD_LIBRARY_PATH=/vendor/lib:/system/lib
PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
ANDROID_DATA=/data
ANDROID_ROOT=/system
export HOME HOSTNAME LD_LIBRARY_PATH PATH ANDROID_DATA ANDROID_ROOT

NOTE:
笔者最后也没有成功, 只能每次在使用前手动执行source /data/home/.shrc

5.2 busybox

笔者使用的Android中, 发现很多命令在执行时需要加上busybox前缀, 查阅后了解到时这些命令到链接到toolbox的缘故

比较常见的修改方式使用busybox --install命令安装到PATH中
而这里的修改方式就是做一个巧妙的映射, 然后将这个映射导入到当前的环境变量中

在上面提到的.shrc加上如下内容

# for busybox
for n in $(busybox --list)
do
eval alias $n=\'busybox $n\'
done

参考:
<Sshd howto for CM>
<理解Android Build系统>
<Android启动过程深入解析>
<从CM刷机过程和原理分析Android系统结构>

Android Sshd使用的更多相关文章

  1. 〖Android〗从Android Studio转为Eclipse开发项目运行程序闪退的解决方法

    很久没有撸Android App开发了- 最近把一个月前通过反编译.二次修改的Android SSHD项目进行简单修改一下: 突然发现迁移项目时,报了一个错误,同时还出现了闪退情况: - ::): t ...

  2. 〖Android〗快速部署SSHD和Bash Shell(程序:DroidSSHD和BetterTerminalEmulatorPro)

    --此文仅做个人配置记录-- 因为我经常需要sshd来连接设备,它抓取logcat日志太方便了,方便排查问题,及多人共享: 及有USB孔限制的人来说,这个更具有意义: 把超级终端增强包部署到内网,也是 ...

  3. 〖Android〗sshd for android, 及映射根文件系统至本地盘符

    严重问题: 若移植失败将可能直接导致手机***无法开机***,导入相关文件需慎重! 达成效果: 1. ssh 远程登录 Android 终端: 2. sftp 挂载/映射 Android 根文件系统至 ...

  4. 〖Android〗利用droidsshd在Android手机中开启 sshd,sftp,..

    源码下载地址: src: git clone https://code.google.com/p/droidsshd/ apk: http://droidsshd.googlecode.com/fil ...

  5. Android ps命令执行后的各项参数含义

    直接输入ps后可以看到如下信息: # ps ps USER     PID   PPID  VSIZE  RSS     WCHAN    PC         NAME root      1    ...

  6. 单机搭建Android开发环境(二)

    前文介绍了如何优化SSD和内存,以发挥开发主机的最佳性能,同时提到在SSD上创建虚拟机.为什么不装双系统呢?双系统性能应该会更好!采用Windows+虚拟机的方式,主要是考虑到安卓开发和日常办公两方面 ...

  7. 单机搭建Android开发环境(三)

    单机搭建Android开发环境,第一篇重点介绍了如何优化Windows 7系统,以提高开发主机的性能并延长SSD的使用寿命.第二篇重点介绍了基于VMWare安装64位版的Ubuntu 12.04,并安 ...

  8. 【Android】源码external/目录中在编译过程中生成的文件列表

    => external/eyes-free:   accessibilityvalidator.jar (host,share) => external/mesa3d:   libMesa ...

  9. android下tcpdump抓包

    tcpdump是最快捷方便的抓包方式,还可以加深对网络协议的理解.android下可以通过如下方式抓包: 1 Android上启动tcpdump Android设备可以把tcpdump的可执行文件上传 ...

随机推荐

  1. C++基础 new和delete

    1.new delete 的使用 (1)基本数据类型 ); delete p; int *p = (int *)malloc(sizeof(int)); *p = ;free(p); (2)数组 ]; ...

  2. 交互式的Bourne shell

    简介 当以交互的方式使用命令行时,shell有一些特殊的内置变量,这些变量中包含一系列选项.如果在选项中包含字母i,则表示shell以交互方式运行. # case "$-" in ...

  3. PTA 7-10(图) 旅游规划 最短路问题

    7-10(图) 旅游规划 (25 分) 有了一张自驾旅游路线图,你会知道城市间的高速公路长度.以及该公路要收取的过路费.现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径.如果 ...

  4. 【UE4】二十三、UE4笔试面试题

    在CSDN博客看到的,带着这些问题,多多留意,正所谓带着问题学习. 一. 1.Actor的EndPlay事件在哪些时候会调用? 2.BlueprintImplementableEvent和Bluepr ...

  5. Android+Handler+Thread 那些事儿

    前言,才开始学安卓十几天,不料被线程挡住了前进的步伐,因为之前操作系统课程并没有认真听老师讲课,导致现在理解这些抽象的东西有些小困难.没关系,苦学之路,总会碰到坎坷,这里也给那些迷失在Android之 ...

  6. 1,版本控制git--仓库管理

    ​ 再开始这个话题之前,让我想起了一件很痛苦的事情,在我大学写毕业论文的时候,我当时的文件是这样保存的 毕业论文_初稿.doc 毕业论文_修改1.doc 毕业论文_修改2.doc 毕业论文_修改3.d ...

  7. Android Studio快速的接受一个项目

    1.关键词搜索法,搜索这个词,然后仔细的去找找.肯定可以找到的,虽然可能会有一些奔波. 2.Android device moniter ,可以抓屏幕,看布局,而且可以看到资源id.看到资源id,你说 ...

  8. 内存压缩PK页面交换 解决内存问题谁更在行

    一台服务器能够支持的虚拟机数量通常取决于物理硬件所能够提供的可用计算资源.大多数资源, 比如处理器周期.存储I/O和网络带宽等,都能够相对简单地进行共享.这种做法的原理在于负载并不总是处于忙碌状态,因 ...

  9. shell脚本递归删除空文件夹

    有时我们需要递归删除空文件夹,网上找了一下,没有发现比较好的脚本,于是自己动手写了一个 脚本 #!/bin/bash # author: 十年后的卢哥哥(http://www.cnblogs.com/ ...

  10. Java基础-4变量与数据类型

    变量:变量是Java程序中的一个基本存储单元.变量是一个标识符.类型及一个可选初始值的组合定义.所有的变量都有一个作用域,即变量在某一区域有效. 基本的变量声明方式如下: int a; float b ...