这篇文章上次修改于 285 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
前言
本文将带领读者学习如何使用stackplz快速定位网络请求位置
正文
对某软件抓包,得见一些wns
开头的请求,显然是有自定义加密在里面的
如何用stackplz快速定位请求呢?答案很简单,直接追踪网络请求有关的syscall即可~
stackplz中对许多有关联性的syscall做了划分,可以通过-s %net
这样快速追踪一些列有关网络的syscall
注意%net
不包含发送接收数据,如果需要追踪请-s %net,%send,%recv
这样写,不过注意发送接收数据通常调用很频繁,建议加上-q
额外补充:read和write系列中的函数也是能通过网络请求的fd读取和写入数据的,所以有时候也有必要追踪它们,那么关闭网络连接用close自然也是合理的
不过这里没有把close这个放进任何一个组,这是因为不管什么情况下,close调用都很频繁,对于需要输出堆栈的情况下,会很慢
%net
- socket,socketpair
- bind,listen,accept,accept4,connect
- getsockname,getpeername,setsockopt,getsockopt
- shutdown
%send
- sendto,sendmsg,sendmmsg
%recv
- recvfrom,recvmsg,recvmmsg
%read
- read,readv,pread64,preadv,pread2
%write
- write,writev,pwrite64,pwritev,pwrite2
于是通过下面的命令来追踪有关网络请求的系统调用,并打印调用栈:
./stackplz -n com.tencent.qqmusic -s %net -o tmp.log --stack
然后在日志翻到这么一条日志:
[18994|19205|cgi-ui-1] socket(domain=2, type=0x80801(SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK), protocol=0) LR:0x7a7a866bdc PC:0x7a8594f038 SP:0x76ea4a0ed0, Backtrace:
#00 pc 000000000009e038 /apex/com.android.runtime/lib64/bionic/libc.so (__socket+8)
#01 pc 0000000000004bd8 /system/lib64/libnetd_client.so ((anonymous namespace)::netdClientSocket(int, int, int) (.cfi)+100)
#02 pc 000000000004f908 /apex/com.android.runtime/lib64/bionic/libc.so (socket+44)
#03 pc 00000000001ccaa8 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so
#04 pc 00000000001d658c /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so (uv_tcp_init_ex+136)
#05 pc 000000000010d0c8 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#06 pc 00000000000e1710 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#07 pc 00000000000df320 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#08 pc 00000000000df100 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#09 pc 00000000000bd860 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#10 pc 00000000001c92b0 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#11 pc 000000000010c480 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#12 pc 00000000001cc404 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so
#13 pc 00000000001dad28 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so
[18994|19205|cgi-ui-1] socket(domain=2, type=0x80801(SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK), protocol=0, ret=219)
我们知道发起请求肯定得去connect,然后顺着这个syscall的返回值219
往下翻到这样一条日志:
端口和截图的不一样?多测试就会发现它会在网络不好的时候换好几个端口尝试
[18994|19205|cgi-ui-1] connect(sockfd=219, addr=0x76ea4a0fe8(family=AF_INET, port=20480, addr=14.116.235.38), addrlen=16) LR:0x7a7a8668e8 PC:0x7a8594f098 SP:0x76ea4a0ef0, Backtrace:
#00 pc 000000000009e098 /apex/com.android.runtime/lib64/bionic/libc.so (__connect+8)
#01 pc 00000000000048e4 /system/lib64/libnetd_client.so ((anonymous namespace)::netdClientConnect(int, sockaddr const*, unsigned int) (.cfi)+280)
#02 pc 00000000001d6818 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so
#03 pc 000000000010d274 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#04 pc 00000000000e1710 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#05 pc 00000000000df320 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#06 pc 00000000000df100 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#07 pc 00000000000bd860 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#08 pc 00000000001c92b0 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#09 pc 000000000010c480 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#10 pc 00000000001cc404 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so
#11 pc 00000000001dad28 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so
[18994|19205|cgi-ui-1] connect(sockfd=219, addr=0x76ea4a0fe8, addrlen=16, ret=-115)
再往后就没有什么发现了,要看发包情况,就要考虑追踪%send
和%write
系列函数了,命令如下:
先确定是哪个系统调用,这里直接grep后重定向日志看看
./stackplz -n com.tencent.qqmusic -s %send,%write | grep wns > tmp.log
结果关键词很多,不过很明显能看出来是write
系统调用在写数据到网络请求fd
这个时候再去追踪write调用,看看堆栈
虽然syscall也提供了直接的过滤功能,但是本身已经通过配置文件预设好了参数类型,比如write的第二个参数是buffer,无法被当作字符串过滤
如果想直接通过syscall去过滤,那么得先通过配置文件修改参数类型,这样还是很麻烦的
stackplz提供了一种uprobe到syscall命令行的转换,即在常规的uprobe写法后面加一个s
即可转为对应的syscall进行hook
于是通过下面的命令即可将write的buf参数当作字符串读,过滤wns开头的字符串(后续为buf类型扩展几个字节的比较,应该更灵活
./stackplz -n com.tencent.qqmusic -w write[int,str.f0]s -f w:wns --stack
然后就能得到这样的调用栈,不会有其他额外的write系统调用刷屏
[12746|12965|cgi-ui-1] write(arg_0=180, arg_1=0xb4000078ab080e10(wns)) LR:0x771b9dae9c PC:0x7a8594e358 SP:0x771a6f21a0, Backtrace:
#00 pc 000000000009d358 /apex/com.android.runtime/lib64/bionic/libc.so (write+8)
#01 pc 00000000001d5e98 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so
#02 pc 00000000001d5dc8 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so (uv_write2+384)
#03 pc 00000000000c4a84 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#04 pc 00000000001c9abc /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#05 pc 000000000010c480 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#06 pc 00000000001cc404 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so
#07 pc 00000000001dad28 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so
不过顺着libWnsLiteNetwork.so + 0xc4a84
这个位置翻了下,看不出什么名堂,只知道这里在发送,不过本文主题是数据包的加解密,所以还得想想怎么找到加解密的位置
这个so中函数看起来都很正规,调用比较实诚,那么猜测发送的数据应该会经历复制操作,不然顺着发送的调用栈怎么也能看出一点端倪
于是尝试hook一把memcpy/memmove
函数,命令如下,这里还是将数据内容当作字符串读取
./stackplz -n com.tencent.qqmusic -w memmove[ptr,str.f0,int] -f w:wns --stack
然后就能得到下面这调用栈了,稍作回溯就能发现加密操作了
[22227|22445|Thread-8] memmove(arg_0=0xb4000078ab111cd0, arg_1=0xb4000078ab111e90(wns), arg_2=428) LR:0x7711d31250 PC:0x7a858fcc20 SP:0x76ece16d20, Backtrace:
#00 pc 000000000004bc20 /apex/com.android.runtime/lib64/bionic/libc.so (memmove)
#01 pc 000000000010a24c /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#02 pc 0000000000082b90 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#03 pc 0000000000198174 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#04 pc 00000000001b0178 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#05 pc 00000000001af998 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#06 pc 00000000001cd15c /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#07 pc 00000000001a9364 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#08 pc 00000000001a4fb4 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#09 pc 00000000001a4b1c /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#10 pc 00000000001b7458 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#11 pc 00000000001b7a44 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#12 pc 00000000000edb98 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#13 pc 00000000000ed264 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#14 pc 000000000010c480 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libWnsLiteNetwork.so
#15 pc 00000000001cc404 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so
#16 pc 00000000001dad28 /data/app/~~5ZUCrylK9S2pGeFpzR2OjQ==/com.tencent.qqmusic-_c0E3UlPZokNS6pya4N3Vg==/lib/arm64/libnetbase.so
对libWnsLiteNetwork.so + 0x82b90
这里往前翻一翻,就会发现zstd compress
和wns_pack
,显然已经八九不离十了
在这个函数进行分析,便能发现还涉及一个关键函数0x71034
函数中的一个数字引起了注意,搜一下就会发现这是TEA加密算法,或者是改动过的,这类算法腾讯的软件经常用,很是合理
交叉引用一下0x71034
,发现有一个Java的native函数,一看就算成对的,这下解密函数的位置也找到了(当然需要hook确定一下
算法还原略
总结
- stackplz追踪
connect
系统调用,配合抓包,对照ip可以快速确定到网络请求发起位置 - stackplz追踪
%send
和%write
系列系统调用,配合grep过滤可以快速确定具体是什么系统调用在操作网络数据 - 通过数据会被复制的思路,追踪libc.so的memmove/memcpy函数,配合过滤,快速定位到数据加密位置
- 在上一步基础上,交叉引用定位到数据解密位置(推测)
没有评论