How to hack certain properties

Blitz3D Forums/Blitz3D Tutorials/How to hack certain properties

jfk EO-11110(Posted 2006) [#1]
This is about how to hack certain properties. Sometimes you will miss a function that will tell you about some settings of a entity or something. One example is "how to determine a brushes alpha setting", that is needed when calculating the visibility of surfaces. Instead of requesting for new features you may try to help yourself and solve the problem as a hacker.

Note: it is not sure if these hacks will still work with future versions of the blitz3D compiler, although it's likely.

What we do is: we take the handle of eg. the brush. We assume this handle is the adress of a pointer to the brush structure. So we read the 32 bit adress found at adress HANDLE. Now we scan the memory beginning at that adress. If we are going to find our highly individual brush setting float then we can assume we have found the offset of the alpha parameter in the brush structure.

This method uses the RTLMoveMemory command so you need a decls file named "kernel32.decls" in your "userlibs" folder, containing at least the following lines:
.lib "kernel32.dll"
RTLMoveMemory2%(Destination*, Source, Length) : "RTLMoveMemory"


RTLMoveMemory2 is used to read the RAM at absolute adresses.

The following example will search for the Alpha setting of a brush. With a little editing it can easily be used to search for other things as well.
Graphics3D 640,480,32,2
SetBuffer BackBuffer()

magic#=0.314159 ; tag used in search

brush=CreateBrush(100,150,200) ; create a dummy brush
BrushAlpha brush,magic#

ba=CreateBank(8)
PokeFloat ba,0,magic# ; get the integer binary equivalent of magic# (using Float directy fails due to NAN values)
magic_i%=PeekInt(ba,0)
FreeBank ba


bank=CreateBank(8) ; used to receive alpha value
adr_bank=CreateBank(8) ; used to receive base adress

For i2=0 To 100 Step 2 ; most pointers may be below 100 and even offsets
 RtlMoveMemory2(adr_bank,brush+i2,4) ; read potential base adress
 adr=PeekInt(adr_bank,0)
 For i=0 To 65535 
  RtlMoveMemory2(bank,adr+i,4) ; seek magic value
  magic_i2%=PeekInt(bank,0)
  If magic_i%=magic_i2% Then
   Print "found:"
   Print "base adress taken from: brush+"+i2
   Print "offset: "+i
  EndIf
  If KeyDown(1) Then End
 Next
Next

Print
Print "ok"
Print


; if an adress is once known it's value can be accessed directly like this:
RtlMoveMemory2(adr_bank,brush+0,4) ; determine absolute adress of a brushes alpha setting
adr=PeekInt(adr_bank,0)+32
RtlMoveMemory2(bank,adr,4) ; read alpha to bank
alpha#=PeekFloat(bank,0)
Print "alpha#: "+alpha#



WaitKey()
End


Of course the same can also be used with integer parameters, after replacing the float access parts.

BTW this program goes further than simply trying to use the HANDLE as pointer, it will also try a number of pointers taken at HANDLE + i2, although if present a parameter will most likely be found in the structure found at pointer HANDLE.


jfk EO-11110(Posted 2006) [#2]
So this would be the way it's used in an app:
global hackbank1,hackbank2
hackbank1=createbank(4)
hackbank2=createbank(4)
...
function GetBrushAlpha#(brush)
 local adr
 RtlMoveMemory2(hackbank1,brush,4)
 adr=PeekInt(hackbank1,0)+32
 RtlMoveMemory2(hackbank2,adr,4) ; read alpha to bank
 return PeekFloat(hackbank2,0)
end function



jfk EO-11110(Posted 2006) [#3]
I just see for some objects you may need to search i2 eg. from -100 to 100 since it seems to be -96 for Entity properties (eg. EntityAlpha).

An Entity structure may be a bit more complex than eg. Brush structures since its dynamic structure may be affected by CopyEntity etc. so handle with care.


DJWoodgate(Posted 2006) [#4]
Yes, I came up with something a while back that displayed memory in a side panel while you changed things on a 3d viewport. Lets you scroll through memory, step into and out of offsets etc. Ugly piece of code though, even by my standards.

Ideally Mark would just add some more functions to the language to get this stuff though, a lot less headache.

Sometimes things are not stored in the same format as provided to a function. An int in the range 0..255 might be stored as a float in the range 0..1, that sort of thing.

Sometimes what appear to be pointers might just be data, so you have to what out for that. There are API functions to check for things like valid read pointers which at least stop things going awry if what appears to be an address is outside valid memory space. I found it easier to display a whole chunk of memory rather than just searching for individual value changes. Gives you a better idea of what is going on, though to be honest it is still a mystery to me what a lot of the values represent.

Watch out for that -96 offset. I would look for a pointer in the structure that points to another structure. Otherwise it might not work reliably.


jfk EO-11110(Posted 2006) [#5]
Of course, it's only a work around. As long as it can be used to determine the state of a certain setting, I don't care that much what it exactly is. Writing to the structures looks much more dangerous to me, and was not the goal of this approach.
Using this method to optain brush information allows me not to use a third party dll that does the same, plus whatnot.

Additionally, a built in function GetBrushAlpha would probably look about the same (esp. if written in ASM): obtain the adress of the structure, read a certain offset or type variable.