Hacking Diablo II之外挂实战教程:去除D2JSP试用版显示的Trial Version信息

前几天一个网友给我发消息请我帮他个忙。他的问题是,他正在使用的D2JSP是免费试用版,试用版在运行时会在游戏的所有游戏画面中央显示一行很大的“Trial Version”字样(见下图中的红圈),很烦人,他想去掉这行字。我想正好用此做个教程解释前面介绍过的hack工作原理,于是答应帮他看看。


我已经很久没有开BOT了,最后一次使用D2JSP还是2003年1.09d时期的事。根据我以前的理解,D2JSP和其他hacks一样,由两部分组成,d2jsp.exe只是一个loader,负责把d2jsp.dll加载到游戏进程。而d2jsp.dll才是D2JSP的运行引擎-真正发挥作用的东西。因此“Trial Version”字符串肯定在d2jsp.dll中。最开始的想法是“Trial Version”可能会以一个常量字符串的形式保存在d2jsp.dll中,因此最容易想到的做法是用UltraEdit打开d2jsp.dll,寻找“Trial Version”,找到的话把它改为空字符串就OK了。然而打开后发现d2jsp.dll是加了壳的,这才想起自从D2 1.10以来D2JSP开始收费,采取了一些措施防止别人破解,加壳就是其中之一(当然还是被人破了)。在d2jsp.dll文件的前面几行看到了aspack字串,看来加的是aspack壳。脱壳我很不在行,但是我知道有一些自动脱壳工具,针对aspack的脱壳工具也肯定有,不妨试试,于是到网上抓了个脱壳软件-AspackDie。当然试验的结果是失败了。又想,不管怎样,d2jsp.dll运行的时候它自己得脱壳吧,那我可以在它自己脱壳后在进程内存中找吧。于是加载D2JSP后用WinHex打开游戏进程,查找Trial Version,然而还是没找到。看来可能用了即时脱壳技术,或者干脆Trial Version根本不是常量字符串,比如我知道如果在C/C++中这样写szVersion就不是常量字符串:

char  szVersion[]  =  { ' T ' ' r ' ' i ' ' a ' ' l ' '   ' ' V ' ' e ' ' r ' ' s ' ' i ' ' o ' ' n ' ' ' };

然后怎么办,继续研究脱壳?不,其实我早就有了更好、更通用的解决方法,但是需要编程。现在看来简单的思路行不通,还是写程序算了。换个角度来看,不管字符串是什么,总得调用某个函数来输出显示吧,看上图中的字样,显然是调用了Diablo II的内部函数显示的,因此如果能截获这个函数过滤掉"Trial Version"字符串就搞定了。而且这种方法不用修改D2JSP程序,对所有D2JSP版本都起作用,因此更通用。问题是它调用了D2X的哪个函数呢?我想起我的d2hackmap中也用到了类似的字符串显示的功能,它们用的有可能是同一个!于是把d2hackmap的源代码翻出来看了看,发现了d2win.dll中导出序号为10064(Diablo II中所有dll导出的函数都只有序号没有名字)的函数做此用途,其函数声明为:

void  __fastcall D2WIN_DrawText(wchar_t  * str,  int  xpos,  int  ypos, DWORD color, DWORD unknown);

 然后用VC++ attach到游戏进程进行调试,想在D2WIN_DrawText设断点监控,结果发现调试器刚attach上去D2JSP就会崩溃。看来它做了反调试处理,这也在意料之中。还是直接写个DLL注入到游戏进程截获D2WIN_DrawText来观测得了,字符串可以用Win32 API OutputDebugString输出然后用DbgView观测:

void  __fastcall MyD2WIN_DrawText(wchar_t  * str,  int  xpos,  int  ypos, DWORD color, DWORD unknown)

{
    
if (str) OutputDebugStringW(str);
}

结果发现“Trial Version”果然是通过D2WIN_DrawText输出的,见下图。


现在只要改变MyD2WIN_DrawText()的实现,判断输出字符串如果为"Trial Version"则跳过真正的D2WIN_DrawText()代码就搞定了,代码见后面的详细源代码分析。改变后的显示结果如下图,画面上方的d2jsp v1.2.0字样还在,Trial Version字样已经没了:


至此,给D2JSP打补丁的程序d2jsppatch.dll已经做好了,然而还有一个问题,就是d2jsppatch.dll如何加载呢?用D2JSP开的BOT一般是无人职守自动运行的,因此d2jsppatch.dll最好能够随着d2jsp.dll自动加载,否则每次都需要人工加载那就太麻烦了。那怎么做到随d2jsp.dll自动加载呢?一个办法是把d2jsp.dll改名为d2jsp2.dll,d2jsppatch.dll改名为d2jsp.dll,这样d2jsp.exe每次加载d2jsp.dll时其实加载的是d2jsppatch.dll。d2jsppatch.dll加载起来后,在它的启动代码里再手工加载d2jsp2.dll(即原来的d2jsp.dll),这样就达到了自动加载d2jsppatch.dll的目的。这种方法的缺点是它改变了D2JSP原有模块之间的关系,可能会导致一些兼容性问题,比如d2jsp.exe可能会校验d2jsp.dll检查它是否被人改过,或者某个依赖于d2jsp.dll工作的程序可能会用LoadLibrary("d2jsp.dll")/GetProcAddress()获取d2jsp.dll的到处函数,这时就会失败。

伴随d2jsp.dll自动加载的另外一种做法是把d2jsppatch.dll静态绑定到d2jsp.dll或者d2jsp.dll会用到的某个DLL。由于d2jsp.dll加了壳,DLL文件的IAT(Import Address Table,即导入表)已经被破坏,最好是从d2jsp.dll会用到的DLL下手。我们知道D2JSP支持jscript脚本程序,它肯定会加载jscript脚本引擎js32.dll,所以我们可以把d2jsppatch.dll静态绑定到js32.dll上去。熟悉Windows编程且喜欢玩API hooking的朋友可能知道微软的Detours Library,其中附带了一个程序setdll.exe可以把一个DLL静态绑定到其他EXE或者DLL。在命令行运行:

setdll . exe -d :d2jsppatch . dll js32 . dll

就把d2jsppatch.dll绑定到了js32.dll,如下图。

以下是对d2jsppatch.dll源代码的详细分析,给感兴趣的朋友参考。d2jsppatch.dll虽然是针对D2JSP的,但是它包含了一个hack的所有基本组成部分,而且功能很简单,用它来了解hack的工作原理是很合适的。d2maphack、d2hackmap等hacks的工作原理和它完全一样,不同的只是实现的功能。

1,d2jsppatch.dll的加载和卸载。DLL入口函数DllMain中一般用来做安装(InstallPatch)、卸载(RemovePatch)旁路点(detour patch)。安装、卸载工作可能导致程序崩溃(见以前的文章),放在DllMain中进行最合适,因为Windows保证在DllMain中的代码执行时进程内的其他线程不会运行,见:http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
    
if (DLL_PROCESS_ATTACH == dwReason)
    
{
        DisableThreadLibraryCalls((HMODULE)hModule);
        
return InstallPatch();
    }

    
else if(DLL_PROCESS_DETACH == dwReason)
    
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值