Android网络开发实例(基于抓包实现的网络模拟登录,登出和强制登出)

yzming2012 9年前
   <p>学习Android有几个月了,最近喜欢上了网络编程,于是想通过Android写一些一个小程序用于连接外网.在这里非常感谢雪夜圣诞的支持,非常感谢,给我打开新的一扇门.</p>    <p>1.声明,本程序只能用于西南大学连接外网登录,其他网站需要自己进行抓包测试.</p>    <p>2.声明,本文更多的是关注网络抓包已经,本地构造,如果有什么错误,请尽情指教,非常感谢.</p>    <p>3.声明,最后源代码,以全部上传github,需要的同志可以自行下载,文章结尾会附带链接.</p>    <p>废话不多说,正文开始:</p>    <p>学校官网</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f26887f7ab519defbcb630b5ef647b0f.jpg"></p>    <p>第一步,首先需要实现的是登录操作:</p>    <p>当我们点击登录外网会出现以下页面:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/3e290ae3a224d4d574c9c5e625d34baa.jpg"></p>    <p>这个页面时关键,我们就要在这个页面进行抓包处理.我使用的是chorme浏览器,我打开chrome浏览器的开发者工具,从中选择network进行信息监控以下界面:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/67b68262c7278c55300ca57192436aed.jpg"></p>    <p>这里需要关注的是,我们需要勾选上Preserve log,这样页面跳转时,发送的信息就不会消失了.然后,我们点击连接按钮,我们我可以发现以下情况:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/6679e63b04470a54458c87daf893cad5.jpg"></p>    <p>其实我们可以发现我们要实现登录按钮,我们需要使用的url就是第一个,我们点击第一个url查看数据包详情,这样子我们就可以知道这个url需要哪些数据:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/9122c9da99bff9d4cdd30bbadfa9c9eb.jpg"></p>    <p>这里我们可以发现,其实浏览器是向这个url发送了一个post请求,在post中放置了如下数据(userId,password,service,queryString,operatroPwd,operatorUserId,validcode).</p>    <p>(弱弱的说一下,这里作者用自己的账号做测试,希望技术大牛,不要来搞我.......),我们很容易就发现userId和passwordId(就是账号和密码),service经过我多次测试并不会改变,应该是固定值,除了queryString之外的属性都是空的.难点就在这个queryString,我们点击view source查看原来编码(这里需要特别注意,浏览器会进行一次编码显示给我们,我们使用的应该是source原来的value值)</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/8c7cb2a44dfd216192970db07a079581.jpg"></p>    <p>我们可以发现,其实两者的内容都是一样的,就是=编码的格式不同而已,因此我们只要向http://222.198.127.170/发送一个get请求,然后把对应的内容截取出来就可以了.</p>    <p>因此登录很简单了,网址有了,填充的数据也知道了,我只要发送一个post请求就可以实现登录功能了.这里贴一下登录函数的代码</p>    <pre>  <code class="language-java">    //进行登录操作      private boolean loginValidate(String username,String passwd) throws Exception      {          final String html = HttpUtil.sendGetRequest("http://222.198.127.170/", false, null, "gbk");          //使用正则表达式获取对应的填充数据          String p = "jsp\\?(.+?)'</script>";          Pattern reg = Pattern.compile(p);          Matcher m= reg.matcher(html);          String FillingStr = "";          if(m.find())          {              FillingStr = m.group(1);          }          //这里需要注意,需要使用utf-8格式进行编码          FillingStr = URLEncoder.encode(FillingStr,"utf-8");          final String url = "http://222.198.127.170/eportal/InterFace.do?method=login";          final String data="userId="+username+"&password="+passwd+"&service=%25E9%25BB%2598%25E8%25AE%25A4&queryString="+FillingStr+"&operatorPwd=&operatorUserId=&validcode=";          //发送登录请求          String html2=HttpUtil.sendPostRequest(url, data, false, null, "gbk");          if(html2.contains("success"))              return true;          return false;      }  </code></pre>    <p>HttpUtil是我自己写的一个发送Http请求的工具类,我把工具类列出来,github中有源码,需要的可以进行查阅.</p>    <pre>  <code class="language-java">package com.network.cjyong.networklogin.util;    /**   * Created by cjyong on 2017/3/5.   */    import java.io.BufferedReader;  import java.io.InputStream;  import java.io.InputStreamReader;  import java.io.OutputStream;  import java.net.HttpURLConnection;  import java.net.URL;  import java.util.concurrent.Callable;  import java.util.concurrent.FutureTask;    public class HttpUtil  {      /**       * 向对应的网址发送get请求,以String的形式返回服务器的相应       *       * @author cjyong at 2017/3/5       * @param url 发送请求的网址       * @param usecookie 是否使用cookie       * @param cookie 需要携带的cookie       * @param encoding 编码格式       * @return 以string的形式返回服务器的响应       * @throws Exception       */      public static String sendGetRequest(final String url,final boolean usecookie,final String cookie,final String encoding) throws Exception      {          FutureTask<String> task = new FutureTask<String>(                  new Callable<String>()                  {                      @Override                      public String call() throws Exception                      {                          URL turl = new URL(url);                          HttpURLConnection conn = (HttpURLConnection) turl.openConnection();                          //设置时间限制,抛出异常                          conn.setConnectTimeout(5000);                          conn.setReadTimeout(5000);                          conn.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");                          conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");                          if(usecookie)                              conn.setRequestProperty("Cookie", cookie);                          InputStream is = conn.getInputStream();                          BufferedReader reader = new BufferedReader(new InputStreamReader(is,encoding));                          StringBuilder sb = new StringBuilder();                          String line = null;                          while((line = reader.readLine())!= null)                              sb.append(line+"\n");                          return sb.toString();                      }                  });          //格外进行一个线程进行网络操作,防止堵塞          new Thread(task).start();          return task.get();      }        /**       * 向对应的网址发送post请求,以String的形式返回服务器的相应       *       * @author cjyong at 2017/3/5       * @param url 发送请求的网址       * @param data 发送post请求携带的数据       * @param usecookie 是否使用cookie       * @param cookie 需要携带的cookie       * @param encoding 编码格式       * @return 以string的形式返回服务器的响应       * @throws Exception       */      public static String sendPostRequest(final String url,final String data,final boolean usecookie,final String cookie,final String encoding) throws Exception      {          FutureTask<String> task = new FutureTask<String>(                  new Callable<String>()                  {                      @Override                      public String call() throws Exception                      {                          URL turl = new URL(url);                          HttpURLConnection conn = (HttpURLConnection) turl.openConnection();                          conn.setRequestMethod("POST");                          conn.setDoOutput(true);                          //设置时间限制,抛出异常                          conn.setConnectTimeout(5000);                          conn.setReadTimeout(5000);                          conn.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");                          conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");                          if(usecookie)                              conn.setRequestProperty("Cookie", cookie);                          OutputStream outStream = conn.getOutputStream();                          outStream.write(data.getBytes());                          outStream.flush();                          outStream.close();                          InputStream is = conn.getInputStream();                          BufferedReader reader = new BufferedReader(new InputStreamReader(is,encoding));                          StringBuilder sb = new StringBuilder();                          String line = null;                          while((line = reader.readLine())!= null)                              sb.append(line+"\n");                          return sb.toString();                      }                  });          //格外进行一个线程进行网络操作,防止堵塞          new Thread(task).start();          return task.get();      }          /**       * 向对应的网址发送post请求,获取对应的cookie,以备后用       *       * @author cjyong at 2017/3/5       * @param url 发送请求的网址       * @param data 发送post请求携带的数据       * @return 以string的形式返回服务器的响应       * @throws Exception       */        public static String getCookie(final String url,final String data)throws Exception      {          FutureTask<String> task = new FutureTask<String>(                  new Callable<String>()                  {                        @Override                      public String call() throws Exception                      {                          byte[] Data = data.getBytes();                          URL turl=new URL(url);                          HttpURLConnection conn = (HttpURLConnection)turl.openConnection();                          conn.setRequestMethod("POST");                          conn.setDoOutput(true);                          //设置连接与读取时间过期返回异常                          conn.setConnectTimeout(5000);                          conn.setReadTimeout(5000);                          conn.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");                          conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");                          OutputStream outStream = conn.getOutputStream();                          outStream.write(Data);                          outStream.flush();                          outStream.close();                          String Cookie=conn.getHeaderField("Set-Cookie");                          return Cookie;                      }                    }          );          //格外进行一个线程进行网络操作,防止堵塞          new Thread(task).start();          return task.get();      }    }  </code></pre>    <p>登出功能类似,我这里就不在赘述了,贴一下登出函数的代码:</p>    <pre>  <code class="language-java">    //进行登出操作      private boolean logoutValidate() throws Exception      {          String html = HttpUtil.sendGetRequest("http://222.198.127.170/eportal/InterFace.do?method=logout",false,null,"utf-8");          if(html.contains("success"))              return true;          return false;      }  </code></pre>    <p>最后来讲一下,强制下线功能的实现(这个需要用到cookie进行信息的交流,比较有代表性)</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/57115c55d46b9cfeb60f8b09326cac86.jpg"></p>    <p>在学校网络管理中心,有校园网推出选项,当我们点击时,会出现如下情况:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/87c4348778c34e0923cbd9cf8264bfb3.jpg"></p>    <p>这说明,强制下线并不是单纯向一个url发送一个链接就可以完成的,在这里我们就需要进行抓包处理:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/c06d3bd458e3665d6e30b73d0e5d7d3a.jpg"></p>    <p>这里我们可以发现,这里发送的请求也很简单,就是向login_judge.jsf发送一个post请求,post中数据也很简单,就两个内容(name,password)</p>    <p>然后我们点击我的设备,就可以进行退出网络操作了,我们截取一下包:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/05c59b2bfbc1143bc8a13982a9c9fc53.jpg"></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2f2446aa5f76c6a84702ddd0088a3cc2.jpg"></p>    <p>我们可以发现,这里需要向userself_ajax.jsf?methodName=xxxxx,发送一个post请求,其中数据特别简单一个key和一串数字,并没有用户名和密码,而Cookie中出现了,很明显2个页面之间的交流是通过cookie来是实现的,所以我们需要在登录的页面获取对应的cookie进行编辑,向这个url发送post请求.难点在于,封装的第二个数据是什么?这里就要进行苦逼的网页代码查询了,我们点开onlinedevice_list.jsf进行代码查询: (由于网页代码太长了,我截取一部分有用的进行分享)</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2d13311b17a651eca4f234587475e16d.jpg"></p>    <p>我们可以发现的第二个数据,其实就是我们不同设备的局域网ip地址,这样子,数据也获取到了,cookie也得到了,我们只要向指定url发送post请求就可以了.</p>    <p>这里贴一下强制下线函数的代码:</p>    <pre>  <code class="language-java"> //进行强制下线操作      private boolean forceLogoutValidate(String username,String passwd) throws Exception      {          //构造填充参数          String data ="name="+username+"&password="+passwd;          String url= "http://service2.swu.edu.cn/selfservice/module/scgroup/web/login_judge.jsf";          //构造cookie          String Cookie=HttpUtil.getCookie(url,data);          Cookie=String.format(Cookie+" rmbUser=true; userName=%s; passWord=%s; oldpassWord=%s;", username,passwd,passwd);          String listurl= "http://service2.swu.edu.cn/selfservice/module/webcontent/web/onlinedevice_list.jsf";          String html= HttpUtil.sendGetRequest(listurl, true, Cookie, "gbk");          //账号密码错误          if(html.contains("您还未登录或会话过期"))              return false;          //获取设备的IP地址构造填充数据          String p = "<span id=\"a1\">IP : (.+?)</span >";          Pattern reg = Pattern.compile(p);          Matcher m=reg.matcher(html);          //将所有的设备进行下线          while(m.find())          {              //执行下线操作              String myurl = "http://service2.swu.edu.cn/selfservice/module/userself/web/userself_ajax.jsf?methodName=indexBean.kickUserBySelfForAjax";              String mydata = "key= "+username+":" +m.group(1);              HttpUtil.sendPostRequest(myurl, mydata, true, Cookie, "utf-8");          }          return true;      }  </code></pre>    <p>到这里,所有的重要的函数和抓包方法都已经讲解完毕,最后贴一下手机APP的截图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/8651ac3dd4d003c6a790339d28063d34.png"></p>    <p>贴一下github地址(欢迎补充):</p>    <p>https://github.com/cai123nb/NetworkLogin/tree/master/main</p>    <p>讲点废话,其实我们可以看出,编码并不困难,困难的使我们怎么抓取准确的网址和数据包,怎么填充正确的数据包.</p>    <p>只要我们这一点学习的好的话,,我们可以拓展开来,抓手机号码的归属地,邮件/快递的送达地址等,都是可以的.</p>    <p>第二,其实我的HttpUtil有点过时了,现在大多数的高手都是使用HttpClient,因为HttpClient支持https,我用老版的用顺手,也就没有换了,如果</p>    <p>有人有不同的思路欢迎补充.在这里,抛砖引玉了,你我共勉.</p>    <p> </p>    <p> </p>    <p>来自:http://www.cnblogs.com/cjyong/p/6506087.html</p>    <p> </p>