Android WIFI密碼檢視器執行個體
實作原理:使用shell指令檢視儲存WIFI密碼的系統檔案
涉及的知識
- 界面展示
- 基本的Shell指令
- shell檢視WIFI密碼
- ShellUtil的使用
- 正規表達式解析字元串
- ExpandableListView的使用
界面展示
主界面隻包含一個 ExpandableListView
ExpandableListView

基本的Shell指令
1.shel由
adb shell
進入,基本指令于Linux下的指令相同,這邊示範幾個常用的指令
因為是在手機的系統檔案下操作,是以部分指令不友善示範,下面直接進入檢視wifi密碼的指令
首先執行 su
擷取root權限
su
執行 cat /data/misc/wifi/wpa_supplicant.conf
來檢視本地的WIFI資訊
cat /data/misc/wifi/wpa_supplicant.conf
在應用内部執行shell指令
此處我們用到是ShellUtil的java檔案,來源于網絡,封裝了一寫方法用于執行shell指令,代碼如下
注釋都在代碼内部,此處不多加解釋
package com.brioal.poswermanager;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
public class ShellUtils {
public static final String COMMAND_SU = "su"; // 擷取root權限的指令
public static final String COMMAND_SH = "sh"; // 執行sh檔案的指令
public static final String COMMAND_EXIT = "exit\n"; // 退出的指令
public static final String COMMAND_LINE_END = "\n"; // 執行指令必須加在末尾
private ShellUtils() {
throw new AssertionError();
}
//檢測root狀态
public static boolean checkRootPermission() {
return execCommand("echo root", true, false).result == ;
}
//執行單行指令,實際還是調用的執行多行 ,傳入指令和是否需要root
public static CommandResult execCommand(String command, boolean isRoot) {
return execCommand(new String[]{command}, isRoot, true);
}
//執行List<String>中的指令 , 傳入List和是否需要root
public static CommandResult execCommand(List<String> commands, boolean isRoot) {
return execCommand(commands == null ? null : commands.toArray(new String[]{}), isRoot, true);
}
//執行多行指令
public static CommandResult execCommand(String[] commands, boolean isRoot) {
return execCommand(commands, isRoot, true);
}
public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) {
return execCommand(new String[]{command}, isRoot, isNeedResultMsg);
}
public static CommandResult execCommand(List<String> commands, boolean isRoot, boolean isNeedResultMsg) {
return execCommand(commands == null ? null : commands.toArray(new String[]{}), isRoot, isNeedResultMsg);
}
//執行指令,獲得傳回的資訊
public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
int result = -;
if (commands == null || commands.length == ) {
return new CommandResult(result, null, null);
}
Process process = null;
BufferedReader successResult = null;
BufferedReader errorResult = null;
StringBuilder successMsg = null;
StringBuilder errorMsg = null;
DataOutputStream os = null;
try {
process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
os = new DataOutputStream(process.getOutputStream());
for (String command : commands) {
if (command == null) {
continue;
}
os.write(command.getBytes());
os.writeBytes(COMMAND_LINE_END);
os.flush();
}
os.writeBytes(COMMAND_EXIT);
os.flush();
result = process.waitFor();
// get command result
if (isNeedResultMsg) {
successMsg = new StringBuilder();
errorMsg = new StringBuilder();
successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String s;
while ((s = successResult.readLine()) != null) {
successMsg.append(s);
}
while ((s = errorResult.readLine()) != null) {
errorMsg.append(s);
}
}
} 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();
}
}
return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null
: errorMsg.toString());
}
//封裝了傳回資訊
public static class CommandResult {
public int result;
public String successMsg; //成功資訊
public String errorMsg; // 錯誤資訊
public CommandResult(int result) {
this.result = result;
}
public CommandResult(int result, String successMsg, String errorMsg) {
this.result = result;
this.successMsg = successMsg;
this.errorMsg = errorMsg;
}
}
}
在應用内部執行 cat /data/misc/wifi/wpa_supplicant.conf
指令
cat /data/misc/wifi/wpa_supplicant.conf
到了這一步就很簡單了,直接看代碼
strings = new ArrayList<>();
strings.add("cd data/" + ShellUtils.COMMAND_LINE_END);
strings.add("cd misc/" + ShellUtils.COMMAND_LINE_END);
strings.add("cd wifi/" + ShellUtils.COMMAND_LINE_END);
strings.add("ls" + ShellUtils.COMMAND_LINE_END);
strings.add("cat wpa_supplicant.conf" + ShellUtils.COMMAND_LINE_END);
ShellUtils.CommandResult result = ShellUtils.execCommand(strings, true, true);
//擷取傳回的結果
String wifis = result.successMsg;
此時傳回的資訊就包含了 wpa_supplicant.conf
檔案内部的所有資訊,此時我們需要做的就是解析WIFI名稱和密碼然後顯示到界面
wpa_supplicant.conf
利用正規表達式解析傳回的資料
首先檢視我們擷取到的傳回資訊,其中wifi的名稱格式是 ssid="......"
密碼的格式是 psk="......"
,這樣我們就可以用正規表達式來截取名稱和密碼
ssid="......"
psk="......"
注:部分機型中文的wifi名稱會顯示為字母和數字的組合,且沒有雙引号,另開放的網絡沒有wifi密碼,密碼一欄的顯示是這樣的 key_mgmt=NONE
,是以第一步執行的是講其中的 key_mgmt=NONE
替換為 key_mgmt="無密碼"
.這樣就不會出現名稱的個數和密碼的個數不相符的問題
key_mgmt=NONE
key_mgmt=NONE
key_mgmt="無密碼"
解析wifi的名稱
Pattern pattern = null;
Matcher matcher = null;
listID = new ArrayList<>();
listPass = new ArrayList<>();
//擷取使用者名
String rexId = "ssid=[\\S]+[\\s]";
pattern = Pattern.compile(rexId);
matcher = pattern.matcher(wifis);
while (matcher.find()) {
listID.add(matcher.group());
}
解析wifi的密碼
//擷取密碼
String rexPass = "psk=\"[^\"]+\"";
pattern = Pattern.compile(rexPass);
matcher = pattern.matcher(wifis);
while (matcher.find()) {
listPass.add(matcher.group());
}
經過這兩步之後我們就擷取到了兩個包含wifi名稱和wifi密碼的LIst
封裝一個儲存wifi資訊的base類
package com.brioal.wifipassword.base;
/**
* Created by Brioal on 2016/3/21.
*/
public class WifiItem {
private String mId ;
private String mPass ;
public WifiItem(String mId, String mPass) {
this.mId = mId;
this.mPass = mPass;
}
public String getmId() {
return mId;
}
public void setmId(String mId) {
this.mId = mId;
}
public String getmPass() {
return mPass;
}
public void setmPass(String mPass) {
this.mPass = mPass;
}
}
擷取 List<WifiItem>
List<WifiItem>
for (int i = ; i < listID.size(); i++) {
String mId = listID.get(i);
String mPass = listPass.get(i);
mId = mId.substring(, mId.length() - );
mPass = mPass.substring(, mPass.length() - );
WifiItem item = new WifiItem(mId, mPass);
wifiList.add(item);
}
接下來就是最後一步,将wifi資訊顯示到ExpandableListView當中
顯示wifi資訊
這一部分比較簡單,就直接上代碼吧
建立Adapter
private class MyAdapter implements ExpandableListAdapter {
@Override
public void registerDataSetObserver(DataSetObserver observer) {
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
}
@Override
public int getGroupCount() {
return listID.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return ;
}
@Override
public Object getGroup(int groupPosition) {
return listID.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
return listPass.get(groupPosition);
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return groupPosition;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
TextView textView = new TextView(MainActivity.this);
textView.setTextSize();
textView.setGravity(Gravity.CENTER_VERTICAL);
textView.setText(" "+wifiList.get(groupPosition).getmId());
textView.setSingleLine();
textView.setMaxWidth();
textView.setTypeface(Typeface.SANS_SERIF);
textView.setEllipsize(TextUtils.TruncateAt.END);
return textView;
}
@Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
TextView textView = new TextView(MainActivity.this);
textView.setTextSize();
textView.setGravity(Gravity.CENTER_VERTICAL);
textView.setText(" "+wifiList.get(groupPosition).getmPass());
textView.setTypeface(Typeface.SANS_SERIF);
return textView;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
@Override
public boolean areAllItemsEnabled() {
return false;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public void onGroupExpanded(int groupPosition) {
}
@Override
public void onGroupCollapsed(int groupPosition) {
}
@Override
public long getCombinedChildId(long groupId, long childId) {
return ;
}
@Override
public long getCombinedGroupId(long groupId) {
return ;
}
}
ExpandableLIstView
設定 Adapter
ExpandableLIstView
Adapter
adapter = new MyAdapter();
listView.setAdapter(adapter);
至此大功告成
源碼已分享到Github,有興趣的同學歡迎下載下傳檢視
歡迎聯系作者交流,作者QQ:821329382