Android網絡開發實例(基于抓包實現的網絡模擬登錄,登出和強制登出)
學習Android有幾個月了,最近喜歡上了網絡編程,于是想通過Android寫一些一個小程序用于連接外網.在這里非常感謝雪夜圣誕的支持,非常感謝,給我打開新的一扇門.
1.聲明,本程序只能用于西南大學連接外網登錄,其他網站需要自己進行抓包測試.
2.聲明,本文更多的是關注網絡抓包已經,本地構造,如果有什么錯誤,請盡情指教,非常感謝.
3.聲明,最后源代碼,以全部上傳github,需要的同志可以自行下載,文章結尾會附帶鏈接.
廢話不多說,正文開始:
學校官網
第一步,首先需要實現的是登錄操作:
當我們點擊登錄外網會出現以下頁面:
這個頁面時關鍵,我們就要在這個頁面進行抓包處理.我使用的是chorme瀏覽器,我打開chrome瀏覽器的開發者工具,從中選擇network進行信息監控以下界面:
這里需要關注的是,我們需要勾選上Preserve log,這樣頁面跳轉時,發送的信息就不會消失了.然后,我們點擊連接按鈕,我們我可以發現以下情況:
其實我們可以發現我們要實現登錄按鈕,我們需要使用的url就是第一個,我們點擊第一個url查看數據包詳情,這樣子我們就可以知道這個url需要哪些數據:
這里我們可以發現,其實瀏覽器是向這個url發送了一個post請求,在post中放置了如下數據(userId,password,service,queryString,operatroPwd,operatorUserId,validcode).
(弱弱的說一下,這里作者用自己的賬號做測試,希望技術大牛,不要來搞我.......),我們很容易就發現userId和passwordId(就是賬號和密碼),service經過我多次測試并不會改變,應該是固定值,除了queryString之外的屬性都是空的.難點就在這個queryString,我們點擊view source查看原來編碼(這里需要特別注意,瀏覽器會進行一次編碼顯示給我們,我們使用的應該是source原來的value值)
我們可以發現,其實兩者的內容都是一樣的,就是=編碼的格式不同而已,因此我們只要向http://222.198.127.170/發送一個get請求,然后把對應的內容截取出來就可以了.
因此登錄很簡單了,網址有了,填充的數據也知道了,我只要發送一個post請求就可以實現登錄功能了.這里貼一下登錄函數的代碼
//進行登錄操作
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;
}
HttpUtil是我自己寫的一個發送Http請求的工具類,我把工具類列出來,github中有源碼,需要的可以進行查閱.
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();
}
}
登出功能類似,我這里就不在贅述了,貼一下登出函數的代碼:
//進行登出操作
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;
}
最后來講一下,強制下線功能的實現(這個需要用到cookie進行信息的交流,比較有代表性)
在學校網絡管理中心,有校園網推出選項,當我們點擊時,會出現如下情況:
這說明,強制下線并不是單純向一個url發送一個鏈接就可以完成的,在這里我們就需要進行抓包處理:
這里我們可以發現,這里發送的請求也很簡單,就是向login_judge.jsf發送一個post請求,post中數據也很簡單,就兩個內容(name,password)
然后我們點擊我的設備,就可以進行退出網絡操作了,我們截取一下包:
我們可以發現,這里需要向userself_ajax.jsf?methodName=xxxxx,發送一個post請求,其中數據特別簡單一個key和一串數字,并沒有用戶名和密碼,而Cookie中出現了,很明顯2個頁面之間的交流是通過cookie來是實現的,所以我們需要在登錄的頁面獲取對應的cookie進行編輯,向這個url發送post請求.難點在于,封裝的第二個數據是什么?這里就要進行苦逼的網頁代碼查詢了,我們點開onlinedevice_list.jsf進行代碼查詢: (由于網頁代碼太長了,我截取一部分有用的進行分享)
我們可以發現的第二個數據,其實就是我們不同設備的局域網ip地址,這樣子,數據也獲取到了,cookie也得到了,我們只要向指定url發送post請求就可以了.
這里貼一下強制下線函數的代碼:
//進行強制下線操作
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;
}
到這里,所有的重要的函數和抓包方法都已經講解完畢,最后貼一下手機APP的截圖:
貼一下github地址(歡迎補充):
https://github.com/cai123nb/NetworkLogin/tree/master/main
講點廢話,其實我們可以看出,編碼并不困難,困難的使我們怎么抓取準確的網址和數據包,怎么填充正確的數據包.
只要我們這一點學習的好的話,,我們可以拓展開來,抓手機號碼的歸屬地,郵件/快遞的送達地址等,都是可以的.
第二,其實我的HttpUtil有點過時了,現在大多數的高手都是使用HttpClient,因為HttpClient支持https,我用老版的用順手,也就沒有換了,如果
有人有不同的思路歡迎補充.在這里,拋磚引玉了,你我共勉.
來自:http://www.cnblogs.com/cjyong/p/6506087.html