由于近期时长会有去除软件中的导出,录制等水印,在此写一篇文章做记录,也分享一下我的个人经验

注:本文为尽可能的分析各种情况下的水印,篇幅较长,建议有一定的逆向基础后再来垂阅本文.

正文

水印类型

就目前来说,水印常以三种方式存在于软件之中,其分别是:图片,文字,ui

其中图片常见为png,jpg,bmp

文字则如”DEMO”等

ui像是html,xml等一类,偶见svg及base64等类型

注:本文原理同样适用于盲水印,但部分思路请按照实际情况灵活变化

水印原理

大部分水印都是在图片/视频/文档等输出文件进行渲染时添加的,因此通过dll注入或者逆向去修改渲染的函数是通用方法

当然,也能直接在程序结构中删除对应水印文件,但有时这种方式会导致软件无法运行,因此一般使用透明图片,或将水印修改为空水印而不进行直接的删除是较为好用的方法

不过,也有个别较为特殊的程序通过联网来实时下载水印,或者将其存在用户文档中的缓存之中,而应对这种则通常得通过动态分析才能找到水印所在地

当然, 一切前提都建立在你能准确无误的找到水印所在地,这样才能进行下一步操作

同时,对于程序结构相近的软件,其水印的存放位置也大体相同,如QT,Electron,.NET等

前置工作

带壳的脱壳,有数据包的解压,上手使用一下软件看看水印长啥样,以推测水印的大概类型,同时动手前建议准备一份备份

花里胡哨复杂图像的,大概率是图片水印

图形结构较为简单的水印,可能是图片和UI水印

纯文字类型的,可能是图片,文字和UI水印

静态分析:不需要运行程序,直接分析文件本体的称为静态分析,如ida,MultiExtractorPortable,ResourceHacker

动态分析:需要运行程序,结合程序和内存共同分析的称为动态分析,如ida,X64dbg,Cheat Engine

工具:

IDA64:逆向经典软件,经久不衰,一般用来对软件进行静态分析和汇编修改

010Editor:用于直接查看和编辑二进制文件的16进制,在有一定逆向基础后属于去水印界的万金油(使用时只可替换16进制,长度用空格补齐,严禁修改文件长度,确保修改后文件大小不变)

Cheat Engine:用于动态分析软件内存,快速定位文字水印所在

X64dbg:动态调试必备武器,用于分析可执行文件的水印所在

MultiExtractorPortable:快速拆取文件并提取替换其中的图像资源,是处理图片水印的主力之一

Passolo:汉化工具,用于处理文字类和部分UI类水印

ResourceHacker:资源替换文件,用于处理封装在二进制文件中的压缩数据包中的水印

寻找水印

为照顾新手,本段先从简单易替换的水印开始,并逐渐向到较难的逆向部分进行过渡

图片水印:

无脑先上MultiExtractorPortable:

把整个程序文件夹的图片全扫一遍,然后一页一页看过去,如果找到疑似水印的,就”右键-导入自”,然后替换上你提前准备好的白色透明图片替换上去,只要替换之后文件名字颜色发生变化,便代表替换成功了

如果替换失败,则不会弹出错误提示,同时文件名字的颜色也不会变化,这个时候通常是因为你修改的软件正在运行,需要关闭对应的进程再来替换图片,替换后看有没有效果,没有则接着找

当你排查完所有图片后还没找到水印时,则进入下一个步骤-关键词寻找

打开你的关键词搜索工具(作者此处用的是Py脚本)

#!/usr/bin/env python
import os

list = [".id0",".id1",".id2",".nam",".til",".txt1",".jpg",".png"]
list_dir = ["node_modules",".git"]
result = dict()

def search(dir, word):
    if os.path.isdir(dir):
        for filename in os.listdir(dir):
            if filename not in list_dir:
                file_address = os.path.join(dir, filename)
                if os.path.isfile(file_address):
                    fileType = os.path.splitext(filename)[-1]

                    if fileType not in list:
                        print("正在搜索文件:%s" % file_address)
                        f = open(file_address, 'r', encoding='utf-8', errors='ignore')
                        fileInfo = []
                        i = 1
                        for info in f.readlines():
                            if info.find(word) > -1:
                                fileInfo.append("第" + str(i) + "行:" + info.strip('\n'))
                            i += 1
                        if len(fileInfo) > 0:
                            result[file_address] = fileInfo
                else:
                    search(file_address, word)





if __name__ == "__main__":
    dir = r"path"
    #sec_check_state sec_check_verify_need
    #Error org.freedesktop.DBus.Error.ServiceUnknown: The name com.upointech.easymesh1 was not provided by any .service files
    searchWord = 'keyword'
    search(dir, searchWord)
    print()
    print("logger")
    for k, v in result.items():
        print()
        print(k)
        for info in v:
            print(info)
            pass

通过关键词搜索对整个软件的安装目录进行检索,一般情况下作者会对如下关键词进行检索:

“watermark” “Watermark” “WaterMark” “Water” “water”

一旦检索到关键词,即通过ida64或者010Editor打开该文件查看该关键词的周围是否存在可疑路径等,如果发现存在可疑路径,则顺着路径找到对应图片查看是否符合并替代

注:avcodec-58.dll和ffmpeg.dll中出现的watermark关键词请忽略,这单纯是作为视频编码库的固有内容,和软件水印关系不大

若是简单的关键词检索没有出现可靠结果或者相关内容可疑路径并非对应目标水印,此时则通过Cheat Engine或者X64dbg来进行动态分析

在通过CE和X64dbg打开软件后,仍然通过搜索字符串的方法来寻找可疑路径,CE检索字符串后选择浏览相关的内存区域,X64dbg检索字符串后则转到字符串所在的汇编区域并范围查看

找到了则将目标路径的水印替换为空白图片,或者直接通过010Editor修改水印的路径为其他路径

若此时二者仍然无效,那就得动用最后的方法了:软件逆向

在软件逆向之中,思路和方法多种多样,笔者在此处挑出实战中最常见的几种:

1.在CE中通过文件的保存路径进行字符串搜索,然后寻找到文件的保存函数,再通过ida静态分析来找到水印添加的相关程序

2.通过X64dbg对保存/导出按钮下断点,找到对应的导出函数,并在其中分析找到水印相关程序

3.分析水印添加的条件,例如“会员验证”,“用户等级”等,尝试通过逆向修改水印添加的判断条件来做到水印去除

文字水印:

以关键词的搜索为重心,尝试检索安装目录中的所有文件,寻找水印关键词,同时结合上述的CE及X64dbg动态分析寻找水印关键词来源

但因编码原因,水印原文可能非正常文字编码,这就使得大部分的关键词检索直接失效,此时我们可以通过Passolo来提取疑似文件的非标准 字符串,通过汉化的方式将水印文字改为空格以实现目的

而若简单的关键词搜索和汉化软件Passolo的字符串搜索均为找到对应目标,则参照上文软件逆向方法进行水印去除

UI水印:

SVG:直接检索软件安装目录中的svg关键词或通过CE和X64dbg动态寻找,并把搜索结果中的svg全部拉出来渲染,以找到目标,找到了则通过010Editor直接替换为空格即可

base64:同理,直接检索相关关键词,在外部进行渲染以寻找目标水印然后修改

html/xml:同上,但html/xml大多数不作为单独文件存储,而被打包为资源文件(resource/app.asar)或作为二进制文件的数据包(bin)而存储,因此可能需要先解压,修改后再打包回去