SoFunction
Updated on 2025-04-07

Non-root packet capture implementation method (Tcpdump method) on Android devices

Usually, when we execute a command in an Android application, we will use "().exec("command path")" method, but when we perform the packet capture operation, using this command will not work anyway. Through the following code printing results, it is found that the command must be executed under root permissions.

BufferedReader brW = new BufferedReader(new InputStreamReader(()));
while((str = ()) != null)
("cwmp", "w:"+str);

However, our Android devices (including set-top boxes, mobile phones, etc.) are usually not rooted, and the highest permissions of apk are only system permissions. How to solve this problem? First of all, we need to know that there are always more methods than problems. In the /system/bin path of an Android device, we will see many binary files, which can obtain root permissions. Therefore, we can implement the packet capture function through C language, cross-compile the C code into a binary file through NDK, place it in the /system/bin path, and give it root permissions. At this time, this binary file has the capability to capture packets. Now the problem is coming again. We now want to call this packet capture specification through apk. How should we notify the apk after the packet capture is completed? In fact, Android can use socket to make the underlying layer communicate with the framework layer. Please refer to it for details.Implementation method of using socket to communicate with the underlying framework in Android

Next we will post the key implementation code.

1. Write socket server code and generate executable script fstiService

#define SOCKET_NAME "fstiService"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "itv_assistance", __VA_ARGS__)
#include <>
#include <>
#include <>
#include <>
#include <>
#include <sys/>
#include <netinet/>
#include <sys/>
#include <sys/>
#include <sys/>
#include <cutils/>
#include <android/>
#include <>
#include <>
#include <sys/>
#include <>
pthread_t thread[2];
char s_time[10]; //Search packet time substringchar s_command[256]; //Substring of packet capture instruction//Bail grab command: system("/system/bin/tcpdump -v -w /sdcard/");//Get the process number of the process tcpdumpint 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))
;
//Uninstall newline characters (10)buff[strlen(buff) - 1] = '\0';
pclose(fp);
char dst[5] = { 0 };
char *p = buff;
char *q = dst;
//The second string of each line of process information is the process numberwhile (*p != ' ')
p++;
while (*p == ' ')
p++;
while (*p != ' ')
*(q++) = *(p++);
*(q++) = '\0';
return atoi(dst);
}
//Intercept substring (packet capture time (seconds): packet capture command)void substring(char *time, char *command, char *src) {
char *p = src;
char *q = time;
char *s = command;
while (*p != '/')
*(q++) = *(p++);
*(q++) = '\0';
//If the Tcpdump command has added an environment variable, add the following code// Otherwise, delete the next line of code, the parameter format passed by client must be: the path where num/tcpdump is locatedp++;
while (*p)
*(s++) = *(p++);
*(s++) = '\0';
}
//Catch the threadvoid *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("Current time(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;
}
//Create child threadvoid 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 layer Socket server
 */
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];
//This step is very critical, which is to obtain the socket named "fstiService" configured in//Get the bound socket and return -1 as an errorfdListen = android_get_control_socket(SOCKET_NAME);
if (fdListen < 0) {
LOGD("failed to get socket '" SOCKET_NAME "' errno %d", errno);
exit(-1);
}
/**
 * Method description: Start listening (waiting for the socket connection of parameter fdListen, parameter connect_number specifies the maximum connection requirement that can be processed at the same time)
 * If the number of connections reaches this upper limit, the client will receive an ECONNREFUSED error.  The listen function does not start connecting, it is just set
 * socket is listen mode, and the one that really receives the client connection is accept().  Usually listen() will be in socket()
 * bind() is called, and then accept() is called.
 * Return value: 0 is returned successfully, -1 is returned for failure, and the error reason is in errno
 */
ret = listen(fdListen, connect_number);
LOGD("listen result %d", ret);
if (ret < 0) {
/**
 * perror(s) outputs the cause of an error in a function to the standard device (stderr)
 * The string referred to by parameter s will be printed first, followed by the error reason string
 */
perror("listen");
exit(-1);
}
/**
 * Method description: accept(int s, struct sockaddr * addr, socklen_t * addrlen) is used to accept socket connections with parameters s.
 * The socket must be processed first by bind() and listen() functions. When a socket client connects in, a new socket will be returned.
 * Code, the subsequent data transmission and reading are processed through a new socket, and the socket with the original parameter s can continue to use accept() to accept new ones.
 * Connection request.  When the connection is successful, the structure referred to by the parameter addr will be filled in the remote host's address data by the system, and the parameter addrlen is sockaddr.
 * Structural length.
 * Return value: The new socket processing code is returned successfully, and the -1 is returned for failure. The error reason exists in 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);
}
//Longly wait for the Socket client to send a messagewhile (1) {
/**
 * Method description: recv(int s, void *buf, size_t len, unsigned int flags) is used to receive
 * The data transmitted from the client socket and store the data in the memory space pointed to by the parameter buf. The parameter len is the maximum length of the data that can be received.
 * Parameter flags are generally set to 0
 * Return value: Failed to return -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";
/**
 * Method description: send(int s, const void *msg, size_t len, unsigned int flags)
 * Parameter s is the socket with a connection established, parameter msg points to the data content to be sent, parameter len is the data length, flags is generally set to 0.
 * Return value: Failed to return -1, the error reason exists in errno
 */
int sendR = send(new_fd, result, strlen(result), 0);
//After apk exits, the previous call command is still cached in the buff. At this time, the packet capture will be performed again. The following substitute rewrites the data in the buffstrcpy(buff, "exit");
if (sendR == -1) {
perror("send");
close(new_fd);
exit(0);
}
}
close(new_fd);
close(fdListen);
return 0;
}

2. Configuration file, add the following configuration

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

Here is a service called "fstiService". The Android device will automatically start and run the script file /system/bin/fstiService when it is turned on. After the server code is completed, we need to compile it into the executable script fstiService, with the following content:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#Specify that the module is compiled in all versionsLOCAL_MODULE_TAGS :=optional
LOCAL_MODULE := fstiService
LOCAL_SRC_FILES := 
LOCAL_LDLIBS := -llog
#Compiled into dynamic library#include $(BUILD_SHARED_LIBRARY)
#Compiled into an executable fileinclude $(BUILD_EXECUTABLE)

3. Android client code

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, );
new ConnectSocketThread().start();
}
/**
 * Send a message
 * @param msg
 * @return Return Socket server message receipt
 */
public String sendMsg(String msg){
if(!isConnected)
return "Connect failure";
try{
BufferedReader in = new BufferedReader(new InputStreamReader(()));
PrintWriter out = new PrintWriter(());
(msg);
();
return ();
}catch(IOException e){
();
}
return "Nothing Return";
}
/**
 * Socket connection thread, if the connection fails, try to reconnect 3 times
 * @author Administrator
 *
 */
private class ConnectSocketThread extends Thread{
@Override
public void run() {
while(!isConnected && connectTime <= 3){
try{
sleep(1000);
("itv_assistance", "Try to connect socket; ConnectTime: "+connectTime);
(address);
isConnected = true;
}catch(Exception e){
connectTime++;
isConnected = false;
("itv_assistance", "Connect Failure");
}
}
}
}
/**
 * Close Socket
 */
public void closeSocket(){
try{
();
}catch(IOException e){
();
}
}
}

At this point, the packet capture implementation method on non-root-based Android devices has been completed. The next step is to compile the system for testing. I did not do this step myself, but handed over the operations of the fstiService script and configuration file to the partner manufacturers. We did the apk ourselves, and everything was OK after testing.

Click to download the source code:http://xiazai./201611/yuanma/AndroidFstiService()

The above is the non-root packet capture implementation method (Tcpdump method) on Android devices introduced to you by the editor, which realizes the effect of simulating background data login. I hope it will be helpful to everyone. If you have any questions, please leave me a message and the editor will reply to everyone in time. Thank you very much for your support for my website!