一:背景

1.讲故事

前几天有位朋友在微信上找到我,说他的一个程序上了生产之后,被运维监控定位到这个程序会向一个网址为: http://m.365ey.net 上不定期打数据,而且还是加密的格式,要他解释到底是怎么回事?朋友说根本不认识这个网址,最后在恐慌中排查到是项目中引用了 DeveloperSharp.RabbitMQ 组件所致,截图如下:

朋友反编译了下sdk源码,发现都是混淆过的没法看,聊的过程中朋友很恐慌,很焦虑,担心生产的数据被泄漏,让我帮忙看下是否有手段定位下到底都采集了什么数据?

说实话,这种事情听起来就很惊魂,情从肺腑出,方能入肺腑。。。只要是一个正能量的人,这个忙肯定是尽最大可能的帮一下。

二:WinDbg 分析

1. 前置工作准备

从 nuget 中把 DeveloperSharp.RabbitMQ 下载下来,写好一个测试案例。


internal class Program
{
static void Main(string[] args)
{
for (int i = 0; i < int.MaxValue; i++)
{
try
{
var queueName = "jk";
var content = $" hello world! {i}";
RabbitMQHelper.SendMessage(queueName, content); Console.WriteLine($"时间:{DateTime.Now}, i={i} 次处理!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Thread.Sleep(1000);
}
}
}
}

为了安全,我把程序放到虚拟机中,同时在 hosts 下给它设置个错误的 ip 地址。


192.168.1.30 m.365ey.net

接下来打开 Fiddler,再用 WinDbg TTD 的方式把程序启动起来来记录程序的全部行为,方便我后续分析,

正如朋友所说,真的有采集行为:

  • http://m.365ey.net:13064/AssistLog.svc
  • http://m.365ey.net:13063/QueryLog.svc

2. 如何寻找请求代码块

截获请求的代码很简单,因为屏蔽了 IP,所以请求肯定会抛异常,我只需要用 sxe clr 拦截下 First Chance Exception 就能捕获到调用代码。


0:013> sxe clr
0:013> g
(3398.3f7c): CLR exception - code e0434352 (first/second chance not available)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
Time Travel Position: 16D93B:0
eax=079befe8 ebx=00000005 ecx=00000005 edx=00000000 esi=079bf0a8 edi=00000001
eip=77207380 esp=079befe0 ebp=079bf040 iopl=0 nv up ei pl nz ac pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000216
ntdll!RtlRaiseException:
77207380 55 push ebp
0:013> !clrstack
OS Thread Id: 0x3f7c (13)
Child SP IP Call Site
079bf0fc 77207380 [HelperMethodFrame: 079bf0fc]
079bf1ac 78861902 System.Net.HttpWebRequest.GetResponse() [f:\dd\NDP\fx\src\net\System\Net\HttpWebRequest.cs @ 2254]
079bf1fc 0a5a2e89 System.ServiceModel.Channels.HttpChannelFactory`1+HttpRequestChannel+HttpChannelRequest[[System.__Canon, mscorlib]].WaitForReply(System.TimeSpan)
079bf24c 0a5a1199 System.ServiceModel.Channels.RequestChannel.Request(System.ServiceModel.Channels.Message, System.TimeSpan)
079bf2c0 0a5a1026 System.ServiceModel.Dispatcher.RequestChannelBinder.Request(System.ServiceModel.Channels.Message, System.TimeSpan)
079bf2d0 0a5703f3 System.ServiceModel.Channels.ServiceChannel.Call(System.String, Boolean, System.ServiceModel.Dispatcher.ProxyOperationRuntime, System.Object[], System.Object[], System.TimeSpan)
079bf3cc 0a57010d System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage, System.ServiceModel.Dispatcher.ProxyOperationRuntime)
079bf3f8 0a56f79e System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)
079bf438 7b224e24 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32) [f:\dd\ndp\clr\src\BCL\system\runtime\remoting\realproxy.cs @ 823]
079bf5d0 7a5df148 [TPMethodFrame: 079bf5d0] wfP8f24Vyfpc8suOyj.bBZbSsm9FOwaYWDWVc.Record1(System.String, System.String, System.String, System.String, System.String, System.String, System.String)
079bf644 067c835f System.Base.ApplicationContext+c.b__19_0()
079bf6b0 7b1dd4bb System.Threading.Tasks.Task.InnerInvoke() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2884]
...

从线程栈看,请求 http://m.365ey.net:13064/AssistLog.svc 是由 Record1 方法发起的,一看就是个 WCF 方法,参数名称和个数都和 Fiddler 中保持一致, 截图如下:

3. 这些参数都是什么

要找到原参数信息,需要找到是谁调用了 Record1 方法,可以用 !U 067c835f 查看函数汇编代码,简化后如下:


0:013> !U 067c835f
Normal JIT generated code
System.Base.ApplicationContext+<>c.<HashObjectMap>b__19_0()
Begin 067c7ed8, size 584
...
067c8333 8b3d74361904 mov edi,dword ptr ds:[4193674h] (Object: System.Runtime.Remoting.Proxies.__TransparentProxy)
067c8339 ff75b0 push dword ptr [ebp-50h]
067c833c ff75ac push dword ptr [ebp-54h]
067c833f ff75a8 push dword ptr [ebp-58h]
067c8342 ff75a4 push dword ptr [ebp-5Ch]
067c8345 ff75a0 push dword ptr [ebp-60h]
067c8348 b94e080000 mov ecx,84Eh
067c834d ff15b05d7a06 call dword ptr ds:[67A5DB0h] (System.Base.ApplicationContext+<>c.zmMLEYhjSCTVEl2CxBD(Int32), mdToken: 0600009e)
067c8353 50 push eax
067c8354 8b55b4 mov edx,dword ptr [ebp-4Ch]
067c8357 8bcf mov ecx,edi
067c8359 ff15d8016d00 call dword ptr ds:[6D01D8h]
...

原来是 <HashObjectMap>b__19_0 方法做的调用,也就是 call dword ptr ds:[6D01D8h] ,不信的话可以截图看源码:

从混淆的代码看,有几个特征:

  • aa 依赖于 n9UuXCvGC
  • bb 依赖于 gY03KpyvZ
  • cc 依赖于 GsvWjQg1p
  • hh 依赖于 text

等等,那怎么提取呢? 这里只演示一个 aa 参数吧,可以在汇编代码的第一个 x4phG7d0qxdP1ZxlQa.pliOsRbOU 方法上下一个断点,即 067c820b 处观察方法参数,下断点后,让程序回流。


0:013> !U 067c8359
Normal JIT generated code
System.Base.ApplicationContext+<>c.<HashObjectMap>b__19_0()
...
067c8206 50 push eax
067c8207 8bd3 mov edx,ebx
067c8209 8bcf mov ecx,edi
067c820b ff15e8667a06 call dword ptr ds:[67A66E8h] (System.Base.ApplicationContext+x4phG7d0qxdP1ZxlQa.pliOsRbOU(System.String, System.String, System.String), mdToken: 0600003e)
067c8211 8945b4 mov dword ptr [ebp-4Ch],eax
... 0:013> bp 067c820b
0:013> g-
Breakpoint 1 hit
Time Travel Position: 117A27:A80
eax=032c0ca4 ebx=032bf94c ecx=0329e558 edx=032bf94c esi=032bea78 edi=0329e558
eip=067c820b esp=079bf640 ebp=079bf6a8 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
067c820b ff15e8667a06 call dword ptr ds:[67A66E8h] ds:002b:067a66e8=067cdf00 0:013> ub 067c820b
067c81ef 8945b8 mov dword ptr [ebp-48h],eax
067c81f2 8b3d68361904 mov edi,dword ptr ds:[4193668h]
067c81f8 8b5e08 mov ebx,dword ptr [esi+8]
067c81fb b914040000 mov ecx,414h
067c8200 ff15b0647a06 call dword ptr ds:[67A64B0h]
067c8206 50 push eax
067c8207 8bd3 mov edx,ebx
067c8209 8bcf mov ecx,edi

上面输出的 ecx, edx, eax 分别就是 pliOsRbOU() 方法的三个参数。


0:013> !do ecx
Name: System.String
MethodTable: 7ad924e4
EEClass: 7ae97690
Size: 40(0x28) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: 192.168.0.106
Fields:
MT Field Offset Type VT Attr Value Name
7ad942a8 4000283 4 System.Int32 1 instance 13 m_stringLength
7ad92c9c 4000284 8 System.Char 1 instance 31 m_firstChar
7ad924e4 4000288 70 System.String 0 shared static Empty
>> Domain:Value 00b0bce8:NotInit <<
0:013> !do edx
Name: System.String
MethodTable: 7ad924e4
EEClass: 7ae97690
Size: 46(0x2e) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: N8CDEFGH+JKLM..P
Fields:
MT Field Offset Type VT Attr Value Name
7ad942a8 4000283 4 System.Int32 1 instance 16 m_stringLength
7ad92c9c 4000284 8 System.Char 1 instance 4e m_firstChar
7ad924e4 4000288 70 System.String 0 shared static Empty
>> Domain:Value 00b0bce8:NotInit <<
0:013> !do eax
Name: System.String
MethodTable: 7ad924e4
EEClass: 7ae97690
Size: 32(0x20) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: TripleDES
Fields:
MT Field Offset Type VT Attr Value Name
7ad942a8 4000283 4 System.Int32 1 instance 9 m_stringLength
7ad92c9c 4000284 8 System.Char 1 instance 54 m_firstChar
7ad924e4 4000288 70 System.String 0 shared static Empty
>> Domain:Value 00b0bce8:NotInit <<

从输出中可以看到,aa 参数原来提取了我的 ip 地址,用同样的方式可以提取出所有的方法参数,这里就不详述了,我做了一个整理,截图如下:

从图中可以看到: AssistLog.svc 请求大概会提取:

  • IP地址
  • 机器码
  • 机器名
  • 时间戳
  • IP地址 + 机器码 + 时间戳

用同样的方式调查请求 http://m.365ey.net:13063/QueryLog.svc,整理如下:

这个请求中主要统计了一些接口版本等信息,并没有发现有消息的外泄,分析到这里还是比较欣慰的,将信息反馈给朋友,让朋友不要担心,应该不会有问题。

三: 总结

总的来说我还是非常相信作者,写一个 SDK 已经够辛苦了,做一些违法犯罪的事情道理上说不通,作者也就是纯技术心,想收集下用户端的使用情况,不过在未经许可的情况下确实有所不妥,但初心不坏。

如果 SDK 的作者能够帮他的使用者解答疑惑,让他的粉丝群体可以安心使用,那就更好了,在此感谢作者的辛苦付出,祝组件越来越强大。

某 .NET RabbitMQ SDK 有采集行为,你怎么看?的更多相关文章

  1. Windows SDK笔记(经典--一定要看)

    Windows SDK笔记(一):Windows程序基本结构 一.概述 Windows程序具有相对固定的结构,对编写者而言,不需要书写整个过程,大部分过程由系统完成.程序中只要按一定的格式填写系统留给 ...

  2. rabbitMQ教程(二)一篇文章看懂rabbitMQ

    一.rabbitMQ是什么: RabbitMQ,遵循AMQP协议,由内在高并发的erlanng语言开发,用在实时的对可靠性要求比较高的消息传递上. 学过websocket的来理解rabbitMQ应该是 ...

  3. rabbitMQ教程(三)一篇文章看懂rabbitMQ

    一.rabbitMQ是什么: RabbitMQ,遵循AMQP协议,由内在高并发的erlanng语言开发,用在实时的对可靠性要求比较高的消息传递上. 学过websocket的来理解rabbitMQ应该是 ...

  4. 为什么下了android 4.1 的SDK后在本地用浏览器看api说明文档时,浏览器打开api的html文件很慢?试了好几款浏览器都一样。为什么?

    http://www.oschina.net/question/436724_61401 http://www.google.com/jsapi  他惹的祸 注释掉就可以了- <!-- < ...

  5. 如何监控业务的响应速度?Cloud Insight SDK 实践分享

    一直在说 Cloud Insight 是数据聚合平台,可以用 SDK 和 API 实现业务监控,如今不拿出点实践人们恐怕是不能信服.那今天本文就先简单介绍一下 SDK 可以应用在哪些方面,再举个真实用 ...

  6. RabbitMQ 发布订阅持久化

    RabbitMQ是一种重要的消息队列中间件,在生产环境中,稳定是第一考虑.RabbitMQ厂家也深知开发者的声音,稳定.可靠是第一考虑,为了消息传输的可靠性传输,RabbitMQ提供了多种途径的消息持 ...

  7. spring boot +RabbitMQ +InfluxDB+Grafara监控实践

    本文需要有相关spring boot 或spring cloud 相关微服务框架的基础,如果您具备相关基础可以很容易的实现下述过程!!!!!!! 希望本文的所说对需要的您有所帮助 从这里我们开始进入闲 ...

  8. .NET文件并发与RabbitMQ(初探RabbitMQ)

    本文版权归博客园和作者吴双本人共同所有.欢迎转载,转载和爬虫请注明原文地址:http://www.cnblogs.com/tdws/p/5860668.html 想必MQ这两个字母对于各位前辈们和老司 ...

  9. 在C#中使用消息队列RabbitMQ

    1.什么是RabbitMQ.详见 http://www.rabbitmq.com/. 作用就是提高系统的并发性,将一些不需要及时响应客户端且占用较多资源的操作,放入队列,再由另外一个线程,去异步处理这 ...

随机推荐

  1. RunCat 怎么白嫖付费图标?这篇文章告诉你!

    RunCat 怎么白嫖付费图标?这篇文章告诉你! 什么是RunCat 为什么要破解RunCat 开始破解 所以可以看出第一个文件就是我们运行图标选项的数据,而stocks.json的就是图标商店的数据 ...

  2. Html飞机大战(一):绘制动态背景

    好家伙,飞机大战终于开始弄了 这会有很多很多复杂的东西,但是我们总要从最简单,和最基础的部分开始,   我们先从背景开始弄吧! 1.绘制静态背景 这里我们会用到canvas <!DOCTYPE ...

  3. PostgreSQL 修改执行计划 GroupAggregate 为 HashAggregate

    1.前言 PostgreSQL 聚合算法有两种,HashAggregate and GroupAggregate .我们知道GroupAggregate 需要对记录进行排序,而 HashAggrega ...

  4. 从代码到发包,一个程序全搞定!Gitea 推出软件包自托管功能 Package Registry

    2022 年 7 月的最后一天,随着 Gitea 1.17.0 版本的正式发布,Gitea 开源社区推出了一项名为 Package Registry 的包管理功能,与 Gitea 代码仓库无缝集成,类 ...

  5. UE4自动打包工具编写

    在UE的开发中,有些项目需要针对不同版本出不同的包,并有一个对应的GUI界面,供大家使用. 1.插件编写 先使用UE4自己的插件模板创建插件,做成插件形式 然后注册Slate UI,编写打开逻辑.并在 ...

  6. 通过vNode实现给列表字段打标签

    问题 如何给列表数据打标签?类似下面这种样子 思路 数模转化(对接口请求回来的数据进行过滤标记,返回新的数据) 渲染新的数据模型 实现 1.过滤数据,需要打标签的采用jsx写法 业务数据的处理我封装在 ...

  7. kubernetes中部署kube-prometheus项目解决ControllerManager与Scheduler无法监控问题

    文章转载自:https://www.kococ.cn/20210302/cid=697.html 一.问题描述 在部署 kube-prometheus 到 kubernetes 集群中总会遇到一个问题 ...

  8. Solutions:Elastic workplace 搜索:随时随地搜索所有内容 (二)

  9. KVM常用命令及配置文件

    1.查看虚拟机配置文件 [root@KVM tmp]# ls /etc/libvirt/qemu/ damowang.xml networks [root@KVM tmp]# ls /etc/libv ...

  10. Elasticsearch准实时索引实现(数据写入到es分片并存储到文件中的过程)

    溢写到文件系统缓存 当数据写入到ES分片时,会首先写入到内存中,然后通过内存的buffer生成一个segment,并刷到文件系统缓存中,数据可以被检索(注意不是直接刷到磁盘) ES中默认1秒,refr ...