前言

  没想到吧,四月份的首杀居然是搞这个,正好清明假期来总结一波。
  ε=(´ο`*)))唉,研究这个那可是说来话长了,主要是想方设法帮我哥解决一下他们单位蛋疼的软件系统。

  他们的软件系统用 .Net FrameWork 做的,需要在老旧的 XP 系统下运行(:з」∠),使用上有很多 BUG
  软件承包商非常不给力,修了东墙又出西墙的问题,简直没完没了。
  这就导致很多需求特性都一直卡着无法落地,然后各种效率低下接踵而至。
  而且这承包商似乎和上层有道不清说不明的关系,还换不得,作为用户就只能干瞪眼。

  我大致了解了情况,实在是看不下去了,作为日常工具人,这种小事写个 Python 脚本就能省下大量时间。
  于是我就开始尝试解决这个问题,然而我还是图样图森破了😔

AHK 自动复制方案

  由于要支持 XP 系统,而且单位的系统实在是老旧的不行,和大学的讲课电脑有的一拼了。
  所以技术使用上有很多限制,很多新东西都无法使用了,比如 Python3 和 VScode
  于是我评估了一下支持老平台技术,恐怕就只有 AutoHotkey 是支持比较好的了。
  刚好那段时间才话时间研究了一下用 AutoHotkey 编写界面 AHK - 实现软件自动安装
  于是我当时想到的方案是通过 ahk 批量移动鼠标,然后找到对应的 GUI 窗口
  随后对窗口进行逐个复制,拿到的数据生成表格通过 AHK 显示出来。

  于是为了实现这个效果,我客服了不少困难,在 Github 上开了仓库干这个事情 AHK_AutoValidate
  要让 ahk 的界面在 XP 系统下运行还需要用 32 位的编译器编译 exe
  开发过程可谓是异常艰难,好不容易才做了一个简单的 csv 表格界面。
  至于怎么定位 .Net 框架的 GUI 心里还是没有数。

  后来我哥说那边的系统有很多硬件问题,回传的数据就已经不对了,别说自动获取了。
  让我不要再搞了,于是遂放弃了这个东西的开发。


  后来我又认识了一个 AHK 录制神器,甚至集成了 GUI 图片识别 & OCR 功能,自动化方面简直超神了 PuloversMacroCreator 官网
  这个如此强大的工具经过我测试可以在 XP 下运行~
  那么也可以利用这个录制出 AHK 脚本然后重复执行复制数据的操作。

  然而我还是想得太简单了,软件界面里面的数据居然有些无法编辑无法复制。
  这一招也有不好使的地方 (:з」∠) ,遂没有进一步研究

Fiddler 请求拦截

  如果要绕过 GUI ,那么就是要解决万变不离其宗的网络通信数据的拦截。
  过去我都是用浏览器自带的开发者模式来获取请求的信息。
  但是如果是本地的软件又要如何操作呢?
  以前大学搞 android 的时候有听说过一个叫 Fiddler 的软件,但是没有深入去研究。
  后来经过一番查找,发现还是这个神器做本地请求拦截是最合适的。

  于是我在网上找了适合 XP 使用的老版本,然后用虚拟机安装了一个 XP 系统进行测试。
  测试的结果没有太大问题,于是我就去教我哥怎么使用这个拦截请求。
  本来还想着远程到电脑端进行处理的,但是单位电脑物理断网的,保证数据安全。
  内网通信也是只能通过指定电脑才能实现,猜测是做了 Mac 地址之类的识别吧。
  所以好不容易教会我哥使用这个拦截,拦截到的数据也是着实让我傻眼了。

alt

  这个请求是基于我先前重来没有了解过的一个 XML 规范做的。
  访问的是 asmx?WSDL 后缀的地址,并且请求和获取的数据都是 base64 加密过的。
  后来再一查才知道,原来这个是 WebService 的 SOAP 协议 SOAP 教程
  写文章之际又去网上搜了一下相关的介绍文章,感觉又有了全新的认识 知乎: 浅谈 RPC 和 REST: SOAP, gRPC, REST

  SOAP 和目前 Web 上使用主流的 Restful API 各有各的特点和应用场景。
  我这里的情况还算是比较合理的企业内通信应用方式。(我之前还以为是老掉牙的过时技术(:з」∠))

  走 SOAP 协议的话,请求构建就非常单一,特别是我这里遇到的场景。
  通过 Fiddler 截获的大部分数据都时通过这个 WebService 路径进行访问的。
  接口很统一,都是 post 的请求。

  然而最让我头疼的地方就是数据似乎被加密过。
  并不像 SOAP 教程中使用的明文数据。

  于是我用 Python 对 base64 数据进行解码。

alt

  获取到的是比较蛋疼的二进制数据,这就让我毫无办法了,如果这个承包商还对数据做了加密处理,那我就原地去世了。

alt

  后来我担心是 Python 的 base64 解码有问题,用 C# 的功能也处理了一下,还是相同的问题。
  只是 C# 把二进制都打印出来了。

ILSpy 逆向

  如果进过了加密,那就得知道加密算法才有办法解密出正确的数据。
  所以如果可以逆向 C# 的代码就可以解决这个问题。

  不过我实际的研究就更加曲折了,在遇到 base64 问题之前,还卡在 AHK 的时候,我就有研究过逆向问题。
  由于我没有内网服务,所以我在本地的虚拟机测试是无法进入到软件的主界面的。
  我顺理成章地想到之前研究 IDA 对 dll 进行逆向破解的操作。 链接
  我想 C# 大概也能整一套这种骚操作,修改 二进制 文件从而实现绕过登录界面进入主界面。
  有了主界面我就可以用 AHK 识别相关 GUI 的位置了。

  显然 IDA 不太适合处理这种复杂的多个 dll 的情况。
  于是我网上搜了一下 C# 的逆向,就找到了神器 ILSpy Github
  这个神器完全开源,可以通过 dll + pdb 文件逆向出项目源码,就问你离谱不离谱。

  配合 Reflexil 二进制编辑插件就可以对项目的 dll 进行魔改了😎
  当时的确尝试修改了 dll 但是未能绕过登录界面反而是导致 C# 错误了
  于是就放弃了,毕竟这个问题并不重要。


  再到如今遇到了 base64 加密问题,我再次想到使用 ILSpy 逆向破解源码,这就可以解决我头疼的加密问题了。
  于是我先从链接上的 RemoteMethodCallListener 下手。
  没想到这个还真是突破口,可以找到源码。

alt

  我居然在客户端上找到了服务端才应该有的代码,这有点不可思议😲
  通过上面的代码可以看到是调用 RemoteCallResult 对象的 ToBinary 方法

alt

  通过这里可以找到调用了 WrapHelper 方法

alt

  然后在这里的 FromBinary 方法就是解密方法。
  原来数据的头尾包了一个数字,来判断是压缩算法和加密算法,然后用 C# 的加密算法进行逆向解密。
  通过这个方法我应该可以自己写一个 C# 程序来破解数据。

dotnet SDK 开发破译程序

  安装 dotnet 开发的 SDK 程序包。
  大多数情况都是 windows 自带的,毕竟是 微软 的亲儿子。
  安装成功的话可以在命令行输入 dotnet 来调用 sdk

alt

  默认创建一个 命令行程序 可以使用 dotnet new Console
  然后在这个目录执行 dotnet run 就可以生成命令的 exe 并运行输出结果。

alt

  目录会生成 bin 和 obj 目录,可以无视,主要是 program.cs 和 csproj 文件。
  通过将 ILSpy 反编译的代码,可以套进去将 Fiddler 截获的二进制转换出来,结果和 ILSpy 破解的代码一样。
  这里并不是明文传输,而是直接传输了对象。
  用 Python 去理解的话,可以理解为 pickle 对象为二进制然后加密包装成 base64 发送。

  但是获取的对象是他们 dll 里面生成的。
  如果直接在命令行打印解密的对象,会直接报错。

alt

  这就是提示缺少了相关的运行库,无法反序列化这个对象。

  为了解决这个问题,我也摸索了很长一段时间,一开始是使用 System.Reflection.Assembly 的方法加载对应的 dll
  然后通过这个加载的 dll 实例获取相关的函数,使用 Invoke 方法进行调用。
  这个处理就异常的麻烦的,我就开始找有没有直接使用 using 关键字的方法,将整个依赖加入全局环境里面。
  但是实在搜不出有用的信息。

  中途还看了一些 IronPython 的相关文章。 链接

1
2
3
4
5
6
7
8
import clr
clr.AddReference('CalcLib')
#clr.AddReferenceToFile('CalcLib.dll')
from CalcLib import Calc
print dir(Calc)
calcObj = Calc()
print "result of 3+4 is:", calcObj.Add(3,4)
print "result of 10+2 is:", calcObj.Sub(10,2)

  看这篇文章的时候才发现, IronPython 居然可以通过 AddReference 加载 dll ,然后就可以直接导入了。
  通过这个引子,我顺藤摸瓜,找到了 Stack Overflow 的一篇回答 链接

alt

  这里面提到在 csproj 文件下可以直接添加 Reference ,然后指向对应位置的 dll 。
  这样全局的运行会将就有了相关 dll 的依赖。
  这样我写的 C# 程序可以直接调用他们程序提供的 dll 封装的方法,直接解析出对应的对象,将数据输出来。

  终于经过了好多坑之后,我真的解决了这个数据加密问题,倍感欣慰。
  最难的骨头被我啃完了,我就不需要用低效的 AHK 方案来解决问题了。
  后续我还需要跟进一下的请求的构建,这样我就可以通过我写的命令行程序绕过软件承包商的 GUI 直接获取原始数据进行处理。

  最后是要输出一个 32 位的程序在 XP 系统运行,需要加上一些配置 链接

总结

  这次不务正业系列其实跨度很长,Anyway,总算是了却了一个心愿。