android vpn service

VPN Service 运行在 IP 层。它创建了一个虚拟的网络接口,可以配置地址和路由规则,并返回一个 file descriptor。每次读这个 fp 返回一个数据包,每次写发送一个数据包。

两个最重要的方法分别是prepare(Context)establish()。前者接受用户响应并关闭其他应用的 VPN 链接,后者使用 VpnService.Builder 的参数创建 VPN 接口。

实现 VpnService 的类必须在 manifest 中声明:

<service android:name=".ExampleVpnService"
         <action android:name=""/>
  1. VpnService works on the network layer, the IP protocol is a point to point protocol, the packet changes between each hop, TCP is a end to end protocol
  2. use the vpn service as a layer4(NAT) router, and then you could modify or relay the packet
  3. IP packet contains only src and dst IP address and upper protocol, the port information is stored in TCP packet
  4. TCP is a stream protocol, so thers is no packet in tcp(see

关于 VPN Service 的一些讨论

you need to reverse the ip order for ip layer headers

ToyVPN is the official example on using vpn service

SSL in java

building a client

Your VPN will need to create a new socket, protect the socket from being routed back into the VPN using VpnService.protect(Socket), and connect the socket to Having set up a tunnel connection to the VPN server, you should proceed to writing the input stream of the VpnService’s interface into the tunnel’s output stream, and in turn write the tunnel response back into the interface output stream.

  1. simple example

Android VPN Service Explained with Packet Bypass Example Program

  1. building a firewall with vpn service

Incoming and outgoing streams of the VpnService are in the network layer( layer); you are receiving (and should in turn be transmitting) raw IP packets, as you describe in your question.

also check out the OSI model and IP header format on WikiPedia

When forwarding the requests, you are in the application layer; you should be transmitting the contents of the UDP or TCP payload (i.e. only their data, not the headers themselves) using respectively a DatagramSocket or a Socket.

Bear in mind that this skips the transport layer as those implementations take care of constructing the UDP header (in case of DatagramSocket) and the TCP header and options (in case of Socket).

all I hava to do is to:

check if the IP packet is for http or https:

if not:

act as a route, forward as is, but ack requests and reconstruct the packet with new src, and

if so:

  • act as the server, ack the request packet
  • act as the client, send new http request to the server and retrive the response
  • act as the server, send back the response packet

The whole process is like we are the router, and dispatch different packet to different nodes(servers).

SSL Pinning 与破解

什么是 SSL Pinning

To view https traffic, you could sign your own root CA, and perform mitm attack to view the traffic. HPKP (http public key pinning) stops this sniffing by only trust given CA, thus, your self-signed certs will be invalid. To let given app to trust your certs, you will have to modify the apk file.

How to break it?

Introducing Xposed

decompile, modify and then recompile the apk file can be very diffcult. so you’d better hook to some api to let the app you trying to intercept trust your certs. xposed offers this kind of ability. moreover, a xposed module called JustTrustMe have done the tedious work for you. just install xposed and JustTrustMe and you are off to go. Here are the detaild steps:

  1. Install Xposed Installer

for android 5.0 above, use the xposed installer.

NOTE: 对于 MIUI,需要搜索 Xposed 安装器 MIUI 专版。

  1. Install Xposed from xposed installer, note, you have to give root privilege to xposed installer

  2. Install JustTrustMe

Android am 命令

am is short for activity manager, which is used to start and stop activity in android.

basic syntax

start an activity

you can get the activity name by decompiling the apk and view the androidmanifest.xml file

am start -n <package_name>/<activity_name> [parameters]
am start -n

stop an activity

am force-stop

get and change android device id

get device id

String id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);

set device id

As far as Settings.Secure.ANDROID_ID goes, this should do the trick:

adb shell sqlite3 /data/data/ "UPDATE secure SET value='newid' WHERE name='android_id'"

Where newid is usually the 16 hex digit code (i.e. don’t append “Android_” to it).
I only tried this on the emulator. I imagine a real phone would need to be rooted first.



download from here:, basically it’s an electorn app

How it works

How to crack it

chrome 插件
/Users/USERNAME/Library/Application Support/Google/Chrome/Profile 1/Extensions

function e() {
this.licensed = false;
this.licenseCached = false

changed to true


let’s assume /system is the rom folder

| Partition | Explanation |
| /boot | kernel & Co. |
| /cache | app cache |
| /data | user data partition¹ |
| /data/data | app data¹ |
| /dev | devices, virtual fs |
| /mnt/asec | encrypted apps (App2SD) |
| /mnt/emmc | internal sdcard³ |
| /mnt/sdcard | external sdcard³ |
| /proc | process information² |
| /recovery | used in recovery mode |
| /system | system ROM (read-only) |

/data and /data/data

These are in most cases two separate partitions, but there might be cases where this is handled otherwise. One thing they have in common (add /cache here as well): they get wiped on a factory-reset, while the other partitions are usually left untouched by that.

| Directory | Explanation |
| /data/anr | traces from app crashes (App Not Responding) |
| /data/app | .apk files of apps installed by the user |
| /data/backup | Googles Cloud-Backup stuff |
| /data/dalvik-cache | optimized versions of installed apps¹ |
| /data/data | app data² |
| /data/local | temporary files from e.g. Google Play³ |
| /data/misc | system configuration (WiFi, VPN, etc.) |
| /data/system | more system related stuff (certs, battstat) |
| /data/tombstones | more crash stuff (“core dumps”) |
| /data/user | multi-user support, /data/user/0 is a symlink to /data/data|



cross compiling on android

basic knowledge

first, we need a cross compiler, which you can download from the source or somewhere.

second, when we use gcc to build stuff, actually we are implicitly linking to the stdlib of c, if we are cross compiling programs for another platform, then we need another platform’s filesystem to be accessible to us. However, we only need the target’s /usr directory, because that’s where the header files lives in.

we place target’s header files in a directory called sysroot, and gcc supports the argument --sysroot

gcc config parameters

|options  | explaination                                    |
|--build  |the machine which you build on                   |
|--host   |the machine which your binary will be running on |
|--target |the machine that GCC will produce code for       |

|--build |--host |--target|result |
|-   |-  | -      |native |
|-   |-      | x      |cross complie|

Argument --target makes sense only when building compiler (e.g. GCC).

How to

Let’s assume you have directory called ~/x-compile

  1. You have your tool-chain installed, that it is the correct tool-chain and the PATH environment variable is correctly set, so that the cross-compiler and all other cross-tools binaries can be called from any folder.
  2. You have the sysroot installed in ~/x-compile/sysroot
  3. Your code depends on a library for which you have the source code in ~/x-compile/depsrc/
  4. You have the source code to be cross-compiled in ~/x-compile/src

  5. compile you dependency lib, if your dependency lib don’t need stdlib

./configure CC=arm-linux-gnueabihf-gcc --prefix=~/x-compile/deps --host=arm-linux-gnueabihf
make install

if your dependency needs system libs, then you need --sysroot as below

  1. compile your program

compile python on android

在安卓上编译 python

compiling 2.7.2

Cross compiling Python for Android

another tutorial

best tutorial


very confusing, the second answer is better


Yifei’s Notes

adb is pretty unstable, it’s meant for debug usage, NOT for a long-running service.


install on ubuntu: apt-get install android-tools-adb android-tools-fastboot

install on mac: brew install android-platform-tools

Connect model

there is a server on PC called adb server, if not started, will be started on first adb client call commands. there is an adbd daemon on phone, run as not root by default.

adb devices

list all devices, give serial number for usb, and ip:port for wifi devices as adb id. if only one device, all commands are issued to that device, if many, use adb -s command to select a device.

Connect over Wifi

  1. first usb adb to the device
  2. second

if rooted and run this on phone

setprop service.adb.tcp.port 5555
stop adbd && start adbd

if not rooted and run this on computer

adb tcpip 5555
  1. adb connect ip:port
  2. adb usb # back to usb mode


adb pull phone_path pc_path
adb push pc_path phone_path


adb install 
adb uninstall
adb shell pm clear PACKAGE_NAME  # clears package data


adb forward local:port android:port
adb wait-for-device

adb forward host device
adb forward tcp:6100 tcp:7100


remounts the /system, /vendor (if present) and /oem (if present) partitions on the device read-write

get running activity name

adb shell dumpsys activity | grep mFocusedActivity


error closed

可能是权限不够,执行了n权限过高的操作,需要首先执行 adb root

能用 ssh,就用 ssh ,不要用 adb

Android Shell Command


32 bit adb 在64位linux上无法运行

The error message is no such file of directory, which is quite miss-leading

adb install 安装失败

apk 没有权限 应该777
apk 有证书不一致的 卸载旧的apk

Configuator 设置 uiautomator 的超时时间,参见[1]



adb shell pm path com.example.someapp
adb pull /data/app/com.example.someapp-2.apk