最近发现有人能在城内强化玩家,上网研究了很久,终于找到方法了。
首先在d2hackmap.cfg中加一行打开自动强化,这样在城外就能自动强化了
Auto Enchant Toggle: 1, -1
而在城内强化,在d2hackmap的代码中是禁止的,上网终于找到了一份d2hackmap的代码可以参考,但编译出来和anhei2上下载的大小不太一样。代码如下,可以看出代码首先判断是不是在城内,如果是就退出了。而且代码中有明显的bug,那就是如果玩家或召唤物编号超过1000,整个程序立刻崩溃。如果你的强化法师进入一个玩了20分钟的游戏,里面有几个新手死灵法师,那你的强化法师一进入立刻窗口就崩溃了。
void AutoEnchantLoop( UnitAny *pUnit ){
static int delays = 0 ;//延时
static int unitCount[2][1000] = {0,}; //1K
if(fPlayerInTown){
//出城后,等会开始
delays = 1000;
return;
}
if ( delays >0 ) {
delays -- ;
return;
}
DWORD dwUnitId = pUnit->dwUnitId ;
if ( pUnit->dwUnitType==UNITNO_PLAYER && dwUnitId == dwPlayerId) return; //不给自己强化
if ( PLAYER->pSkill->pRightSkill->pSkillInfo->wSkillId !=52 ) return;//需要右键开启强化
if ( pUnit->dwUnitType==UNITNO_MONSTER ){
dwUnitId = D2GetMonsterOwner(pUnit->dwUnitId);
if (dwUnitId == (DWORD)-1)return; //非玩家随从
}
if ( D2CheckUnitState(pUnit, 16) )return; //已强化
if ( unitCount[pUnit->dwUnitType][pUnit->dwUnitId] >0 ) {
//没强化状态,但计时未结束,不做强化动作
unitCount[pUnit->dwUnitType][pUnit->dwUnitId] = unitCount[pUnit->dwUnitType][pUnit->dwUnitId] -1;
return;
}
if ( TestPvpFlag( dwPlayerId, dwUnitId )>=2 ){
//只能给盟友
unitCount[pUnit->dwUnitType][pUnit->dwUnitId] = 2000; //开始计时
delays = 800 ; //在下次发送前,全局计时
BYTE castTP1[9] = {0x0D};
*(DWORD*)&castTP1[1] = pUnit->dwUnitType;
*(DWORD*)&castTP1[5] = pUnit->dwUnitId;
D2SendPacket(sizeof(castTP1), 0, castTP1);
}
return;
}
在anhei2上下载的113map的d2hackmap.dll内存中AutoEnchantLoop对应代码如下:
AutoEnchantLoop
d2hackmap.dll+11AB0 - 55 - push ebp
d2hackmap.dll+11AB1 - 8B EC - mov ebp,esp
d2hackmap.dll+11AB3 - 83 EC 14 - sub esp,14
d2hackmap.dll+11AB6 - A1 40808A01 - mov eax,[d2hackmap.dll+28040]
d2hackmap.dll+11ABB - 33 C5 - xor eax,ebp
d2hackmap.dll+11ABD - 89 45 F8 - mov [ebp-08],eax
d2hackmap.dll+11AC0 - 83 3D FCBB8A01 00 - cmp dword ptr [d2hackmap.dll+2BBFC],00 { (1),0 }
d2hackmap.dll+11AC7 - 74 0F - je d2hackmap.dll+11AD8
可以看出程序是在d2hackmap.dll+11AC0判断是不是在城内的,只要改两个字节,直接跳到11AD8就可以在城内强化了。
d2hackmap.dll+11AC0 - EB 16 - jmp d2hackmap.dll+11AD8
这行代码在dllhackmap.dll文件的位置是0x10ec0, 这里的dllhackmap.dll必须是anhei2网站上下载的那个大小为193536字节的,如果是别的地方下载的可能位置不一样,需要自己找。
下面这段C代码可以自动修改d2hackmap.dll打开城内强化,但是dwUnitId的bug没有改正,在新建的游戏里用没有问题,时间久了强化法师就会退出,那就再建个新游戏吧,或者自己把后面的汇编代码看一下打上补丁。
要运行C代码可以下载tcc,一共只有4MB
http://download.savannah.gnu.org/releases/tinycc/
http://download.savannah.gnu.org ... .9.27-win32-bin.zip
http://download.savannah.gnu.org ... full-for-0.9.27.zip
使用类似下面的命令行来运行C程序
d:\tcc\tcc\tcc.exe -luser32 -ID:/tcc/winapi-full-for-0.9.27/include/winapi -run d:\git\diablo2\patch_d2hackmap.c
---------patch_d2hackmap.c-------------
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <assert.h>
char *load(char *path,int *psize) {
FILE *fp=fopen(path,"rb");
if (!fp) {printf("Can't open %s\n",path);assert(0);}
fseek(fp,0,2);int size=ftell(fp);*psize=size;
char *p=malloc(size+1);p[size]=0;fseek(fp,0,0);
int n=fread(p,1,size,fp);assert(n==size);fclose(fp);
return p;
}
void save(char *path,char *buf,int size) {
FILE *fp=fopen(path,"wb+");assert(fp);
int n=fwrite(buf,1,size,fp);assert(n==size);fclose(fp);
}
int check_code(unsigned char *code,int off,char *ptn,int n) {
for (int i=0;i<n;i++) {
unsigned char c=ptn
;if (c==0xFF) continue;
if (code[off+i]!=c) return 0;
}
return 1;
}
void auto_enchant_patch() {
//d2hackmap.dll+11AC0 - 83 3D FCBB8A01 00 - cmp dword ptr [d2hackmap.dll+2BBFC],00 { (1),0 }
//d2hackmap.dll+11AC7 - 74 0F - je d2hackmap.dll+11AD8
//d2hackmap.dll+11AC9 - C7 05 F08BAA01 E8030000 - mov [d2hackmap.dll+228BF0],000003E8 { (0),1000 }
unsigned char org[19]={0x83,0x3d,0xff,0xff,0xff,0xFF,0,
0x74,0xF,
0xC7,0x05,0xFF,0xFF,0xFF,0xFF,0xE8,3,0,0};
unsigned char patch[2]={0xeb,0x16};
char *path="D:/game/diablo2/113map/d2hackmap.dll";
char *outpath="D:/game/diablo2/113map/d2hackmap_qh.dll";
int size;char *code=load(path,&size);
int offset=0x10ec0;
printf("Load %s size %d\n",path,size);
if (!check_code(code,offset,org,19)) {
printf("ERROR: dll mismatch\n");
return;
}
printf("Check OK\n");
memcpy(code+offset,patch,2);
printf("save to %s\n",outpath);
save(outpath,code,size);
return;
}
int main( void ) {
auto_enchant_patch();return 0;
}
另外还有一个更重要的程序,那就是以窗口模式启动暗黑2后去掉窗口标题和边框并且最大化,效果和全屏一样,但是可以输入中文,而且可以两个窗口快速切换,适合双开。在战网上最郁闷的就是遇到有人用玄文了,遇到基本马上就退,而且几天内也不想加入公开的游戏了。我也看过天书,知道使用玄文九成可能是故意不让人看明白。但有人说我不会英文,又非要用全屏模式启动,输入不了中文,而且我一定要不停发大段的消息。所以了,下面的程序可以达到全屏并且输入中文的效果,如果还不使用通用语言的话,那我也肯定不看。当然了,估计没多少人会用,因为用玄文是暗黑2的惯例,网上关于暗黑2的中文贴子新人估计一句也看不懂,比如说dykb指的是地狱Kill Baal,前面一半是拼音,后面一半是英文,这已经是很高级别的玄学了。再比如说anhei2网站一直置顶的贴子《法师不能进房间的请尽快覆盖 》,我就一直不知道是什么意思,直到现在我还经常看到有法师不停进入和离开游戏,估计是没装验证码补丁,我以前也要连续进几十次,一直显示“加入游戏失败”,后来有老玩家告诉我建立游戏叫开房,加入游戏叫进房,我才知道是怎么回事,为什么不让法师进,刺客和亚马逊就可以。
---------fullscreen.c-------------
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <assert.h>
char *dir="D:\\game\\diablo2";
char *cmdline="D:\\game\\diablo2\\D2Loader.exe -locale chi -lq -pdir 113map -direct -skiptobnet -w -title %s";
int main(int argc,char *argv[]) {
char title[256];
char cmd[256];
for (int i=1;i<1000;i++) {
snprintf(title,256,"D2_%d",i);
HWND hwnd=FindWindowA(NULL,title);
if (!hwnd) break;
}
snprintf(cmd,256,cmdline,title);
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
printf("%s\n",cmd);
if( !CreateProcess( NULL, // No module name (use command line)
cmd, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
dir, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed.\n");
return;
}
for (int i=0;i<20;i++) {
HWND hwnd=FindWindowA(NULL,title);
if (hwnd) {
int style=GetWindowLongA (hwnd,GWL_STYLE);
if (style&WS_CAPTION) {
style=style&(~WS_CAPTION);
SetWindowLongA(hwnd,GWL_STYLE,style);
}
ShowWindow(hwnd,SW_SHOWMAXIMIZED);
break;
}
Sleep(500);
}
return 0;
}