当前位置: 首页 > news >正文

网络抓包07 - 自编译openssl

有一些项目会自己编译openssl库,进行魔改等操作。对于这样的项目,之前所讨论的通杀方案, hook SSL_read 与 SSL_write 的方案就可能行不通了,因为这两个符号不一定是导出符号了。

自编译openssl

在网上找了一个已经编译成静态库的 .a 文件的项目:

https://github.com/leenjewel/openssl_for_ios_and_android

已经是一个很老的项目了,编译不过,改了一下,重新上传到了 github:

https://github.com/aprz512/openssl_for_android

有几个地方需要注意:

abiFilters "x86_64", "x86", "armeabi-v7a"

原项目中的 .a 文件很老了,编 arm64 的时候会报错:

relocation R_AARCH64_PREL64 against symbol `OPENSSL_armcap_P' which may bind externally can not be used when making a shared object; recompile with -fPIC

需要重新编译 .a 文件,懒得编译的,就干掉了 arm64 的选项。反正也是学习,用 arm32 的也够了。需要研究 arm64 的,可以找最新的已经编译好的文件,替换报错的文件。

为了模拟符号魔改的情况,需要将 so 中的符号都隐藏起来:

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,ALL")#使所有静态库中的符号都不被导出
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs,libabc.a")#使 libabc.a 的符号都不被导出

这样编译出来的 so 就看不到符号了。

IDA反编译

将编译出来的 so,使用 IDA 打开,看 exports 窗口:

 

发现只有一项。

这个时候使用 frida 通杀脚本肯定是不管用了。

所以我们需要使用堆栈回溯的方式来找到 SSL_read 与 SSL_write 函数。

SSL_read 最终会调用到 libc.so 中的 read 函数,我们 hook 这个方法,打印堆栈,看看有哪个堆栈是有 libnative_lib.so 的。

frida脚本

以 write 方法为例:

    Interceptor.attach(write_addr, {onEnter: function (args) {this.arg0 = args[0];this.arg1 = args[1];this.arg2 = args[2];this.socketinfo = getsocketdetail(this.arg0.toInt32());this.flag = false;if (this.socketinfo.indexOf("tcp") >= 0) {this.flag = true;}if (this.flag) {printNativeStack(this.context, Process.getCurrentThreadId() + "write");var size = ptr(this.arg2).toInt32();if (size > 0) {console.log(Process.getCurrentThreadId() + "---libc.so->write:" + hexdump(this.arg1, {length: size}));}}}, onLeave(retval) {LogPrint("leave libc.so->write");}});

frida 为 Sock 提供了很多的 api,我们可以直接使用。

write 方法的第一次参数是一个 fd:

ssize_t write(int fd, const void buf[.count], size_t count);

使用:

Socket.type(fd);
Socket.peerAddress(fd);
Socket.localAddress(fd);

这些 api,可以获取 socket 的一些信息,利用这些信息,我们可以过滤一些不关心的方法调用。

堆栈分析

看其中的一个堆栈:

[00:55:36:420]->threadid:17931-------------start:17931read--------------
[00:55:36:420]->threadid:17931--0xd45be9f8 libnative-lib.so!0x15f9f8
0xd45bcf1c libnative-lib.so!0x15df1c
0xd45bbff4 libnative-lib.so!0x15cff4
0xd45aa5fc libnative-lib.so!0x14b5fc
0xd45bbf0c libnative-lib.so!0x15cf0c
0xd456e19c libnative-lib.so!0x10f19c
0xd45707d8 libnative-lib.so!0x1117d8
0xd45aa234 libnative-lib.so!0x14b234
0xf3f8324a libc.so!malloc+0x15
0xd456f604 libnative-lib.so!0x110604
0xd459ce2c libnative-lib.so!0x13de2c
0xd4593590 libnative-lib.so!0x134590
0xd4658ddc libnative-lib.so!0x1f9ddc
0xd4554300 libnative-lib.so!0xf5300
0xf3fe80ec libc.so!__vfprintf+0x1917
0xf312dc3a libart.so!artQuickToInterpreterBridge+0x409
[00:55:36:420]->threadid:17931-------------end:17931read--------------

看对应位置的 IDA 反编译代码:

libnative-lib.so!0x15f9f8 --> BL              read
libnative-lib.so!0x15df1c --> BLX             R3

看起来堆栈没啥问题。

后续就可以一点点尝试看看哪个方法是 SSL_write 了,结合源码分析与对比反编译代码中出现的字符串,最后得到 SSL_write 对应的方法。

由于这个是学习,所以我们可以再编译一个不隐藏符号的 so,对比看一下:

[01:27:19:672]->threadid:19325-------------start:19325read--------------
[01:27:19:672]->threadid:19325--0xd42ac9f8 libnative-lib.so!0x1a79f8
0xd42aaf1c libnative-lib.so!bread_conv+0x20
0xd42a9ff4 libnative-lib.so!0x1a4ff4
0xd42a9f0c libnative-lib.so!BIO_read+0x20
0xd425c19c libnative-lib.so!ssl3_read_n+0x23c
0xd425e568 libnative-lib.so!ssl3_get_record+0x8c
0xf3f8324a libc.so!malloc+0x15
0xd425d604 libnative-lib.so!ssl3_read_bytes+0x1ac
0xd4263c10 libnative-lib.so!0x15ec10
0xd4263b8c libnative-lib.so!ssl3_read+0x18
0xd426caec libnative-lib.so!SSL_read+0x1c
0xd4245a10 libnative-lib.so!0x140a10
0xd424ea08 libnative-lib.so!0x149a08
0xd4248430 libnative-lib.so!0x143430
0xd424981c libnative-lib.so!nghttp2_session_send+0x84
0xd424e1c0 libnative-lib.so!nghttp2_session_resume_data+0xc
[01:27:19:672]->threadid:19325-------------end:19325read--------------

发现堆栈并不是完全一样。后来发现是 curl 的原因,不会稳定触发 SSL_read,比较奇怪。

需要使用 https 的 demo,但是编译比较麻烦,可以自己调用 SSL_read,然后想办法找到这个函数,也是一样的。

发送https请求

    stringstream stream;stream << "GET https://" << host << " HTTP/1.0\r\n";stream << "Accept: */*\r\n";// stream << "Accept-Encoding: gzip, deflate,// br\r\n";//不要编码,否则还得多一个解码的步骤stream << "Accept-Language: zh-Hans-CN, zh-Hans; q=0.8, en-US; q=0.5, en; ""q=0.3\r\n";stream << "Connection: Keep-Alive\r\n";stream << "Host: " << host << "\r\n";stream << "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ""AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 ""Safari/537.36 Edge/17.17134\r\n";stream << "\r\n";string s = stream.str();const char *sendData = s.c_str();ret = SSL_write(ssl, sendData, strlen(sendData));

完整代码,放到工程里面了。

我们 hook SSL_read,得到输出:

---29213---libssl.so->SSL_write:           0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
e139d7c0  47 45 54 20 68 74 74 70 73 3a 2f 2f 77 77 77 2e  GET https://www.
e139d7d0  67 6f 6f 67 6c 65 2e 63 6f 6d 20 48 54 54 50 2f  google.com HTTP/
e139d7e0  31 2e 30 0d 0a 41 63 63 65 70 74 3a 20 2a 2f 2a  1.0..Accept: */*
e139d7f0  0d 0a 41 63 63 65 70 74 2d 4c 61 6e 67 75 61 67  ..Accept-Languag
e139d800  65 3a 20 7a 68 2d 48 61 6e 73 2d 43 4e 2c 20 7a  e: zh-Hans-CN, z
e139d810  68 2d 48 61 6e 73 3b 20 71 3d 30 2e 38 2c 20 65  h-Hans; q=0.8, e
e139d820  6e 2d 55 53 3b 20 71 3d 30 2e 35 2c 20 65 6e 3b  n-US; q=0.5, en;
e139d830  20 71 3d 30 2e 33 0d 0a 43 6f 6e 6e 65 63 74 69   q=0.3..Connecti
e139d840  6f 6e 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d 0a  on: Keep-Alive..
e139d850  48 6f 73 74 3a 20 77 77 77 2e 67 6f 6f 67 6c 65  Host: www.google
e139d860  2e 63 6f 6d 0d 0a 55 73 65 72 2d 41 67 65 6e 74  .com..User-Agent
e139d870  3a 20 4d 6f 7a 69 6c 6c 61 2f 35 2e 30 20 28 57  : Mozilla/5.0 (W
e139d880  69 6e 64 6f 77 73 20 4e 54 20 31 30 2e 30 3b 20  indows NT 10.0; 
e139d890  57 69 6e 36 34 3b 20 78 36 34 29 20 41 70 70 6c  Win64; x64) Appl
e139d8a0  65 57 65 62 4b 69 74 2f 35 33 37 2e 33 36 20 28  eWebKit/537.36 (
e139d8b0  4b 48 54 4d 4c 2c 20 6c 69 6b 65 20 47 65 63 6b  KHTML, like Geck
e139d8c0  6f 29 20 43 68 72 6f 6d 65 2f 36 34 2e 30 2e 33  o) Chrome/64.0.3
e139d8d0  32 38 32 2e 31 34 30 20 53 61 66 61 72 69 2f 35  282.140 Safari/5
e139d8e0  33 37 2e 33 36 20 45 64 67 65 2f 31 37 2e 31 37  37.36 Edge/17.17
e139d8f0  31 33 34 0d 0a 0d 0a                             134....

对应的堆栈如下:

[21:59:59:409]->threadid:29213-------------start:29213SSL_write--------------
[21:59:59:409]->threadid:29213--0xd43fc777 libnative-lib.so!main+0x236
0xd43fc076 libnative-lib.so!Java_com_example_test_1curl_1with_1ssl_1and_1http2_1android_MainActivity_stringFromJNI+0x21
0xf2df251a libart.so!art_quick_generic_jni_trampoline+0x29
0xf2e35f9c libart.so!_ZN3art10ClassTable6LookupEPKcj+0x107
0xf2dedbc6 libart.so!art_quick_invoke_stub_internal+0x45
0xf3143fea libart.so!art_quick_invoke_stub+0xfd
0xf2e35f9c libart.so!_ZN3art10ClassTable6LookupEPKcj+0x107
0xf2df5fba libart.so!_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+0xb1
0xf2e0d282 libart.so!_ZN3art11ClassLinker11LookupClassEPNS_6ThreadEPKcjNS_6ObjPtrINS_6mirror11ClassLoaderEEE+0x75
0xf2f269fc libart.so!_ZN3art11interpreter34ArtInterpreterToCompiledCodeBridgeEPNS_6ThreadEPNS_9ArtMethodEPNS_11ShadowFrameEtPNS_6JValueE+0x11b
0xf2e0dc4c libart.so!_ZN3art11ClassLinker9FindClassEPNS_6ThreadEPKcNS_6HandleINS_6mirror11ClassLoaderEEE+0x4b
0xf2f2233e libart.so!_ZN3art11interpreter6DoCallILb0ELb0EEEbPNS_9ArtMethodEPNS_6ThreadERNS_11ShadowFrameEPKNS_11InstructionEtPNS_6JValueE+0x309
0xf31392bc libart.so!MterpInvokeVirtual+0x22f
0xf2e0097e libart.so!_ZN3art11ClassLinker13ResolveMethodILNS0_11ResolveModeE0EEEPNS_9ArtMethodEjNS_6HandleINS_6mirror8DexCacheEEENS5_INS6_11ClassLoaderEEES4_NS_10InvokeTypeE+0xe1
0xf2de8818 libart.so!mterp_op_invoke_virtual+0x18
0xf313a9ac libart.so!MterpInvokeInterface+0x59b
[21:59:59:410]->threadid:29213-------------end:29213SSL_write--------------

调用链没问题。

再看 libc.so 的 write 方法的堆栈:

[21:59:59:499]->threadid:29213-------------start:29213write--------------
[21:59:59:499]->threadid:29213--0xd44b0b64 libnative-lib.so!0x1aab64
0xd44af084 libnative-lib.so!bwrite_conv+0x20
0xd44ae3c4 libnative-lib.so!0x1a83c4
0xd44ae2d4 libnative-lib.so!BIO_write+0x20
0xd4460888 libnative-lib.so!ssl3_write_pending+0xac
0xd4460a08 libnative-lib.so!do_ssl3_write+0x8c
0xd455a414 libnative-lib.so!0x254414
0xcca27d68 frida-agent-32.so!0x4cbd68
0xcca16e0c frida-agent-32.so!0x4bae0c
0xccb14f52 frida-agent-32.so!0x5b8f52
0xcca9a8ae frida-agent-32.so!0x53e8ae
0xcca9a610 frida-agent-32.so!0x53e610
0xccab94a0 frida-agent-32.so!0x55d4a0
0xcca66718 frida-agent-32.so!0x50a718
0xeb06fb24
0xd44606ec libnative-lib.so!ssl3_write_bytes+0x2ac
[21:59:59:499]->threadid:29213-------------end:29213write--------------

这里看不到 SSL_write,看来堆栈不是很准确。

换个堆栈模式:

[22:36:03:983]->threadid:29213-------------start:29213write--------------
[22:36:03:983]->threadid:29213--0xd44b0b64 libnative-lib.so!0x1aab64
0xd44b0b64 libnative-lib.so!0x1aab64
[22:36:03:983]->threadid:29213-------------end:29213write--------------

一样不行。

看来遇到这种还不大好搞,还得重头开始。

关注我的公众号:二手的程序员。


http://www.mrgr.cn/news/49810.html

相关文章:

  • 建造者模式(Builder Pattern)
  • 利用 LangChain 增强 LLMs 的工具调用能力:一步步实现
  • 5G 技术是如何改变数据通信的?
  • 队列和栈是什么?有什么区别?
  • Docker 部署 RocketMQ
  • 系统集成十大管理相关管理计划内容记忆篇-1
  • 【C++】C++ STL 树形结构容器全解析:map、set、multimap、multiset 的使用与区别
  • 项目管理系统如何助力新药研发?药物研发企业康诺亚上线瑞杰项目管理系统
  • 画质修复哪个软件清晰?摄影圈在用的提升画质小技巧分享
  • 国际象棋棋盘
  • 道路垃圾识别数据集 含pt模型界面 18类 共7542张图片,xml和txt标签都有;
  • 2024双十一买什么好?这些你绝对值得入手的好物推荐!
  • Harmony Navigation的使用
  • mysql-数据库的操作
  • Docker 命令替代(ctr和 crictl)
  • 【数据结构】图的最短路径
  • 【云原生】Kubernetes (K8s)
  • 板级支持包构建2
  • 现今 CSS3 最强二维布局系统 Grid 网格布局
  • uniapp uni.uploadFile errMsg: “uploadFile:fail