文档章节

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

FRED丶DON
 FRED丶DON
发布于 2016/04/28 16:54
字数 1539
阅读 970
收藏 10

首先这个功能仅供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:=uninstall
LOCAL_SRC_FILES:=uninstall.c

LOCAL_C_INCLUDES:= $(LOCAL_PATH)/include
LOCAL_SHARED_LIBRARIES := liblog libcutils
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
include $(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 feedback
JNIEXPORT 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);


转载请注明: http://my.oschina.net/freddon/blog/667695

© 著作权归作者所有

FRED丶DON
粉丝 9
博文 17
码字总数 10487
作品 0
徐汇
程序员
私信 提问
那些年Android黑科技③:干大事不择手段

“我在发抖么? 你开什么玩笑。我只是在跳愉快的尬舞。 暗影是不会向邪恶势力低头的。 万岁(≧▽≦)/!!” -- 来自暗世界android工程师 前言: 本篇是本系列的最后一个篇章。其实这些活儿也...

猴亮屏
2017/10/24
33
0
卸载Android app弹出浏览器的一种实现

卸载Android应用程序时,经常会弹出网页,做些用户数据的调查统计。Android是可以获取到其它应用被卸载掉这个事件,但是并不能获取自身被卸载这个事件。从纯粹的java层是没法实现的,本文介绍...

jacksonke
2015/08/25
1K
2
Android--判断App处于前台还是后台的方案

很多场景下,都需要判断某个App处于前台还是后台。本文集网上编写的前台判断方案于一体。 目前,有6种方案: 接下来,就对以上6种方法展开详细说明: 目录 1. RunningTask 1.1 原理 1.2 代码...

徐风来
2018/11/19
0
0
Android_JellyBean 4.2.1 Camera Service 请求过程分析

Camera子系统采用C/S架构,客户端和服务端在两个不同的进程当中,它们使用android中的binder机制进行通信,本系列文章将从Android Camera应用程序到硬件抽象的实现一步一步对照相机系统进行分析...

Jerikc
2013/03/09
988
0
那些年Android黑科技②:欺骗的艺术

“我的能量无穷无尽,只有强大暗能量才能统治Android界。 受屎吧!!! =≡Σ((( つ•̀ω•́)つ ” -- 来自暗世界android工程师 前言: 这是黑科技系列的第二篇,是Android知识正营中较有深...

猴亮屏
2017/10/24
133
0

没有更多内容

加载失败,请刷新页面

加载更多

《Designing.Data-Intensive.Applications》笔记 四

第九章 一致性与共识 分布式系统最重要的的抽象之一是共识(consensus):让所有的节点对某件事达成一致。 最终一致性(eventual consistency)只提供较弱的保证,需要探索更高的一致性保证(stro...

丰田破产标志
今天
6
0
docker 使用mysql

1, 进入容器 比如 myslq1 里面进行操作 docker exec -it mysql1 /bin/bash 2. 退出 容器 交互: exit 3. mysql 启动在容器里面,并且 可以本地连接mysql docker run --name mysql1 --env MY...

之渊
今天
7
0
python数据结构

1、字符串及其方法(案例来自Python-100-Days) def main(): str1 = 'hello, world!' # 通过len函数计算字符串的长度 print(len(str1)) # 13 # 获得字符串首字母大写的...

huijue
今天
5
0
OSChina 周日乱弹 —— 我,小小编辑,食人族酋长

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @宇辰OSC :分享娃娃的单曲《飘洋过海来看你》: #今日歌曲推荐# 《飘洋过海来看你》- 娃娃 手机党少年们想听歌,请使劲儿戳(这里) @宇辰OSC...

小小编辑
今天
1K
11
MongoDB系列-- SpringBoot 中对 MongoDB 的 基本操作

SpringBoot 中对 MongoDB 的 基本操作 Database 库的创建 首先 在MongoDB 操作客户端 Robo 3T 中 创建数据库: 增加用户User: 创建 Collections 集合(类似mysql 中的 表): 后面我们大部分都...

TcWong
今天
40
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部