旁路保护:Reversing和重构受保护的dll
本帖最后由 linso 于 2017-3-8 11:13 编辑文章授权地址https://zhuanlan.zhihu.com/p/25571400
http://www.52pojie.cn/thread-584822-1-1.html
0x00 前言
本文将讲述如何绕过在实施中有一些缺陷的保护。
在这个例子中,我们会看到一个使用asprotect保护的dll,并使用一个简单的方法来重新创建它。
由于这个受保护的dll只执行许可证检查程序,我们很容易在Delphi重建dll,绕过所有保护。
有些应用程序的作者喜欢将所有的许可证管理代码放入单个dll中,应用程序的所有模块都引用它来确定它是否被注册。
由于这将处理所有许可证管理,所有这便会是程序中的弱点。
我们将逆向这个小dll,并重新构造delphi中的所有函数和过程,以便他们总是返回正确的值。
出于保护原因我不会在过程中提到该程序的名字,但是足以熟悉这个“套路”
下一章会讲到利用激活访问敏感数据
0x01 正文
下载应用程序。运行时,弹出此窗口。用protectedID检测目录,就会发现,名为ba8pro的dll被ASProtect保护。让我们在PETools中查看ba8pro的导出表,看看它包含了什么函数和执行过程。
我们可以看到,这包含了4个过程。如果我们检查主可执行文件,我们看到没有对这个DLL的导入引用,并且在启动时,这个DLL不在内存中。
这意味着它可能使用LoadLibrary函数加载此DLL,并使用GetProcAddress获取过程VA。
这种情况,我们可以通过简单地搜索函数名的字符串引用来找到这些过程的名称。
当我们在ollydbg中加载主可执行文件时,我们可以看到主程序中引用的ba8pro dll。
下面我们可以看到CheckVersion和CheckDays的引用。
在标记为Call To CheckVersion的点之后,我们注意到在调用此函数之前没有任何东西被推入堆栈。
因此,我们可以得出结论,CheckVersion函数不接受参数。
然后,我们将$ FFFFFFFF的值返回到EAX并将其存储在5D9B04。
由于我们将完整的EAX寄存器移动到这个值,我们可以得出结论CheckVersion返回一个整数。
尝试之后,我发现如果我们从CheckVersion返回0,它将作为注册运行。
因此,我们可以在Delphi中重新创建这个dll函数,如下所示:
Function CheckVersion(): Integer; stdcall;
Begin
Result:=0; //pro
End;
The next function CheckDays works the same way. It does not take parameters and returns the number of days as an integer. We can declare it like this:
Function CheckDays():Integer;stdcall;
Begin
Result:=255; //Any value greater than 0 and <= $7FFFFFFF will work
End;
让我们在这里切换断点,运行应用程序,转到帮助,然后单击关于按钮。
这会导致ollydbg在这里被打断。
一旦我们下到调用,我们意识到一个值在进入这个调用之前被推入堆栈。
记下该值。让我们进入这个例程,来了解这个过程到底发生了什么。
在步骤结束之后,我们发现推送到堆栈的值是一个指向一个Unicode字符串值的指针,该字符串值将填充将出现在about表单上的注册信息字符串。
此例程不向EAX返回值,因此我们可以得出结论,这是一个程序。
使用这个程序,我发现如果注册它将返回以下字符串:
Procedure GetModeVersion(s:pWideString); stdcall;
Begin
s^:='Registered Version'+#13+'Single User License'+#13+'Lifetime Free Upgrades'; //Write to the String.
End;
最后,我们将看看最终的函数RegisterApplication。
由于我们默认使这个注册,这个功能我们不使用,但我们将添加这反正来完成DLL。
让我们重新启动应用程序。
在快速字符串搜索之后,我们可以找到对RegisterApplication的调用。
让我们运行应用程序并输入一些随机注册详细信息。
我们可以看到,这是传递两个字符串到函数。
当我们从这个例程返回时,我们看到a1被填充0.由于下一个函数测试a1是否等于0,我们可以确定a1是一个布尔值,其中0 =假和1 =真。
这意味着RegisterApplication函数接受两个常量(不变)字符串作为参数,并返回一个布尔值。
我们可以这样重建这个函数:
Function RegisterApplication(CONST s,s2:string):Boolean; stdcall;
Begin
Result:=true;
End;
现在我们已经重构了这些代码,执行效果如下
剩下要做的是将目录中的dll替换为我们创建的dll,修补模块中的完整性检查,并在注册表中添加假key即可。
这个厉害,思路不错 下载看看 学习下思路 谢谢楼主分享{:1_902:}
页:
[1]