推荐给好友 上一篇 | 下一篇

热血江湖免费挂制作

对热血江湖这样的游戏来说,外挂的商业意义不大,这是由运营商的经营策略决定的。
对它进行分析完全是个人兴趣所致,贴出来希望对大家学习外挂技术有所帮助:)
游戏名称:热血江湖
版本:1.28
第一部分 网络封包分析
包结构
struct {
char tagHead[2]; //AA 55
short dataLen; //实际数据长度+9
char encFlag; //加密标志
struct{
short tagDataHead; //数据头标
short cmd; //命令字节
char cmdPara[n]; //命令参数,长度n=dataLen-9-4
}data;
char tagFill[6]; //填充字节
short packNo; //包计数
char tagTail[2]; //55 AA
};

客户端中的对发送包的加密算法代码是动态生成的,有不同的版本。但是其入口是固定的,在xp sp2下地址是0070B220,C原型为 int stdcall EncData(char *p).(不要直接调用,因为发送包中填充字节跟栈中的返回地址有关,不小心就会被封号!)

前4个填充字节的大概算法:

int calcFill;
unsigned short *magicNum = 0x0070B8D5;
int sel=(sendPack.packNo/8)%8;
if (*magicNum ==0)
{
if (sel == 0) calcFill = 固定数; //[0070B8C9]=0042E35F,
//指向调用解密子函数(0070B010)指令的下一条指令地址
else if (sel ==1) calcFill = 栈中的二级返回地址;
else calcFill = 栈中的三级返回地址;
} else
{
calcFill = *magicNum;
if ((*magicNum < 0x100) && ((sendPack.packNo & 0x0f) == 0)) *magicNum = 0;
}
*((int*)&sendPack.tagFill[0]) = calcFill - 0x499031A8; //0x499031A8这个数字跟算法有关,会变化

后2个填充字节的大概算法:

unsigned short calcFill = 0x410C; //0x410C这个数字跟算法有关,会变化
unsigned short *magicNum = 0x0070B8D1;
unsigned char *p = (unsigned char *)0x0070AD00;//某段代码区地址
if (*magicNum == 0) *((unsigned short*)&sendPack.tagFill[4])=0;
else
{
for(int i=0; i<*magicNum; i++) calcFill+=p[i];
*((unsigned short*)&sendPack.tagFill[4])= ~(calcFill + *magicNum);
}

第一次对明文的xor算法:
unsigned char *pData = (unsigned char *)sendPack.data;
for (int i=0; i<sendPack.dataLen-9-6; i++)
pData[i+6] ^=sendPack.tagFill[i%8];


第二次对明文的加密算法:

unsigned char *tbl64k = 0x054E50E8;//64k字节的代码转换表
unsigned char *tbl32b = 0x0070B887;//32字节的中间计算表

unsigned char *pData = (unsigned char *)sendPack.data;

for(int i=0; i<sendPack.dataLen-3-2; i++)
pData[i+2] = tbl64k[((tbl32b[i%32]^0x01^(sendPack.packNo & 0x0ff))<<8)+pData[i+2]]; //0x01这个数字跟算法有关,会变化

以上是客户端发送包时的加密算法,服务器发来的包只需要解一次密。

对收到的包密文的解密算法:
unsigned char *tbl64k = 0x054E50E8;//64k字节的代码转换表
unsigned char *tbl32b = 0x0070B887;//32字节的中间计算表

unsigned char *pData = (unsigned char *)recvPack.data;
unsigned selSeg;

for(int i=0; i<recvPack.dataLen-3; i++)
{
selSeg = (tbl32b[i%32]^(recvPack.packNo & 0x0ff))<<8;
for(int j=0; j<0x100; j++)
if (tbl64k[selSeg + j] == pData[i]) break;
pData[i] = j;
}
最后提一下,客户端在处理收到的包时,会根据包尾的填充数据recvPack.tagFill前四个字节重设
后2个填充字节的算法里面的unsigned char *p(指向某段代码区的地址)和unsigned short *magicNum的数据
以及前4个填充字节的算法里面的unsigned short *magicNum的数据,这就意味着服务器
能轻而易举地能发现脱机外挂(只要改变这几个参数),对注入型的内挂来说,避过这样的检测手段也比较困难:(。


 

评分:0

我来说两句

seccode