NAME
AutoHits Source for D2 v1.09b — Annotated ASM source for AutoHits — a Diablo II hack that fires multiple attack packets per click by patching game memory at runtime.
METADATA
OVERVIEW
This is the cut-down source code for the AutoHits hack for Diablo II v1.08/v1.09b. What’s presented here is the payload itself — the code that gets patched into Diablo II’s virtual memory at runtime.
This demonstrates one way to send packets in response to in-game events. Specifically, it intercepts the click-on-monster and click-on-player code paths and replaces them with a loop that fires the attack packet multiple times per click.
MEMORY LAYOUT
The payload occupies free space in D2’s address range from 6FC365FB to 6FC3667B.
Attack Packet Buffer
Located at 6FC3663B, the buffer is 9 bytes:
06 01 00 00 00 01 00 00 00
| Offset | Value | Description |
|---|---|---|
+00 | 06 | Packet ID — identifies this as an attack action |
+01 | 01/00 | Target type: 01 = monster, 00 = player |
+05 | DWORD | Target entity ID in the current game session |
- Target type byte is at
6FC3663C - Target ID DWORD is at
6FC36640 - Hit count (loop iterations) is a WORD at
6FC3664B
HOOK POINTS
Two locations in D2’s original code are overwritten with call instructions:
| Address | Original purpose | Replacement |
|---|---|---|
6FB77C46 | Conditional jump — causes character to run + attack | call 6FC365FB (monster subroutine) |
6FB77C29 | Short subroutine — player clicked hostile player outside town | call 6FC3665B (player subroutine) |
The original conditional jumps are NOP’d out so the character fires without moving.
A third hook fires the packet loop using whatever is already in the buffer:
| Address | Trigger |
|---|---|
6FAFCFF0 | Space bar pressed |
ANNOTATED SOURCE
Monster Click Hook
; Overwrites a conditional jump at 6FB77C46 — prevents run-and-attack behavior
:6FB77C46 call 6FC365FB ; Call monster subroutine
:6FB77C4B nop
:6FB77C4C nop
Monster Subroutine
:6FC365FB mov byte ptr [6FC3663C], 01 ; Set target-type flag: monster
:6FC36602 call 6FC3660B ; Call "Send packet" routine
:6FC36607 mov eax, dword ptr [esi+1c] ; Restore EAX (overwritten original instruction)
:6FC3660A ret
Player Click Hook
; Overwrites subroutine at 6FB77C29 — triggers when D2 confirms a hostile player click outside town
:6FB77C29 call 6FC3665B ; Call player subroutine
:6FB77C2E nop
:6FB77C2F nop
:6FB77C30 nop
:6FB77C31 nop
:6FB77C32 nop
Player Subroutine
:6FC3665B mov byte ptr [6FC3663C], 00 ; Set target-type flag: player
:6FC36662 call 6FC3660B ; Call "Send packet" routine
:6FC36667 ret
Send Packet (Core Loop)
:6FC3660B mov dword ptr [6FC36640], ebx ; Patch target ID into buffer (EBX = entity ID)
:6FC36611 pushad
:6FC36612 mov si, word ptr [6FC3664B] ; SI = hit count (loop counter)
:6FC36619 mov ecx, 6FC3663B ; ECX = address of packet buffer
:6FC3661E mov edx, dword ptr [6FC3B084] ; EDX = connected socket descriptor
:6FC36624 push 00 ; flags = 0
:6FC36626 push 09 ; buffer length = 9 bytes
:6FC36628 push ecx
:6FC36629 push edx
:6FC3662A call dword ptr [6FC37184] ; Winsock send()
:6FC36630 dec si
:6FC36632 test si, si
:6FC36635 jnz 6FC36619 ; Loop until SI == 0
:6FC36637 popad
:6FC36638 ret
Space Bar Hook
; Fires the loop immediately using whatever target is already in the buffer
:6FAFCFF0 call 6FC36611 ; Jump into send loop (skips the target ID setup)
:6FAFCFF5 ret
NOTES
Why SI instead of ECX for the loop counter?
ECX is clobbered by the Winsock send() call. Saving and restoring it around the pushes would have required an extra push/pop on the stack, interleaved with the other function arguments. SI is not touched by send() and stays intact across the loop.
Jumping into the send routine at 6FC36611 (after the mov [6FC36640], ebx line) lets the Space bar hook reuse whatever target ID was last written — no separate target lookup needed.
SEE ALSO
- d2-autohits(6) — How to send multiple attack packets per click in Diablo II v1.09b
TECHNOLOGIES
- x86 Assembly
- Packet Injection
- Reverse Engineering
- Diablo II