Log in

View Full Version : [Linux][Tutorial]Reading Memory, Bypassing BattleEye and defeating Dma Tibia 12.31



Darkbyte
03-02-2020, 03:59
Note: You must use python 2.7 for this , something changed in 3.7 that makes the code not work , im not sure what it was. I get no errors but the code just fails to find addresses so its probly some module change somewhere.
In linux when we load a process a folder with the process id is created in

/proc/processid/

Inside this folder we have a bunch of files that contain info on the process two of them are extremely useful to us.

1./proc/processid/maps.

This contains the map of all memory addresses and points to classes/modules within our process lets take a look at tibias map:



00400000-014ee000 r-xp 00000000 08:15 6441562 /home/steven/.local/share/CipSoft GmbH/Tibia/packages/Tibia/bin/client



021f6000-0a2a2000 rw-p 00000000 00:00 0 [heap]



The actual file is alot bigger than this , but for now thats not to important. Next I used a tool called GameConqueror. This a simple tool just like cheat engine but without debugger stuff so its not detected. I wont talk your through how to find a address with this , its easy as pie and you should know this already. Anyway I am going to look for mana address in this tutorial so lets find it in GameConqueror for me it was at:

5afe708

Now of course if we reload tibia , this address will change and we cant attach a debugger without battleye blocking us. But heres the thing , we now know that
5afe708 was used once to store our mana address. We also have a list of ranges in which memory is allocated and these ranges never change. So if we find the range that 5afe708 is in this range will always contain our mana so using the above we can at least narrow our search down to only hundreds of thousands of adresses rather than billions. Progress! Lets find the range below that contains "5afe708"







def find_target_range(self):
target = int("5afe708",16)
maps_file = open("/proc/{}/maps".format(self.processid), 'r')

for line in maps_file.readlines(): # for each mapped region
splitter = line.split(" ") #Split the line into spaces
region_low = int(splitter[0].split("-")[0],16) #region low of chunk
region_high = int(splitter[0].split("-")[1],16) #region high of chunk

if target > region_low:
if target < region_high:
returndata = {"region_low" : region_low,
"region_high" : region_high}
return(returndata)



this gives us:
{'region_low': 35610624, 'region_high': 178696192}

I am converting values to ints , rather than there hex offset just because its easier to do math on however if you convert them to hex you can see we have out memory range.


Now stick with me. This will seem convuluded at first:
Next I used GameConqueror to find my mana address. I then browsed memory on that location and copied backwards as much of the hext data as I could this gave me a long hex string. I made a new python script like so:


import textwrap
hexstring = """F8 CD 0D 20 6D 7F 00 00 2B 00 00 00 00 00 00 00
F0 AE A3 38 6D 7F 00 ..........""" ###This is trimmed so I dont hit the char limit on forum

hexstring = hexstring.replace(" ","")
thelist = textwrap.wrap(hexstring, 16)
for item in thelist:
print(item)

All this script does is to take my bytes from memory and spit them out in 8 byte chunks. I now used this site:
https://www.textfixer.com/tools/remove-duplicate-lines.php

to remove the duplicates and then saved the none dupes in 1.txt I then closed the game and repeated the above for the new mana address and saved as 2.txt. I did this again , 3.txt.

Now i combined all 3 text files into one single text file list and used https://www.somacon.com/p568.php to count duplicates. I was looking for entrys with 3 counts. I got these:


3 | 3900000000000000
3 | 4800000000000000
3 | 70D0780100000000
3 | 9B18000000000000
3 | A100000000000000
3 | F0AA780100000000

If you are confused what I just did , I just found the memory addresses near the address I want (mana) that never change. Even if we open a new client. All will become clear as to why shortly:

the last value we extracted above seems the best to use for now:
F0AA780100000000

Infact this value can be found -120 bytes of our target mana address.

remember earlier I said there was two interesting files in /proc/ ? The second one contains all our memory values! This is /proc/processid/mem.

This is a raw byte file so we cant use it like a normal file , we have to use .open (as rb) .read() and .seek

so our plan of attack is this:
1.Get the address range from the map file, our target mana address is in there somewhere!
2.We open our .mem file and jump to range start.
3.We search every 8 bytes for F0AA780100000000.
4.Once we find this we add the distance to our mana value (its exactly 120) this is our mana address.
5.Read the above value.

lets goo...


def find_mana_address(self,heapdata):
print("Scanning memory , this could take a few seconds....")
mem_file = open("/proc/{}/mem".format(self.processid), 'rb')

region_low=heapdata["region_low"]
region_high=heapdata["region_high"]
mem_file.seek(region_low) #Goto the start address of our heap
memoryposition = region_low #Just a buffer so we know what address we are at currently


while memoryposition<region_high: #Stop searching when we exit end of heap
memoryposition = memoryposition +8
chunks=""
count = 0
while count<8: #Read every 8 bytes and stick them into a string
count=count+1
chunk = binascii.hexlify(mem_file.read(1))
chunks = chunks + str(chunk)
shifted_bytes = chunks.upper()
if shifted_bytes == "F0AA780100000000":
print("Signature found at - " + str(memoryposition))

int_memory_address = (memoryposition+120)
print("Memory address is - " + str(int_memory_address))
return int_memory_address

This prints:
Scanning memory , this could take a few seconds....
Signature found at - 94777736
Memory address is - 94777856
94777856 is just the int for 5afe708 I added this to GameConqurer and indeed it works Below I have added a function to read this address and a loop that prints whenever our mana changes:

https://i.imgur.com/qrj7yN8.png


Final Code:
https://pastebin.com/UqtmsJBs

I ran out of space so stuck it on pastebin.

The important thing about this is:
We never interact with the game client at all. We are reading files from the operating system we call no functions what so ever on the game!

felipe93
04-13-2020, 11:53
Thanks you so much mat ei want to make a bot for myself this will help

felipe93
05-05-2020, 06:09
@Darkbyte
DO YOU HAVE DISCORD TO HELP ME ? IM VERY INTERESTED IN THIS
im having problem running you script i have instaled the python verson 2.7 ubuntu 18,.04

rata@la-rata:~$ ./tibiamemory.py
Traceback (most recent call last):
File "./tibiamemory.py", line 85, in <module>
heapdata = (testhandler.find_target_range())
File "./tibiamemory.py", line 10, in find_target_range
maps_file = open("/proc/{}/maps".format(self.processid), 'r')
IOError: [Errno 2] No such file or directory: '/proc/14982/maps'


THANKS IN ADVANCE