Remove em dashes from the README
This commit is contained in:
@@ -20,25 +20,25 @@ protecting you, and one priest levitating nearby can drop you out of the game.
|
|||||||
## What it fixes
|
## What it fixes
|
||||||
|
|
||||||
Every character animation has a number. Running is 0, walking 1, standing 2,
|
Every character animation has a number. Running is 0, walking 1, standing 2,
|
||||||
falling 35 — hovering is 137.
|
falling 35, and hovering is 137.
|
||||||
|
|
||||||
Your character model has around 150 animations. The things you *wear* — helm,
|
Your character model has around 150 animations. The things you *wear* (helm,
|
||||||
shoulders, cape, weapon — are separate small models, and the client keeps them in
|
shoulders, cape, weapon) are separate small models, and the client keeps them in
|
||||||
sync by telling each one: *play the same animation number as your wearer.*
|
sync by telling each one: *play the same animation number as your wearer.*
|
||||||
|
|
||||||
A helm does not have 150 animations. Most have exactly one. Its table is one entry
|
A helm does not have 150 animations. Most have exactly one. Its table is one entry
|
||||||
long.
|
long.
|
||||||
|
|
||||||
Nobody checks whether the number fits the table. The helm is told "play number 137",
|
Nobody checks whether the number fits the table. The helm is told "play number 137",
|
||||||
and the client counts 137 entries forward from a table that ended after one — landing
|
and the client counts 137 entries forward from a table that ended after one, landing
|
||||||
in memory belonging to something else entirely, and reading whatever happens to be
|
in memory belonging to something else entirely and reading whatever happens to be
|
||||||
there. That value is then used as a position. Usually it is obvious nonsense and gets
|
there. That value is then used as a position. Usually it is obvious nonsense and gets
|
||||||
rejected. Sometimes it is a huge number, the client reads an address a gigabyte away
|
rejected. Sometimes it is a huge number, the client reads an address a gigabyte away
|
||||||
that does not exist, and Windows kills the game.
|
that does not exist, and Windows kills the game.
|
||||||
|
|
||||||
This is why the crash:
|
This is why the crash:
|
||||||
|
|
||||||
- hits **bystanders**, never the person who cast the spell — their own model has all
|
- hits **bystanders**, never the person who cast the spell, whose own model has all
|
||||||
the animations,
|
the animations,
|
||||||
- depends on what the levitating player is **wearing**,
|
- depends on what the levitating player is **wearing**,
|
||||||
- happens **sometimes** rather than every time,
|
- happens **sometimes** rather than every time,
|
||||||
@@ -56,7 +56,7 @@ in game.
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- WoW **1.12.1**, client build **5875**
|
- WoW **1.12.1**, client build **5875**
|
||||||
- A `dlls.txt` loader — **VanillaFixes**
|
- A `dlls.txt` loader: **VanillaFixes**
|
||||||
|
|
||||||
If you already use nampower, SuperWoW, UnitXP or transmogFix, you have VanillaFixes
|
If you already use nampower, SuperWoW, UnitXP or transmogFix, you have VanillaFixes
|
||||||
already and `dlls.txt` exists.
|
already and `dlls.txt` exists.
|
||||||
@@ -95,11 +95,11 @@ prevented=0
|
|||||||
worst_index=0
|
worst_index=0
|
||||||
```
|
```
|
||||||
|
|
||||||
- **`status`** — `installed …` means the fix is active. Anything starting with
|
- **`status`**: `installed at ...` means the fix is active. Anything starting with
|
||||||
`refused:` means it patched nothing; see Safety below.
|
`refused:` means it patched nothing; see Safety below.
|
||||||
- **`prevented`** — how many out-of-range lookups it has refused. Each one is a read
|
- **`prevented`**: how many out-of-range lookups it has refused. Each one is a read
|
||||||
that would otherwise have gone past the end of a table.
|
that would otherwise have gone past the end of a table.
|
||||||
- **`worst_index`** — the largest out-of-range animation number seen so far. Expect
|
- **`worst_index`**: the largest out-of-range animation number seen so far. Expect
|
||||||
**137** to appear after someone levitates near you.
|
**137** to appear after someone levitates near you.
|
||||||
|
|
||||||
The file is rewritten every few seconds while the count changes.
|
The file is rewritten every few seconds while the count changes.
|
||||||
@@ -109,8 +109,8 @@ The file is rewritten every few seconds while the count changes.
|
|||||||
## Safety
|
## Safety
|
||||||
|
|
||||||
Before patching anything, LeviFix compares the six bytes at the target address against
|
Before patching anything, LeviFix compares the six bytes at the target address against
|
||||||
what it expects to find. If they differ — a different client build, a game update, or
|
what it expects to find. If they differ (a different client build, a game update, or
|
||||||
another mod that got there first — **it patches nothing at all** and records the reason
|
another mod that got there first) **it patches nothing at all** and records the reason
|
||||||
in `levifix.txt`. It cannot corrupt a client it does not recognise.
|
in `levifix.txt`. It cannot corrupt a client it does not recognise.
|
||||||
|
|
||||||
It hooks exactly one function, changes six bytes **in memory only, never on disk**,
|
It hooks exactly one function, changes six bytes **in memory only, never on disk**,
|
||||||
@@ -118,7 +118,7 @@ touches no game files, sends nothing anywhere, and has no effect on gameplay. Th
|
|||||||
observable change is that an attached model can hold a single animation frame instead
|
observable change is that an attached model can hold a single animation frame instead
|
||||||
of the game crashing.
|
of the game crashing.
|
||||||
|
|
||||||
It does **not** fix the underlying bug — that is in the client, and only the client
|
It does **not** fix the underlying bug. That is in the client, and only the client
|
||||||
authors can fix it properly. It stops the crash at the last moment. If a different
|
authors can fix it properly. It stops the crash at the last moment. If a different
|
||||||
crash appears, check `status` in `levifix.txt` first, and disable the DLL to rule it
|
crash appears, check `status` in `levifix.txt` first, and disable the DLL to rule it
|
||||||
out.
|
out.
|
||||||
@@ -156,13 +156,13 @@ If the hash does not match, do not use the file.
|
|||||||
## Technical detail
|
## Technical detail
|
||||||
|
|
||||||
- Faulting instruction: `0x00713DFF`, `mov ebx, [ecx+edx*4]`, inside `sub_00713D50`.
|
- Faulting instruction: `0x00713DFF`, `mov ebx, [ecx+edx*4]`, inside `sub_00713D50`.
|
||||||
That function receives an M2 animation track — confirmed by the
|
That function receives an M2 animation track (confirmed by the
|
||||||
`word [track+2] == 0xFFFF` global-sequence test at `0x713D96` — plus an animation
|
`word [track+2] == 0xFFFF` global-sequence test at `0x713D96`) plus an animation
|
||||||
index.
|
index.
|
||||||
- It loads the track's entry count from `[track+4]`, tests it **only against zero**,
|
- It loads the track's entry count from `[track+4]`, tests it **only against zero**,
|
||||||
and then indexes an 8-byte-stride range table at `[track+8]` with the animation
|
and then indexes an 8-byte-stride range table at `[track+8]` with the animation
|
||||||
index, without ever comparing the two. The only follow-up check is `start < end`,
|
index, without ever comparing the two. The only follow-up check is `start < end`,
|
||||||
and both of those come from the same, possibly out-of-bounds entry — two garbage
|
and both of those come from the same, possibly out-of-bounds entry, so two garbage
|
||||||
values in ascending order pass it.
|
values in ascending order pass it.
|
||||||
- The index arrives from the model instance's field `+0x9C`, which at `0x00714650` is
|
- The index arrives from the model instance's field `+0x9C`, which at `0x00714650` is
|
||||||
copied verbatim from another model instance: an attachment inherits its wearer's
|
copied verbatim from another model instance: an attachment inherits its wearer's
|
||||||
@@ -170,7 +170,7 @@ If the hash does not match, do not use the file.
|
|||||||
- Measured across one installation: of 4502 attachment models, 3837 have exactly one
|
- Measured across one installation: of 4502 attachment models, 3837 have exactly one
|
||||||
animation, and 305 have at least one animation track shorter than index 137. Of the
|
animation, and 305 have at least one animation track shorter than index 137. Of the
|
||||||
1239 short tracks, reading at index 137 yields a value that passes the `start < end`
|
1239 short tracks, reading at index 137 yields a value that passes the `start < end`
|
||||||
check and is large enough to fault in about 17% of cases — which is why the crash is
|
check and is large enough to fault in about 17% of cases, which is why the crash is
|
||||||
occasional rather than constant.
|
occasional rather than constant.
|
||||||
- The hook refuses the lookup and returns `{0, 0, 0.0f}`, matching the client's own
|
- The hook refuses the lookup and returns `{0, 0, 0.0f}`, matching the client's own
|
||||||
degenerate-range path at `0x00713D7F`.
|
degenerate-range path at `0x00713D7F`.
|
||||||
|
|||||||
Reference in New Issue
Block a user