[Android]通过JNI实现卸载自身App后台发送Http请求~

来源:互联网 发布:小甲鱼java 编辑:程序博客网 时间:2024/06/08 03:56
摘要: 使用JNI fork进程实现 监控自身App被卸载

首先这个功能仅供cankao 毕竟这个行为已经跟数字公司一样不人道了 

可以使用linux exec命令跳转到浏览器的反馈页

防工具盗链抓取【如果显示此文字,代表来自第三方转发】 freddon所有 

我使用的环境

IDE:Android Studio 2.0

gj:Android 4.4.2

Android.mk

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE:=uninstallLOCAL_SRC_FILES:=uninstall.cLOCAL_C_INCLUDES:= $(LOCAL_PATH)/includeLOCAL_SHARED_LIBRARIES := liblog libcutilsLOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -lloginclude $(BUILD_SHARED_LIBRARY)

C代码:

原理是借用网上的监控文件夹变化(因为如果应用卸载了 对应的/data/data/包 文件夹也会发生变化)

// uninstall.c// Created by Fred on 16/4/19.//// email:gsiner@live.com#include <stdio.h>#include <string.h>#include <jni.h>#include <android/log.h>#include <sys/socket.h>#include <arpa/inet.h>#include <unistd.h>#include <netinet/in.h>#include <sys/inotify.h>#include <stdlib.h>#include <stdbool.h>#include <netdb.h>#include <sys/time.h>#include <pthread.h>#include <errno.h>#include <sys/types.h>#include <fcntl.h>#include <sys/wait.h>#include "GUNetDef.h"#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "fred", __VA_ARGS__)static char c_TAG[] = "onEvent";#define BUFFER_SIZE 2/** * 感谢大风提供的三个发送或处理请求的方法 * @edited fred */int Connect(int *sock, const char *address, unsigned short port) {    int _sk = socket(AF_INET, SOCK_STREAM, 0);    if (_sk == INVALID_SOCKET)        return NET_SOCKET_ERROR;    struct sockaddr_in sockAddr;    memset(&sockAddr, 0, sizeof(sockAddr));    sockAddr.sin_family = AF_INET;    sockAddr.sin_addr.s_addr = inet_addr(address);    sockAddr.sin_port = htons(port);    if (sockAddr.sin_addr.s_addr == INADDR_NONE) {        struct hostent *host = gethostbyname(address);        if (host == NULL) {            return NET_SOCKET_ERROR;        }        sockAddr.sin_addr.s_addr = ((struct in_addr *) host->h_addr)->s_addr;    }    fcntl(_sk, F_SETFL, O_NONBLOCK | fcntl(_sk, F_GETFL)); // 设置成非阻塞    int ret = connect(_sk, (struct sockaddr *) &sockAddr, sizeof(struct sockaddr));    fd_set fdset;    struct timeval tmv;    FD_ZERO(&fdset);    FD_SET(_sk, &fdset);    tmv.tv_sec = 15; // 设置超时时间    tmv.tv_usec = 0;    ret = select(_sk + 1, 0, &fdset, 0, &tmv);    if (ret == 0) {        return NET_CONNNECT_TIMEOUT;    }    else if (ret < 0) {        return NET_SOCKET_ERROR;    }    int flags = fcntl(_sk, F_GETFL, 0);    flags &= ~O_NONBLOCK;    fcntl(_sk, F_SETFL, flags); // 设置成阻塞    *sock = _sk;    return SUCCESS;}int SendData(int _sk, const UInt8 *buffer, int bufferSize) {    int ret = send(_sk, buffer, bufferSize, 0);    if (ret != bufferSize)        return NET_SOCKET_ERROR;    return SUCCESS;}int DisConnect(int _sk) {    if (_sk != INVALID_SOCKET) {        close(_sk);        _sk = INVALID_SOCKET;    }    return SUCCESS;}//    signal(SIGPIPE,SIG_IGN);//自己可以处理一些信号void request(char *host, int port, char *reqHead) {    int sk = INVALID_SOCKET;    int ret = Connect(&sk, host, port);    if (ret != SUCCESS)        return;    ret = SendData(sk, reqHead, strlen(reqHead));    LOGI("SendData TRACE");    if (ret != SUCCESS) {        LOGI("send data error");        return;    }    LOGI("send data success");    DisConnect(sk);    LOGI("DisConnect");    //后续处理返回的数据即可 由于本功能不需要 so省略}typedef struct paraStruct {    char *watch_path;    char *cpath;    char *chost;    char *para;    char *method;    int cport;} paraStruct;int httpRequester(paraStruct *data) {    char s[2048] = {0};    LOGI("c-code::method=%s",data->method);    if (strcmp(data->method, "POST") == 0) {        sprintf(s,                "POST %s HTTP/1.1\r\nHost: %s\r\nCache-Control: no-cache\r\nContent-Length: %d\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n%s",                data->cpath, data->chost, strlen(data->para), data->para);    }    else if (strcmp(data->method, "GET") == 0) {        sprintf(s,                "GET %s HTTP/1.1\r\nHost: %s\r\nCache-Control: no-cache\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n",                data->cpath, data->chost);    } else {        return 1;    }    request(data->chost, data->cport, s);    return 0;}void *threadBegin(void *arg) {    paraStruct *data = arg;    if (data) {        int fileDescriptor = inotify_init();        if (fileDescriptor < 0) {            LOGI("inotify_init failed !!!");            exit(1);        }        int watchDescriptor;        watchDescriptor = inotify_add_watch(fileDescriptor,                                            data->watch_path, IN_DELETE);        if (watchDescriptor < 0) {            LOGI("inotify_add_watch failed !!!");            exit(1);        }        //分配缓存,以便读取event,缓存大小=一个struct inotify_event的大小,这样一次处理一个event        void *p_buf = malloc(sizeof(struct inotify_event));        if (p_buf == NULL) {            LOGI("malloc failed !!!");            exit(1);        }        //开始监听        LOGI("start observer");        //read会阻塞进程,b        size_t readBytes = read(fileDescriptor, p_buf,                                sizeof(struct inotify_event));        //走到这里说明收到目录被删除的事件,注销监听器        free(p_buf);        inotify_rm_watch(fileDescriptor, IN_DELETE);        //目录不存在log        LOGI("uninstalled");        //扩展:可以执行其他shell命令,am(即activity manager),可以打开某程序、服务,broadcast intent,等等        data->method="POST";        httpRequester(data);        exit(0);    }    return 0;}int commonJavaSegment(const char *watch_path,                      const char *cpath, const char *chost,                      const char *para, int port) {    //初始化log    LOGI("init OK");    //fork子进程,以执行轮询任务    pid_t pid;    pid = fork();    if (pid) {        LOGI("pid=%d", pid);    } else if (pid == 0) {        //子进程注册目录监听器        LOGI("child:: start");        paraStruct *data = malloc(sizeof(paraStruct));        data->watch_path = watch_path;        data->cpath = cpath;        data->chost = chost;        data->para = para;        data->cport = port;        threadBegin(data);    } else {        //父进程直接退出,使子进程被init进程领养,以避免子进程僵死        LOGI("fork failed !!!");    }    return 0;}static int start_count=0;//【当然也可以通过互斥锁来标记子进程是否正在运行】//this jni method made by rec unistall event and feedbackJNIEXPORT int Java_com_freddon_android_app_utils_JNILoader_uninstall(JNIEnv *env, jobject thiz,                                                                  jarray path,                                                                  jstring httppath, jstring cs,                                                                  jstring host, jint port) {    ++start_count;    if(start_count>2){//为什么会设置大于2不是1 我测试下来至少为2才会执行        return 0;//说明已经执行过了监控代码     }else{        const char *watch_path = (*env)->GetStringUTFChars(env, path, NULL);        const char *cpath = (*env)->GetStringUTFChars(env, httppath, JNI_FALSE);        const char *chost = (*env)->GetStringUTFChars(env, host, JNI_FALSE);        const char *para = (*env)->GetStringUTFChars(env, cs, JNI_FALSE);        return commonJavaSegment(watch_path, cpath, chost, para, port);    }}/** * C语言的Http请求方法 【此方法备用】 * @author fred */JNIEXPORT int Java_com_freddon_android_app_utils_JNILoader_httpConnect(JNIEnv *env, jobject thiz,                                                                       jstring method,                                                                       jstring host,                                                                       jstring httppath, jstring cs,                                                                  jint port) {    const char *cpath = (*env)->GetStringUTFChars(env, httppath, JNI_FALSE);    const char *chost = (*env)->GetStringUTFChars(env, host, JNI_FALSE);    const char *para = (*env)->GetStringUTFChars(env, cs, JNI_FALSE);    const char *cmethod = (*env)->GetStringUTFChars(env, method, JNI_FALSE);    paraStruct *data = malloc(sizeof(paraStruct));    data->cpath = (char *)cpath;    data->chost =(char *)chost;    data->para = (char *)para;    data->cport = port;    data->method = (char *)cmethod;    return httpRequester(data);}

GUNetDef.h  相关错误码

////  GUNetDef.h//#ifndef MyGoUDome_GUNetDef_h#define MyGoUDome_GUNetDef_h#define NET_Header_ID (0x7F)#define NET_Header_VER (0x01)#define NET_MAX_PACKET_SIZE (4096)#define NET_NETWORK_PUBLIC (0) // 是否为公网环境#if NET_NETWORK_PUBLIC# define NET_AUTHSERVER_ADDR "s1.goyou.cn"# define NET_AUTHSERVER_PORT (33880)#else# define NET_AUTHSERVER_ADDR "192.168.108.181"# define NET_AUTHSERVER_PORT (33880)#endif#define NET_TOKEN_SIZE (16)#define NET_UUID_SIZE (16)typedef unsigned char UInt8;// 数据头typedef struct {    UInt8 head4[4]; // index 0: NET_Header_ID; index 1: NET_Header_VER; 2:插件号 ;3:命令字    int dataLen;}t_net_header;#define kMyGoUNetworkErrorDomain @"MyGoUNetworkErrorDomain" // 通信错误码定义#define SUCCESS 0// socket 相关错误码#define INVALID_SOCKET (~0)#define NET_SOCKET_ERROR -1#define NET_CONNNECT_TIMEOUT -100#define NET_RECV_TIMEOUT -200#define NET_COMMUNICATOR_ERROR -500#endif


android 

    JNILoader.java
防工具盗链抓取【如果显示此文字,代表来自第三方转发】 freddon所有 

package com.freddon.android.app.utils;/** * Created by fred on 16/4/16. */public class JNILoader {    static {        System.loadLibrary("uninstall");    }    /**     * 【Native】核心方法 只支持POST 可以自己更改 [不处理响应]【请处理异常】     *     * @param path 包名data/data 的包路径     * @param path     * @param cs     * @param host     * @param port     * @return     */    public static native int uninstall(String androidPath, String path, String cs, String host, int port);    /**     * 【Native】发送http请求 [不处理响应]【请处理异常】     *     * @param method 请求方式 大写     * @param host   主机地址 域名或ip [不需要携带协议名]     * @param path   请求路径 /开头     * @param cs     携带参数 仅POST使用     * @param port   端口 目前固定 80     */    public static native int httpConnect(String method, String path, String cs, String host, int port);}

调用代码

防工具盗链抓取【如果显示此文字,代表来自第三方转发】 freddon所有 
String host = 192.168.11.10;//host地址【域名也可以不要带协议头】String path = "/unistall";String cs = "ver=1.1";return JNILoader.unistl("/data/data/" + context.getPackageName(), path, cs, host, port);




0 0
原创粉丝点击