大神论坛

找回密码
快速注册
查看: 187 | 回复: 0

[原创] 嗨格式录屏大师VIP功能逆向破解(VMP带壳调试)

主题

帖子

0

积分

初入江湖

UID
593
积分
0
精华
威望
0 点
违规
大神币
68 枚
注册时间
2023-09-16 15:10
发表于 2024-03-18 22:19
本帖最后由 星空~夜影 于 2024-03-18 22:19 编辑

一、软件介绍
众所周知,Windows系统自带的截图、录频功能很难用,这么多年了一直没改进。截图在聊天软件中基本都自带了,做得很好而且可以免费使用,这倒不需担心。

但屏幕录制功能大多需要付费,例如WPS截图功能免费,但录频要开通会员才能使用。本文将讲解一款专业录频软件的VIP验证过程,在不充值的情况下,每次只能
录制1分钟且带有水印,几乎等于没法用,就是想让你充钱!在开通会员之后才能解锁全部功能,设置选项里内容丰富,适合用来录频。因为软件带了VMP壳,
不方便修改原可执行文件,可以制作内存补丁来绕过VIP验证。

友情提示:阅读本文需要有X64汇编基础,了解x64dbg调试器的使用方法。


二、查壳+分析目录结构
ExeInfo 查壳显示 *** x64 Unknown Packer-Protector , 10 sections - CRC Set -  , Overlay :  Signed
Die  查壳显示 保护器: VMProtect(2.XX-3.XX) ,签名工具: Windows Authenticode(2.0)[PKCS #7]

由此确定本程序使用VMP加壳,还有两点可以证明:
(1)对程序添加补丁后保存打开时出现错误弹窗,这段内容是VMP的特有标记,并不是系统自带的出错提示。
"File corrupted!. This program has been manipulated and maybeit's infected by a Virus or cracked. This file won't work anymore."
(2)先把调试器的各种隐藏插件关掉,然后运行此软件出现错误弹窗。
"A debugger has been found running in your system.Please,unload it from memory"

安装目录中发现:
(1)sciter.dll , UIBase.dll,说明界面是用Web方式开发的,UIBase中的一些GUI函数尤其值得注意,可以下API断点帮助分析。
(2)log4z.dll, LogServer.dll  说明程序有写入日志的行为,因为调用此类函数时要传入字符串,所以可以从明文中获取一些线索。
(3)libMediaCam64.dll, libFFmpeg64.dll , libcurl.dll 等大量多媒体和网络库,推测业务逻辑是用C++写的,调用这些开源库。


接下来开始调试,以管理员身份运行x64dbg,开启HyperHide插件所有选项,等程序运行后再附加上去。不要使用调试器直接运行程序,因为程序启动时
执行VMP壳的检测代码,在函数头添加软件断点之类的操作会被发现,导致报错退出。通过后面的分析,我们知道程序并没有对关键验证代码进行混淆,
加密的代码段反而是无关紧要的,说明软件开发者不太会用VMP。存在的干扰项只有VMP自带的反调试和防止修改文件。反调试用插件绕过,防修改用
内存补丁绕过,技术难度不高。经测试,ScyllaHide插件不行,会导致程序操作后卡住。建议使用虚拟机安装Win10系统在上面调试。


接下来有三种方法分析:字符串搜索、暂停法、API断点法。(后两个方法暂时先不写,看看评论区反馈如何)


三、字符串搜索
记录关键字符串:“登录”、“注册”、“试用”、“VIP”、“开通”、“特权”,依次搜索,为了节省文章篇幅,我就不一个个演示了。
有些人不知道如何在指定模块中搜索字符串,这里说一下。如果搜索所有用户模块太费时间,之前分析知道程序使用了很多开源库,这里面的字符串对我们没用。
附加进程后CPU页面停留在ntdll模块,系统模块的字符串我们也不关心。我们要在符号页面搜索模块名,右键在反汇编中转到,然后在新页面中右键搜索,如下图所示:

大部分字符串是界面初始化时加载的内容,并没有关联跳转和比较,对分析没有帮助。看到一处关键提示:“抱歉,您还不是VIP用户.......”,说明软件中有对应功能,
点击后如果不是VIP则弹窗。究竟是哪个功能呢?一番尝试后发现,设置页面中的图片水印功能会触发此弹窗,如下图所示

在所有"*不是VIP*"处下断点,回到软件设置图片水印,但没有触发任何中断。看来这些字符串也是初始化操作,并不是实际会执行到的代码片段。
字符串下面有个call调用,进入到此函数里面下断点有意外发现。当设置图片水印时,软件中断三次,最后一次中断后会弹窗,中断时分析RIP周围代码没有任何线索。

上面几个函数在UIBase.dll中,功能是设置窗口位置、模态、显示等,如果执行到此处代码就说明用户不是VIP,程序准备显示弹窗。
所以向下找exe模块的函数,跳转到此处,如下图:

先把之前下的断点全部删除,转而在“不是VIP弹窗”的call处下断点,看看程序是如何进入到这一步的。当设置图片水印时,软件只中断一次,说明位置找得很准确!
如下图,在这两处下断点,发现程序没有进行跳转,顺着往下执行,有一处关键比较,即 cmp eax, 4 , eax的值是上面函数的返回值。如果等于4就跳转
此时我没有登录,eax值为1。当我登录后,eax值为2。这就很有意思了,上面那个函数返回的是个枚举变量,和用户信息密切相关,把这个函数叫做疑似验证函数。

进入疑似验证函数,如下图,解读出以下信息:
(1)rdx 作为参数转递局部变量的地址,即 rsp+20
(2)调用真正的验证函数,此函数会改写 rsp+20 的内容
(3)eax 的值就是 rsp+20 的内容(枚举用户状态),判断是否登录

不再深入验证函数了,看看还有哪些地方会调用验证函数,右键函数头地址,查找引用->选定的地址,发现有这么多地方调用了验证函数。到每一处去看看!

很多调用处都会把函数返回值eax与4做比较,我猜测4代表VIP身份的枚举量。修改验证函数头,直接返回4。继续运行,再次设置一遍,发现可以使用了!
屏幕录制时也不会出现最开始的弹窗,说明修改成功!

四、修改方案
代码地址为 hirecmaster.exe+2EA60,把函数头修改为

mov eax, 4 
ret

能不能使用补丁保存为新的可执行文件? 答案是不行! VMP壳启动时会校验文件的完整性,如果发现有修改就报错退出,所以可以编写代码制作内存补丁,
等程序初始化完成后再修改代码段。我给出了参考代码,有些地方写得不完善,可能还要改一下。

#include <windows.h>
#include <psapi.h>
#include <stdio.h>

#define HeaderBytesCount 6

int main()
{
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
si.cb = sizeof(si);

// Start the process.
if( !CreateProcess(L"C:/Program Files (x86)/Auntec/HiRecMasterLY/HiRecMaster.exe", // No module name (use command line)
NULL, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0,
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%lu).\n", GetLastError() );
return 1;
}

// Wait the program init
Sleep(1000);
printf( "PID=%lu\n", pi.dwProcessId );
SuspendThread(pi.hThread);

// Find EXE module
HMODULE hMods[1024];
DWORD cbNeeded;
void *lpBase = NULL;

if(EnumProcessModulesEx(pi.hProcess, hMods, sizeof(hMods), &cbNeeded, LIST_MODULES_64BIT))
{
printf("module: %llu\n", cbNeeded / sizeof(HMODULE));
TCHAR szModName[MAX_PATH];
MODULEINFO modInfo;
for (int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
{
// Get the full path to the module's file.

if (GetModuleBaseName(pi.hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
{
if (wcscmp(szModName, L"HiRecMaster.exe") == 0)
{
if (GetModuleInformation(pi.hProcess, hMods[i], &modInfo, sizeof(modInfo)))
{
lpBase = modInfo.lpBaseOfDll;
}
break;
}
}
}
}

// Find the verify function
if (lpBase) {
void *lpFunction = (char*)lpBase + 0x2EA60;
printf("lpBase: %p \n lpFunction: %p \n", lpBase, lpFunction);

char header[HeaderBytesCount] = {0};
char target[HeaderBytesCount] = {0x40, 0x53, 0x48, 0x83, 0xEC, 0x40};
char replace[HeaderBytesCount] = {0xB8, 0x04, 0x00, 0x00, 0x00, 0xC3};
SIZE_T cbReaded;
SIZE_T cbWritten;
if (ReadProcessMemory(pi.hProcess, lpFunction, header, sizeof(header), &cbReaded) && cbReaded == HeaderBytesCount)
{
if (memcmp(header, target, HeaderBytesCount) == 0)
{
printf("find target \n");
if (WriteProcessMemory(pi.hProcess, lpFunction, replace, HeaderBytesCount, &cbWritten) && cbWritten == HeaderBytesCount)
{
printf("replaced \n");
}
}
}
}
ResumeThread(pi.hThread);
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
system("pause");
return 0;
}


注:若转载请注明大神论坛来源(本贴地址)与作者信息。

返回顶部