因为蜜汁自信导致我在短短两天内重装了7次系统,导致Everedit当年的注册码生成次数耗尽,所以想着先把试用限制过了凑合着用到明年。

1.分析

从4.0版本开始授权文件就没有保存在本地的选项了,都是保存在注册表里,试用限制也是如此,先跟一下。

其实都不用查壳都知道是vmp,先拉到x64dbg里面对(RegQueryValueExW)跨模块调用里面的关键函数下断:

跑起来以后断下了:

RDX应该是第二个参数: lpValueName(在x64下对函数的调用都是优先使用寄存器的,第一个参数是RCX),license不是我们想要的,继续跑。F9以后直接跑飞了,说明试用限制的call被加密了。直接对kernelbase.RegQueryValueExW这个函数下断,并记录他的RBX。跑了一遍以后发现了一个可疑的字符串:

跟踪他的来源,发现调用果然被加密了:

但是我们的目的已经达到了,打开注册表编辑器,看看这个项到底有什么玄机:

我觉得这个默认项很像时间戳啊,于是转换之:

5ECCEFBD -> 1590489021 -> 2020-05-26 18:30:21

那我们把试用条件改成今天0点试试:

2020-08-10  00:00:00 -> 1596988800 -> 5F301D80

发现还是提示过期,尝试将Value这个值删除,能正常打开了。

分析部分就到此结束了,下面开始敲代码

2.编码

采用劫持导入表hook的方案。

由前面的分析已经可以大致确定几个关键点了:

RegQueryValueExW

L"ZQBKAF8AMQA0ADIANGA4"

由于我们并没有去找机器码的算法,所以要做一些额外的工作。

大致思路如下:hook advapi32.RegOpenKeyW获取项的名称和HKey用于比对。

hook kernelbase.RegQueryValueExW 欺骗程序,告诉它:值“Value”并不存在;生成一个合法的“时间点”,然后改写函数的参数。

dllmain.cpp:// dllmain.cpp : 定义 DLL 应用程序的入口点。

#include "framework.h"

#include "DllModule.h"

extern "C" __declspec(dllexport) void Out();

void Out()

{

OutputDebugStringW(L"Out");

}

namespace

{

bool is_init = false;

}

BOOL APIENTRY DllMain(HMODULE hModule,

DWORD  ul_reason_for_call,

LPVOID lpReserved

)

{

if (DLL_PROCESS_ATTACH == ul_reason_for_call)

{

UNREFERENCED_PARAMETER(lpReserved);

DisableThreadLibraryCalls(hModule);

if (is_init)

{

return TRUE;

}

if (nullptr == g_DMod)

{

g_DMod = std::make_unique();

}

g_DMod->Attach();

is_init = true;

}

else if (DLL_PROCESS_DETACH == ul_reason_for_call)

{

if (nullptr == g_DMod)

{

return TRUE;

}

g_DMod->Detach();

if (is_init)

{

is_init = false;

}

}

return TRUE;

}

创建一个名为“Out”的导出函数用于导入表劫持。

DllModule.h:#pragma once

#include

#include

class DllModule

{

public:

DllModule() = default;

virtual ~DllModule() = default;

static void Attach();

static void Detach();

private:

};

using DllModulePtr = std::unique_ptr;

extern DllModulePtr g_DMod;

DllModule.cpp:#include "DllModule.h"

#include "hooks.h"

DllModulePtr g_DMod;

void DllModule::Attach()

{

hooks::Install();

}

void DllModule::Detach()

{

hooks::UnInstall();

}

hooks.cpp:#include "hooks.h"

#include "date_time.h"

#include

#include

#include

#include

#include

#include

#include

#pragma comment(lib,"advapi32.lib")

namespace

{

int32_t g_reg_open_key_w_call_count = 0;

DWORD g_value_length = 0;

PHKEY g_phkey = nullptr;

bool g_is_reg_open_key_w_uninstall = false;

bool g_is_reg_query_value_w_uninstall = false;

std::wstring g_sub_key;

}

namespace hooks

{

namespace hook_t

{

base::hook::hook_t RegOpenKeyW;

base::hook::hook_t RegQueryValueExW;

}

namespace real

{

uintptr_t RegOpenKeyW = 0;

uintptr_t RegQueryValueExW = 0;

}

namespace fake

{

static LSTATUS

APIENTRY

RegQueryValueExW(

_In_ HKEY hKey,

_In_opt_ LPCWSTR lpValueName,

_Reserved_ LPDWORD lpReserved,

_Out_opt_ LPDWORD lpType,

_Out_writes_bytes_to_opt_(*lpcbData, *lpcbData) __out_data_source(REGISTRY) LPBYTE lpData,

_When_(lpData == NULL, _Out_opt_) _When_(lpData != NULL, _Inout_opt_) LPDWORD lpcbData

)

{

static bool only_call_once = false;

auto ret_val = base::std_call(\

real::RegQueryValueExW, \

hKey, lpValueName, lpReserved, \

lpType, lpData, lpcbData);

if (only_call_once)

{

return ret_val;

}

//ERROR_FILE_NOT_FOUND

if (nullptr != lpValueName)

{

std::wstring_view ValueName{ lpValueName };

if (ValueName == xorstr_(L"Value"))

{

const auto ret = ERROR_FILE_NOT_FOUND;

return ret;

}

}

if (nullptr == g_phkey || nullptr == hKey)

{

return ret_val;

}

if (INVALID_HANDLE_VALUE == hKey)

{

return ret_val;

}

if (TRUE == IsBadReadPtr(g_phkey, sizeof(HKEY)))

{

return ret_val;

}

if (*g_phkey != hKey)

{

return ret_val;

}

if (0 == g_value_length)

{

if (nullptr != lpcbData)

{

if (FALSE == IsBadReadPtr(lpcbData, sizeof(DWORD)))

{

g_value_length = *lpcbData;

OutputDebugStringEx(L"DEBUG_INFO | g_value_length: %d", g_value_length);

}

}

}

if (nullptr != lpData)

{

if (FALSE == IsBadReadPtr(lpData, g_value_length))

{

const auto arr_size = static_cast(g_value_length);

auto& arr = lpData;

ev_date_time::DateTime d;

auto time = d.Gen();

auto str = d.GenString();

OutputDebugStringEx("DEBUG_INFO | str: %s", str.c_str());

memcpy(arr, &time, 4);

//for (size_t i = 0; i

//{

//OutputDebugStringEx(L"DEBUG_INFO | arr[i]: %X", arr[i]);

//}

only_call_once = true;

UnInstall();

return ret_val;

}

}

return ret_val;

}

static LSTATUS

APIENTRY

RegOpenKeyW(

_In_ HKEY hKey,

_In_opt_ LPCWSTR lpSubKey,

_Out_ PHKEY phkResult

)

{

g_reg_open_key_w_call_count += 1;

auto ret_val = base::std_call(real::RegOpenKeyW, hKey, lpSubKey, phkResult);

if (g_reg_open_key_w_call_count

{

return ret_val;

}

if (!g_is_reg_open_key_w_uninstall)

{

if (nullptr != hook_t::RegOpenKeyW)

{

base::hook::uninstall(&hook_t::RegOpenKeyW);

g_is_reg_open_key_w_uninstall = true;

}

}

if (nullptr == lpSubKey)

{

return ret_val;

}

//如果能取到

const std::wstring sub_key{ lpSubKey };

const std::wstring_view sub_key_front{ xorstr_(L"Software\\Classes\\") };

auto start_pos = sub_key.find(sub_key_front);

//找不到就返回

if (std::wstring::npos == start_pos)

{

return ret_val;

}

const auto sub_key_front_length = sub_key_front.length();

start_pos += sub_key_front_length;

OutputDebugStringEx(L"DEBUG_INFO | start_pos: %d", start_pos);

const auto key_length = sub_key.length() - sub_key_front.length();

//机器码长度(?)应为20个

//e.g.: L"Software\\Classes\\ZQBKAF8AMQA0ADIANGA4"

if (20 != key_length)

{

return ret_val;

}

OutputDebugStringEx(L"DEBUG_INFO | sub_key: %s", sub_key.c_str());

auto key{ sub_key.substr(start_pos,20) };

OutputDebugStringEx(L"DEBUG_INFO | key: %s", key.c_str());

if (g_sub_key.empty())

{

g_sub_key = sub_key;

}

if (nullptr == g_phkey)

{

g_phkey = phkResult;

}

return ret_val;

}

}

void Install()

{

if (0 != real::RegOpenKeyW)

{

return;

}

auto* const adv_api_32 = GetModuleHandleW(xorstr_(L"advapi32.dll"));

if (nullptr == adv_api_32)

{

return;

}

real::RegOpenKeyW = reinterpret_cast(GetProcAddress(adv_api_32, xorstr_("RegOpenKeyW")));

if (0 == real::RegOpenKeyW)

{

return;

}

base::hook::install(static_cast(&real::RegOpenKeyW), \

reinterpret_cast(fake::RegOpenKeyW), &hook_t::RegOpenKeyW);

auto* const kernel_base = GetModuleHandleW(xorstr_(L"kernelbase.dll"));

if (nullptr == kernel_base)

{

return;

}

real::RegQueryValueExW = reinterpret_cast(GetProcAddress(kernel_base, xorstr_("RegQueryValueExW")));

if (0 == real::RegQueryValueExW)

{

return;

}

base::hook::install(static_cast(&real::RegQueryValueExW), \

reinterpret_cast(fake::RegQueryValueExW), &hook_t::RegQueryValueExW);

}

void UnInstall()

{

if (nullptr == hook_t::RegQueryValueExW)

{

return;

}

if (g_is_reg_query_value_w_uninstall)

{

return;

}

base::hook::uninstall(&hook_t::RegQueryValueExW);

g_is_reg_query_value_w_uninstall = true;

}

}

detour RegOpenKeyW的流程大致如下:使用一个全局静态变量g_reg_open_key_w_call_count记录其被调用的次数。

当次数为3的时候进入我们的流程。

找到关键项并记录、记录HKey用于比对。

卸载hook。

detour RegQueryValueExW的流程大致如下:

1. 定一个静态局部变量only_call_once用于确保流程只执行一次。

2. 先判断lpValueName是不是L“Value”,若是,直接返回ERROR_FILE_NOT_FOUND告诉程序不存在这个项。

3.调用原函数。

4.用在detour RegOpenKeyW中获得的 HKEY和sub_key确保当前流程是读取试用起始日期。

5.获取默认值的长度。

6.获取由函数填充的lpData。

7.生成一个合法的日期,然后替换它。

date_time.h:#pragma once

#include

namespace ev_date_time

{

using namespace boost::gregorian;

class DateTime

{

public:

DateTime();

~DateTime() = default;

date GetNow() const;

static date::ymd_type GetTodayBase();

static boost::posix_time::ptime GetToDay();

int Gen() const;

std::string GenString() const;

private:

date now_;

};

}

date_time.cpp:#include "date_time.h"

namespace ev_date_time

{

DateTime::DateTime()

:now_(day_clock::universal_day())

{

}

date DateTime::GetNow() const

{

return now_;

}

date::ymd_type DateTime::GetTodayBase()

{

return day_clock::universal_day_ymd();

}

boost::posix_time::ptime DateTime::GetToDay()

{

const auto base = GetTodayBase();

const boost::posix_time::ptime p(date(base.year, base.month, base.day));

return p;

}

int DateTime::Gen() const

{

auto base = to_time_t(GetToDay());

return static_cast(base);

}

std::string DateTime::GenString() const

{

auto base = to_time_t(GetToDay());

return std::to_string(base);

}

}

大致阐述一下思路:

使用boost的day_clock::universal_day_ymd();获取当前的日期(精确到天)。

使用boost::posix_time::ptime创建“今天0点”这个时间点(有bug,东8区要减去8,不过无伤大雅)。

使用to_time_t()将它转换为unix时间戳。

3.总结

麻雀虽小,五脏俱全。

最后于 2020-8-12 17:04

被黑洛编辑

,原因:

上传的附件:

base.zip

(2.53kb,32次下载)

everedit 格式化json_[原创]Everedit的试用限制绕过相关推荐

  1. 格式化json_在Spring Boot中格式化JSON日期

    1.概述 在本教程中,我们将展示如何在Spring Boot应用程序中格式化JSON日期字段. 我们将探讨使用Jackson格式化日期的各种方法,它被Spring Boot用作默认的JSON处理器. ...

  2. thinkphp json_原创干货 | Thinkphp序列化合总

    听说转发文章 会给你带来好运 最近Thinkphp几个版本都出了反序列化利用链,这里集结在一起,下面是复现文章,poc会放在最后01Thinkphp5.1.37 环境搭建 composercreate ...

  3. vue日期格式化实例

    这段代码是我常用来格式化日期用的,很好用. Date.prototype.toLocaleString = function () { // 重写日期函数格式化日期return `${this.get ...

  4. 格式化字符串漏洞利用

    学习资料: https://ctf-wiki.github.io/ctf-wiki/pwn/linux/fmtstr/fmtstr_exploit/                        ht ...

  5. 驱动专题:第五章MTD及Flash驱动 1.mtd框架分析

    MTD(memory technology device):内存技术设备,是linux用于描述ROM,NAND,NOR等设备的子系统的抽象,MTD设备可以按块读写也可以按字节读写,也就是说MTD设备既 ...

  6. 【工作效率】Windows平台提升工作效率常用软件

    1. 资源管理工具 Clover(给资源文件添加像chrome标签页) : http://cn.ejie.me/ Directory Opus : http://www.appcgn.com/dire ...

  7. 学习PWN一个月后能做什么?

    本文为笔者初学pwn的知识梳理,如有错误之处,敬请斧正. 栈溢出漏洞 原理 栈是一种后进先出的数据结构.在调用函数的时候,都会伴随着函数栈帧的开辟和还原(也称平栈).栈结构示意图如下(以32位程序为例 ...

  8. ctf web5 练习_Writeup - CTF - WEB - 练习平台(123.206.31.85)

    签到题 这个直接加群就好了 Web2 打开这个页面,面对铺天盖地而来的滑稽,直接F12查看源代码 文件上传测试 虽然知道题目没那么简单,但是先上传一个PHP文件,看一下反应 点击上传后查看页面的返回情 ...

  9. everedit选择_EverEdit(文本编辑器)

    EverEdit是一个快速.轻量级和易于扩展的集文本.源代码编辑于一身的高性能纯文本编辑器.除了大幅度加强的文本编辑能力之外,EverEdit也为网页作者.程序员和管理人员提供了大量的可定制特性,可以 ...

  10. python字符串函数运算_Python入门教程2. 字符串基本操作【运算、格式化输出、常用函数】 原创...

    前面简单介绍了python基本运算,这里再来简单讲述一下Python字符串相关操作 1. 字符串表示方法 >>> "www.jb51.net" #字符串使用单引号 ...

最新文章

  1. 易语言单窗口单ip软件源码_好人多窗口同步器:多台电脑同步视频演示
  2. 《数据结构与算法》实验报告——快速排序
  3. 【JavaEE企业应用实战学习记录】struts配置文件详细解析
  4. android图片加载库Glide
  5. [Leetcode]-containsNearbyDuplicate
  6. NGUI中UILabel使用url标签的一个bug
  7. [css] css怎样使每个字符宽度一样?
  8. 第九十一期:架构设计常用到的10种设计模式,你都知道吗?
  9. emmc固件开发_UP2开发板简易开箱(二)
  10. 探索篇 | 接口字段容错测试(三)
  11. 使用redis批量生成主键(订单)Id
  12. swift语言 编写 ios开发 第一个程序hello world!
  13. 《SEO的艺术(原书第2版)》——3.3 理解搜索引擎流量和用户意图
  14. [问题探讨]ECharts实现带钓鱼岛和南海诸岛的中国(China)地图
  15. idea数据库管理工具配置连接数据库
  16. 101平衡模式 DIR的理解
  17. less 或 scss 覆盖UI组件样式并集选择器使用
  18. 2021最新 深圳互联网公司排名
  19. 魔方世界服务器文件,魔方世界服务器指令 | 手游网游页游攻略大全
  20. 字节跳动自研万亿级图数据库 图计算实践

热门文章

  1. Android系统sdcard目录
  2. Vmware虚拟机ikuai路由配置
  3. 黑屏出现An operating system wasn't found.解决方案
  4. 时间戳——微信保存视频时发现的问题
  5. 阿里云高校训练营-class6-感悟
  6. Redhawk 如何gds2def?
  7. 搭建PHP网站开发环境
  8. 论文阅读 | Tackling Adversarial Examples in QA via Answer Sentence Selection
  9. 《墨菲定律》——决策中的学问
  10. 聊聊小程序第三方登录