/*
* 作者:蟑螂一号
* 原文链接:http://www.sanwho.com/155.html
* 转载请注明出处
*/
在android系统中,可以使用iptables控制单个应用网络访问。在google code上有一个开源项目-droidwall就是基于iptables实现的。除了iptables可以实现控制单个应用网络访问外,还可以通过拦截应用中的connect函数,达到控制应用访问网络的目的。下面从几个方面分析android应用中connect调用流程为例来实现拦截connect实现网络禁用和ip过滤。(以下分析基于4.2源码)
1.android中网络访问流程
1)android系统中访问网络可以通过Socket.java、URL.java、HttpPost.java、HttpGet.java等关键类来访问网络资源。通过代码追踪,这些类访问网络资源最终需要通过native方式,调用linux系统下的socket函数访问网络。在android4.2源码中,java层访问网络得native方法定义在源码路径libcore/luni/src/main/java/libcore/io/Posix.java中(4.0之前的网络系统、文件系统的native方法是独立分开得,4.0之后组织在Posix.java中)。如下是Posix.java中的代码片段:
1
2
3
4
5
6
7
8
9
|
public
final
class
Posix
implements
Os
{
Posix
(
)
{
}
public
native
FileDescriptor
accept
(
FileDescriptor
fd
,
InetSocketAddress
peerAddress
)
throws
ErrnoException
,
SocketException
;
public
native
boolean
access
(
String
path
,
int
mode
)
throws
ErrnoException
;
public
native
void
bind
(
FileDescriptor
fd
,
InetAddress
address
,
int
port
)
throws
ErrnoException
,
SocketException
;
.
.
.
.
.
.
//对应linux下的connect系统调用
public
native
void
connect
(
FileDescriptor
fd
,
InetAddress
address
,
int
port
)
throws
ErrnoException
,
SocketException
;
|
2)Posix.java中的native方法实现源码路径libcore/luni/src/main/native/libcore_io_Posix.cpp文件中,native connect方法实现代码片段如下:
1
2
3
4
5
6
7
8
9
10
|
static
void
Posix_connect
(
JNIEnv
*
env
,
jobject
,
jobject
javaFd
,
jobject
javaAddress
,
jint
port
)
{
sockaddr_storage
ss
;
if
(
!
inetAddressToSockaddr
(
env
,
javaAddress
,
port
,
&
ss
)
)
{
return
;
}
const
sockaddr
*
sa
=
reinterpret_cast
<
const
sockaddr
*
>
(
&
ss
)
;
(
void
)
NET_FAILURE_RETRY
(
env
,
int
,
connect
,
javaFd
,
sa
,
sizeof
(
sockaddr_storage
)
)
;
}
|
有上代码可知,java层connect最终功能由linux系统connect函数实现。
2.so注入
so注入可以参考古河大哥牛逼的libInject(点击这里访问)。
3.拦截connect库编写
在connect中,获取传入的参数ip地址,根据需要把需要禁用的ip地址改为127.0.01.以下是我测试的拦截connect函数关键代码:
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
43
44
45
46
47
48
|
int
new_connect
(
int
sockfd
,
const
struct
sockaddr
*
addr
,
socklen_t
addrlen
)
{
LOGDD
(
"HOOK ====>new connect****************"
)
;
char
ip
[
128
]
=
{
0
}
;
int
port
=
-
1
;
if
(
addr
->
sa_family
==
AF_INET
)
{
struct
sockaddr_in
*
sa4
=
(
struct
sockaddr_in
*
)
addr
;
inet_ntop
(
AF_INET
,
(
void
*
)
(
struct
sockaddr
*
)
&
sa4
->
sin_addr
,
ip
,
128
)
;
port
=
ntohs
(
sa4
->
sin_port
)
;
LOGDD
(
"AF_INET IP===>%s:%d"
,
ip
,
port
)
;
}
else
if
(
addr
->
sa_family
==
AF_INET6
)
{
struct
sockaddr_in6
*
sa6
=
(
struct
sockaddr_in6
*
)
addr
;
char
*
ipv6
=
NULL
;
inet_ntop
(
AF_INET6
,
(
void
*
)
(
struct
sockaddr
*
)
&
sa6
->
sin6_addr
,
ip
,
128
)
;
ipv6
=
strstr
(
ip
,
"f:"
)
;
if
(
NULL
!=
ipv6
)
{
strcpy
(
ip
,
ipv6
+
2
)
;
}
port
=
ntohs
(
sa6
->
sin6_port
)
;
LOGDD
(
"af_inet6 IP===>%s:%d"
,
ip
,
port
)
;
}
else
{
return
old_connect
(
sockfd
,
addr
,
addrlen
)
;
}
if
(
strcmp
(
ip
,
"115.23.20.178"
)
==
0
)
{
LOGDD
(
"%s ==>127.0.0.1"
,
ip
)
;
struct
sockaddr_in
my_addr
;
int
my_len
=
sizeof
(
struct
sockaddr_in
)
;
bzero
(
&
my_addr
,
sizeof
(
my_addr
)
)
;
my_addr
.
sin_family
=
AF_INET
;
my_addr
.
sin_port
=
htons
(
80
)
;
my_addr
.
sin_addr
.
s_addr
=
inet_addr
(
"127.0.0.1"
)
;
return
old_connect
(
sockfd
,
(
const
sockaddr
*
)
&
my_addr
,
sizeof
(
my_addr
)
)
;
}
else
{
return
old_connect
(
sockfd
,
addr
,
addrlen
)
;
}
}
|
4.拦截connect函数功效
1)禁用应用网络访问。
2)过滤广告ip
3)禁用定位功能
以上仅个人见解,各位大牛多多指教。