羽夏逆向破解日记簿——RunAsDate的实现原理分析
前言
RunAsDate
是一个小工具,允许您在指定的日期和时间运行程序,不过有人用它来破解有时间限制了。此实用程序不会更改计算机的当前系统日期和时间,但只会将指定的日期/时间注入所需的应用程序。该软件是个免费软件,可以通过 官网 下载。有一天想看看它到底怎么实现的。经过分析是通过注入dll
来Hook
几个关于时间获取API
实现的。32位的和64位的代码实现没啥区别,本篇以64位进行分析,32位感兴趣自行分析。
主角和工具
- Detect it easy 1.01
- IDA 7.5
- X64Dbg
- RunAsDate
探测
我们先到官网下载原汁原味的程序,如下图所示进行下载:
解压后,得到了3个文件:
运行该软件,界面如下:
为了检验工具的效果,先写一个获取时间的C
代码(随便一个语言就可,不过代码需要自己写),如下:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main()
{
time_t t;
time(&t);
struct tm _t;
errno_t err = localtime_s(&_t, &t);
err ? puts("获取时间失败!!!") : printf_s("%d/%0.2d/%0.2d\n", _t.tm_year + 1900, _t.tm_mon + 1, _t.tm_mday);
system("pause");
return 0;
}
编译运行,获取得到当前时间:
来试试工具有没有效果,注意把下图所示的红框框住的选项选中,否则没效果,然后点击运行,发现起作用:
初步分析
既然工具咋用已经探测完毕了,我们来进入分析环节。先用Detect it easy 1.01
探测一下:
是C++写的,且没有任何加壳,为逆向分析降低了足够的难度。直接拖到IDA
进行抄底。启动一个新进程的API函数有很多,有ShellExecuteEx
系列函数、ShellExecute
系列函数和CreateProcess
系例函数。我们都给下上断点,来看看它到底是用哪个函数启动的,设置好点击运行,断点断到CreateProcessW
,如下图所示。
通过堆栈定位可以定位到调用地址,如下图所示:
定位到IDA
中,然后大体分析一下函数,重命名一些函数方便进一步分析,并发现一些可疑函数,命名好名字,关键伪代码如下面几张图所示:
下图是执行上面子函数的主过程。有经验的一看就知道,这就是典型的远程线程注入过程。
什么是远程线程注入呢?首先你准备一个待注入的Dll
,假设名字为A.DLL
。如果加载一个Dll,常规的办法就是用LoadLibrary
函数加载。然而我是A
进程,想让B
进程调用函数,就必须启用一个线程,需要调用的API
就是CreateRemoteThread
函数,只能通过lpParameter
传递一个参数。它们的函数原型如下:
HANDLE WINAPI CreateRemoteThread(
__in HANDLE hProcess,
__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize,
__in LPTHREAD_START_ROUTINE lpStartAddress,
__in LPVOID lpParameter,
__in DWORD dwCreationFlags,
__out LPDWORD lpThreadId
);
HMODULE WINAPI LoadLibrary(
_In_ LPCTSTR lpFileName
);
而每一个进程中,LoadLibrary
函数地址都是一致的。故我需要通过一段ShellCode
,将一些参数聚合起来直接传给它,让它负责分析传来的参数并实现注入功能。而ShellCode
怎样写到B
进程呢?通过VirtualAllocate(Ex)
函数和WriteProcessMemory
函数配合将ShellCode
和待解析的参数一块写进去。从IDA
分析结果可知,ShellCode
就是sub_140006B3C
,我们来看一下:
为了方便阅读,伪C代码如下:
从ShellCode
很明显看出。a1
就是通过CreateRemoteThread
传来的参数。a1
的地址加40偏移
的值就是一个函数地址,在把a1
的地址加上64的偏移
作为参数传入得到返回值v2
。v3
应该是一个函数地址,通过a1
加上48的偏移
,把v2
和a1加上586的偏移
作为参数传入得到返回值v3
,如果返回值不为空调用v3
,把a1
加上620的偏移
作为参数进行传入。只从ShellCode
看不太出来是啥,如果有经验就应该大体能猜出来。具体分析一下它传过来的参数是如何包装的。
从上图发现*(lpFileName + 66)
就是所谓待注入进程调用ShellCode
的参数。而从Buffer
存储写进去,但遗憾的是,我压根不知道Buffer
里面的内容到底是啥,看前面的伪代码也看不出来,只看到它的首地址被清零。这个就是F5
插件的缺陷。它反编译成伪C代码不是准确的,甚至是错误的,比如函数调用的参数有时会有错误,或者直接JMPOUT
,还是看汇编准确。不过我们可以看一下Buffer
被IDA
识别为char
,但明显看到使用该变量的函数告诉咱们这个是大小至少为0x288
的char数组
。故我们可以看看Buffer
的堆栈来进行修正。
从堆栈可以明显看出所谓是fucs
就是属于Buffer
的,所以上面的部分就是给参数打包的过程。我们直接改Buffer
,将它改为char Buffer[288]
。然后重新F5
,看一下代码的变化:
反编译出来的伪C代码就看起来正常了,虽然看起来还是比较别扭,不过包装参数的过程比较明晰了。然后我们把它拖到X64Dbg
,来进行验证一下过程,我们先通过下VirtualAllocEx
断点获取它们返回的申请到的物理页虚拟首地址,把它记录下来。
然后在CreateRemoteThread
下断点,停住创建的待注入的程序。然后另起一个X64Dbg
附加上,直接看一下记录的地址的内容。首先我看的是参数部分,直接在内存窗口选好0x288
字节保存到文件,方便一一对应,如下图所示:
下图就是所谓的ShellCode
,在函数头部下一个断点:
然后放开RunAsDate
程序,被注入的程序就停在上一步下的断点上,然后我们一步一步的跟,看看调用的是什么函数,先跟到第一个,发现是LoadLibraryW
函数:
其次就是GetProcAddress
函数,用来获取Dll
中InitDate
函数地址:
然后校验获取是否成功,传参FILETIME
结构体调用InitDate
函数:
根据IDA和X64Dbg的分析,每个数据的对应如下图所示:
深入分析
通过初步分析我们知道了这个软件的基本原理。但功能实现全部在所谓的dateinjo1_64.dll
当中。我们可以在注入的程序时,直接从临时文件夹薅出来。在之前函数分析也知道它是直接把资源释放出来的,直接用资源编辑工具也能提取出来,这我就不继续描述了,直接开始分析。具体分析过程就不详细描述了,完全凭自己的正向开发经验,这个Dll很简单,最后命名好名字后如下图所示:
综上可以看出,它是通过对GetLocalTime
、GetSystemTime
、GetSystemTimeAsFileTime
这三个函数进行挂钩子。怎么挂钩子的可以在详细介绍一下:
可以看出,它是通过构造一个mov
和jmp+死地址
进行Hook
,感觉不直观,来看一下下面一个被RunAsDate
注入的被挂钩的函数:
通过上图,知道为什么代码要这样构造了吧?
总结与思考
RunAsDate
并不高大上,原理很简单,其实本质就是用了远程线程注入
+Hook
所有获取时间函数的API
的方式实现时间的控制。- 有些人利用
RunAsDate
,来破解一些软件时间使用限制。想要保护自己商业软件的合法权益,可以通过它的实现原理,检查是否程序模块有没有它的Dll
,有的话直接退出程序或者修复Hook
。也可以检查函数是否被Hook
的方式进行反制。 - 使用
IDA
时,不要过于依赖F5
,虽然直观方便,但它反编译出的伪C代码并不是完全正确的,甚至是错误的,如果想弄对必须进行修改调整。 - 软件的
Hash
值:EF847F60C02856AB013438D7A55A6CC1
。 - 64位的注入的Dll的IDA分析结果:蓝奏云下载 —— 密码:f854
羽夏逆向破解日记簿——RunAsDate的实现原理分析的更多相关文章
- 羽夏逆向指引—— Hook
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你的, ...
- CrackMe005-下篇 | 逆向破解分析 | 160个CrackMe(视频+图文)深度解析系列
作者:逆向驿站微信公众号:逆向驿站知乎:逆向驿站 CrackMe005,上篇说了具体方法,下篇来发逆向分析过程,看看老夫是如何得到上篇的具体方法的! 准备 [环境和工具] win7/xp虚拟机环境 C ...
- 跟羽夏学 Ghidra ——工具
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...
- 跟羽夏学 Ghidra ——引用
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...
- 跟羽夏学 Ghidra ——导航
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...
- 2018-2019-2 20165312《网络攻防技术》Exp1 PC平台逆向破解
2018-2019-2 20165312<网络攻防技术>Exp1 PC平台逆向破解 一.Exp1.1 直接修改程序机器指令,改变程序执行流程 知识要求:Call指令,EIP寄存器,指令跳转 ...
- 羽夏看Win系统内核——简述
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...
- 羽夏看Win系统内核——SourceInsight 配置 WRK
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...
- 羽夏看Win系统内核——系统调用篇
写在前面 此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...
随机推荐
- 【译】flutter中如何较好地实现隐藏和显示widget
通常情况下,显示有四种情况: 1.(visible)显示 2.(invisible)隐藏: 这种隐藏是指在屏幕中占据空间,只是没有显示.这种情况出现场景如:用带有背景色的Container Widge ...
- flutter添加启动图及设置启动时间
首先贴个官方的设置方法,看这里:https://flutterchina.club/assets-and-images/#%E6%9B%B4%E6%96%B0%E5%90%AF%E5%8A%A8%E9 ...
- c++与c#混合编程
C#写界面比较方便,而C++则擅长写算法,所以将两者结合起来将会加快程序的开发速度,并保证程序的质量.但C#与C++的混合编程有很多细节问题需要注意,下面简要列举一些并指出相应的解决办法. 1. 将本 ...
- linux中 ~ 表示的是什么目录?
~ 表示代码主目录,也就是当前登录用户的用户目录.比如:我登录用户是chencd ~~ 代表的就是 /home/chen/当然前提是有用户目录,如果没有/home/chen目录的话情况就比较多了.总之 ...
- C# 检测某版本VC++是否安装
一.根据微软的产品号GUID,调用msi.dll class Program { static void Main(string[] args) { if (GetProcuct("{GUI ...
- Go版本管理--处理不兼容
目录 1. 简介 2.能否引起不兼容的包 3.如何处理incompatible 1. 简介 Go module的版本选择机制,其中介绍了一个Module的版本号需要遵循v<major>.& ...
- Qt5之正则表达式
字符 描述 \ 将下一个字符标记为一个特殊字符.或一个原义字符.或一个 向后引用.或一个八进制转义符.例如,'n' 匹配字符 "n".'\n' 匹配一个换行符.序列 '\\' 匹配 ...
- 【详细、开箱即用】.NET企业微信回调配置(数据回调URL和指令回调URL验证)
前言: 前段时间因为公司业务需求,需要将微信小程序与企业微信对接通,也就是把小程序绑定到对应的企业微信账号下,在该企业微信的用户可以将该小程序绑定到工作台中,然后可以在工作台中打开该小程序并授权.不过 ...
- 移动端ios上下滑动翻页事件失效
移动端开发过程中,在添加上下滑动事件时候,引入了最常用的移动端库zepto.js及其touch模块,有一种现象,安卓的手机没有问题,上下滑动翻页很正常 :但是到了ios上面,好啊,上下滑动会出现弹性滚 ...
- JDK1.8源码(六)——java.util.ArrayList类
ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了Clonea ...