• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Feature [DLL] Simple WSAD in C++

kor

PHP ziom
Premium User
Joined
Jul 12, 2008
Messages
252
Solutions
13
Reaction score
410
Location
Bialystok, Poland
GitHub
rookgaard
YouTube
Rookgaard
Hello.

At the beginning I wanted to ask a few questions how to approach the topic of DLL injection and hooking into functions in memory, but to be fair to this community, I am sharing with you a very very simple code that allows you to control your character using WSAD keys.


The principle of operation is that in the compilation process we get the ddraw.dll file that we put next to the Tibia.exe client (memory addresses correspond only to the client 8.60, on the others it will not work due to other addresses). Thanks to this, the client that loads the ddraw.dll system library by default, encounters this file in the same directory and it get priority in loading. Then, in the input function (rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L105)) the system library is loaded, and then the function (rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L127)) that the Tibia client needs. The graphic below shows why the choice was ddraw.dll - the client imports only one function from it (although it would probably be the same with the glu32.dll or winmm.dll libraries).

UvMyO0q.png


Next, I found the addresses in the client's memory responsible for sending the letter (0x458200), the place where sending the letter is called (0x4CFB8A) and where the CreateWindowExA function from the user32.dll library (0x5B8574) is called.

1. Hook at rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L115), then https://github.com/rookgaard/tibia-wsad/blob/master/dllmain. cpp#L58 is responsible for intercepting user actions. This is where I get information about which button was pressed (W/S/A/D) and then I change it to an arrow key (rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L21-L41)).
2. Hook at rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L112) is needed, because despite the user action being intercepted, the letter is sent to the text field anyway, so I can block it on rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L69-L83)
3. Information about the address for sending the letter in rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L111) is needed to write the letter in rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad) /blob/master/dllmain.cpp#L85 if the letter is not W/S/A/D.

The whole thing is additionally checked so that the action takes place only when the character is logged in (i.e. that when entering a password that contains, for example, the letter A, it is not changed to a left arrow) - rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L9-L11)

The code currently works on the principle that if there is a file next to the client, it is not possible to type these letters because they are converted into arrows - but this is not a problem, because you can easily add an additional flag/condition (e.g. activated with another key like ESC) which will control whether WSAD is active or not (however, this is not the topic I wanted to ask about, hence the lack of this code in the project).

What I don't like, however:
1. Mimicking the ddraw.dll system library

In the Erpegia client (formerly Fania OTS for 8.60) which I found somewhere in the internet (credits for @mateuszx), loading the erpegia.dll library was done by editing .exe files, where the application at some point "jumps" to another memory location:

4LOmc2H.png

on the left the original client with bytes 6A606858A95D00, on the right a modified client with bytes E9FA570500​

then loads the library into a free space in the code, and then recalls previously overwritten bytes:

lmnonLt.png

on the left the original client with zeros, on the right, a modified client with the name of the file to be loaded, where you can see the same overwritten bytes 6A606858A95D00​

Thanks to this, in the InitMain function (rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L101)) you can completely skip loading the system library and its functions - unfortunately it requires modification and sending the appropriate client to the users.

2. The way I capture functions
For one address I used the HookCall function (rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L88)), while in the second I had to use a different method - rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L114-L119) - where the common part is to reserve memory and release it for modification.

I am not a C ++ programmer myself and I feel very weak about this topic, so I do not understand why brewsterl/tibianic-dll (https://github.com/brewsterl/tibianic-dll/blob/master/main.cpp#L1911) uses two different solutions.

Could any of the subject matter experts help me evaluate/review this code? Advise what solutions are okay, which should be changed, and which are completely unacceptable? How else (apart from impersonating ddraw.dll and the mentioned client modification) can I inject dll on the user's side so that he can use WSAD?

P.S. In the repository there is a .dll file, so everyone can test it on it's own - just place it near Tibia client and press WSAD while logged in.

Sincerely,
Michał "Gubihe"
 
Well, actually checked the sources before and I can vouch for this little masterpiece ;)
 
Thanks, but there are some places I don't fully understand how they works (it was copied from tibianic dll), so I guess I've mixed different approaches.

@emil92b to work with 7.72 version, you just need to replace addresses that can be found in the tibianic repository. I can add a shortcut to toggle mode.
 
Thanks, but there are some places I don't fully understand how they works (it was copied from tibianic dll), so I guess I've mixed different approaches.

@emil92b to work with 7.72 version, you just need to replace addresses that can be found in the tibianic repository. I can add a shortcut to toggle mode.
cool i got it to work :) can you help with toggle? :D
 
I am using IIDKing to "import" your own dll to client. You can import to client exported functions from your dll for inline usage but main of DLL is always loaded on the start of client so you dont have to carry about anything pretty much. IIDKing.zip - Serwis skanujący Jotti (https://virusscan.jotti.org/pl-PL/filescanjob/6d94pwsrs2)
HookCall is your friend :D When you hook functions you always need to check in debugger if hook is valid, for example createwindowex hook needs one nop after because its call from memory (if i remember correctly).
C++:
    //8.54 addresses 
    HookCall(0x56EC55, (DWORD)&MyCreateWindowExA);
    Nop(0x56EC5A, 1);

Gratis, you have my old hooking funcs XD
 

Attachments

@emil92b Here you are - addes unilicense and toggle wsad by ctrl+tab · rookgaard/tibia-wsad@09b6922 (https://github.com/rookgaard/tibia-wsad/commit/09b69221626e5192da2685a312b92b1307e24204)

@Qbazzz Thanks for response! I've seen in some clients where authors used IIDKing for import DLL, but I didn't liked how much it interfere with original executable (+ I didn't understand why I see DirectDraw functions instead of DllMain). Good point about checking hooks, I will pay attention to them.
thanks!
 
Also to block opening skills or selecting all text in chat window while dancing on WSAD you will also need to block special keycodes in hooked pushLetter func.

C++:
 if ((Letter==1121)||(Letter==1139)) {
    return;
}
 
Thanks, but there are some places I don't fully understand how they works (it was copied from tibianic dll), so I guess I've mixed different approaches.

@emil92b to work with 7.72 version, you just need to replace addresses that can be found in the tibianic repository. I can add a shortcut to toggle mode.
Was it made or no?
 
Hello.

At the beginning I wanted to ask a few questions how to approach the topic of DLL injection and hooking into functions in memory, but to be fair to this community, I am sharing with you a very very simple code that allows you to control your character using WSAD keys.


The principle of operation is that in the compilation process we get the ddraw.dll file that we put next to the Tibia.exe client (memory addresses correspond only to the client 8.60, on the others it will not work due to other addresses). Thanks to this, the client that loads the ddraw.dll system library by default, encounters this file in the same directory and it get priority in loading. Then, in the input function (rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L105)) the system library is loaded, and then the function (rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L127)) that the Tibia client needs. The graphic below shows why the choice was ddraw.dll - the client imports only one function from it (although it would probably be the same with the glu32.dll or winmm.dll libraries).

UvMyO0q.png


Next, I found the addresses in the client's memory responsible for sending the letter (0x458200), the place where sending the letter is called (0x4CFB8A) and where the CreateWindowExA function from the user32.dll library (0x5B8574) is called.

1. Hook at rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L115), then https://github.com/rookgaard/tibia-wsad/blob/master/dllmain. cpp#L58 is responsible for intercepting user actions. This is where I get information about which button was pressed (W/S/A/D) and then I change it to an arrow key (rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L21-L41)).
2. Hook at rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L112) is needed, because despite the user action being intercepted, the letter is sent to the text field anyway, so I can block it on rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L69-L83)
3. Information about the address for sending the letter in rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L111) is needed to write the letter in rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad) /blob/master/dllmain.cpp#L85 if the letter is not W/S/A/D.

The whole thing is additionally checked so that the action takes place only when the character is logged in (i.e. that when entering a password that contains, for example, the letter A, it is not changed to a left arrow) - rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L9-L11)

The code currently works on the principle that if there is a file next to the client, it is not possible to type these letters because they are converted into arrows - but this is not a problem, because you can easily add an additional flag/condition (e.g. activated with another key like ESC) which will control whether WSAD is active or not (however, this is not the topic I wanted to ask about, hence the lack of this code in the project).

What I don't like, however:
1. Mimicking the ddraw.dll system library

In the Erpegia client (formerly Fania OTS for 8.60) which I found somewhere in the internet (credits for @mateuszx), loading the erpegia.dll library was done by editing .exe files, where the application at some point "jumps" to another memory location:

4LOmc2H.png

on the left the original client with bytes 6A606858A95D00, on the right a modified client with bytes E9FA570500​

then loads the library into a free space in the code, and then recalls previously overwritten bytes:

lmnonLt.png

on the left the original client with zeros, on the right, a modified client with the name of the file to be loaded, where you can see the same overwritten bytes 6A606858A95D00​

Thanks to this, in the InitMain function (rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L101)) you can completely skip loading the system library and its functions - unfortunately it requires modification and sending the appropriate client to the users.

2. The way I capture functions
For one address I used the HookCall function (rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L88)), while in the second I had to use a different method - rookgaard/tibia-wsad (https://github.com/rookgaard/tibia-wsad/blob/master/dllmain.cpp#L114-L119) - where the common part is to reserve memory and release it for modification.

I am not a C ++ programmer myself and I feel very weak about this topic, so I do not understand why brewsterl/tibianic-dll (https://github.com/brewsterl/tibianic-dll/blob/master/main.cpp#L1911) uses two different solutions.

Could any of the subject matter experts help me evaluate/review this code? Advise what solutions are okay, which should be changed, and which are completely unacceptable? How else (apart from impersonating ddraw.dll and the mentioned client modification) can I inject dll on the user's side so that he can use WSAD?

P.S. In the repository there is a .dll file, so everyone can test it on it's own - just place it near Tibia client and press WSAD while logged in.

Sincerely,
Michał "Gubihe"
with this i will be able to get the bytes from for example addons and mounts so it could be posible add them into tibianic dll, right?
 
can somebody explain how to use it? i have added outfits with addons to my 7.72 files and tibianic now is giving me bugs on login even when im not using those outfits so want to know what is happening, i can pay for teaching me via paypal
 
Probably server is sending (or missing) additional byte for addon for every outfit (NPC and few monsters can also have addons if they're using outfit looktypes), so data received is different from what client expects.

Also, you didn't even specify where it's "giving you bugs" - server-side (text in console/engine crash) or client-side (debug assertion)...
 
Probably server is sending (or missing) additional byte for addon for every outfit (NPC and few monsters can also have addons if they're using outfit looktypes), so data received is different from what client expects.

Also, you didn't even specify where it's "giving you bugs" - server-side (text in console/engine crash) or client-side (debug assertion)...
it was not the outfit nor the monster because im not using them its something related to skull
Lua:
+---------------------------------------------------------------
Debug Assertion 7.72 MapWindow.cpp 699
Wed May 04 02:03:25 2022
Windows Version: 6.2 build 9200 on 2
Graphic Engine: 2
Last Packet Types: 144 162 180 180 160 143 162 141 130 161
Last Packet: 091 011 010 000 000 000 016 050 000 001 011 255 255 255 255 255
Player Position: [32455,32326,7]
Player.cpp 383: exception occurred, reason:
Player.cpp 456: exception occurred, reason:
Control.cpp 1560: exception occurred (Type = 0), reason:
Control.cpp 366: exception occurred (Force?1:0 = 0), reason:
MainWindow.cpp 127: exception occurred (Surface = 1), reason:
GUI.cpp 1408: exception occurred (Surface = 1), reason:
MapWindow.cpp 834: exception occurred (Surface = 1), reason:
MapWindow.cpp 757: exception occurred, reason:
MapWindow.cpp 699: unknown creature PK flag (Creature->PKFlag = 48)
----------------------------------------------------------------
totally client side think since this does not happens in otclient and ain't getting errors in console either
the problem is on login, anyway i want to know how should i add this code into 7.72 client to add the packets/bytes maybe find something not fitting?
 
You have to capture packet data to file (record it on engine or capture from client) and compare with what server should send and client will expect.

NPC and monster can also have skulls.
 
it was not the outfit nor the monster because im not using them its something related to skull
Lua:
+---------------------------------------------------------------
Debug Assertion 7.72 MapWindow.cpp 699
Wed May 04 02:03:25 2022
Windows Version: 6.2 build 9200 on 2
Graphic Engine: 2
Last Packet Types: 144 162 180 180 160 143 162 141 130 161
Last Packet: 091 011 010 000 000 000 016 050 000 001 011 255 255 255 255 255
Player Position: [32455,32326,7]
Player.cpp 383: exception occurred, reason:
Player.cpp 456: exception occurred, reason:
Control.cpp 1560: exception occurred (Type = 0), reason:
Control.cpp 366: exception occurred (Force?1:0 = 0), reason:
MainWindow.cpp 127: exception occurred (Surface = 1), reason:
GUI.cpp 1408: exception occurred (Surface = 1), reason:
MapWindow.cpp 834: exception occurred (Surface = 1), reason:
MapWindow.cpp 757: exception occurred, reason:
MapWindow.cpp 699: unknown creature PK flag (Creature->PKFlag = 48)
----------------------------------------------------------------
totally client side think since this does not happens in otclient and ain't getting errors in console either
the problem is on login, anyway i want to know how should i add this code into 7.72 client to add the packets/bytes maybe find something not fitting?
Tibianic dll have problems with skulls search here on the forum about it
 
Tibianic dll have problems with skulls search here on the forum about it
i'm using saiyasking tibianic it has everything fixed, i commited that part to test, the issue was in the script of the server, thanks though man
 
hi, i have been trying to use this on tibia 10.98 with no success, did someone compiled it for 10.98?
i want to use wasd instead of the supers small arrows keys on the laptop.
im currently using otclient only for the wasd thing.
 
Back
Top