SG Input 软件安全分析之逆向分析
前言
通过本文介绍怎么对一个 windows
程序进行安全分析。分析的软件版本为 2018-10-9
, 所有相关文件的链接
链接:https://pan.baidu.com/s/1l6BuuL-HPFdkFsVNOLpjUQ
提取码:erml
逆向分析
定位核心代码
拿到一个软件首先需要进行攻击面的探测,即找到尽可能多的可以与程序进行交互的入口点,有数据交互的地方就有可能会出现漏洞。首先对软件的功能做一个大概的了解,发现搜狗输入法能够安装用户自定义的皮肤,这是一个比较好的入口点,于是下面分析分析处理皮肤文件的逻辑。
先从官网随便下个皮肤,然后拿 010editor
简单看看能不能拿到一些有用的信息。
使用 binwalk
也没有识别出文件格式,于是猜测应该是输入法自己实现的格式。
后来在对皮肤相关的功能进行浏览的时候发现有皮肤编辑器这个软件
https://pinyin.sogou.com/skins/design.php
下载下来随便创建一个皮肤,发现此时的皮肤格式为 zip
格式,双击也能正常安装。皮肤编辑器的最近更新在 13 年,估计输入法是为了做兼容,同时支持两种格式的皮肤文件。
下载下来的皮肤双击就可以安装,这样的安装方式我们不好定位具体安装皮肤的程序,这时我们可以使用 api montor
监控当双击皮肤文件时系统所执行的命令,以便进行下一步的分析。
打开 api monitor
, 然后打开皮肤文件可以监控到搜狗输入法处理皮肤文件执行的命令
"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
分析,其实最后调用
"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
看看程序到底走了哪些路径
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
文件,会首先使用
"C:\Program Files (x86)\SogouInput\9.1.0.2657\SGTool.exe" -daemon
开启一个类似于服务器的进程,然后在使用
"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
里面找,可以找到一些信息,最后通过对
皮肤解压失败:skin.ini不存在
交叉引用, 然后不断回溯, 发现了一个有趣的函数 0x07A72D0
这个函数首先 调用 0x7A84F0
检测了某些参数。
从我们的参数进行对比,猜测这里校验的应该是最后那两个参数
然后猜测 -q
应该是安静模式,于是删掉 -q
试了一试
发现居然会有提示框,那这个提示框的代码附件应该离处理 皮肤文件的代码更加近了。
对字符串交叉引用,发现其实就是上面的那个代码(0x007A75DC
)
所以从这里开始,应该就开始对皮肤文件进行处理了。
分析皮肤处理相关的代码
经过不断的调试以及查看函数调用的参数,发现当我们点击 确认 的时候,会调用位于0x914980
的函数。
这个函数传入的参数是一个对象指针,对象内部有我们皮肤文件的路径,这个函数会对传入的 皮肤文件 进行第一次的判断。
函数首先会打开文件, 然后取出开头的4
个字节作为文件类型,判断是不是Skin。
如果是的话就认为是最新的皮肤格式然后进入后续的操作。
如果不是就认为是第一代皮肤格式 ,即用zip
格式打包的皮肤。
调试时,可以看到 type
的值。 下面是打开的官网下载的皮肤文件,所以 type
为 Skin
.
当皮肤文件的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
里面的函数, 把皮肤包里面的文件解压出来。
for ( i = v25 - 3; v28 < v27; ++v28 )
{
..................................................................
..................................................................
..................................................................
..................................................................
if ( decompress_file_from_zip(v46, v65, &path, target, &len, &buf) )
{
v47 = len;
if ( len <= 0x80000000 && len )
{
len = target;
(*v51)(&v51, &len, 0);
v48 = buf;
v54 = v47;
v53 = buf;
sub_53ACE0(obj1, &v50, 0);// 做一些析构操作
sub_49F5C0(ziplib_obj, v65, v47, v48);
}
v24 = v62;
}
..................................................................
..................................................................
..................................................................
..................................................................
}
下面对decompress_skinv3(0x053B320)
进行分析,以便理解最新皮肤包的格式
首先打开皮肤包,读取文件内容到内存,然后把文件内容,大小传给 handle_skinv3 0x0053A8C0
进行处理。
通过对这个函数的逆向,可以明白.ssf
文件开头 8个字节的结构为 4字节的 Skin 和 4 字节的 version 字段
校验完版本信息后, 会对文件头部后的数据使用程序自己实现的算法进行解码,然后对解码之后的数据使用zlib
再次解码。
zlib
解码完成后,把解码后的数据传入 0x53bf50
(调试时确认)对文件进行提取
这个函数对传入的数据进行解析,提取出相关的文件
// 调用者 0x53AAE1
unsigned int __thiscall skin_v3_step2(int this, unsigned int *buf, unsigned int size, int a4)
{
len = *buf; // 取出 buf 开始的 4 个字节, 表示数据的长度
if ( *buf > size )
return -1;
new_size = size - 4;
sizea = size - 4;
if ( *buf )
{
if ( (**(this + 4))(this + 4, buf + 1, new_size, a4) < 0 )// 调用0x53c110L,第 2, 3个参数为 buf + 4, size-4
// 就是忽略掉头4个字节
// 函数作用复制 zlib 解码后的数据 0x8-0x40 到对象里面
do // 循环的从 zlib 解压过的文件里面提取出文件
{
offset = *(v12 + 4 * v9);
if ( offset < data_len )
{
v17 = (**v15)(cur, sizea, a4); // 调用 0x923f70L, 提取文件名
if ( v17 < 0 )
goto LABEL_19;
v18 = &cur[v17];
v19 = (*v22[3])(v18, sizea - v17, a4);// 调用的是 0x53c1c0L, 提取文件内容
}
++v9;
}
while ( v9 < v11 );
文件格式汇总
老版本的皮肤格式
其实就是一个 zip
包, 里面有配置文件和一些图片。
新版本的皮肤格式
首先是 .ssf
文件
开头 8个字节为 4字节的 Skin
和 4 字节的 version
- 然后调用
0x0639610
对 文件偏移 8开始进行解码, 解码后的数据A
偏移 4 字节开始 为zlib
压缩的数据。 - 然后对
A + 4
使用zlib
解码,得到zlib
解码后的数据B
- 然后把
B
和B
的长度传入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 软件安全分析之逆向分析的更多相关文章
- SG Input 软件安全分析之fuzz
前言 前面介绍了通过静态读代码的方式去发现问题,这里介绍两种 fuzz 目标软件的方式. 相关文件 链接:https://pan.baidu.com/s/1l6BuuL-HPFdkFsVNOLpjUQ ...
- 病毒木马查杀实战第016篇:U盘病毒之逆向分析
比对脱壳前后的程序 我们这次所要研究的是经过上次的脱壳操作之后,所获取的无壳病毒样本.其实我们这里可以先进行一下对比,看看有壳与无壳的反汇编代码的区别.首先用IDA Pro载入原始病毒样本: 图1 可 ...
- cm3 逆向分析
目录 cm3 逆向分析 前言 逆向分析 cm3 逆向分析 前言 这道题没加壳,也没加密算法,主要看代码逻辑. 逆向分析 代码很短,一共这么几句. 看提示知道只让我们输入w.s.a.d这几个字符,并且用 ...
- cm2 逆向分析
目录 cm2 逆向分析 前言 查壳 逆向分析 encrypt函数 POC代码 cm2 逆向分析 前言 这是逆向实战之CTF比赛篇的第3篇,在这里我就不再讲的特别小白了,有些简单操作可能会略过. 查壳 ...
- IM通信协议逆向分析、Wireshark自定义数据包格式解析插件编程学习
相关学习资料 http://hi.baidu.com/hucyuansheng/item/bf2bfddefd1ee70ad68ed04d http://en.wikipedia.org/wiki/I ...
- Android逆向分析(2) APK的打包与安装背后的故事
前言 上一次我们反编译了手Q,并遇到了Apktool反编译直接crash的问题,虽然笔者很想在这次解决这个问题,但在解决途中,发现该保护依赖于很多知识,所以本次先插入一下,正所谓知其然知其所以然,授之 ...
- Android逆向分析(2) APK的打包与安装
http://blog.zhaiyifan.cn/2016/02/13/android-reverse-2/ 2/18日增加对aidl和java编译的描述. 前言 上一次我们反编译了手Q,并遇到了Ap ...
- [Android Security] Smali和逆向分析
copy : https://blog.csdn.net/u012573920/article/details/44034397 1.Smali简介 Smali是Dalvik的寄存器语言,它与Java ...
- MacOS微信逆向分析-Frida
MacOS微信逆向分析-Frida 0.前言 PC下的微信二次开发相信大家都会了,那么本篇文章将带领大家使用Frida框架对Mac下微信来进行二次开发! PS:还有一种静态注入的方式也不错,但是考虑到 ...
随机推荐
- 转---深入浅出妙用 Javascript 中 apply、call、bind
作者:伯乐在线专栏作者 - chokcoco 如有好文章投稿,请点击 → 这里了解详情 如需转载,发送「转载」二字查看说明 这篇文章实在是很难下笔,因为网上相关文章不胜枚举. 巧合的是前些天看到阮老师 ...
- Docker 与 虚拟机比较
1, 更高效的利用系统资源2,更快速的启动时间3,一致的运行环境4,持续交付(Continuous Integration)和部署(Continuous Delivery) 5, 更轻松的迁移 6,更 ...
- 【Spark调优】:结合业务场景,优选高性能算子
聚合操作使用reduceByKey/aggregateByKey替代groupByKey 参见我的这篇博客说明 [Spark调优]:如果实在要shuffle,使用map侧预聚合的算子 内存充足前提下使 ...
- Python - 集成开发环境Pycharm的使用方法和技巧
PyCharm HomePage:PyCharm 我的Pycharm,我做主 Getting Started with PyCharm Pycharm使用技巧 Documentation & ...
- JS 数据类型和数据分析
栈区:(stack)-由编译器自动分配释放,存放函数的参数值,局部变量的值等. 特点是存放体积小,使用频率高的数据.可以类比内存. 堆区:(heap)-一般由程序员分配释放,若开发者不释放,程序结束时 ...
- .NET手记-ASP.NET MVC快速分页的实现
对于Web应用,展示List是很常见的需求,随之而来的常见的分页组件.jQuery有现成的分页组件,网上也有着大量的第三方分页组件,都能够快速实现分页功能.但是今天我描述的是用基本的C#和html代码 ...
- postgresql-无序uuid tps测试
# postgresql-无序uuid tps测试 ## 无序uuid对数据库的影响 由于最近在做超大表的性能测试,在该过程中发现了无序uuid做主键对表插入性能有一定影响.结合实际情况发现当表的数据 ...
- Python模块——xml
xml模块 xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单, 不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行 ...
- 第一次用python 写的简单爬虫 记录在自己的博客
#python.py from bs4 import BeautifulSoup import urllib.request from MySqlite import MySqlite global ...
- Linux_CentOS-服务器搭建 <五> 补充
O:文件的编码格式 1.文件转码问题 Windows中默认的文件格式是GBK(gb2312),而Linux一般都是UTF-8. 那么先说,如何查看吧.这时候强大的vi说,I can do that.( ...