今天无聊在手机上翻了一下开发者选项,无意中发现测试功能里面有一个叫WiFi嗅探的功能。听到Wifi嗅探的功能我的第一反应就是曾经使用抓包的方式可以破解WEP加密。或者是抓取公开wifi的网络流量。

大部分关于嗅探的教程都是需要购买特定型号的无线网卡的,但一加手机的开发者选项里面居然有这个功能,这么好玩的功能当然是要试试看了。

界面截图

输出文件是pacp格式,复制到电脑上可以用Wireshark打开看到802.11数据包

既然一加是高通Soc,那其他的高通Soc手机能否使用这个功能?这个功能如何使用命令启动?这便是这篇文章的目的

从这个应用开始

既然这是从一个测试APP找到的,那么自然从这个app入手了。使用adb找到当前activity,然后将该程序的apk复制到电脑使用jadx打开

打开后,一眼就找到了一个叫做WifiSniffer的类

然后找到了下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void setSnifferEnabled(boolean z) {
if (z) {
Log.i("WifiSniffer", "Start sniffing.");
Toast.makeText(getApplicationContext(), getString(2131690071), 0).show();
Utils.setSystemProperty("vendor.wlan.sniffer.file", "airport_" + getCurrentTime() + ".pcap");
Utils.transact("OEM_WIFI_SNIFFLOG_START");
Handler handler = this.mHandler;
handler.sendMessage(handler.obtainMessage(0, 10, 1));
return;
}
Log.i("WifiSniffer", "Stop sniffing.");
Toast.makeText(getApplicationContext(), getString(2131690075), 0).show();
Utils.transact("OEM_WIFI_SNIFFLOG_STOP");
Handler handler2 = this.mHandler;
handler2.sendMessage(handler2.obtainMessage(0, 10, 0));
}

继续查找Utils.transact的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static synchronized String transact(String str) {
synchronized (Utils.class) {
if (!connect()) {
Log.e("OpLogkit Utils", "connection failed");
return "-1";
}
if (!writeCommand(str)) {
Log.e("OpLogkit Utils", "write command failed? reconnect!");
if (!connect() || !writeCommand(str)) {
return "-1";
}
}
Log.i("OpLogkit Utils", "send: '" + str + "'");
return "1";
}
}

继续查找writeCommand

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

public static boolean writeCommand(String str) {
byte[] bytes = str.getBytes();
int length = bytes.length;
byte[] bArr = new byte[1024];
if (length >= 1 && length <= bArr.length) {
bArr[0] = (byte) (length & 255);
bArr[1] = (byte) ((length >> 8) & 255);
try {
mSocketOut.write(bArr, 0, 2);
mSocketOut.write(bytes, 0, length);
mSocketOut.flush();
return true;
} catch (IOException e) {
Log.e("OpLogkit Utils", "write socket error");
disconnect();
e.printStackTrace();
}
}
return false;
}

public static boolean connect() {
if (mSocket != null) {
return true;
}
Log.i("OpLogkit Utils", "socket connecting...");
try {
mSocket = new LocalSocket();
mSocket.connect(new LocalSocketAddress("oemlogkit", LocalSocketAddress.Namespace.RESERVED));
mSocket.setSoTimeout(120000);
mSocketIn = mSocket.getInputStream();
mSocketOut = mSocket.getOutputStream();
return true;
} catch (IOException e) {
disconnect();
e.printStackTrace();
return false;
}
}


看起来关键的逻辑并不在这个apk里,这个apk干了下面几件事情

  1. 设置了几个propprop可以简单认为是系统配置
  2. 向一个本地的UnixSocket发送了一些信息

到native

很显然,大部分逻辑应该都在oemlogkit这个UnixSocket对应的程序里。通过查找文档,找到了这个文件的路径是/dev/socket/oemlogkit。但是这没啥用。

到处找找吧,使用ps -A | grep oem可以找到一个叫做oemlogkit的进程

1
2
3
4
5
6
127|OnePlus7Pro:/dev/socket $ ps -A | grep oem
root 412 2 0 0 0 0 I [oem_key_dump]
root 1032 1 12366952 1336 0 0 S oemlogkit
system 6103 812 16067252 110532 0 0 S com.oem.oemlogkit
root 26341 1032 0 0 0 0 Z [oemlogkit]
system 27653 812 15906224 52108 0 0 S com.oem.logkitsdservice

使用 which oemlogkit 可以找到该进程的文件路径

1
2
OnePlus7Pro:/dev/socket $ which oemlogkit
/system_ext/bin/oemlogkit

使用adb将这个文件拉到电脑上,发现这是一个elf二进制文件,使用ida载入,然后找到了下面的代码

这些代码最主要部分还是修改了几个prop,同时也从prop里获取信息

其中最重要的是vendor.wlan.sniffer.enabled;同时也可以看到抓包使用的程序是熟悉的tcpdump

进入prop

修改一个prop就能启动监听模式,起初我以为这是内核的事情,在GitHub的一加内核代码仓库里搜索了半天没有任何结果。

使用adb shell setprop vendor.wlan.sniffer.enabled 1得到了一个权限错误

1
2
Failed to set property 'vendor.wlan.sniffer.enabled' to '1'.
See dmesg for error reason.

可以使用dmesg查看原因?然而使用的时候提示权限不足。。。这时候想起来开发人员工具内可以抓取内核日志,于是抓取日志找到了下面的信息

1
2
3
4
5
6
7
8
9
10
11
12
08-09 18:31:12.849     0     0 I [20210809_18:31:12.844281]@7 init: processing action (vendor.wlan.sniffer.enabled=1) from (/vendor/etc/init/hw/init.oem.rc:785)
08-09 18:31:12.849 0 0 I [20210809_18:31:12.844911]@7 init: starting service 'launch_sniffer'...
08-09 18:31:12.945 0 0 I [20210809_18:31:12.945092]@4 [sh][0xc5673c92c51][18: 31:12.945089] wlan: [20078:I:HDD] __hdd_driver_mode_change: 15669: Driver mode changing to 4

......



08-09 18:31:25.854 0 0 I [20210809_18:31:25.853580]@6 init: processing action (vendor.wlan.sniffer.enabled=0) from (/vendor/etc/init/hw/init.oem.rc:789)
08-09 18:31:25.863 0 0 I [20210809_18:31:25.858894]@7 init: starting service 'terminate_sniffer'...
08-09 18:31:25.884 0 0 I [20210809_18:31:25.881416]@5 init: processing action (vendor.wlan.sniffer.dump=1) from (/system_ext/etc/init/wifi-events.rc:75)

这下就应该去/vendor/etc/init/hw/init.oem.rc找信息了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

service launch_sniffer /vendor/bin/sh /vendor/bin/launch_sniffer.sh ${vendor.wlan.sniffer.iface} ${vendor.wlan.sniffer.channel} ${vendor.wlan.sniffer.bandwidth}
class main
user root
group root
disabled
oneshot

service terminate_sniffer /vendor/bin/sh /vendor/bin/terminate_sniffer.sh
class main
user root
group root
disabled
oneshot
#endif

找到了两个脚本。但是我的设备没有root。

启动脚本

最后找了朋友得到了这两个文件的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/vendor/bin/sh
# launch_sniffer.sh

iface=$(getprop vendor.wlan.sniffer.iface)
channel=$(getprop vendor.wlan.sniffer.channel)
bandwidth=$(getprop vendor.wlan.sniffer.bandwidth)
vendor_dir=$(getprop vendor.wlan.sniffer.vendor_dir)
file=$(getprop vendor.wlan.sniffer.file)
setprop vendor.wlan.sniffer.pid 0

mkdir -p $vendor_dir
if [ ! $(echo $vendor_dir | grep "/$") ]
then
vendor_dir=$vendor_dir/
fi
vendor_path=$vendor_dir$file

if [[ $(lsmod | grep "^wlan") == "" ]]
then
insmod /vendor/lib/modules/qca_cld3_wlan.ko
sleep 1
fi

ifconfig $iface down
sleep 3
echo 4 > /sys/module/wlan/parameters/con_mode
ifconfig $iface up

if [ $bandwidth -eq "80" ]
then
iwpriv $iface setMonChan $channel 2
else
bandwidth=HT$bandwidth
iw dev $iface set channel $channel $bandwidth
fi

tcpdump -i $iface -w $vendor_path &
setprop vendor.wlan.sniffer.pid $!

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/vendor/bin/sh
# terminate_sniffer.sh

iface=$(getprop vendor.wlan.sniffer.iface)
pid=$(getprop vendor.wlan.sniffer.pid)

kill -s SIGINT $pid
setprop vendor.wlan.sniffer.pid 0
ifconfig $iface down
sleep 3
echo 0 > /sys/module/wlan/parameters/con_mode
ifconfig $iface up

可以所有的逻辑都很明显了

总结一下就是下面的代码。很显然这个功能应该是高通设备都能用的,只是需要iwprivtcpdump两个程序。这两个程序不知道其他设备是否自带

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 开启
ifconfig wlan0 down
sleep 3
echo 4 > /sys/module/wlan/parameters/con_mode
ifconfig wlan0 up
iwpriv wlan0 setMonChan 频道 2

tcpdump -i wlan0 -w 路径

# 关闭
ifconfig wlan0 down
sleep 3
echo 0 > /sys/module/wlan/parameters/con_mode
ifconfig wlan0 up

后续

既然是通用的,可以写个小软件来快速使用这个功能。但是我root过的手机放学校了没带回家(),那就开学再见吧