• 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!
  • If you're using Gesior 2012 or MyAAC, please review this thread for information about a serious security vulnerability and a fix.

Feature [DLL] Simple WSAD in C++

kor

PHP ziom
Premium User
Joined
Jul 12, 2008
Messages
222
Solutions
13
Reaction score
338
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"
 

LordCompi

Banned User
Joined
May 2, 2013
Messages
216
Solutions
4
Reaction score
186
Well, actually checked the sources before and I can vouch for this little masterpiece ;)
 
OP
OP
kor

kor

PHP ziom
Premium User
Joined
Jul 12, 2008
Messages
222
Solutions
13
Reaction score
338
Location
Bialystok, Poland
GitHub
rookgaard
YouTube
Rookgaard
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.
 

emil92b

Intermediate OT User
Joined
Aug 21, 2013
Messages
324
Solutions
13
Reaction score
124
Location
Sweden
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
 

Qbazzz

Pół człowiek, pół litra
Joined
Jul 3, 2009
Messages
106
Solutions
1
Reaction score
98
Location
inside of the box
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

OP
OP
kor

kor

PHP ziom
Premium User
Joined
Jul 12, 2008
Messages
222
Solutions
13
Reaction score
338
Location
Bialystok, Poland
GitHub
rookgaard
YouTube
Rookgaard

emil92b

Intermediate OT User
Joined
Aug 21, 2013
Messages
324
Solutions
13
Reaction score
124
Location
Sweden
@emil92b Here you are - addes unilicense and toggle wsad by ctrl+tab · rookgaard/[email protected] (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!
 

LordCompi

Banned User
Joined
May 2, 2013
Messages
216
Solutions
4
Reaction score
186
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;
}
 

johnsamir

Banned User
Joined
Oct 13, 2009
Messages
555
Solutions
5
Reaction score
98
Location
Nowhere
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?
 

johnsamir

Banned User
Joined
Oct 13, 2009
Messages
555
Solutions
5
Reaction score
98
Location
Nowhere
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?
 

johnsamir

Banned User
Joined
Oct 13, 2009
Messages
555
Solutions
5
Reaction score
98
Location
Nowhere
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
 
OP
OP
kor

kor

PHP ziom
Premium User
Joined
Jul 12, 2008
Messages
222
Solutions
13
Reaction score
338
Location
Bialystok, Poland
GitHub
rookgaard
YouTube
Rookgaard
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)...
 

johnsamir

Banned User
Joined
Oct 13, 2009
Messages
555
Solutions
5
Reaction score
98
Location
Nowhere
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?
 
OP
OP
kor

kor

PHP ziom
Premium User
Joined
Jul 12, 2008
Messages
222
Solutions
13
Reaction score
338
Location
Bialystok, Poland
GitHub
rookgaard
YouTube
Rookgaard
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.
 

Olddies

Classicot.com
Joined
Nov 21, 2009
Messages
1,161
Solutions
12
Reaction score
296
Location
Rep.Dom
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
 

Il Knight

Veteran OT User
Joined
Dec 1, 2014
Messages
676
Solutions
7
Reaction score
350
Location
Spain
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.
 
Top