找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 139|回复: 2

[客户端] 一个有趣的技改--dota2 哈斯卡和拍拍熊

[复制链接]

5

主题

6

回帖

30

积分

新手上路

积分
30
发表于 2025-10-24 20:01:47 | 显示全部楼层 |阅读模式
本帖最后由 plshelloworld 于 2025-10-30 13:04 编辑

经过神秘修炼,冒险家逐渐掌握了特殊的战斗技巧,这些战斗技巧将赋予冒险家以下特性:

  • “超强力量”,每20级提高1%触发的概率,增加一次攻击快速数量,增加1s持续时间。当触超强力量时,攻击间隔降低至10%,该效果在达到攻击次数达到或持续时间消失后结束。 内置冷却时间10s.
  • “狂战士之血”,冒险家生命值每降低10%,相应的攻击间隔降低10%
  • ~~“永恒”,冒险家在生命值低于1%时,会触发永恒效果,在接下来的5s内,任何伤害均不会导致死亡,内置冷却时间10s。~~



  1. #pragma once
  2. #include <thread>
  3. #include <chrono>
  4. #include"Hooks.h"

  5. class Dota2
  6. {
  7. public:

  8.     static int ReadPointerSignedInt(ULONG ulBase, int iOffset) {
  9.         __try { return *(LONG*)(*(ULONG*)ulBase + iOffset); }
  10.         __except (EXCEPTION_EXECUTE_HANDLER) { return 0; }
  11.     }

  12.     static UINT8 readCharValueZtlSecureFuse(int at) {
  13.         UINT8 result;
  14.         try {
  15.             UCHAR v2 = *(PUCHAR)at;
  16.             at = *(PUINT8)(at + 1);
  17.             result = at ^ v2;
  18.         }
  19.         catch (...) { return 0; }
  20.         return result;
  21.     }


  22.     static void MakePageWritable(ULONG ulAddress, ULONG ulSize) {
  23.         MEMORY_BASIC_INFORMATION* mbi = new MEMORY_BASIC_INFORMATION;
  24.         VirtualQuery((PVOID)ulAddress, mbi, ulSize);
  25.         if (mbi->Protect != PAGE_EXECUTE_READWRITE) {
  26.             ULONG* ulProtect = new unsigned long;
  27.             VirtualProtect((PVOID)ulAddress, ulSize, PAGE_EXECUTE_READWRITE, ulProtect);
  28.             delete ulProtect;
  29.         }
  30.         delete mbi;
  31.     }
  32.     static void WriteMemory(ULONG ulAddress, ULONG ulAmount, ...) {
  33.         va_list va;
  34.         va_start(va, ulAmount);

  35.         MakePageWritable(ulAddress, ulAmount);
  36.         for (ULONG ulIndex = 0; ulIndex < ulAmount; ulIndex++)
  37.             *(UCHAR*)(ulAddress + ulIndex) = va_arg(va, UCHAR);

  38.         va_end(va);
  39.     }

  40.     static void Jump(ULONG ulAddress, PVOID Function, unsigned Nops) {
  41.         MakePageWritable(ulAddress, Nops + 5);
  42.         *(UCHAR*)ulAddress = 0xE9;
  43.         *(ULONG*)(ulAddress + 1) = (int)(((int)Function - (int)ulAddress) - 5);
  44.         memset((PVOID)(ulAddress + 5), 0x90, Nops);
  45.     }

  46. public:
  47.     // 静态函数启动定时器
  48.     static void monitorAttackCount(int interval_ms = 100, int acceleration_probability = 20, int acceleration_cooldown_seconds = 10) {
  49.         // 初始化随机数生成器
  50.       
  51.         std::srand(static_cast<unsigned int>(std::time(nullptr)));

  52.         // 设置静态成员变量
  53.         acceleration_probability_ = acceleration_probability;
  54.         acceleration_cooldown_seconds_ = acceleration_cooldown_seconds;
  55.         lastValue = -1;
  56.         isAccelerating = false;

  57.         // 设置定时器,每interval_ms毫秒调用一次TimerProc函数
  58.         SetTimer(NULL, 1, interval_ms, (TIMERPROC)TimerProcStatic);
  59.         // 程序结束时清除定时器
  60.         KillTimer(NULL, 1);
  61.     }

  62. private:
  63.     // 存储必要的状态信息
  64.     inline static int lastValue = -1;
  65.     inline static bool isAccelerating = false;
  66.     inline static std::chrono::steady_clock::time_point lastAccelerationTime;
  67.     inline static int acceleration_probability_ = 20;
  68.     inline static int acceleration_cooldown_seconds_ = 3;
  69.     inline static ULONG UserLocalBaseex = 0xBEBF98;
  70.     inline static ULONG OFS_AttackCount = 0x2B88;
  71.     inline static ULONG attackDelayAddrex = 0x00454795;
  72.     inline static int changeCount = 0;
  73.     inline static const int maxChangeCount = 12;
  74.     inline static ULONG CharacterStatBase = 0xBF3CD8;
  75.     inline static ULONG OFS_Level = 0x33;
  76.     inline static ULONG OFS_JobID = 0x39;
  77.     inline static ULONG statHookAddr = 0x008D8581;


  78.     inline  static std::chrono::steady_clock::time_point lastTriggerTime;
  79.     inline  static std::atomic<bool> isUnyieldingActive;
  80.     inline  static std::atomic<bool> isTimerRunning;

  81.     inline static std::atomic<bool> isAlive = true;

  82.   

  83.     // 定时器回调函数,静态成员函数
  84.     static void CALLBACK TimerProcStatic(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {
  85.         TimerProc();
  86.         TimerProcHSK();
  87.     }

  88. #if 1
  89.     //神灵武士
  90.     static void TimerProcHSK() {
  91.         int currentValue = ReadPointerSignedInt(UserLocalBaseex, OFS_AttackCount);
  92.         //HP
  93.         {
  94.             Jump(statHookAddr, Assembly::StatHook, 0);
  95.             if (Assembly::maxHP != 0) {
  96.                 double val = ((double)Assembly::curHP / Assembly::maxHP) * 100.0;               
  97.                 ULONG targetValue = 0x01 + (ULONG)((val / 100.0) * 9);               
  98.                 static ULONG previousTargetValue = 0x0A;
  99.                 if (targetValue != previousTargetValue) {                                 
  100.                     previousTargetValue = targetValue;
  101.                     WriteMemory(attackDelayAddrex, 3, 0x83, 0xC0, previousTargetValue); //add ecx, [animDelay]
  102.                 }              
  103.             }
  104.         }
  105.     }

  106. #endif // 0


  107.     //超强力量版本
  108. #if 1
  109.     static void TimerProc() {
  110.         int currentValue = ReadPointerSignedInt(UserLocalBaseex, OFS_AttackCount);
  111.         //HP
  112.         {
  113.             Jump(statHookAddr, Assembly::StatHook, 0);
  114.             if (Assembly::maxHP != 0) {
  115.                 double val = ((double)Assembly::curHP / Assembly::maxHP) * 100.0;
  116.                 // std::cout << " hp percent: " << val << "%" << std::endl;
  117.             }

  118.         }
  119.         //获取玩家等级
  120.         auto level = readCharValueZtlSecureFuse(*(ULONG*)CharacterStatBase + OFS_Level);

  121.         // std::cout << "level:   "<< (int)level << std::endl;
  122.         if (currentValue != lastValue) {
  123.             // 20%的概率打印 "加速"
  124.             if (std::rand() % 100 < acceleration_probability_) {
  125.                 if (!isAccelerating || std::chrono::steady_clock::now() - lastAccelerationTime > std::chrono::seconds(acceleration_cooldown_seconds_)) {
  126.                   
  127.                     lastAccelerationTime = std::chrono::steady_clock::now();  // 更新加速时间
  128.                     isAccelerating = true;  // 设置加速状态
  129.                     WriteMemory(attackDelayAddrex, 3, 0x83, 0xC0, 0x06); //add ecx, [animDelay]
  130.                     changeCount = 0;
  131.                     int maxCnt = level / 20;                  

  132.                 }
  133.             }
  134.             // 增加变化次数
  135.             if (isAccelerating) {
  136.                 changeCount++;
  137.                 int maxCnt = level / 20;               

  138.                 // 如果变化次数达到6次,则结束狂暴
  139.                 if (changeCount >= maxCnt) {                  
  140.                     //isAccelerating = false;  // 结束狂暴
  141.                  //   WriteMemory(attackDelayAddrex, 3, 0x83, 0xC0, 0x0A); // add eax, 0a
  142.                     //也许我应该把攻速调整至当前血量?
  143.                      //HP
  144.                     {
  145.                         Jump(statHookAddr, Assembly::StatHook, 0);
  146.                         if (Assembly::maxHP != 0) {
  147.                             double val = ((double)Assembly::curHP / Assembly::maxHP) * 100.0;
  148.                             ULONG targetValue = 0x01 + (ULONG)((val / 100.0) * 9);
  149.                             static ULONG previousTargetValue = 0x0A;
  150.                             if (targetValue != previousTargetValue) {
  151.                                 previousTargetValue = targetValue;
  152.                                 WriteMemory(attackDelayAddrex, 3, 0x83, 0xC0, previousTargetValue); //add ecx, [animDelay]
  153.                             }
  154.                         }
  155.                     }




  156.                 }
  157.             }
  158.             // 打印当前值           
  159.             lastValue = currentValue;  // 更新上次的值
  160.         }

  161.         // 如果加速状态已经超过cooldown,允许再次触发"加速"
  162.         if (isAccelerating && std::chrono::steady_clock::now() - lastAccelerationTime > std::chrono::seconds(acceleration_cooldown_seconds_)) {
  163.             isAccelerating = false;  // 重置加速状态
  164.          
  165.           //  WriteMemory(attackDelayAddrex, 3, 0x83, 0xC0, 0x0A); //add eax,0a

  166.                //HP
  167.             {
  168.                 Jump(statHookAddr, Assembly::StatHook, 0);
  169.                 if (Assembly::maxHP != 0) {
  170.                     double val = ((double)Assembly::curHP / Assembly::maxHP) * 100.0;
  171.                     ULONG targetValue = 0x01 + (ULONG)((val / 100.0) * 9);
  172.                     static ULONG previousTargetValue = 0x0A;
  173.                     if (targetValue != previousTargetValue) {
  174.                         previousTargetValue = targetValue;
  175.                         WriteMemory(attackDelayAddrex, 3, 0x83, 0xC0, previousTargetValue); //add ecx, [animDelay]
  176.                     }
  177.                 }
  178.             }


  179.         }
  180.     }
  181. #endif // 0

  182. };

复制代码
hooks.h  一些人物状态的hook
  1. #pragma once

  2. #include<Windows.h>
  3. #define CodeCaveEx(name) static void __declspec(naked) ##name() { _asm
  4. #define EndCodeCaveEx }

  5. namespace Assembly {
  6.         extern ULONG curHP;
  7.         extern ULONG maxHP;
  8.         extern ULONG curMP;
  9.         extern ULONG maxMP;
  10.         extern ULONG curEXP;
  11.         extern ULONG maxEXP;
  12.         extern ULONG mapNameAddr;
  13.         extern ULONG statHookAddr;
  14.         extern ULONG statHookAddrRet;
  15.         CodeCaveEx(StatHook) {
  16.                 push eax
  17.                         mov eax, [ebp + 0x08]
  18.                         mov[curHP], eax
  19.                         mov eax, [ebp + 0x0C]
  20.                         mov[maxHP], eax
  21.                         mov eax, [ebp + 0x10]
  22.                         mov[curMP], eax
  23.                         mov eax, [ebp + 0x14]
  24.                         mov[maxMP], eax
  25.                         mov eax, [ebp + 0x18]
  26.                         mov[curEXP], eax
  27.                         mov eax, [ebp + 0x1C]
  28.                         mov[maxEXP], eax
  29.                         pop eax
  30.                         lea ecx, [eax + eax * 0x4]
  31.                         cmp ecx, ebx
  32.                         jmp dword ptr[statHookAddrRet]
  33.         } EndCodeCaveEx
  34. }

复制代码


补充一个遗漏的Hooks.cpp

  1. #include"Hooks.h"

  2. namespace Assembly {
  3.         ULONG curHP = 0, maxHP = 0, curMP = 0, maxMP = 0, curEXP = 0, maxEXP = 0, mapNameAddr = 0x0;
  4.         ULONG statHookAddr = 0x008D8581; //Inside CUIStatusBar::SetNumberValue
  5.         ULONG statHookAddrRet = statHookAddr + 5;
  6. #pragma unmanaged
  7.         /*CodeCaveEx(AnimDelay) {
  8.                 add eax, [animDelay]
  9.                 jmp dword ptr[animDelayAddrRet]
  10.         } EndCodeCaveEx*/

  11.         

  12. }
复制代码

评分

参与人数 1蘑菇币 +50 收起 理由
leevccc + 50 很给力!

查看全部评分

5

主题

6

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2025-10-24 20:09:14 | 显示全部楼层
Dota2::monitorAttackCount();  就可以了

4

主题

21

回帖

10

积分

新手上路

积分
10
发表于 7 天前 | 显示全部楼层
前来学习啦。你是打算把所有职业都觉醒吗
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|小黑屋|蘑菇物语

GMT+8, 2025-11-5 04:48 , Processed in 0.093246 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表