System MapLock

Jesus4Lyf

Good Idea™
Reaction score
397
MapLock​
Version 1.0​

Requirements:
- Jass NewGen

Description:
Locks your map so it can't be edited (as easily) by hackers.

North:
JASS:
library MapLockNorth
    private function C2I takes code f returns integer
        return f
        return 0
    endfunction
    public function GetIndex takes nothing returns integer
        return C2I(function GetIndex)
    endfunction
endlibrary


South:
JASS:
scope MapLockSouth initializer CheckLock
    globals
        private constant boolean LOCKED=false
        private constant integer KEY=0x96E0000
        
        private constant integer KEYDEPTH=0x10000000 // Add/remove 0's to change key's max length.
//****************************************************
        private string array TOCHAR
    endglobals
    private function InitTOCHAR takes nothing returns nothing
        set TOCHAR[0]="0"
        set TOCHAR[1]="1"
        set TOCHAR[2]="2"
        set TOCHAR[3]="3"
        set TOCHAR[4]="4"
        set TOCHAR[5]="5"
        set TOCHAR[6]="6"
        set TOCHAR[7]="7"
        set TOCHAR[8]="8"
        set TOCHAR[9]="9"
        set TOCHAR[10]="A"
        set TOCHAR[11]="B"
        set TOCHAR[12]="C"
        set TOCHAR[13]="D"
        set TOCHAR[14]="E"
        set TOCHAR[15]="F"
    endfunction
    private function ToHex takes integer i returns string
        local integer r
        local string result=""
        call InitTOCHAR()
        loop
            exitwhen i==0
            set r=i-(i/16)*16
            set result=TOCHAR[r]+result
            set i=(i-r)/16
        endloop
        return "0x"+result
    endfunction
    
    private function C2I takes code f returns integer
        return f
        return 0
    endfunction
    private function GetKey takes code f returns integer
        local integer key=C2I(f)-MapLockNorth_GetIndex()
        return key-(key/KEYDEPTH)*KEYDEPTH
    endfunction
    private function FatalError takes nothing returns nothing
        call C2I(function IsNoVictoryCheat) // Fatal error, gg.
    endfunction
    private function CheckLock takes nothing returns nothing
        if LOCKED then
            if GetKey(function CheckLock)!=KEY then
                call FatalError()
            endif
        else
            call BJDebugMsg("Key: "+ToHex(GetKey(function CheckLock)))
        endif
    endfunction
endscope


Explanation:
Put MapLockNorth as the first thing in your map, and MapLockSouth as the last. All your map code goes in between them. Think of them like magnets. In the field between them they generate a protection whereby if anything is changed, the map will crash with a fatal error.

Simply set LOCKED to false while working on the map. Hitting test map will display the map's KEY value. When you wish to lock the map, simply run the map, note the KEY, change the KEY constant to whatever it says, and change LOCKED to true.

If you wish to use the optimizer with this, you must optimize the map before getting the KEY, as the optimizer changes the code of the map.

Updates:
Version 1.0 - Release.
 

Jesus4Lyf

Good Idea™
Reaction score
397
>key-(key/KEYDEPTH)*KEYDEPTH = 0 ?
Nope. They're integers. So if key/KEYDEPTH is between 0 and 1, it becomes 0, for example. So this is the equivalent of "Subtract KEYDEPTH from key as many times as possible without going below 0". A modulo function. :thup:

>this "simply" gets the difference between the integer of code CheatLock and code GetIndex and check if it's different of the normal key?
Yep. That integer represents where in bytecode the start of that function is. So by doing that, it gets the "length" of the code between the two functions. Try it. If you lock a map and add a function call somewhere, or remove a line, or even change a setvariable line to a function call, it breaks, and the lock will cause a fatal error on map init. There was quite a bit of research behind this, but basically it's a secure map protection technique. Unless the hacker knows specifically about this system, they're unlikely to figure out what's causing the problem. :D
 

black.sheep

Active Member
Reaction score
24
Pretty kewl, i have afew questions about this though.
Can't they just destroy this via deleting the maplocknorth functions?
Does the Key work simply by generating a random string which is then added to a point?
Would it be possible to change afew things to remake this in just JASS?(I'm not asking anyone to do this for me)
Would it be possible to add gobals in the two functions that would cause problems with the entire script if they were removed/changed?
 

Jesus4Lyf

Good Idea™
Reaction score
397
>Pretty kewl, i have afew questions about this though.
Yay!

>Can't they just destroy this via deleting the maplocknorth functions?
Well no, because they won't know what they are, and they're referenced in the maplocksouth functions so it wouldn't compile.

>Does the Key work simply by generating a random string which is then added to a point?
The key is not a string! It is an integer. The key is a um... hashcode?... which represents the distance in memory between the North and South poles of MapLock. So think of it as a checksum sort of thing. :)

>Would it be possible to change afew things to remake this in just JASS?(I'm not asking anyone to do this for me)
Absolutely. In fact, this should be quite easy.

>Would it be possible to add gobals in the two functions that would cause problems with the entire script if they were removed/changed?
Global declarations can't be secured by MapLock because they must be declared before any functions. Of course, this shouldn't matter anyway because somewhere globals need to be used. The code that uses them will be secured by MapLock. So changing this code will cause a fatal error unless the correct new key is used.
 

Chocobo

White-Flower
Reaction score
409
normal JASS version (I can't use vjass)

JASS:
globals
    boolean udg_LOCKED=false
    integer udg_KEY=0x96E0000
    integer udg_KEYDEPTH=0x10000000 // Add/remove 0's to change key's max length.
    string array udg_TOCHAR
endglobals

function C2I takes code f returns integer
    return f
    return 0
endfunction

function GetIndex takes nothing returns integer
    return C2I(function GetIndex) //GetIndex to int
endfunction

//ALL BEFORE THIS = TOP (at top of custom script)
//ALL AFTER THIS = BOTTOM (create a dummy trigger if you have to do so and input all after it)

function InitTOCHAR takes nothing returns nothing
    set udg_TOCHAR[0]="0"
    set udg_TOCHAR[1]="1"
    set udg_TOCHAR[2]="2"
    set udg_TOCHAR[3]="3"
    set udg_TOCHAR[4]="4"
    set udg_TOCHAR[5]="5"
    set udg_TOCHAR[6]="6"
    set udg_TOCHAR[7]="7"
    set udg_TOCHAR[8]="8"
    set udg_TOCHAR[9]="9"
    set udg_TOCHAR[10]="A"
    set udg_TOCHAR[11]="B"
    set udg_TOCHAR[12]="C"
    set udg_TOCHAR[13]="D"
    set udg_TOCHAR[14]="E"
    set udg_TOCHAR[15]="F"
endfunction

function ToHex takes integer i returns string
    local integer r
    local string result=""
    call InitTOCHAR()
    loop
        exitwhen i==0
        set r=i-(i/16)*16
        set result=udg_TOCHAR[r]+result
        set i=(i-r)/16
    endloop
    return "0x"+result // Hex Key
endfunction

function GetKey takes code f returns integer
    local integer key=C2I(f)-GetIndex()
    return key-(key/udg_KEYDEPTH)*udg_KEYDEPTH // Modulo
endfunction

function FatalError takes nothing returns nothing
    call C2I(function IsNoVictoryCheat) // Fatal error
endfunction

function CheckLock takes nothing returns nothing
    if udg_LOCKED then // Script locked?
        if GetKey(function CheckLock)!=udg_KEY then // Not same as KEY?
            call FatalError() // Crash
        endif
    else
        call BJDebugMsg("K"+"e"+"y"+":"+" "+ToHex(GetKey(function CheckLock))) //Show key
    endif
endfunction
 

Chocobo

White-Flower
Reaction score
409
hmm, the only thing is that this script can be easily spotted (I could spot it easily on a 30000 line script and delete it).

to find it I done this :
- search "code f returns integer" -> kill the function itself and the function below it
- search "[15]="F" -> kill the function itself, the function below it.
- search "IsNoVictoryCheat" -> kill the function itself, the function after it.
- search for "<function name of function killed after IsNoVictoryCheat>" -> remove trigger action


ofc, the way to spot it in the map can be changed.


I would even do this :

JASS:
globals
    boolean udg_LOCKED=false
    integer udg_KEY=0x96E0000
    integer udg_KEYDEPTH=0x10000000 // Add/remove 0&#039;s to change key&#039;s max length.
    string array udg_TOCHAR
    code udg_CODE=function IsNoVictoryCheat
endglobals

function C2I takes code f returns integer
    return f
    return 0
endfunction

//ALL BEFORE THIS = TOP (at top of custom script)
//ALL AFTER THIS = BOTTOM (create a dummy trigger if you have to do so and input all after it)

function InitTOCHAR takes nothing returns nothing
    set udg_TOCHAR[11]=&quot;0&quot;
    set udg_TOCHAR[12]=&quot;1&quot;
    set udg_TOCHAR[13]=&quot;2&quot;
    set udg_TOCHAR[14]=&quot;3&quot;
    set udg_TOCHAR[15]=&quot;4&quot;
    set udg_TOCHAR[16]=&quot;5&quot;
    set udg_TOCHAR[17]=&quot;6&quot;
    set udg_TOCHAR[18]=&quot;7&quot;
    set udg_TOCHAR[19]=&quot;8&quot;
    set udg_TOCHAR[20]=&quot;9&quot;
    set udg_TOCHAR[21]=&quot;A&quot;
    set udg_TOCHAR[22]=&quot;B&quot;
    set udg_TOCHAR[23]=&quot;C&quot;
    set udg_TOCHAR[24]=&quot;D&quot;
    set udg_TOCHAR[25]=&quot;E&quot;
    set udg_TOCHAR[26]=&quot;F&quot;
endfunction

function ToHex takes integer i returns string
    local integer r
    local string result=&quot;&quot;
    call InitTOCHAR()
    loop
        exitwhen i==0
        set r=i-(i/16)*16
        set result=udg_TOCHAR[r+11]+result
        set i=(i-r)/16
    endloop
    return &quot;0+&quot;+&quot;x&quot;+result // Hex Key
endfunction

function GetKey takes code f returns integer
    local integer key=C2I(f)-C2I(function C2I)
    return key-(key/udg_KEYDEPTH)*udg_KEYDEPTH // Modulo
endfunction

function FatalError takes nothing returns nothing
    call C2I(udg_CODE) // Fatal error
endfunction

function CheckLock takes nothing returns nothing
    if udg_LOCKED then // Script locked?
        if GetKey(function CheckLock)!=udg_KEY then // Not same as KEY?
            call FatalError() // Crash
        endif
    else
        call BJDebugMsg(&quot;K&quot;+&quot;e&quot;+&quot;y&quot;+&quot;:&quot;+&quot; &quot;+ToHex(GetKey(function CheckLock))) //Show key
    endif
endfunction



y, "Key: " = "K"+"e"+"y"+":"+" "
 

Viikuna

No Marlo no game.
Reaction score
265
Doesnt optimizer change your code so unreadable that this is actually pretty hard to spot?
 

Chocobo

White-Flower
Reaction score
409
>Doesnt optimizer change your code so unreadable that this is actually pretty hard to spot?

doesn't make much unreadable, even if I use a charkey of letters.


for GUI users this can be easily implemented by doing this :

create 4 globals :
- KEY = integer
- KEYDEPTH = integer
- LOCKED = boolean
- TOCHAR = string array

JASS:
function C2I takes code f returns integer
    return f
    return 0
endfunction

//ALL BEFORE THIS = TOP (at top of custom script)


put this at the top of the custom script


create a trigger (call it whatever you want to but add an event so it fires at init/elasped 0.0 second)

all before :

JASS:
//===========================================================================


remove everything and add :

JASS:
//ALL AFTER THIS = BOTTOM (create a dummy trigger if you have to do so and input all after it)

function InitTOCHAR takes nothing returns nothing
    set udg_TOCHAR[11]=&quot;0&quot;
    set udg_TOCHAR[12]=&quot;1&quot;
    set udg_TOCHAR[13]=&quot;2&quot;
    set udg_TOCHAR[14]=&quot;3&quot;
    set udg_TOCHAR[15]=&quot;4&quot;
    set udg_TOCHAR[16]=&quot;5&quot;
    set udg_TOCHAR[17]=&quot;6&quot;
    set udg_TOCHAR[18]=&quot;7&quot;
    set udg_TOCHAR[19]=&quot;8&quot;
    set udg_TOCHAR[20]=&quot;9&quot;
    set udg_TOCHAR[21]=&quot;A&quot;
    set udg_TOCHAR[22]=&quot;B&quot;
    set udg_TOCHAR[23]=&quot;C&quot;
    set udg_TOCHAR[24]=&quot;D&quot;
    set udg_TOCHAR[25]=&quot;E&quot;
    set udg_TOCHAR[26]=&quot;F&quot;
endfunction

function ToHex takes integer i returns string
    local integer r
    local string result=&quot;&quot;
    call InitTOCHAR()
    loop
        exitwhen i==0
        set r=i-(i/16)*16
        set result=udg_TOCHAR[r+11]+result
        set i=(i-r)/16
    endloop
    return &quot;0&quot;+&quot;x&quot;+result // Hex Key
endfunction

function GetKey takes code f returns integer
    local integer key=C2I(f)-C2I(function C2I)
    set udg_KEYDEPTH=0x10000000
    return key-(key/udg_KEYDEPTH)*udg_KEYDEPTH // Modulo
endfunction

function FatalError takes nothing returns nothing
    call C2I(function IsNoVictoryCheat) // Fatal error
endfunction

function CheckLock takes nothing returns nothing
    if udg_LOCKED then // Script locked?
        if GetKey(function CheckLock)!=udg_KEY then // Not same as KEY?
            call FatalError() // Crash
        endif
    else
        call BJDebugMsg(&quot;K&quot;+&quot;e&quot;+&quot;y&quot;+&quot;:&quot;+&quot; &quot;+ToHex(GetKey(function CheckLock))) //Show key
    endif
endfunction


find "TriggerAddAction" (at bottom of the custom script page) : where you see "function <blabla>)", replace all that by "function CheckLock)".


anyway, can't find "code" in global list in the regular worldedit.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Your understanding is dead on there, Chocobo.
The princible of this system is the hackers don't know how it works yet. It's not popular. Furthermore, once it is, it's easily customisable anyway. I was thinking of releasing flavours with all kinds of stupid mechanisms in there just to give them a real pain, so users can pick a random flavour. Then it would be hard to detect.

But you have to remember that very few hackers right now will know this code, and if they haven't specifically seen this very thread they stand little chance of figuring out what on earth is going on. :)

The reason the vJass version (my version) doesn't just take C2I(function C2I) as the top is vJass doesn't let you use functions that take parameters, sadly.

PS. "set udg_KEYDEPTH=0x10000000" should be at the start of CheckLock. :)
 

Cohadar

master of fugue
Reaction score
209
Great now all you have to do is make some maps that people actually want to play bad enough to cheat...
 

SerraAvenger

Cuz I can
Reaction score
234
And where is the great difference between this and Saw's version?
Apart from the fact that I can be sure that Saw's Index does change whenever I inject anything. I'm not sure whether this one does, too.
And ofc that Saw uses triggers while you use code : /

And for you I have to say the same I said to Saw:

Just crashing the map can easily be circumvented by lads that know how to break this sort of things, and by anyone who can read their tutorials.

Instead, use a global "IsMapHacked = true" boolean. Then your users can disable their code if IsMapHacked is true.
That way it becomes much harder to deactivate the system. Just removing a structure like the following:
JASS:
if xxx then
if yyy(function zzz )!=xxx then
call xxx()
endif
else
call BJDebugMsg(&quot;Key: &quot;+xxx( yyy( function zzz )))
endif

where xxx can be any string, yyy and zzz are random but the same string.
As soon as this is removed, the map won't crash anymore.
HOWEVER if you use a
JASS:
set IsMapHacked = GetKey(function CheckLock) != KEY

and then use
JASS:
if not IsMapHacked then
   // SOME INIT CODE
endif


the map will be much harder to hack.

This is just to give you an idea of what I'd change; Even this won't ensure a high level of security.

Personalising this stuff is a great idea, but even more will have to be done to really make this feature safe.

It should still be easy to mess up such a system using a simple regex, and if your map really gets good enough to be hacked then such an advanced system won't help anymore either.

EDIT:
JASS:
scope MapSafe

public function GetSafety takes nothing returns boolean
  return SafetyA_IsMapSafe() == SafetyB_IsMapSafe()
endfunction

endscope

//! textrepeat takes A = &quot;A&quot; to &quot;D&quot; // Replace &quot;D&quot; with another character Which isn&#039;t &quot;A&quot; 
library Safety$A$
globals
  private integer MapStage
  private boolean MapSafe   = false
  private string  MapValue

  private timer   MapTimer  = CreateTimer()
endglobals

private function SafeRefresh takes nothing returns nothing
  set MapSafe = // GetKey() == SAFED_KEY
  if MapSafe then
    set MapStage = MapStage + 1
  endif
  set MapValue = I2S( S2I( MapValue ) + 1 )
  set MapSafe = S2I( MapValue ) == MapStage
endfunction

public function IsMapSafe takes nothing returns boolean
  local real reloaderTime = GetRandomReal( 1, 1.6 )
  set MapSafe = // GetKey() == SAFED_KEY
  if MapSafe then
    set MapStage = 1
    if not MapSafe then
      set MapStage = 0
    endif
    if MapSafe then
      set MapStage = 1
    endif
  else
    set MapValue = I2S( MapStage - 1 )
  endif
  set MapValue = I2S( 1 )
  call TimerStart( MapTimer, reloaderTime, true, function SafeRefresh )
  return MapSafe
endfunction
endlibrary

//! endtextrepeat


I was thinking of something like this.
It cannot be hacked using regular expressions.
The only way I can think of to hack this is finding the MapSafe booleans and replacing all sets with = true.
However, as there are 2 - X of them of which only 2 are important, this is lots of work.
If you require some of the libraries that you create, this will even be much cooler as they won't be next to each other anymore.

I'm quite sure there are better ways, though.
I'm not a security expert, you know ; )
 

Jesus4Lyf

Good Idea™
Reaction score
397
Saw's looks poor to me (in comparison). All it does is check the handle count? That probably wouldn't even detect modifications most of the time (except for cheat packs because they add triggers). Mine actually checks the LINES. If you do so much as modify a function by adding a call BJDebugMsg you will get a fatal error. If you even add set i=i you will get a fatal error! There's no similarity in level of protection. :p

And thanks for the feedback, but honestly setting a global boolean seems kind of obvious to me. A fatal error is actually really subtle. It means the mapper can think they screwed up the checksum MPQ header, they wouldn't expect the code in the map to be purposely checking this. I've actually unprotected a map before and know what it's like. This system would be VERY hard to track if I didn't know it - you may notice, actually, that the map doesn't even get through loading before it crashes.

If it was a boolean, you'd see as a hacker that some boolean is being checked all the time, and when you change something some code doesn't run. Look for where it gets set instead, change that to true or false or w/e and you're done. This doesn't give the hint that the map code itself is doing it.
 

SerraAvenger

Cuz I can
Reaction score
234
Saw's looks poor to me (in comparison). All it does is check the handle count? Big deal. Unless I missed something, it probably wouldn't even work most of the time. Mine actually checks the LINES. If you do so much as modify a function by adding a call BJDebugMsg you will get a fatal error. If you even add set i=i you will get a fatal error! :p

You add a little line and it crashes. You think "WTF?!?";
And then you will ask some of the "cracking gurus". They already have a program at hand that will search for a structure like this one
Code:
if xxx then
if yyy(function zzz )!=xxx then
call xxx()
endif
else
call BJDebugMsg("Key: "+xxx( yyy( function zzz )))
endif
and automatically removes it.

This is a ruby regex coded without an editor that should find all your instances:
Code:
mapCode.gsub!(/if \w+ then
if \w+\(function \w+ \) != \w+ then
call \w+\(\)
endif
else
call BJDebugMsg\("Key: " + \w+\(\1\(function \2\)\)\)
endif/,"")

ofc all whitespaces would have to be replaced by \s* instead.
I'm not sure if this is the correct regex, but even if it isn't it should be easy to find the correct one. This one took me 2 minutes to code.
It would be easy to implement this into any existing deprotector within 30 minutes.

Mine is harder to spot. As I said, setting it to true would break the system, but it is much harder to find these variables.

There is a major difference between using code and trigger. Code is not a handle. It is a bytecode pointer. So unless I've missed something, this offers a whole new level of protection. :)
Yeah, have just seen your post about that.
This is just awesome : )
Perhaps I'll be able to do a couple of really mean things that way - thanks for "discovering" it; I'm sure I wouldn't have found out myself.

BTW:
What I was referencing was that you cannot be sure that the lines will be added before the GetIndex function that your are applying C2I() onto.
 

Igor_Z

You can change this now in User CP.
Reaction score
61
Question... I don't know JASS so Can i use it in my map? I don't know what it means. What to do? Just copy the text in my trigger
 

saw792

Is known to say things. That is all.
Reaction score
280
Saw's looks poor to me (in comparison). All it does is check the handle count? That probably wouldn't even detect modifications most of the time (except for cheat packs because they add triggers).

Mine was named Anti-CheatPack system...

I'll edit this post in a few minutes after checking out your system.
 

Azlier

Old World Ghost
Reaction score
461
It would probably be best to install this directly into the war3Map.j (taking care to use normal Jass syntax, of course). That way you could be 100% sure that MapLock South was at the bottom of your code. You can never really know, with scopes.
 

saw792

Is known to say things. That is all.
Reaction score
280
Yes you can. Scopes are added to the map script in the order they are added through the world editor. If you add that scope last then save you are safe.

This seems to work fairly well on an unoptimized map. A few minor changes made to the map script made the program crash properly. The problem comes mainly from the name of the library and scope that any would be hacker would notice on just a cursory scroll through the map script. Seeing as you have to add this code after optimizing it would stand out even more (compared to shortname functions/variables and such). To me it seems a huge amount of effort to put into your map which can still be defeated quite easily if you know what you are doing. If your map is popular it is far more likely somebody experienced will try to hack it, find your script and post it on wc3edit.net or something. If your map isn't popular then it is probably too much effort to put it into the map properly. Those are my thoughts, anyway. At least it does what it says it does.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top