一种鸿蒙应用网络数据监控方法

678 阅读2分钟

鸿蒙网络请求流程

  1. @ohos.net.http

juejin.cn/post/730190…

鸿蒙的网络库请求逻辑在libhttp.z.so中,内部使用curl实现。

寻找hook点

基于curl提供的debug功能 curl.se/libcurl/c/d…

我们需要想办法利用 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace); 设置上我们自己的trace函数。

查看libhttp.z.so plt表 中curl相关方法

hook代码实现

Hook方法 利用xhook(从Android版本简单修改适配鸿蒙版本) 这边选择hook curl_easy_setopt方法

int *curl_easy_setopt_origin;

typedef int *(*type_t2)(void *, int, void *);

static void hookCurl() {
    int r = xh_core_register("libhttp.z.so", "curl_easy_setopt", (void *)curl_easy_setopt_proxy,
                              (void **)&curl_easy_setopt_origin);  

    xh_core_refresh(0);
    xh_core_clear();
}

代理方法

当监听到10002 也就是url被设置时 同时设置curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);

int *curl_easy_setopt_proxy(void *curl, int i, void *args) {
    int *res = ((type_t2)curl_easy_setopt_origin)(curl, i, args);
    if (i == 10002) {
        ((type_t2)curl_easy_setopt_origin)(curl, 20094, (void *)my_trace);
        ((type_t2)curl_easy_setopt_origin)(curl, 41, (void *)1L);
    }
    return res;
}

调用堆栈

trace及dump方法

把trace数据写入文件路径 /data/storage/el2/base/haps/entry/files/1234

static int my_trace(void *handle, curl_infotype type, char *data, size_t size, void *userp) {
    struct data *config = (struct data *)userp;
    const char *text;
    (void)handle; /* prevent compiler warning */

    switch (type) {
    case CURLINFO_TEXT:
    default: /* in case a new one is introduced to shock us */
        return 0;

    case CURLINFO_HEADER_OUT:
        text = "=> Send header";
        break;
    case CURLINFO_DATA_OUT:
        text = "=> Send data";
        break;
    case CURLINFO_HEADER_IN:
        text = "<= Recv header";
        break;
    case CURLINFO_DATA_IN:
        text = "<= Recv data";
        break;
    }
    FILE *stream = fopen("/data/storage/el2/base/haps/entry/files/1234", "a");
    if (stream == NULL) {
        return 0;
    }
    dump(text, stream, (unsigned char *)data, size, 1);
    return 0;
}
static void dump(const char *text, FILE *stream, unsigned char *ptr, size_t size, char nohex) {
    unsigned int width = 0x10;

    if (nohex)
        /* without the hex output, we can fit more on screen */
        width = 0x80;

    fprintf(stream, "%s, %10.10lu bytes (0x%8.8lx)\n", text, (unsigned long)size, (unsigned long)size);
    char *dest = (char *)malloc(size + 1);
    snprintf(dest, size + 1, "%s\n", ptr);
    fprintf(stream, "%s\n", dest);
    fflush(stream);
    free(dest);
}

实现效果

image.png

总结

整体实现还很粗糙,但总算也缓解了鸿蒙上调试接口时拿不到接口调试数据的困难。plt hook是比较稳定的hook方式,如果后续鸿蒙还使用curl作为网络库,我们可以基于此做更多便捷的网络工具。