Android设备上非root的抓包实现方法(Tcpdump方法)

通常我们在Android应用中执行某个命令时会使用“Runtime.getRuntime().exec("命令路径")”这种方式,但是当我们执行抓包操作时,使用这条命令无论如何都不行,通过下面代码打印结果发现,该命令一定要在root权限下才能执行。

BufferedReader brW = new BufferedReader(new InputStreamReader(p.getErrorStream())); while((str = brW.readLine()) != null) Log.d("cwmp", "w:"+str);

但是我们的Android设备(包括机顶盒、手机等)通常并没有root过,apk的最高权限也只是system权限,这该怎么解决?首先我们要知道,方法总比问题多,在Android设备的/system/bin路径下,我们会看到很多二进制文件,这些二进制文件可以获得root权限。因此,我们可以通过C语言来实现抓包功能,通过NDK把该C代码交叉编译成二进制文件置于/system/bin路径下,并赋予其root权限,此时,这个二进制文件就具备了抓包能力了。现在问题又来了,我们现在是想通过apk去调用这个抓包指定,抓包完成后又该怎么通知apk呢?其实,Android可以通过socket使底层与framework层进行通信,具体请参考Android中使用socket使底层和framework通信的实现方法。

接下来我们将贴出关键实现代码。

1、编写socket服务端代码fstiService.cpp,生成可执行脚本fstiService

#define SOCKET_NAME "fstiService" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "itv_assistance", __VA_ARGS__) #include <jni.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/wait.h> #include <sys/un.h> #include <cutils/sockets.h> #include <android/log.h> #include <unistd.h> #include <time.h> #include <sys/time.h> #include <pthread.h> pthread_t thread[2]; char s_time[10]; //抓包时间子串 char s_command[256]; //抓包指令子串 //抓包指令:system("/system/bin/tcpdump -v -w /sdcard/te.pcap"); //获取进程tcpdump的进程号 int getPid() { //for Linux C //FILE *fp = popen("ps -e | grep \'tcpdump\' | awk \'{print $1}\'", "r"); //for Android(ARM) //FILE *fp = popen("ps | grep \'tcpdump\'", "r"); FILE *fp = popen("ps | grep \'tcpdump\'", "r"); char buff[1024] = { 0 }; while (NULL != fgets(buff, sizeof(buff), fp)) ; //取消换行符(10) buff[strlen(buff) - 1] = '\0'; pclose(fp); char dst[5] = { 0 }; char *p = buff; char *q = dst; //每一行进程信息的第二个字符串为进程号 while (*p != ' ') p++; while (*p == ' ') p++; while (*p != ' ') *(q++) = *(p++); *(q++) = '\0'; return atoi(dst); } //截取子串(抓包时间(秒):抓包命令) void substring(char *time, char *command, char *src) { char *p = src; char *q = time; char *s = command; while (*p != '/') *(q++) = *(p++); *(q++) = '\0'; //如果Tcpdump命令已添加环境变量,则添加下行代码 //否则删除下一行代码,client传递的参数格式必须为: num/tcpdump所在路径 p++; while (*p) *(s++) = *(p++); *(s++) = '\0'; } //抓包线程 void *thread1(void *arg) { system(s_command); } void *thread2(void *arg) { int i_time = atoi(s_time); int begin = time((time_t*) NULL); while (1) { if (time((time_t*) NULL) - begin < i_time) { //printf("当前时间(s):%ld\n", time((time_t*)NULL)); continue; } else { int n = kill(getPid(), SIGKILL); LOGD("the kill process result is n=%d", n); break; } } return 0; } //创建子线程 void thread_create() { int temp; memset(&thread, 0, sizeof(thread)); if ((temp = pthread_create(&thread[0], NULL, thread1, NULL)) != 0) LOGD("create tcpdump thread failure"); else LOGD("create tcpdump thread success"); if ((temp = pthread_create(&thread[1], NULL, thread2, NULL)) != 0) LOGD("create count thread failure"); else LOGD("create count thread success"); } void thread_wait() { if (thread[0] != 0) { pthread_join(thread[0], NULL); LOGD("tcpdump thread has terminated"); } if (thread[1] != 0) { //pthread_join(thread[1], NULL); printf("counter thread has terminated"); } } /** * Native层Socket服务端 */ int main() { int connect_number = 6; int fdListen = -1, new_fd = -1; int ret; struct sockaddr_un peeraddr; socklen_t socklen = sizeof(peeraddr); int numbytes; char buff[256]; //这一步很关键,就是获取init.rc中配置的名为 "fstiService" 的socket //获取已绑定的socket,返回-1为错误情况 fdListen = android_get_control_socket(SOCKET_NAME); if (fdListen < 0) { LOGD("failed to get socket '" SOCKET_NAME "' errno %d", errno); exit(-1); } /** * 方法说明:开始监听(等待参数fdListen的socket连接,参数connect_number指定同时能处理的最大连接要求) * 如果连接数目达此上限则client端将收到ECONNREFUSED的错误。listen函数并未开始连接,只是设置 * socket为listen模式,真正接收client端连接的是accept()。通常listen()会在socket() * bind()之后调用,接着才调用accept(). * 返回值:成功返回0,失败返回-1,错误原因存在errno中 */ ret = listen(fdListen, connect_number); LOGD("listen result %d", ret); if (ret < 0) { /** * perror(s)将一个函数发生错误的原因输出到标准设备(stderr) * 参数s所指的字符串会先打印出,后面再加上错误原因字符串 */ perror("listen"); exit(-1); } /** * 方法说明:accept(int s, struct sockaddr * addr, socklen_t * addrlen)用来接受参数s的socket连接。 * socket必须先经bind()、listen()函数处理过,当有socket客户端连接进来时会返回一个新的socket处理 * 代码,往后的数据传送与读取就是经由新的socket处理,而原来参数s的socket能继续使用accept()来接受新的 * 连接请求。连线成功时, 参数addr 所指的结构会被系统填入远程主机的地址数据,参数addrlen为sockaddr的 * 结构长度。 * 返回值:成功返回新的socket处理代码,失败返回-1,错误原因存在于errno中。 */ new_fd = accept(fdListen, (struct sockaddr *) &peeraddr, &socklen); LOGD("accept_fd %d", new_fd); if (new_fd < 0) { LOGD("%d", errno); perror("accept error"); exit(-1); } //循环等待Socket客户端发来消息 while (1) { /** * 方法说明:recv(int s, void *buf, size_t len, unsigned int flags)用来接收 * 客户端socket传来的数据,并把数据存到由参数buf指向的内存空间,参数len为可接收数据的最大长度。 * 参数flags一般设0 * 返回值:失败返回-1 */ if ((numbytes = recv(new_fd, buff, sizeof(buff), 0)) == -1) { LOGD("%d", errno); perror("recv"); continue; } LOGD("the parameter received from socket client is %s", buff); if(strcmp(buff, "exit") != 0){ substring(s_time, s_command, buff); thread_create(); thread_wait(); } char result[10] = "successp"; /** * 方法说明:send(int s, const void *msg, size_t len, unsigned int flags) * 参数s为已建立好连接的socket,参数msg指向欲发送的数据内容,参数len为数据长度,flags一般置0. * 返回值:失败返回-1,错误原因存在errno中 */ int sendR = send(new_fd, result, strlen(result), 0); //apk退出后,buff中仍然缓存之前的调用命令,此时会额外再执行一次抓包,固下面代用重写buff中数据 strcpy(buff, "exit"); if (sendR == -1) { perror("send"); close(new_fd); exit(0); } } close(new_fd); close(fdListen); return 0; }

2、配置init.rc文件,添加如下配置

service fstiService /system/bin/fstiService socket fstiService stream 777 system system class main

此处配置了一个名为“fstiService”的服务,Android设备开机会自动启动并运行/system/bin/fstiService这个脚本文件。服务端代码完成后,我们需要将其编译成可执行脚本fstiService,Android.mk内容如下:

LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) #指定该模块在所有版本下都编译 LOCAL_MODULE_TAGS :=optional LOCAL_MODULE := fstiService LOCAL_SRC_FILES := fstiService.cpp LOCAL_LDLIBS := -llog #编译成动态库 #include $(BUILD_SHARED_LIBRARY) #编译成可执行文件 include $(BUILD_EXECUTABLE)

3、Android客户端代码

public class SocketClient { private final String SOCKET_NAME = "fstiService"; private LocalSocket client = null; private LocalSocketAddress address = null; private boolean isConnected = false; private int connectTime = 1; public SocketClient(){ client = new LocalSocket(); //A socket in the Android reserved namespace in /dev/socket. //Only the init process may create a socket here address = new LocalSocketAddress(SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED); new ConnectSocketThread().start(); } /** * 发送消息 * @param msg * @return 返回Socket服务端消息回执 */ public String sendMsg(String msg){ if(!isConnected) return "Connect failure"; try{ BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out = new PrintWriter(client.getOutputStream()); out.println(msg); out.flush(); return in.readLine(); }catch(IOException e){ e.printStackTrace(); } return "Nothing Return"; } /** * Socket连接线程,若连接失败会尝试重连3次 * @author Administrator * */ private class ConnectSocketThread extends Thread{ @Override public void run() { while(!isConnected && connectTime <= 3){ try{ sleep(1000); Log.d("itv_assistance", "Try to connect socket; ConnectTime: "+connectTime); client.connect(address); isConnected = true; }catch(Exception e){ connectTime++; isConnected = false; Log.d("itv_assistance", "Connect Failure"); } } } } /** * 关闭Socket */ public void closeSocket(){ try{ client.close(); }catch(IOException e){ e.printStackTrace(); } } }

  至此,基于非root的Android设备上的抓包实现方法就完成了,接下来就是编译系统进行测试了,这步我没有亲自去做,而是把fstiService脚本及init.rc配置文件的操作交给合作厂商来做了,apk是我们自己做的,经测试一切OK。

点击下载源码:http://xiazai.jb51.net/201611/yuanma/AndroidFstiService(jb51.net)

以上所述是小编给大家介绍的Android设备上非root的抓包实现方法(Tcpdump方法),实现一个模拟后台数据登入的效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

时间: 2024-09-17 04:00:26

Android设备上非root的抓包实现方法(Tcpdump方法)的相关文章

Android设备上非root的抓包实现方法(Tcpdump方法)_Android

通常我们在Android应用中执行某个命令时会使用"Runtime.getRuntime().exec("命令路径")"这种方式,但是当我们执行抓包操作时,使用这条命令无论如何都不行,通过下面代码打印结果发现,该命令一定要在root权限下才能执行. BufferedReader brW = new BufferedReader(new InputStreamReader(p.getErrorStream())); while((str = brW.readLine(

Android常用抓包工具之TcpDump

原文出自[听云技术博客]:http://blog.tingyun.com/web/article/detail/480   做为一个测试人员,工作中经常会用到数据抓包工具来进行数据分析和验证,下面就简单介绍一下工作中常用的抓包工具. TcpDump抓包 Tcpdump是一个用于截取网络分组,并输出分组内容的工具.它凭借强大的功能和灵活的截取策略,使其成为类UNIX系统下用于网络分析和问题排查的首选工具. 可以将网络中传送的数据包的"头"完全截获下来提供分析.它支持针对网络层.协议.主机

远程执行 Android 设备上的代码 【已翻译100%】(1/2)

"你走进一个咖啡店坐下来.等咖啡的时候,你拿出你的智能手机开始玩一款你前些天下载的游戏.接着,你继续工作并且在电梯里收邮件.在你不知情下,有攻击者获取了公司网络的地址并且不断地感染你所有同事的智能手机. 等下, 什么? 我们在Bromium实验室博客上不会谈论Android太多.但是不时地我们喜欢修修补补.近来,我的同事Thomas Coudray 和我探索了下Android远程代码执行的易损性,想弄明白易损性在现实应用中是多大的问题. 尽管权限提升技术在Android上很普遍(并形成了&quo

Android设备上的解压缩工具:RAR for Android

RAR for Android 是老牌解压缩工具 WinRAR 推出的免费 Android 工具,可以让你在 Android 设备上压缩.解压缩文件. via @Xang Azu 在中国盗版率排名前列的 WinRAR 推出了免费的解压缩工具,支持 RAR, ZIP, TAR, GZ, BZ2, XZ, 7z, ISO, ARJ 格式. RAR for Android 还支持选择压缩率.分卷压缩.遗憾的是内部没有分享工具,压缩后还需要其他工具分享出去. @Scavin 在使用手机的时候唯一遇到了几

vpn server amdroid-如何在android 设备上创建一个vpn server

问题描述 如何在android 设备上创建一个vpn server 怎么创建一个手机端的 vpn server,怎么创建啊 找了好多 就只有client的 解决方案 用openvpn.建立server

【百度地图API】手机浏览器抓包工具及其使用方法

原文:[百度地图API]手机浏览器抓包工具及其使用方法 摘要:为了测试地图API在手机浏览器上的性能,需要给手机浏览器设置代理.通过代理,我们可以在PC上获取到抓包数据.进而对性能做进一步分析.   ------------------------------------------------------ 一.手机浏览器抓包工具 Paros 3.2.13   二.如何配置 1.将电脑和手机连到同一个wifi环境中 2.找到电脑的IP 可以点击网卡图标,找到IP信息 也可以在cmd下,使用ipc

远程执行 Android 设备上的代码 【已翻译100%】(2/2)

我设置好AP后,从13,119个标明有潜在漏洞的app中随机选了一些,把它们安装到接入了AP的一台Nexus 5(运行4.4.3)和一台三星XE700t(运行AOSP 4.2的x86平板).我们只不过是启动每个App,做些简单的交互操作,就成功地在超过半数的应用中触发了远程代码执行,它们加载了通过中间人代理注入的恶意代码. 为了好玩,我们把注入到一个app中javascript代码反复修改,直到显示Bromium的标志替换了原有广告. 被扰乱而显示了Bromium标志的app的UI截屏. 全是广

Android利用Fiddler进行网络数据抓包

主要介绍Android及IPhone手机上如何利用Fiddler进行网络数据抓包,比如我们想抓某个应用(微博.微信.墨迹天气)的网络通信请求就可以利用这个方法. Mac 下请使用 Charles 代替 Fiddler. 相对于tcpdump配合wireshark抓包的优势在于:(1)无需root (2)对Android和Iphone同样适用 (3)操作更简单方便(第一次安装配置,第二次只需设置代理即可) (4)数据包的查看更清晰易懂,Fiddler的UI更简单明了 (5) 可以查看https请求

在Android设备上提高工作效率和安全性的10招

 或许阁下刚刚买入第一款安卓设备,或许阁下使用安卓设备已经有一段时间了但却觉得可能没有最有效地利用它.无论是那种情况,阁下今天行好运了:利用各种调整.应用程序.选项和配置等方法可以使得安卓设备更加强大和有效.下面列出10个笔者最喜欢的技巧,以期帮助阁下在安卓平台上获得最大的好处. 1.使用谷歌 关于安卓的第一件要知道的事是,安卓是与谷歌紧密地整合在一起的.如果不利用二者之间这种整合的优势,就白白错过好东西.笔者说的不仅仅是谷歌网盘.日历.邮件.照片等等,还有搜索."谷歌Now"时下是安