诛仙挂机外挂拣物分析

本文仅为探讨。使用数据为7月10号更新的35版。
http://www.cnblogs.com/birdshover/

拣物方式有两类,模拟按键和CALL。模拟按键没什么好说的,不能保证一定能把自己的东西全部捡取。而CALL的方式也存在是否全部捡取了和捡取效率的问题。

本文介绍的内容不采用诛仙内存地址自带的地面物品数量,而让自己来计算地面物品数量。算法为取自身5距离内的地面物品,每个捡一次。


oid AddressMap::GetAllAddress(void)
{
 if(!Gobal::ReadAddressError)
 {
   //7月10号基址
  BaseAddress = (LPVOID)0x90664c;
  SecondAddress = (LPVOID)(Gobal::ReadMemoryAddress(BaseAddress) + 0x28);

  ItemBase = (LPVOID)Gobal::ReadMemoryAddress((LPVOID)(Gobal::ReadMemoryAddress((LPVOID)(Gobal::ReadMemoryAddress(BaseAddress) + 0x8)) + 0x24));
  ItemCount = (LPVOID)((DWORD)ItemBase + 0x14);
 }
}

//物品结构
 struct Items{
  DWORD ItemID;   //物品ID
  DWORD ItemSystemID; //物品系统ID
  CString ItemName;   //物品名称
  float ItemX;   //X坐标
  float ItemY;   //Y坐标
 };

//物品信息
AddressMap::Items AddressMap::GetItem(int i)
{
 AddressMap::Items item;
 DWORD dmbase = Gobal::ReadMemoryAddress((LPVOID)(Gobal::ReadMemoryAddress((LPVOID)((DWORD)ItemBase + 0x18)) + 0x4 * i));
 if(dmbase <= 0)
 {
  item.ItemID = 0;
  item.ItemSystemID = 0;
  return item;
 }
 DWORD theAddress = Gobal::ReadMemoryAddress((LPVOID)(dmbase + 0x4));
 item.ItemID = Gobal::ReadMemoryValue((LPVOID)(theAddress + 0x110));
 item.ItemSystemID = Gobal::ReadMemoryValue((LPVOID)(theAddress + 0x10C));
 item.ItemName = Gobal::ReadMemoryTextValueL((LPVOID)Gobal::ReadMemoryAddress((LPVOID)(theAddress + 0x164)));
 item.ItemX = Gobal::ReadMemoryFloatValue((LPVOID)(theAddress + 0x3C));
 item.ItemY = Gobal::ReadMemoryFloatValue((LPVOID)(theAddress + 0x44));
 return item;
 //return Items();
}

捡取物品CALL
void MyCall::CallPickItem(DWORD itemID, DWORD itemSysID)
{
 DWORD address = 0x578ca0;
 __asm
 {
      pushad
   mov ecx, dword ptr ds:[0x902b3c]
      mov edx, itemID
      push edx
   mov ecx, dword ptr ds:[ecx+0x20]
      mov eax, itemSysID
      push eax
      add  ecx, 0xD4
      call address
      popad
 }
}

读取内存
DWORD Gobal::ReadMemoryAddress(LPVOID address)
{
 DWORD dwValue = 0;
 DWORD length = 0;
 bool read = (ReadProcessMemory(Gobal::hProcess,address,&dwValue,sizeof(DWORD),&length) == 1);
 if(read && length == sizeof(DWORD))
 {
  Gobal::ReadAddressError = true;
  return dwValue;
 }
 else
 {
  Gobal::ReadAddressError = false;
  return 0;
 }
}


主过程:

公用变量申明
//////////////////////////////////////////////////////////////////////////////////////
//捡取状态,0为计数,1为捡取
int baseItemMy = 0;
//当前计算所得物品数量
int itemAllNum = 0;
//存放物品信息的数组,供拣物CALL使用
DWORD itemArray[10][2];
//当前人物坐标
float nowx = 0;float nowy = 0;
//////////////////////////////////////////////////////////////////////////////////////////////////////////

过程内操作:
//读取地址
 AddressMap::GetAllAddress();

 DWORD second = Gobal::ReadMemoryAddress(AddressMap::SecondAddress);

//当前人物坐标
 nowx = Gobal::ReadMemoryFloatValue(LPVOID(second + 0x3d8));
 nowy = Gobal::ReadMemoryFloatValue(LPVOID(second + 0x3e0));

   
   //baseItemMy 计算物品数量
     if(baseItemMy == 0)
     {
      for(int i = 0;i<768;i++)
      {
         //取得物品信息
       AddressMap::Items items = AddressMap::GetItem(i);
       if(items.ItemID > 0)
       {
         //如果距离人物距离不超过5,并且数量小于10的时候
        if(abs((float)items.ItemX - nowx) < 5 && abs((float)items.ItemY - nowy) < 5 && itemAllNum < 10)
        {
         //存入物品ID和物品系统ID
         itemArray[itemAllNum][0] = items.ItemID;
         itemArray[itemAllNum][1] = items.ItemSystemID;
         //物品数量增加1
         itemAllNum++;
        }
       }
      }
      //计数完毕,切换状态
      baseItemMy = 1;
     }

      //进入拣物状态

     if(itemAllNum > 0)
     {
      //调用拣物CALL
      MyCall::CallPickItem(itemArray[itemAllNum - 1][0],itemArray[itemAllNum - 1][1]);
      //物品数量减少1
      itemAllNum--;
     }
     else
     {
         //没有物品,重置状态
      Gobal::UserState = 1;
      itemAllNum = 0;
      baseItemMy = 0;
     }
     //int itemCount = (int)Gobal::ReadMemoryValue(AddressMap::ItemCount);

到此,就完成了。
http://www.cnblogs.com/birdshover/

posted @ 2007-07-11 11:17  Birdshover  阅读(2592)  评论(5编辑  收藏  举报