Android SSH反向连接实践

2019-04-29  本文已影响0人  cg1991

方案实现依靠以下几篇文章:
http://blog.163.com/leekwen@126/blog/static/3316622920118144927681/
http://www.cnblogs.com/whltingyu/p/4083448.html
https://segmentfault.com/a/1190000002718360

在android系统中移植ssh服务是基于实时维护移动端设备而提出来的需求,在客户的设备出现问题而研发人员无法处于现场时提出的解决方案。
在实现这个方案之后可以通过终端执行adb指令,可以进入终端的文件系统删除或修改一些文件,以保证系统能够流畅运行。
该方案实现思路如下:


image

解释一下,C端是PC端的一些ssh客户端,比如bitvise,SecureCRT等;B端是指后台服务器;A是指客户手上的机器,现在要实现的是C通过B连接A,处理A上面出现的问题。

C端很好解决,下载一个SSH客户端就可以解决问题。B端是后台开发人员需要解决的问题,基本上安装一个ssh服务就可以解决了。A端是要重点解决的地方,涉及到了ssh服务的移植,包含移动端和服务端,另外还要移植ftp,开启服务之后保证服务的稳定性。

private void initSSHFile(){
    MyLog.e(TAG, "init ssh file");
    String[]commands = {
        "rm-rf /data/dropbear/","mkdir /data/dropbear", "mkdir/data/dropbear/.ssh",
        
        "cp-rf /system/dss_host_key /data/dropbear/",//作为服务端生成的密钥
        
        "cp-rf /system/authorized_keys /data/dropbear/.ssh",//客户端生成的密钥pub文件
        
        "chmod-R 0744 /data/dropbear","mount -o rw,remount /",
        
        "echo\"root:x:0:0::/root:/system/bin/sh\" > /etc/passwd",
        
        "echo\"root::14531:0:99999:7:::\" > /etc/shadow",
        
        "echo\"root:x:0:\" > /etc/group",
        
        "echo\"root:!::\" > /etc/gshadow",
        
        "echo\"/system/bin/sh\" > /etc/shells",
        
        "echo\"PATH=\\\"/usr/bin:/usr/sbin:/bin:/sbin:/system/sbin:/system/bin:/system/xbin:/data/local/bin\\\"\"> /etc/profile",
        
        "echo\"export PATH\" >> /etc/profile",
        
        "mkdir/usr", "mkdir /usr/libexec",
        
        "cp-rf /system/bin/sftp-server /usr/libexec/",
        
        "rm-rf /system/priv-app/DLNARemoteService.apk",
        
        "mount-o ro,remount /"
    };
    ShellUtils.CommandResultresult = ShellUtils.execCommand(commands, true, true);
    MyLog.e(TAG,"error is "+ result.errorMsg);
    MyLog.e(TAG,"success is "+ result.successMsg);
}

方法中需要说明几个的地方是:

  1. dss_host_key是PC端ssh客户端生成的公钥文件,因为ssh是非对称加密,需要将公钥放到远端,私钥放到本地
  2. 需要从system cp到目标目录的几个文件都是需要提前放到升级包(update.zip)中,然后OTA升级。
  3. sftp-server文件在此处是为了PC客户端能够通过ftp打开A端的文件系统
    至此差不多将ssh服务移植到了Android系统了。
private voidexecuteReverseConnectServerCommand(String command){
    Log.e(TAG , "executeReverseConnectServerCommand:" + command);
    //ShellUtils.CommandResult reverseResult = ShellUtils.execCommand(commands, true , true);
    //Log.e(TAG , "fail result = " + reverseResult.errorMsg);
    //Log.e(TAG , "success result = " + reverseResult.successMsg);
    DataOutputStream os = null;
    Process process = null;
    BufferedReader successResult = null;
    BufferedReader errorResult = null;
    try {
        process = Runtime.getRuntime().exec("su");
        os = new DataOutputStream(process.getOutputStream());
        successResult = new      BufferedReader(newInputStreamReader(process.getInputStream()));
        errorResult = new BufferedReader(new  InputStreamReader(process.getErrorStream()));
        os.write((command + "\n").getBytes());
        os.flush();
        String s = null;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder errorMsg = new StringBuilder();
        while ((s = errorResult.readLine())!= null) {
            MyLog.e(TAG , "error msg =" + s);
            if(!StringUtil.isEmpty(s)&& s.contains("password")){
                MyLog.e(TAG ,"password msg = " + s);
                os.write("yourpassward\n".getBytes());
                os.flush();
            }else if(!StringUtil.isEmpty(s)&& s.contains("fingerprint")){
                MyLog.e(TAG ,"fingerprint msg = " + s);
                os.write("y\n".getBytes());
                os.flush();
            }else if(!StringUtil.isEmpty(s)&& s.contains("connecting")){
                MyLog.e(TAG ,"connecting msg = " + s);
                os.write("y\n".getBytes());
                os.flush();
            }
            errorMsg.append(s);
            s = null;
        }
        MyLog.e(TAG , "start exit");
        os.write("exit\n".getBytes());
        os.flush();
        int result = process.waitFor();
        MyLog.e(TAG , "result = " + result);
        MyLog.e(TAG , "success msg = " + successMsg.toString());
        MyLog.e(TAG , "error msg1 = " + errorMsg.toString());
    } catch (IOException e) {
        e.printStackTrace();
    }catch(Exception e){
        e.printStackTrace();
    } finally {
        try {
            if (os != null) {
                os.close();
            }
            if (successResult != null) {
                successResult.close();
            }
            if (errorResult != null) {
                errorResult.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (process != null) {
            process.destroy();
            }
        }
    }
}

总共确认了三个信息,分别是密码,是否连接这个地址,是否连接。

在确认完成之后接连接成功了,此时点击PC端的ftp按钮应该是可以弹出远端A的文件系统了,ssh在PC端连接成功之后就相当于是一个终端了,可以执行各种指令操作了。
相关连接思路的实现参考文章开头的第三篇文章。
需要注意的是整个过程的实现需要该app有root权限或是系统签名加android:sharedUserId="android.uid.system",不然权限不够执行ssh和dropbear相关指令的时候会失败。

实现整个方案的过程中比较艰难的是:

  1. ssh服务和客户端的移植,研究在A端支持ftp服务
  2. 移植成功之后,将ssh服务跑起来并将来来回回的流程跑通
  3. 网上没有在android上做ssh反向连接的先例,但是还是一往无前的做了,并做出来了。
    微信公众号:Android部落格
上一篇下一篇

猜你喜欢

热点阅读