• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Accessing memory from the script - it's time of the revolution

Status
Not open for further replies.
Level 19
Joined
Dec 12, 2010
Messages
2,069
ok i used that and found where limit is saved
yLKz.png


game stores 300 000 (300k) at gameDLL + 0x3a8389
at the pseudocode it looks like that
0CW0.png


they're using x10 value and cut it down by 10. I used 8950752, so it got rounded

this value being kept through whole game, until restart of wc3, as many other constants. im almost sure this area is read-only protected as well, but thats not problem for us neither. guess our offset-restoring dll will be useful in the end, since there's no other way to restore altered read-only areas.

0 value = nothing ever being evaluated. that can be even be used to fuckup wc3 until restart :D
I've also tried 0x0fffffff and that was hard to even pass first 3 steps
rF0q.png



so, no more limits. yay
 
  • Like
Reactions: ~El

~El

Level 17
Joined
Jun 13, 2016
Messages
556
Holy hell, you sure were quick to figure it out. Great job!

So, that means it really is possible to prevent the ops limit from fucking shit up, which sure is nice! Setting it to a high value (like you did), would probably make long loops potentially useful again.

I am completely clueless as to how to alter it throug JASS, though, since I'm a worthless dummy :v
 
Level 19
Joined
Dec 12, 2010
Messages
2,069
Nice find, although there are some practical reasons for the OP limit to exist.

Just imagine running an endless loop without the OP limit in place. Instead of just halting the thread, the game would just freeze. It's nice to extend the OP limit, but removing it completely might be a bad choice.
sounds like that's game fault and not creator's. while it's obviously mapmaker's issue
 
Level 6
Joined
Jul 30, 2013
Messages
282
Nice find, although there are some practical reasons for the OP limit to exist.

Just imagine running an endless loop without the OP limit in place. Instead of just halting the thread, the game would just freeze. It's nice to extend the OP limit, but removing it completely might be a bad choice.

that would in many ways be preferable. at least it would fail early and we could fix our map the same day.. or hour in stead of fishing for obscure bugs and desyncs 10 years later.

altho it would be nice if it would like log a warning or sth if this happened (for debugging). would be too much of a luxury to ask for tho? :(
 

~El

Level 17
Joined
Jun 13, 2016
Messages
556
The ops limit is a nice thing for when people who have little experience with programming are making triggers in the GUI. However, it should not really be enforced upon more experienced mapmakers that know what they are doing. Instead, blizzard decided to group everyone together in this regard, and now we have to live with the consequences of this hilariously restrictive limit.

And after all, if you have an infinite loop in your map - well, that's your fault. It's a bug, a bug just like any other, and not one that is hard to fix at that. I don't think it legitimately deserves special attention. Most programming languages do not prevent against that kind of thing, they don't babysit you, so why should JASS? And even though debug facilities in JASS are rather lacking, you can still make do with printed messages or even file logs (using the preload exploit), if needs be. It is more than enough to debug most scenarios, even if it is cumbersome.

tl;dr Infinite loops are just a regular bug like any other and shouldn't deserve special attention. Bad mapmakers will always be bad mapmakers, and bad maps will always be bad maps, even if there are limits in the game to help them.

edit: Not to mention that checking the ops limit at every operation to see if it has been exceeded incurs an overhead for the VM. Even if it is negligible, it is still there, especially since the thread can crash at any operation, thus it must check the ops limit after every instruction.
 
Level 19
Joined
Dec 12, 2010
Messages
2,069
edit: Not to mention that checking the ops limit at every operation to see if it has been exceeded incurs an overhead for the VM. Even if it is negligible, it is still there, especially since the thread can crash at any operation, thus it must check the ops limit after every instruction.
not really, C is fastest languange anyway. and debugging is easier thing to do today, just look in my signature. JassSpy got updates, but I have no time to properly update instructions. It became a real debug tool
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
C is fastest languange anyway
C is not the fastest language. Most languages are equally fast for similar purposes thanks to optimizing compilers. It is completely possible for a Java program to execute at the same piece of code at the same speed as a C or C++ program if what is being executed in functionally equivalent.

Ultimately it is the compilers and linkers which make a language fast, not the language itself. Some lower level languages like C allow for some tasks to be implemented with less logical overhead and hence be faster than possible in other languages. However C will still perform equally when it comes to executing high level tasks supported by the other higher level languages.

The reason JASS is so slow is because of its very poor virtual machine implementation. It performs a run time lookup for every name to resolve its meaning and value (no linking). It has as good as no optimization during compilation. It also has no JIT compiler, instead executing JASS byte code in an interpreter. The JASS interpreter is also not the fastest due to checks like oplimit etc.

Also it should not be possible to modify the game DLL files from within WC3 as it will throw a security exception as DLL files are memory mapped in as read only. One would have to remap those pages to make modifications to them which could throw security exceptions unless run as an administrator.
 
Last edited:
Level 19
Joined
Dec 12, 2010
Messages
2,069
Also it should not be possible to modify the game DLL files from within WC3 as it will throw a security exception as DLL files are memory mapped in as read only. One would have to remap those pages to make modifications to them which could throw security exceptions unless run as an administrator.
we dont modify gamedll but memory. win7 sp1 on user-level gave no security warnings whatsoever.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
we dont modify gamedll but memory. win7 sp1 on user-level gave no security warnings whatsoever.
However dll code should be read only memory and is memory mapped in some way to allow for deferred loading and low memory footprint.

Unless of course it is compressed...
Wikipedia said:
If a DLL is compressed by certain executable packers (e.g. UPX), all of its code sections are marked as read and write, and will be unshared. Read-and-write code sections, much like private data sections, are private to each process. Thus DLLs with shared data sections should not be compressed if they are intended to be used simultaneously by multiple programs, since each program instance would have to carry its own copy of the DLL, resulting in increased memory consumption.
 
Level 19
Joined
Dec 12, 2010
Messages
2,069
However dll code should be read only memory and is memory mapped in some way to allow for deferred loading and low memory footprint.

Unless of course it is compressed...
it's not my field, but - this memory cannot be overwritten freely. we remove it's protection before doing so, then recover it back. that what I call read-only. any 3rd side software can change those adressess anytime, it's not "real" read-only, but from within.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
it's not my field, but - this memory cannot be overwritten freely. we remove it's protection before doing so, then recover it back. that what I call read-only. any 3rd side software can change those adressess anytime, it's not "real" read-only, but from within.
However if its memory mapped what is to stop it writing out those changes back to the DLL file? Or what happens if the page is pushed out of memory due to a page fault?
 
Level 19
Joined
Dec 12, 2010
Messages
2,069
However if its memory mapped what is to stop it writing out those changes back to the DLL file? Or what happens if the page is pushed out of memory due to a page fault?
well, I only needed to change some bytes, not to write another. all functions within gamedll have plenty space between each other, like 8 bites, which is enough for small injections. obviously, you cannot modify gamedll itself since it's busy by wc3. but we can address default win's functions to allocate memory if needed and do other stuff of any kind.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
obviously, you cannot modify gamedll itself since it's busy by wc3.
Except that is exactly what I am talking about. If you modify the loaded code from the dll what is to stop those changes being pushed out by the memory mapping system when the code page is pushed out? If the changes are not written out what stops the page mutating as a result of a page fault? Or does WC3 used some form of compressed DLL which does not memory map code?
 
Level 9
Joined
Jul 30, 2012
Messages
156
Also it should not be possible to modify the game DLL files from within WC3 as it will throw a security exception as DLL files are memory mapped in as read only. One would have to remap those pages to make modifications to them which could throw security exceptions unless run as an administrator.

Raichu has already demonstrated the possibility to overwrite the table of Jass natives at runtime, replacing the address of any specific native with any address we want. This allows the possibility of calling the Win32 API directly from Jass code. And with that power, you can simply use VirtualProtect to change the page protection of game.dll to read/write, unlocking the ability to modify the game code in memory. (And this doesn't require administrator privileges, since its a modification from inside the process)

@topic: I've been very busy with college for the past month, but I'll probably release some updates next week or so, when my tests are finished.
 
Level 6
Joined
Jul 30, 2013
Messages
282
if that's possible it would be awesome..

Its rly annoying to trigger a certain anti-spoofing mechanism in replays..
 
Level 19
Joined
Dec 12, 2010
Messages
2,069
Random idea :
Maybe it's possible to know when it's a replay or not, now ?
I know there is a such system lying somewhere but it's not bug free.
sure, we check for replay's button overlay to do so
You mentioned HTTP briefly in one of the first pages. Have you guys managed to do any network access of any kind?
pure http isnt that good from inside the code due to big chunks of data, we only did this via dll. surely its possible but takes much time to do
 
Level 9
Joined
Jun 21, 2012
Messages
432
This is amazing....

First it was vexorian with JassHelper and now you say that we can read the memory of Warcraft III using jass.
I have a several questions and suggestions that I wish that you to consider:

  • How is your progress in this?

This snippet requires that you use the [post=2822976]experimental version of pjass[/post], that can disable syntax checking on specific functions. After all, the code makes pretty much no sense. But it works!

  • Where I can get this experimental version of pjass?

The following code provides the ability to read from any place in WC3 memory, but NOT write. It is split into 2 parts: the first library provides typecasting, and the second uses it to get memory access.

  • I think if can read also can write.


JASS:
library Utils requires Memory, Bitwise, ObjectData

/* Takes a handle from the Jass world, and returns the memory address of the corresponding native
   object. Don't use non-agent handles (<1048576) with this function, or the game crashes! */
function ConvertHandle takes handle h returns integer
    return Memory[Memory[Memory[Memory[GameState]/4+7]/4+103]/4 + GetHandleId(h)*3 - 0x2FFFFF]
endfunction

// Returns the total armor of the unit, with all bonuses applied
function GetUnitArmor takes unit u returns real
    return indexToReal(Memory[ConvertHandle(u)/4+56])
endfunction

// Returns 1 for Str, 2 for Int and 3 for Agi. Crashes if called on non-hero units
function GetHeroPrimaryAttribute takes unit u returns integer
    return Memory[Memory[ConvertHandle(u)/4+124]/4+51]
endfunction

function GetAbilityMaxLevel takes integer abil returns integer
    return Memory[GetObjectData(pAbilityData, abil)+20]
endfunction

// Returns the mana cost of an ability for the specified level. Don't pass a level above the max
function GetAbilityManaCost takes integer abil, integer level returns integer
    return Memory[Memory[GetObjectData(pAbilityData, abil)+21]/4-22+level*26]
endfunction

// Returns the base cooldown of an ability for a specified level.
function GetAbilityCooldown takes integer abil, integer level returns real
    return indexToReal(Memory[Memory[GetObjectData(pAbilityData, abil)+21]/4-21+level*26])
endfunction

/* This function returns the CURRENT cooldown of an ability, after it's cast. This is a per-instance
   value, and so it requires an ability handle, not an ability id. Currently the only way to obtain
   such a handle is the native GetSpellAbility (usable only from spell events). You can then save
   that handle in a hashtable if you need */
function GetAbilityCurrentCooldown takes ability a returns real
    local integer pData = Memory[ConvertHandle(a)/4+55]/4
    if pData != 0 then
        return cleanReal(indexToReal(Memory[pData+1])) - cleanReal(indexToReal(Memory[Memory[pData+3]/4+16]))
    endif
    return .0
endfunction

endlibrary

  • Maybe these functions can be included into a new version of JassHelper like as "MemoryScript natives"
Well for the moment that's all, I'll be preparing a list of all possible functions that can be achieved with this method.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
Where I can get this experimental version of pjass?
It is needed because JASSHelper is better at checking syntax than Warcraft III so it flags up some errors which WC3 will parse.

I think if can read also can write.
He can write to memory, just he has not made an easy to use snippet to do so and is trying to limit the public use of the functionality. The reason for this is that this is a critical security exploit that could be used by hackers to put malware into maps.

As good as this feature may seem, it is too dangerous to leave in. Blizzard really needs to patch it out.
 

Deleted member 219079

D

Deleted member 219079

I tested this on my windows 7, with patch 1.27a and it doesn't work. Every time I start the map, I'm redirected to the main Warcraft menu. o_O

Pls help.
I think it worked after you inlined ImLazy(). It was a while since I tested this so I'm not 100% sure.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
I tried what you said
JASS:
        local integer i
        call ImLazy()
==>
        local integer i
        set l__A[1] = 1

still didn't work

EDIT:
I think it worked after you inlined ImLazy(). It was a while since I tested this so I'm not 100% sure.
Well, instead I commented out the ImLazy() line, and there it runs now.
I'm not sure though if that line's needed for it to work, is it?
 
Last edited:

Deleted member 219079

D

Deleted member 219079

I made the code in vJASS: (Edit: I mean typecasting, the only useful thing about this thread for normal vJASSer)
JASS:
library Typecast

    globals
        integer tcRevert
        integer l__tcRevert
    endglobals

    private function Revert takes integer i returns nothing
        set l__tcRevert = i
        return
    endfunction

    //! textmacro TYPECAST_NEW takes TYPE,NAME,REVNAME
    globals
        $TYPE$ $NAME$var
        $TYPE$ l__$NAME$var
    endglobals

    private function $NAME$Set takes $TYPE$ var returns nothing
        set l__$NAME$var = var
        return
    endfunction

    private function $NAME$Exploit takes nothing returns nothing
        local integer $NAME$var
        local $TYPE$ tcRevert
    endfunction

    function $NAME$ takes $TYPE$ var returns integer
        call $NAME$Set(var)
        return l__$NAME$var
    endfunction

    function $REVNAME$ takes integer i returns $TYPE$
        call Revert(i)
        return l__tcRevert
    endfunction

    private function $NAME$Unexploit takes nothing returns nothing
        local integer tcRevert
    endfunction
    //! endtextmacro
 
    //! runtextmacro TYPECAST_NEW ("code","C2I","I2C")
    //! runtextmacro TYPECAST_NEW ("string","SH2I","I2SH")
    //! runtextmacro TYPECAST_NEW ("boolean","B2I","I2B")
 
endlibrary
 
Level 13
Joined
Nov 7, 2014
Messages
571
JASS:
//# +nosemanticerror
function realToIndex takes real r returns integer
    return r
endfunction

function cleanInt takes integer i returns integer
    return i
endfunction

//# +nosemanticerror
function indexToReal takes integer i returns real
    return i
endfunction

function cleanReal takes real r returns real
    return r
endfunction

JASS:
local real r = 6.28
local integer r_as_int

// set r_as_int = realToIndex(r)
// call BJDebugMsg(I2S(r_as_int)) // "crash", forgot to "clean"

set r_as_int = cleanInt(realToIndex(r))
call BJDebugMsg(I2S(r_as_int)) // 1086911939 (0x40C8F5C3)

Why do we have to "clean" when reinterpreting the bits of a real as an int and vice versa? In the "forgot to clean" case, why does the execution stops/"crashes", as if the variable was uninitialized?
 
Status
Not open for further replies.
Top