记一次破解全屏水印的思路
逻辑分析
对于全屏水印,可能是打开了一个全屏透明的窗口,并将该窗口置顶,先尝试关闭该窗口。
使用火绒的弹窗拦截尝试屏蔽该弹窗,发现拦截后会继续弹窗,弹窗后再次拦截,出现了水印闪烁的情况
js// 伪代码while(true){checkWatermarkWindow();sleep();}
使用火绒剑观察发现图片水印被保存到文件中
代码分析
用 x64dbg 附加目标进程, 点击重新运行后进入 ntdll.dll 再点击运行进入程序入口,再点击运行使程序正常运行。
在符号中 找到 水印模块,发现导入了 gdiplus.GdipSaveImageToFile 保存图片到文件。 双击进入该方法入口 按 F2 下断
运行到返回 再 步进一次 即可来到该方法的调用位置。 重复该步骤,发现屏幕上出现了水印。 最后来到了关键之处
这里可以修改 call 为 nop 以不执行水印方法。
破解方法
将 6B69CDE3 处的 call fwatermarksc.6B69C080 改为 nop 即可, 修补文件以将改动保存到文件。
>fwatermarksc.dll 0001CDE3:E8->90 0001CDE4:98->90 0001CDE5:F2->90 0001CDE6:FF->90 0001CDE7:FF->90
对应文件偏移 1C1E3 使用其它 支持 hex 的编辑器也可以。
规避签名验证
保存文件后运行程序还发现程序校验了 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;// NOPBYTE 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;}