Windows桌面水印去除工具Universal Watermark Disabler原理分析及实现

这篇具有很好参考价值的文章主要介绍了Windows桌面水印去除工具Universal Watermark Disabler原理分析及实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.背景

  最近做驱动开发,开启了系统测试模式,于是桌面的右下角就有一个水印,如下图:

桌面水印程序,Windows系统,windows,c++

  测试了网上修改注册表方法不起作用,最后找到一款工具Universal Watermark Disabler可以把水印去除掉。于是对其原理有些兴趣,就有了相关的分析及编程实现。

2、相关分析

2.1 相关行为分析

  使用Process Monitor抓取相关操作,发现可用的操作如下:

  2.1.1 创建了一个名为painter_x64.dll的文件

桌面水印程序,Windows系统,windows,c++

  2.1.2 修改为注册表 HKCR\CLSID\{ab0b37ec-56f6-4a0e-a8fd-7a8bf7c2da96}\InProcServer32的值

桌面水印程序,Windows系统,windows,c++

  注册表相应的原值现为%SystemRoot%\system32\explorerframe.dll, 而修改后的值为如下

桌面水印程序,Windows系统,windows,c++

  2.1.3 大致结论

  注册表项的相关文件和桌面进程相关,应该是在桌面进程启动时加载了相应的dll文件,而该工具替换成painter_x64.dll,该dll做了相应的功能来实现水印过滤。结下来应该分析该dll的功能。

2.2 分析painter_x64.dll

  直接上IDA看相关的功能。

  2.2.1 主入口代码如下:

BOOL __stdcall DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
  HMODULE v4; // rbx
  HMODULE v5; // rax
  BOOL (__stdcall *ExtTextOutW)(HDC, int, int, UINT, const RECT *, LPCWSTR, UINT, const INT *); // rax
  HMODULE v7; // rax
  int (__stdcall *LoadStringW)(HINSTANCE, UINT, LPWSTR, int); // rax
  const CHAR *v9; // rcx
  HMODULE v10; // rax

  if ( fdwReason == 1 )
  {
    OutputDebugStringA("Loaded");
    v4 = GetModuleHandleW(L"shell32.dll");
    if ( v4 )
    {
      v5 = GetModuleHandleW(L"gdi32.dll");
      ExtTextOutW = (BOOL (__stdcall *)(HDC, int, int, UINT, const RECT *, LPCWSTR, UINT, const INT *))GetProcAddress(v5, "ExtTextOutW");
      if ( ExtTextOutW )
        sub_180001000("gdi32.dll", (__int64)ExtTextOutW, (__int64)sub_180001120, (__int64)v4);
      v7 = GetModuleHandleW(L"api-ms-win-core-libraryloader-l1-2-0.dll");
      LoadStringW = (int (__stdcall *)(HINSTANCE, UINT, LPWSTR, int))GetProcAddress(v7, "LoadStringW");
      if ( LoadStringW )
      {
        v9 = "api-ms-win-core-libraryloader-l1-2-0.dll";
LABEL_9:
        sub_180001000(v9, (__int64)LoadStringW, (__int64)sub_180001100, (__int64)v4);
        goto LABEL_10;
      }
      v10 = GetModuleHandleW(L"api-ms-win-core-libraryloader-l1-1-1.dll");
      LoadStringW = (int (__stdcall *)(HINSTANCE, UINT, LPWSTR, int))GetProcAddress(v10, "LoadStringW");
      if ( LoadStringW )
      {
        v9 = "api-ms-win-core-libraryloader-l1-1-1.dll";
        goto LABEL_9;
      }
    }
LABEL_10:
    DisableThreadLibraryCalls(hinstDLL);
  }
  return 1;
}

        2.2.2 sub_180001000功能的代码如下:

__int64 __fastcall sub_180001000(LPCSTR lpString2, __int64 a2, __int64 a3, __int64 a4)
{
  _DWORD *v8; // rbx
  unsigned int i; // eax
  __int64 *v10; // rbx
  DWORD flOldProtect; // [rsp+40h] [rbp+8h] BYREF

  if ( !lpString2 || !a2 || !a3 )
    return 0i64;
  v8 = (_DWORD *)(a4 + *(unsigned int *)(*(int *)(a4 + 60) + a4 + 144));
  for ( i = v8[3]; i; v8 += 5 )
  {
    if ( !lstrcmpiA((LPCSTR)(a4 + i), lpString2) )
      break;
    i = v8[8];
  }
  if ( !v8[3] )
    return 0i64;
  v10 = (__int64 *)(a4 + (unsigned int)v8[4]);
  if ( !*v10 )
    return 0i64;
  do
  {
    if ( *v10 == a2 )
      break;
    ++v10;
  }
  while ( *v10 );
  if ( !*v10 )
    return 0i64;
  VirtualProtect(v10, 8ui64, 0x40u, &flOldProtect);
  *v10 = a3;
  VirtualProtect(v10, 8ui64, flOldProtect, &flOldProtect);
  return 1i64;
}

  2.2.3 sub_180001120代码如下:

BOOL __fastcall sub_180001120(HDC a1, int a2, int a3, UINT a4, const RECT *a5, const WCHAR *a6, UINT a7, const INT *a8)
{
  BOOL result; // eax

  if ( a4 || !a7 )
    result = ExtTextOutW(a1, a2, a3, a4, a5, a6, a7, a8);
  else
    result = 1;
  return result;
}

2.3 结论

  通过分析加猜测(后边也证实了)相关逻辑是启动进程时加载此dll,此dll在加载时进程导入表Hook,对shell32.dll中导入的gdi32.dll的ExtTextOutW函数进行挂钩,然后过滤相关字符串。

3、代码实现

  完整代码如下:

  • 头文件 
typedef BOOL(*EXTTEXTOUTW)(HDC hdc, int x, int y, UINT options, RECT* lprect, LPCWSTR lpString, UINT c, INT* lpDx);
typedef int (*GETIAT)(PVOID, BOOLEAN, USHORT, PULONG);
typedef int(__fastcall* LOADSTRINGW)(HINSTANCE, UINT, LPWSTR, int);
extern HMODULE hShell32;
extern HMODULE hGdi32;
extern HMODULE hDbgHelp;
extern EXTTEXTOUTW pExtTextOutW;
extern GETIAT pGetIAT;

void InitializeHook();
BOOL HookFunction(LPCSTR szDllName, PVOID pFuncAddress, PVOID pHookFuncAddess, HMODULE hMod);
BOOL __stdcall MyExtTextOutW(HDC hdc, int x, int y, UINT options, RECT* lprect, LPCWSTR lpString, UINT c, INT* lpDx);
int __fastcall MyLoadStringW(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int cchBufferMax);
  • cpp文件
#include "pch.h"
#include "Implement.h"
#include <atlstr.h>
#include <DbgHelp.h>

#pragma comment(lib, "dbghelp.lib")
#pragma comment(linker, "/EXPORT:DllCanUnloadNow=explorerframe.DllCanUnloadNow,@1")
#pragma comment(linker, "/EXPORT:DllGetClassObject=explorerframe.DllGetClassObject,@2")

HMODULE hShell32 = NULL;
HMODULE hGdi32 = NULL;
HMODULE hDbgHelp = NULL;
EXTTEXTOUTW pExtTextOutW = NULL;
GETIAT pGetIAT = NULL;

void InitializeHook()
{
	do 
	{
		hShell32 = GetModuleHandleW(L"shell32.dll");
		if (hShell32 == NULL)
		{
			break;
		}
		hGdi32 = GetModuleHandleW(L"gdi32.dll");
		if (hGdi32 == NULL)
		{
			break;
		}
		pExtTextOutW = (EXTTEXTOUTW)GetProcAddress(hGdi32, "ExtTextOutW");
		if (pExtTextOutW == NULL)
		{
			break;
		}
		HMODULE hModuleApiMsWinCoreLibraryloader_l1_2_0 = GetModuleHandleW(L"api-ms-win-core-libraryloader-l1-2-0.dll");
		LOADSTRINGW pLoadStringW = (LOADSTRINGW)GetProcAddress(hModuleApiMsWinCoreLibraryloader_l1_2_0, "LoadStringW");
		if (pLoadStringW)
		{
			HookFunction("api-ms-win-core-libraryloader-l1-2-0.dll", pLoadStringW, MyLoadStringW, hShell32);
		}
		else
		{
			HMODULE hModuleApiMsWinCoreLibraryloader_l1_1_1 = GetModuleHandleW(L"api-ms-win-core-libraryloader-l1-1-1.dll");
			pLoadStringW = (LOADSTRINGW)GetProcAddress(hModuleApiMsWinCoreLibraryloader_l1_1_1, "LoadStringW");
			if (pLoadStringW)
			{
				HookFunction("api-ms-win-core-libraryloader-l1-1-1.dll", pLoadStringW, MyLoadStringW, hShell32);
			}
		}
		BOOL OK = HookFunction("gdi32.dll", pExtTextOutW, MyExtTextOutW, hShell32);
	} while (false);
}

int __fastcall MyLoadStringW(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int cchBufferMax)
{
	if (uID - 62000 <= 1)
	{
		return 0;
	}
	else
	{
		return LoadStringW(hInstance, uID, lpBuffer, cchBufferMax);
	}
}

BOOL HookFunction(LPCSTR szDllName, PVOID pFuncAddress, PVOID pHookFuncAddess, HMODULE hMod)
{
	if ((szDllName == NULL) ||
		(pFuncAddress == NULL) ||
		(pHookFuncAddess == NULL) ||
		(hMod == NULL))
	{
		return FALSE;
	}

	ULONG ulSize = 0;
	PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor =
		(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(
			hMod, 
			TRUE,
			IMAGE_DIRECTORY_ENTRY_IMPORT,
			&ulSize);
	CStringA  strModuleName = "";
	while (pImportDescriptor->Name)
	{
		PSTR pszModuleName = (PSTR)((PBYTE)hMod + pImportDescriptor->Name);
		strModuleName = pszModuleName;
		if (strModuleName.CompareNoCase(szDllName) == 0)
		{
			break;
		}
		pImportDescriptor++;
	}
	
	if (strModuleName.GetLength() > 0)
	{
		PIMAGE_THUNK_DATA pThunk =
			(PIMAGE_THUNK_DATA)((PBYTE)hMod + pImportDescriptor->FirstThunk);

		while (pThunk->u1.Function)
		{
			PROC* ppfn = (PROC*)&pThunk->u1.Function;
			BOOL bFound = (*ppfn == pFuncAddress);

			if (bFound)
			{
				MEMORY_BASIC_INFORMATION mbi = { 0 };
				VirtualQuery(
					ppfn,
					&mbi,
					sizeof(MEMORY_BASIC_INFORMATION)
				);
				VirtualProtect(
					mbi.BaseAddress,
					mbi.RegionSize,
					PAGE_READWRITE,
					&mbi.Protect
				);
				*ppfn = ((PROC)pHookFuncAddess);
				VirtualProtect(
					mbi.BaseAddress,
					mbi.RegionSize,
					mbi.Protect,
					&mbi.Protect
				);
				return TRUE;
			}
			pThunk++;
		}
	}
	return FALSE;
}


BOOL __stdcall MyExtTextOutW(HDC hdc, int x, int y, UINT options, RECT* lprect, LPCWSTR lpString, UINT c, INT* lpDx)
{
	BOOL bResult = FALSE;
	//CString str = lpString;
	//if (str.Find(L"测试模式") != -1 ||
	//     str.Find(L"Windows ") != -1 ||
	//     str.Find(L"Build ") != -1)
	//{
	//	return TRUE;
	//}
	if ((options != 0) || (c == 0))
	{
		return ExtTextOutW(hdc, x, y, options, lprect, lpString, c, lpDx);
	}
	return  TRUE;
}

BOOL APIENTRY DllMain(HMODULE hModule,
	DWORD  ul_reason_for_call,
	LPVOID lpReserved
)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	{
		InitializeHook();
		DisableThreadLibraryCalls(hModule);
	}
	break;
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

4、PS

  关于自定义ExtTextOutW,用上边代码可以去除一般水印,也可以使用函数中注释的代码去除指定水印。

BOOL __stdcall MyExtTextOutW(HDC hdc, int x, int y, UINT options, RECT* lprect, LPCWSTR lpString, UINT c, INT* lpDx)
{
	BOOL bResult = FALSE;
	CString str = lpString;
	if (str.Find(L"测试模式") != -1) 
	{
		return TRUE;
	}
	return ExtTextOutW(hdc, x, y, options, lprect, lpString, c, lpDx);
}

  上边代码只把测试模式去掉,效果如下

桌面水印程序,Windows系统,windows,c++

  或者:

BOOL __stdcall MyExtTextOutW(HDC hdc, int x, int y, UINT options, RECT* lprect, LPCWSTR lpString, UINT c, INT* lpDx)
{
	BOOL bResult = FALSE;
	CString str = lpString;
	if (str.Find(L"测试模式") != -1 ||
	   str.Find(L"Windows ") != -1)
	{
		return TRUE;
	}
	return  ExtTextOutW(hdc, x, y, options, lprect, lpString, c, lpDx);;
}

  上边代码把测试模式、Windows都去掉,效果如下:

桌面水印程序,Windows系统,windows,c++

  或者:

BOOL __stdcall MyExtTextOutW(HDC hdc, int x, int y, UINT options, RECT* lprect, LPCWSTR lpString, UINT c, INT* lpDx)
{
	BOOL bResult = FALSE;
	CString str = lpString;
	if (str.Find(L"测试模式") != -1 ||
	   str.Find(L"Windows ") != -1||
	     str.Find(L"Build ") != -1)
	{
		return TRUE;
	}
	return  ExtTextOutW(hdc, x, y, options, lprect, lpString, c, lpDx);;
}

  以是代码把之前的三行水印都去除,效果如下:

桌面水印程序,Windows系统,windows,c++

5、特别注意

  完成相关开发后的dll要修改相应的注册表后重启explorer.exe进程起效,注册表修改的路径为HKEY_CLASSES_ROOT\CLSID\{ab0b37ec-56f6-4a0e-a8fd-7a8bf7c2da96}\InProcServer32 默认值。

         在不需要进行去除水印时应将注册表值修改回%SystemRoot%\system32\explorerframe.dll。文章来源地址https://www.toymoban.com/news/detail-642149.html

到了这里,关于Windows桌面水印去除工具Universal Watermark Disabler原理分析及实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 视频中的水印如何去除?教你几种简单去除视频水印方法

    视频中的水印如何去除掉呢?如果我们经常观看视频,可能会注意到一些视频上有水印。水印是在视频中嵌入的品牌标志或文字。这些水印可能会影响视频的观感,去除水印可以帮助我们在学习和研究方面更有效地使用视频资源。有时候,我们可能需要将视频插入到演示文稿

    2024年02月16日
    浏览(42)
  • 剪映怎么去除视频水印?分享这3个方法助你视频去除水印!

    如何在剪映中去除水印?剪映是一款广泛使用的短视频剪辑软件,但是有时我们使用的素材可能带有水印。今天我将分享三种方法,帮助你在剪映中去除水印。 方法一:放大视频画面 在剪映中导入视频后,你会发现视频的左上角和右下角有抖音号水印。单击视频素材。 选中

    2024年02月07日
    浏览(46)
  • 【flink番外篇】6、flink的WaterMark(介绍、基本使用、kafka的水印以及超出最大允许延迟数据的处理)介绍及示例(1) - 介绍

    一、Flink 专栏 Flink 专栏系统介绍某一知识点,并辅以具体的示例进行说明。 1、Flink 部署系列 本部分介绍Flink的部署、配置相关基础内容。 2、Flink基础系列 本部分介绍Flink 的基础部分,比如术语、架构、编程模型、编程指南、基本的datastream api用法、四大基石等内容。 3、

    2024年02月01日
    浏览(55)
  • 【flink番外篇】6、flink的WaterMark(介绍、基本使用、kafka的水印以及超出最大允许延迟数据的处理)介绍及示例 - 完整版

    一、Flink 专栏 Flink 专栏系统介绍某一知识点,并辅以具体的示例进行说明。 1、Flink 部署系列 本部分介绍Flink的部署、配置相关基础内容。 2、Flink基础系列 本部分介绍Flink 的基础部分,比如术语、架构、编程模型、编程指南、基本的datastream api用法、四大基石等内容。 3、

    2024年02月02日
    浏览(53)
  • 【教程】去水印开源工具Lama Cleaner在Windows的安装和使用

    Lama Cleaner是一款 开源且免费 的人工学习图片去水印程序(个人主要学习用途),没有图片分辨率限制(个人使用暂未发现),并且保存的图片质量很高(个人觉得跟原图差不多),还能下载处理后的图片到本地。 项目地址:https://github.com/Sanster/lama-cleaner 原作者:Sanster 截止

    2024年02月03日
    浏览(46)
  • js 视频水印去除

    参考文档:http://txapi.cn/api 收费 识别要解析的类型(需要收费) 不收费:(这边只说下大概实现思路,具体操作没试过,因为我们这边是通过接口python来实现的) 抖音去水印 逻辑: 通过短链获取到视频mid,通过mid获取到视频详情,再通过视频详情拿到视频地址,将有水印替

    2024年02月14日
    浏览(47)
  • python实战之去除视频水印&字幕

    获取资源链接:https://null119.lanzoul.com/b050jscbg         结果如下图所示:         python软件在官网下载即可,这里我们仅对如何批量安装包进行介绍,如下所示         注意:要求文件的分辨率一致,水印位置相同,否则无法进行批量操作。         打开命令行,

    2024年02月07日
    浏览(50)
  • 基于python实现去除视频的水印

    在终端下载相关依赖包 将要去除水印的视频放在video目录下,运行一下         用鼠标操作去除的部分,回车即可 去除了水印的视频输出到了output文件夹下 查看效果,还不错   

    2024年02月16日
    浏览(40)
  • 使用Java实现去除和屏蔽视频水印

    使用Java实现去除和屏蔽视频水印 在视频编辑和处理过程中,常常会遇到需要去除或屏蔽视频水印的需求。水印是一种在视频中插入的标识,通常用于版权保护或品牌展示。然而,有时候我们希望在编辑或分享视频时去除这些水印,以获得更干净和专业的效果。本文将介绍如

    2024年03月15日
    浏览(48)
  • 去除pdf/word的水印艺术字

    对于pdf中的水印如果无法去除水印,则先另存为word,然后再按下面办法处理即可: 查看宏,创建:删除艺术字 添加内容: 如下图,保存。 最后运行多次就行。 相关参考: word批量删除艺术字_起不好名字就不起了的博客-CSDN博客 Word2007版批量删除艺术字水印 - 知乎

    2024年02月07日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包