主要内容:
-
在超级Root权限进程中创建socket server监听连接
-
基于socket通信实现一个简单的类似su程序的调用功能
本节达到的目的:
-
系统没有su程序但是也能执行和su差不多的功能效果
1.实现原理
在adbd中建立一个socket server。App通过发送socket连接,并发送需要执行的shell命令。adbd中的socket server收到客户端发送的shell命令之后,执行system函数来调用相应的shell命令。由于adbd具备超级root权限,所以App发送执行的命令最终也是常说中的Root权限情况下执行命令。
2.adbd中创建socket server
(1).创建shell_socket_service.h文件
在路径"systemcoreadbdaemon"下创建"shell_socket_service.h"头文件。内容如下:
#pragma once
#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
void create_shell_socket_service();
#endif
(2).创建shell_socket_service.cpp文件
在路径"systemcoreadbdaemon"下创建"shell_socket_service.cpp"源文件。内容如下:
#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
#include <unistd.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <sys/sendfile.h>
#include <fcntl.h>
#include <socket.h>
#include <cinttypes>
#include <wait.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <unistd.h>
#include <cerrno>
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <android/log.h>
#include "shell_socket_service.h"
#define FRIDA_INJECT_TAG "ss_server"
// #define NOT_DEBUG_SOCKET 1
#ifdef NOT_DEBUG_SOCKET
#define MYLOGDX(...)
#define MYLOGEX(...)
#else
#define MYLOGDX(...) __android_log_print(ANDROID_LOG_DEBUG, FRIDA_INJECT_TAG, __VA_ARGS__)
#define MYLOGEX(...) __android_log_print(ANDROID_LOG_ERROR, FRIDA_INJECT_TAG, __VA_ARGS__)
#endif
static void process_client_socket(int sockfd)
{
MYLOGDX("process_client_socket++++++++++");
FILE *cin=NULL;
FILE *client_output=NULL;
char *p=NULL;
char buf[1024]={0};
char reply[1024]={0};
cin = fdopen(sockfd, "r");
if(cin==NULL)
{
MYLOGEX("fdopen(sockfd,'r') erro:%s",strerror(errno));
close(sockfd);
return;
}
client_output=fdopen(dup(sockfd),"w");
if(client_output==NULL)
{
MYLOGEX("fdopen(sockfd,'w') erro:%s",strerror(errno));
close(sockfd);
return;
}
setbuf(cin, (char *)0);
sprintf(reply,"ERROR|invalid commandrn");
char* tempData=fgets(buf, 1023, cin);
if(tempData==NULL)
{
MYLOGDX("readData from client error");
close(sockfd);
return;
}
MYLOGDX("readData from client,data:%s",buf);
/* 去掉buf末尾的换行符 */
while ((p = &buf[strlen(buf)-1]) && (*p == 'r' || *p == 'n')) *p = 0;
if(strstr(buf,"do_cmd|")!=NULL)
{
MYLOGDX("recv data==>%s",buf);
//do command
char* temp=strstr(buf,"|");
if(temp!=NULL)
{
char* mycmd=(char*)(temp+1);
MYLOGDX("start to do command:%s",mycmd);
system(mycmd);
sprintf(reply,"SUCCESS:do command okrn");
}
}
fprintf(client_output,"%s",reply);
fclose(cin);
fclose(client_output);
close(sockfd);
}
void *my_create_shell_socket_service2(void *args) {
int clifd;
int one=-1;
struct sockaddr_in addr;
struct sockaddr_in from;
socklen_t fromlen = sizeof(from);
int server_socket_fd=-1;
int myport=11111;
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=INADDR_ANY;
addr.sin_port=htons(myport);
bool isExit=false;
if ((server_socket_fd = socket(PF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0) {
MYLOGEX("socket create failure");
return NULL;
}
if (setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
MYLOGEX("setsockopt %d SO_REUSEADDR error",myport);
}
if (bind(server_socket_fd, (struct sockaddr *) (&addr),sizeof(struct sockaddr)) < 0) {
MYLOGEX("bind %d error",myport);
return NULL;
}
MYLOGDX("socket created");
if (listen(server_socket_fd, 10) == -1) {
MYLOGEX("listen happen error");
return NULL;
}
while (!isExit) {
MYLOGDX("waiting for client connect............");
clifd = accept4(server_socket_fd, (struct sockaddr *) &from, &fromlen, SOCK_CLOEXEC);
MYLOGDX("client %d connecting server",clifd);
if (clifd == -1) {
if (errno == EINTR) {
if (server_socket_fd == -1) {
MYLOGEX("interrupted system call");
isExit=true;
continue;
} else {
continue;
}
} else {
MYLOGEX("accept error,continue accept");
continue;
}
}
//using thread to process client socket
//now only single thread do
process_client_socket(clifd);
}
return NULL;
}
void create_shell_socket_service(){
MYLOGDX("create_shell_socket_service start ");
pthread_t thread_id;
pthread_create(&thread_id, NULL, &my_create_shell_socket_service2,NULL);
MYLOGDX("create_shell_socket_service thread is created!");
}
#endif
(3).调用create_shell_socket_service创建socket server监听
在文件中路径"systemcoreadbdaemonmain.cpp"中的"drop_privileges"方法中添加调用"create_shell_socket_service"方法的代码。添加之后参考如下:
static void drop_privileges(int server_port) {
...
if (should_drop_privileges()) {
...
} else {
// minijail_enter() will abort if any priv-dropping step fails.
minijail_enter(jail.get());
if (root_seclabel != nullptr) {
if (selinux_android_setcon(root_seclabel) < 0) {
LOG(FATAL) << "Could not set SELinux context";
}
///ADD START
#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)
create_shell_socket_service();
#endif
///ADD END
}
...
}
}
(4).将新增的源码文件加入adbd编译链中
在文件"systemcoreadbAndroid.bp"中将新增的"shell_socket_service.cpp"源文件添加到adbd模块编译依赖的源文件中。添加之后如下所示:
...
cc_binary {
name: "adbd",
defaults: ["adbd_defaults", "host_adbd_supported"],
recovery_available: true,
srcs: [
"daemon/main.cpp",
///ADD START
///ADD END
"daemon/shell_socket_service.cpp",
],
cflags: [
"-D_GNU_SOURCE",
"-Wno-deprecated-declarations",
],
strip: {
keep_symbols: true,
},
shared_libs: [
"libadbd",
"libadbd_services",
"libbase",
"libcap",
"libcrypto",
"libcutils",
"liblog",
"libminijail",
"libselinux",
],
}
...
(5).编译模块到手机系统
执行如下命令将模块编译并push到手机系统进行测试:
qiang@ubuntu:~/lineageOs$ source build/envsetup.sh
qiang@ubuntu:~/lineageOs$ breakfast oneplus3
qiang@ubuntu:~/lineageOs$ make adbd
qiang@ubuntu:~/lineageOs$ adb remount
qiang@ubuntu:~/lineageOs$
qiang@ubuntu:~/lineageOs$ adb push out/target/product/oneplus3/system/bin/adbd /system/bin/adbd
qiang@ubuntu:~/lineageOs$
qiang@ubuntu:~/lineageOs$
执行以上拷贝成功之后,重启adbd进程。立即生效。
3.编写测试代码验证
新建一个App工程,然后使用如下的关键代码测试是否能连接到adbd中的server,并执行命令成功。关键测试代码如下:
public static String magiskSu(String cmd)
{
String retString="";
try {
//创建socket
String myCmd="do_cmd|"+cmd;
Socket mSocket = new Socket();
InetSocketAddress inetSocketAddress=new InetSocketAddress("127.0.0.1",11111);
mSocket.connect(inetSocketAddress);
BufferedWriter bufferedWriter=new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream()));
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
bufferedWriter.write(myCmd+"rn");
bufferedWriter.flush();
retString=bufferedReader.readLine();
bufferedReader.close();
bufferedWriter.close();
}catch (Exception eeeee)
{
eeeee.printStackTrace();
}
return retString;
}
private String testLocalSocket()
{
String retString="";
retString=magiskSu("mkdir -p /data/local/tmp/test_localsocket");
return retString;
}
原文始发于微信公众号(卓码星球):FB_02.基于tcp通信实现类su调用
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论