前言

通过本文介绍怎么对一个 windows 程序进行安全分析。分析的软件版本为 2018-10-9 , 所有相关文件的链接

  1. 链接:https://pan.baidu.com/s/1l6BuuL-HPFdkFsVNOLpjUQ
  2. 提取码:erml

逆向分析

定位核心代码

拿到一个软件首先需要进行攻击面的探测,即找到尽可能多的可以与程序进行交互的入口点,有数据交互的地方就有可能会出现漏洞。首先对软件的功能做一个大概的了解,发现搜狗输入法能够安装用户自定义的皮肤,这是一个比较好的入口点,于是下面分析分析处理皮肤文件的逻辑。

先从官网随便下个皮肤,然后拿 010editor 简单看看能不能拿到一些有用的信息。

使用 binwalk 也没有识别出文件格式,于是猜测应该是输入法自己实现的格式。

后来在对皮肤相关的功能进行浏览的时候发现有皮肤编辑器这个软件

  1. https://pinyin.sogou.com/skins/design.php

下载下来随便创建一个皮肤,发现此时的皮肤格式为 zip 格式,双击也能正常安装。皮肤编辑器的最近更新在 13 年,估计输入法是为了做兼容,同时支持两种格式的皮肤文件。

下载下来的皮肤双击就可以安装,这样的安装方式我们不好定位具体安装皮肤的程序,这时我们可以使用 api montor 监控当双击皮肤文件时系统所执行的命令,以便进行下一步的分析。

打开 api monitor , 然后打开皮肤文件可以监控到搜狗输入法处理皮肤文件执行的命令

  1. "C:\Program Files (x86)\SogouInput\SogouExe\SogouExe.exe" "C:\Program Files (x86)\SogouInput\9.1.0.2657\SGTool.exe"-line 0 -border --appid=skinreg -list "C:\Users\XinSai\Desktop\test.ssf"

通过使用 Procmon.exe 分析,其实最后调用

  1. "C:\Program Files (x86)\SogouInput\9.1.0.2657\SGTool.exe" -line 0 -border --appid=skinreg -install -c "C:\Users\XinSai\Desktop\test.ssf" -q -ef

通过执行这条命令就可以把皮肤安装到输入法内部。

下面把 SGTool.exe 拖到 IDA 里面, 使用命令行选项来搜索字符串的交叉引用去找到相关的处理代码。通过对命令行参数的交叉引用逐步向上追溯,在 0x07A04D0 发现程序会根据 appid 参数的值,决定下一步进行处理的函数

然后调试发现一直断不到这,于是用 drrun 看看程序到底走了哪些路径

  1. drrun.exe -t drcov -- "C:\Program Files (x86)\SogouInput\9.1.0.2657\SGTool.exe" -line 0 -border --appid=skinreg -install -c "C:\Users\XinSai\Desktop\test.ssf" -q -ef

发现直接点击 ssf 文件还是没有进入这个分支。

经过不断的尝试 + 使用一些监控软件,发现在关闭所有搜狗输入法相关进程的情况下,双击 .ssf 文件,会首先使用

  1. "C:\Program Files (x86)\SogouInput\9.1.0.2657\SGTool.exe" -daemon

开启一个类似于服务器的进程,然后在使用

  1. "C:\Program Files (x86)\SogouInput\9.1.0.2657\SGTool.exe" -line 0 -border --appid=skinreg -install -c "C:\Users\XinSai\Desktop\test.ssf" -q -ef

另外再起一个 SGTool.exe 的进程向刚刚启动服务进程发送消息,后续的皮肤处理在服务进程进行。猜测可能是使用了 windows 本地通信机制实现 C/S 架构

后续在瞎试的时候,将一个非皮肤文件命名成 .ssf 后缀,然后双击会出现报错信息。

根据这些字符串在 od 里面找,可以找到一些信息,最后通过对

  1. 皮肤解压失败:skin.ini不存在

交叉引用, 然后不断回溯, 发现了一个有趣的函数 0x07A72D0

这个函数首先 调用 0x7A84F0检测了某些参数。

从我们的参数进行对比,猜测这里校验的应该是最后那两个参数

然后猜测 -q 应该是安静模式,于是删掉 -q 试了一试

发现居然会有提示框,那这个提示框的代码附件应该离处理 皮肤文件的代码更加近了。

对字符串交叉引用,发现其实就是上面的那个代码(0x007A75DC

所以从这里开始,应该就开始对皮肤文件进行处理了。

分析皮肤处理相关的代码

经过不断的调试以及查看函数调用的参数,发现当我们点击 确认 的时候,会调用位于0x914980 的函数。

这个函数传入的参数是一个对象指针,对象内部有我们皮肤文件的路径,这个函数会对传入的 皮肤文件 进行第一次的判断。

函数首先会打开文件, 然后取出开头的4个字节作为文件类型,判断是不是Skin。如果是的话就认为是最新的皮肤格式然后进入后续的操作。

如果不是就认为是第一代皮肤格式 ,即用zip格式打包的皮肤。

调试时,可以看到 type 的值。 下面是打开的官网下载的皮肤文件,所以 typeSkin.

当皮肤文件的type值不为Skin时,程序会进入decompress_skin_ini (0x063F340), 这个函数里面会调用ziplib.dll 里面的函数对皮肤文件进行解压,提取并解析skin.ini文件。

总的来说,0x914980 函数其实只是校验了皮肤文件的版本信息,对于 文件头 不是 Skin 的文件,则认为是第一代皮肤格式文件,然后会使用 ziplib.dll 里面的函数提取 skin.ini 文件并尝试解析它。

在进行完第一次的校验后,会回到 0x7A72D0, 将文件拷贝到用户的皮肤保存目录,然后对皮肤文件进行解析,提取出里面的文件。

其中 0x7A6230 deal_skin 就是解析皮肤文件的入口,它会调用 0x63E3F0 完成具体文件解析流程。

这个函数首先判断文件头 , 如果是 Skin , 表示为最新格式的皮肤文件

则通过 decompress_skinv3 0x053B320 进行解析并提取出皮肤包里面包含的文件。否则就认为是第一代皮肤文件, 使用 ziplib 里面的函数, 把皮肤包里面的文件解压出来。

  1. for ( i = v25 - 3; v28 < v27; ++v28 )
  2. {
  3. ..................................................................
  4. ..................................................................
  5. ..................................................................
  6. ..................................................................
  7. if ( decompress_file_from_zip(v46, v65, &path, target, &len, &buf) )
  8. {
  9. v47 = len;
  10. if ( len <= 0x80000000 && len )
  11. {
  12. len = target;
  13. (*v51)(&v51, &len, 0);
  14. v48 = buf;
  15. v54 = v47;
  16. v53 = buf;
  17. sub_53ACE0(obj1, &v50, 0);// 做一些析构操作
  18. sub_49F5C0(ziplib_obj, v65, v47, v48);
  19. }
  20. v24 = v62;
  21. }
  22. ..................................................................
  23. ..................................................................
  24. ..................................................................
  25. ..................................................................
  26. }

下面对decompress_skinv3(0x053B320)进行分析,以便理解最新皮肤包的格式

首先打开皮肤包,读取文件内容到内存,然后把文件内容,大小传给 handle_skinv3 0x0053A8C0 进行处理。

通过对这个函数的逆向,可以明白.ssf 文件开头 8个字节的结构为 4字节的 Skin 和 4 字节的 version 字段

校验完版本信息后, 会对文件头部后的数据使用程序自己实现的算法进行解码,然后对解码之后的数据使用zlib再次解码。

zlib 解码完成后,把解码后的数据传入 0x53bf50 (调试时确认)对文件进行提取

这个函数对传入的数据进行解析,提取出相关的文件

  1. // 调用者 0x53AAE1
  2. unsigned int __thiscall skin_v3_step2(int this, unsigned int *buf, unsigned int size, int a4)
  3. {
  4. len = *buf; // 取出 buf 开始的 4 个字节, 表示数据的长度
  5. if ( *buf > size )
  6. return -1;
  7. new_size = size - 4;
  8. sizea = size - 4;
  9. if ( *buf )
  10. {
  11. if ( (**(this + 4))(this + 4, buf + 1, new_size, a4) < 0 )// 调用0x53c110L,第 2, 3个参数为 buf + 4, size-4
  12. // 就是忽略掉头4个字节
  13. // 函数作用复制 zlib 解码后的数据 0x8-0x40 到对象里面
  14. do // 循环的从 zlib 解压过的文件里面提取出文件
  15. {
  16. offset = *(v12 + 4 * v9);
  17. if ( offset < data_len )
  18. {
  19. v17 = (**v15)(cur, sizea, a4); // 调用 0x923f70L, 提取文件名
  20. if ( v17 < 0 )
  21. goto LABEL_19;
  22. v18 = &cur[v17];
  23. v19 = (*v22[3])(v18, sizea - v17, a4);// 调用的是 0x53c1c0L, 提取文件内容
  24. }
  25. ++v9;
  26. }
  27. while ( v9 < v11 );

文件格式汇总

老版本的皮肤格式

其实就是一个 zip 包, 里面有配置文件和一些图片。

新版本的皮肤格式

首先是 .ssf 文件

开头 8个字节为 4字节的 Skin 和 4 字节的 version

  • 然后调用 0x0639610文件偏移 8开始进行解码, 解码后的数据 A 偏移 4 字节开始 为 zlib 压缩的数据。
  • 然后对 A + 4 使用 zlib 解码,得到 zlib 解码后的数据 B
  • 然后把 BB 的长度传入 0x53bf50 继续处理

B 的结构为

开头4个字节为数据的总长度

然后根据 0x53C110 , 后面紧跟着的 4 个字节为文件映射表的长度,即 0x38 字节。每一个表项4个字节,代表表项指示其所表示的文件在整个文件中的偏移地址。

如图所示, 第一个表项的值为 0x40, 所以第一个文件应该在 0x40 处。

经过一定的观察发现一个文件的表示方式为

  • 4字节: 文件名的长度
  • 文件名( unicode 编码)
  • 4字节: 文件数据的长度
  • 文件数据

发现漏洞

分析完整个皮肤处理的代码后发现整个代码的逻辑还是不怎么复杂的。于是可以直接读反编译的代码来找找看是否存在什么漏洞。在读代码找漏洞时重点关注缓冲区的操作, 内存的分配大小以及对文件中表示长度的字段的使用是否合理。

经过一番仔细的走查发现在对皮肤文件第一步用自己实现的解密算法解密后的开始 4 个字节为 deocded_data_size , 之后会把它加上 8 然后去分配内存。

deocded_data_size 是从解密后的文件中取出的,当把 deocded_data_size 改成 0xffffffff 时,在分配内存时会整数溢出导致分配比较小的内存块,然后后续的代码在使用这个缓冲区时会造成一个堆溢出。漏洞已于3个月前提交并修复。

总结

在分析软件功能实现时,可以采用一些监控软件比如 api monitor 来辅助定位关键代码。一些程序中的提示,报错信息也可以用来定位。最重要的就是多调试,多调试。程序从文件内容中取 size 时要注意校验。

SG Input 软件安全分析之逆向分析的更多相关文章

  1. SG Input 软件安全分析之fuzz

    前言 前面介绍了通过静态读代码的方式去发现问题,这里介绍两种 fuzz 目标软件的方式. 相关文件 链接:https://pan.baidu.com/s/1l6BuuL-HPFdkFsVNOLpjUQ ...

  2. 病毒木马查杀实战第016篇:U盘病毒之逆向分析

    比对脱壳前后的程序 我们这次所要研究的是经过上次的脱壳操作之后,所获取的无壳病毒样本.其实我们这里可以先进行一下对比,看看有壳与无壳的反汇编代码的区别.首先用IDA Pro载入原始病毒样本: 图1 可 ...

  3. cm3 逆向分析

    目录 cm3 逆向分析 前言 逆向分析 cm3 逆向分析 前言 这道题没加壳,也没加密算法,主要看代码逻辑. 逆向分析 代码很短,一共这么几句. 看提示知道只让我们输入w.s.a.d这几个字符,并且用 ...

  4. cm2 逆向分析

    目录 cm2 逆向分析 前言 查壳 逆向分析 encrypt函数 POC代码 cm2 逆向分析 前言 这是逆向实战之CTF比赛篇的第3篇,在这里我就不再讲的特别小白了,有些简单操作可能会略过. 查壳 ...

  5. IM通信协议逆向分析、Wireshark自定义数据包格式解析插件编程学习

    相关学习资料 http://hi.baidu.com/hucyuansheng/item/bf2bfddefd1ee70ad68ed04d http://en.wikipedia.org/wiki/I ...

  6. Android逆向分析(2) APK的打包与安装背后的故事

    前言 上一次我们反编译了手Q,并遇到了Apktool反编译直接crash的问题,虽然笔者很想在这次解决这个问题,但在解决途中,发现该保护依赖于很多知识,所以本次先插入一下,正所谓知其然知其所以然,授之 ...

  7. Android逆向分析(2) APK的打包与安装

    http://blog.zhaiyifan.cn/2016/02/13/android-reverse-2/ 2/18日增加对aidl和java编译的描述. 前言 上一次我们反编译了手Q,并遇到了Ap ...

  8. [Android Security] Smali和逆向分析

    copy : https://blog.csdn.net/u012573920/article/details/44034397 1.Smali简介 Smali是Dalvik的寄存器语言,它与Java ...

  9. MacOS微信逆向分析-Frida

    MacOS微信逆向分析-Frida 0.前言 PC下的微信二次开发相信大家都会了,那么本篇文章将带领大家使用Frida框架对Mac下微信来进行二次开发! PS:还有一种静态注入的方式也不错,但是考虑到 ...

随机推荐

  1. bootstrap使用之多个弹窗和拖动效果[开发篇]

    有时开发一些特效,自己感觉挺爽的,像操作自己电脑一样操作你的网页,这里就介绍一个使用bootstrap的一点多窗口和拖动效果吧! 这里,我们不使用静态打开的的方式,low...,1.添加一个a链接 触 ...

  2. 【Spark调优】Shuffle原理理解与参数调优

    [生产实践经验] 生产实践中的切身体会是:影响Spark性能的大BOSS就是shuffle,抓住并解决shuffle这个主要原因,事半功倍. [Shuffle原理学习笔记] 1.未经优化的HashSh ...

  3. css高级选择器&盒模型

    css高级选择器&盒模型 1.组合选择器 群组选择器 /* 每个选择器为可以为三种基础选择器的任意一个,用逗号隔开,控制多个*/ div,.div,#div{ color:red } 后代(子 ...

  4. HoloLens开发手记-全息Hologram

    HoloLens使我们可以通过周边世界的光线和声音来创建全息场景和物体,使得它们像真实物体那样.全息场景能够响应你的凝视.手势和语音指令,同时还会和你周边世界的表面交互.借助全息场景,你可以在周边世界 ...

  5. 14-使用glusterfs做持久化存储

    使用glusterfs做持久化存储 我们复用kubernetes的三台主机做glusterfs存储. 以下步骤参考自:https://www.xf80.com/2017/04/21/kubernete ...

  6. [Objective-C语言教程]协议(31)

    Objective-C允许定义协议,声明预期用于特定情况的方法. 协议在符合协议的类中实现. 一个简单的例子是网络URL处理类,它将具有一个协议,其中包含processCompleted委托方法等方法 ...

  7. [视频]K8飞刀--WinRAR远程代码执行漏洞利用视频

    [视频]K8飞刀--WinRAR远程代码执行漏洞利用视频 链接:https://pan.baidu.com/s/17_0kgNsDejJS0hvgLiMD7A 提取码:zkc2

  8. JAVA中的COPYONWRITE容器

    Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...

  9. jenkins配置邮件 -- com.sun.mail.smtp.SMTPSenderFailedException: 550 5.7.1 Client does not have permissions to send as this sender

    jenkins配置邮件设置 发送邮件测试时,报错: com.sun.mail.smtp.SMTPSenderFailedException: Client does not have permissi ...

  10. 服务端如何安全获取客户端请求IP地址

    服务端如何获取客户端请求IP地址,网上代码一搜一大把.其中比较常见有x-forwarded-for.client-ip等请求头,及remote_addr参数,那么为什么会存在这么多获取方式,以及到底怎 ...