Android Sshd使用
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使用的更多相关文章
- 〖Android〗从Android Studio转为Eclipse开发项目运行程序闪退的解决方法
很久没有撸Android App开发了- 最近把一个月前通过反编译.二次修改的Android SSHD项目进行简单修改一下: 突然发现迁移项目时,报了一个错误,同时还出现了闪退情况: - ::): t ...
- 〖Android〗快速部署SSHD和Bash Shell(程序:DroidSSHD和BetterTerminalEmulatorPro)
--此文仅做个人配置记录-- 因为我经常需要sshd来连接设备,它抓取logcat日志太方便了,方便排查问题,及多人共享: 及有USB孔限制的人来说,这个更具有意义: 把超级终端增强包部署到内网,也是 ...
- 〖Android〗sshd for android, 及映射根文件系统至本地盘符
严重问题: 若移植失败将可能直接导致手机***无法开机***,导入相关文件需慎重! 达成效果: 1. ssh 远程登录 Android 终端: 2. sftp 挂载/映射 Android 根文件系统至 ...
- 〖Android〗利用droidsshd在Android手机中开启 sshd,sftp,..
源码下载地址: src: git clone https://code.google.com/p/droidsshd/ apk: http://droidsshd.googlecode.com/fil ...
- Android ps命令执行后的各项参数含义
直接输入ps后可以看到如下信息: # ps ps USER PID PPID VSIZE RSS WCHAN PC NAME root 1 ...
- 单机搭建Android开发环境(二)
前文介绍了如何优化SSD和内存,以发挥开发主机的最佳性能,同时提到在SSD上创建虚拟机.为什么不装双系统呢?双系统性能应该会更好!采用Windows+虚拟机的方式,主要是考虑到安卓开发和日常办公两方面 ...
- 单机搭建Android开发环境(三)
单机搭建Android开发环境,第一篇重点介绍了如何优化Windows 7系统,以提高开发主机的性能并延长SSD的使用寿命.第二篇重点介绍了基于VMWare安装64位版的Ubuntu 12.04,并安 ...
- 【Android】源码external/目录中在编译过程中生成的文件列表
=> external/eyes-free: accessibilityvalidator.jar (host,share) => external/mesa3d: libMesa ...
- android下tcpdump抓包
tcpdump是最快捷方便的抓包方式,还可以加深对网络协议的理解.android下可以通过如下方式抓包: 1 Android上启动tcpdump Android设备可以把tcpdump的可执行文件上传 ...
随机推荐
- C语言进阶—— 接续符和转义符13
接续符的意义: C语言中的接续符 (\) 是指示编译器行为的利器 我们来看一个案例: #in\ clud\ e <st\ dio.h> in\ t m\ ain(\ ) { pri\ nt ...
- No module named appium
在脚本中会有:from appium import webdriver 第一次运行时可能会遇到这样的error:No module named appium 之所以会报这样的error是因为没有装cl ...
- 2 http协议
http协议简介: HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于万维网(WWW:World Wide Web )服务器与本地浏览器之间传输超文 ...
- 网络编程介绍(uninx/windows)
1.网络中进程之间如何通信? 2.Socket是什么? 3.socket的基本操作 3.1.socket()函数 3.2.bind()函数 3.3.listen().connect()函数 3.4.a ...
- 手把手教你如何逐步安装OpenStack
[TechTarget中国原创] 尽管OpenStack官方提供的在线安装教程和分步向导能够为管理员提供很大帮助,但是依然存在很多不尽如人意的地方.因此在Ubuntu上安装OpenStack的过程当中 ...
- python考点
Python考点 1.Python类继承,内存管理(阿里) 答:内存管理机制包括:引用计数机制,垃圾回收机制,内存池机制 a = 1,1就是对象,a就是引用,引用a指向对象1. 2.Python装饰器 ...
- 如何使用malloc申请一个二位数组
fscanf(file, "%d", &iVertexNum); // Read number of Vertices double **G = (double **)ma ...
- hasOne
public boolean hasOne(int n) { int lastdigit=0; while( n >0 ){ lastdigit=(n % 10); if(lastdigit== ...
- 《Cracking the Coding Interview》——第1章:数组和字符串——题目1
2014-03-18 01:25 题目:给定一个字符串,判断其中是否有重复字母. 解法:对于可能有n种字符的字符集,用一个长度为n的数组统计每个字符的出现次数,大于1则表示有重复. 代码: // 1. ...
- C:\Windows\System32目录可执行文件列表(Win7 64)
C:\Windows\System32>where /? C:\Windows\System32>where "c:\windows\system32:*.exe" & ...