记一次破解全屏水印的思路

发表于 2021-12-27 00:00:00 | 阅读时长 ≈ 1分钟 | 1 个月前

逻辑分析

对于全屏水印,可能是打开了一个全屏透明的窗口,并将该窗口置顶,先尝试关闭该窗口。 使用火绒的弹窗拦截尝试屏蔽该弹窗,发现拦截后会继续弹窗,弹窗后再次拦截,出现了水印闪烁的情况

火绒弹窗拦截
火绒弹窗拦截

js
// 伪代码
while(true){
checkWatermarkWindow();
sleep();
}

使用火绒剑观察发现图片水印被保存到文件中

image-20211228143041980
image-20211228143041980

代码分析

用 x64dbg 附加目标进程, 点击重新运行后进入 ntdll.dll 再点击运行进入程序入口,再点击运行使程序正常运行。

在符号中 找到 水印模块,发现导入了 gdiplus.GdipSaveImageToFile 保存图片到文件。 双击进入该方法入口 按 F2 下断

x64dbg 模块
x64dbg 模块
在软件中登录账号,程序在断点处停下,继续运行忽略掉非关键文件,来到此处
x64dbg CPU
x64dbg CPU

运行到返回 再 步进一次 即可来到该方法的调用位置。 重复该步骤,发现屏幕上出现了水印。 最后来到了关键之处

image-20211228130844553
image-20211228130844553

这里可以修改 call 为 nop 以不执行水印方法。

破解方法

将 6B69CDE3 处的 call fwatermarksc.6B69C080 改为 nop 即可, 修补文件以将改动保存到文件。

image-20211228131512439
image-20211228131512439

>fwatermarksc.dll 0001CDE3:E8->90 0001CDE4:98->90 0001CDE5:F2->90 0001CDE6:FF->90 0001CDE7:FF->90

对应文件偏移 1C1E3 使用其它 支持 hex 的编辑器也可以。

image-20211228131640733
image-20211228131640733

规避签名验证

保存文件后运行程序还发现程序校验了 fwatermarksc.dll 的文件签名。 这里可以不修改文件,通过直接修改内存来跳过水印方法

cpp
#include <wtypes.h>
#include <WinUser.h>
#include <TlHelp32.h>
const char *targetProcessName = "xxx.exe";
const char *targetModuleName = "fwatermarksc.dll";
// 代码偏移
int lpBaseAddress = 0x1CDE3;
DWORD GetProcessID(const char *lpName) {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot) {
return NULL;
}
PROCESSENTRY32 processEntry = {sizeof(processEntry)};
BOOL fOk;
for (fOk = Process32First(hSnapshot, &processEntry); fOk; fOk = Process32Next(hSnapshot, &processEntry)) {
if (strcmp(processEntry.szExeFile, lpName) == 0) {
CloseHandle(hSnapshot);
return processEntry.th32ProcessID;
}
}
return NULL;
}
HMODULE GetProcessModuleHandle(DWORD pid, CONST CHAR *moduleName) {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
if (INVALID_HANDLE_VALUE == hSnapshot) {
return nullptr;
}
MODULEENTRY32 moduleEntry = {sizeof(moduleEntry)};
BOOL fOk;
for (fOk = Module32First(hSnapshot, &moduleEntry); fOk; fOk = Module32Next(hSnapshot, &moduleEntry)) {
if (strcmp(moduleEntry.szModule, moduleName) == 0) {
CloseHandle(hSnapshot);
return moduleEntry.hModule;
}
}
return nullptr;
}
int main() {
// 获取进程编号
DWORD processID = GetProcessID(targetProcessName);
// 获取进程句柄
HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if (processHandle == nullptr) {
::MessageBox(nullptr, "ERROR: Process not found.", "WatermarkCracker", MB_ICONERROR);
return 0;
}
// 取得水印模块基址
HMODULE moduleBaseAddress = GetProcessModuleHandle(processID, targetModuleName);
// 代码地址
int codeAddress = (int) moduleBaseAddress + lpBaseAddress;
// NOP
BYTE shellData[5] = {0x90, 0x90, 0x90, 0x90, 0x90};
SIZE_T lpNumberOfBytesWritten = 0;
WriteProcessMemory(processHandle, (LPVOID) codeAddress, &shellData, sizeof(shellData), &lpNumberOfBytesWritten);
CloseHandle(processHandle);
::MessageBox(nullptr, "Success", "WatermarkCracker", MB_ICONINFORMATION);
return 0;
}

Categorized under