Giriş yap
En iyi yollayıcılar
Hello EMO | ||||
EMO | ||||
eMoStyLe | ||||
BesimBICER | ||||
GameKinG | ||||
Crysis | ||||
~>!.DεvιLρяιεsт.!<~ | ||||
MeTaL | ||||
TrueCrime | ||||
djhayal3t |
Istatistikler
Toplam 203 kayıtlı kullanıcımız varSon kaydolan kullanıcımız: crayzboy76
Kullanıcılarımız toplam 1186 mesaj attılar bunda 862 konu
Arama
Sosyal yer imi
Sosyal bookmarking sitesinde Emo, Emo nedir, Emo resimleri, Emo Kıyafetleri, Emo Sözleri, Emo Oyunları, EmoTurkey, Emo Nickler, Emo Avatarları, Punk, Punk Resimleri, Punk Avatarları, Rock, Rock Resimleri, Rock Avatarları, Msn Nickleri, Msn Avatarları, Müzik adresi saklayın ve paylaşın
Sosyal bookmarking sitesinde EMO Style ForumPro - Hos Geldiniz adresi saklayın ve paylaşın
Kimler hatta?
Toplam 9 kullanıcı online :: 0 Kayıtlı, 0 Gizli ve 9 Misafir Yok
Sitede bugüne kadar en çok 217 kişi C.tesi Tem. 29, 2017 1:46 am tarihinde online oldu.
En son konular
Reklam
[1.298] Name change hack fix
EMO Style ForumPro - Hos Geldiniz :: Online Oyunlar :: Knight Online :: Knight Online Private Serverlar :: Prosedür ve Kod Paylasımları
1 sayfadaki 1 sayfası
[1.298] Name change hack fix
[quote name='twostars' timestamp='1296418198' post='125']
The way the name change hack works is not specifically by EVT, instead by sending the "name change reply" packet to the server.
Name change should normally work like this:
1. Player clicks NPC,
2. Client sends the event ID as a request to Ebenezer,
3. This goes through the event logic and will finally trigger hit the EVT function that triggers name change,
4. The "call to name change" then tells the client to load up the name change edit box,
5. Player types their desired name in the edit box and it is sent to Ebenezer as a separate "reply" packet,
6. The server (CUser::RecvChangeName) then tells the client what the result was (if the name is in use, an edit box will be sent again to the client, otherwise it'll have succeeded and will take a name change scroll and change the name).
What the hack is doing is:
1. Player clicks NPC,
2. Client sends the event ID as a request to Ebenezer,
3. This goes through the event logic and will finally trigger hit the EVT function that triggers name change,
4. The "call to name change" then tells the client to load up the name change edit box,
5. Hack sends the desired name (actually, nothing/0x00 by default - though it could be sending the character name in the packet if it was a little smarter) to Ebenezer as a separate "reply" packet,
6. The server (CUser::RecvChangeName) then tells the client what the result was (if the name is in use, an edit box will be sent again FOR THE FIRST TIME to the client, otherwise it'll have succeeded and will take a name change scroll and change the name).
As you can see, the hack is skipping a whole load of steps there.
Now that we've figured out how the exploit works, let's see how we can patch it!
We should really start from the beginning. What checks is the hack actually skipping?
Well.. this is actually, really easy. If your EVT is scripted correctly, you should be checking to see if the user has a name change scroll!
So with this in mind, what we can do now, is add this check to CUser::RecvChangeName(). And this we shall do!
For this, we'll need to make use of our trusty CUser::CheckExistItem() function, which requires two parameters - the item ID that we're checking for, and the minimum count (stack size). As the name change scroll is a non-stackable item, we'll pass 1 for the latter. CUser::CheckExistItem() returns true or false, depending on whether or not the item was found or not (true in the event it was, false in the event it wasn't).
I, somewhat inconveniently, decided to patch a jump to our code-cave here:
Going to our code-cave:-
Save the registers (so that we don't have to worry about changing anything that is used later on - so long as we restore them when we're done!).
We tend to work "backwards" when passing arguments to a function. So, we're storing argument 2 here - which is our minimum count (stack size!) - so that we can pass it as a full 4 bytes, rather than take the chance and have it think we're passing a byte.
Push our minimum count (stack size) onto the stack for use with CUser::CheckExistItem(). (CUser::CheckExistItem(, 1))
Push 2FAF8500 onto the stack. Wait... WHAT? As you may have guessed, this is hex. Olly uses numbers you give it in hex, not decimal - so, we pass 2FAF8500 instead of... 800032000! As 800032000 is the "Scroll of Identity", aka, name change scroll, we're now passing our FIRST argument (remember - we're working backwards) to CUser::CheckExistItem(). (CUser::CheckExistItem(800032000, 1)).
As we're now done with our parameters, we'll finally make our call to CUser::CheckExistItem(). Note: The return value will be stored in EAX.
The next step is checking the result of CUser::CheckExistItem(). To do this, we'll use "TEST". We could alternatively use "CMP EAX,0" here, but we're saving bytes in our code-cave. tongue.gif
This check doesn't completely make much sense without the conditional jump that follows it... so stay tuned... we're getting there!
Take the opportunity to restore the registers to how they were (so we don't have to do it twice after our conditional jump [if the condition matches and if it doesn't]!).
Finally.. our conditional jump! Step two of the check two instructions above. We're checking to see if it was a match to what we were checking. If you recall:
is the equivalent of:
which is comparing EAX to 0, so:
will jump if they match (are EQUAL - JE = Jump if Equal).
Remember that EAX is the result of CUser::CheckExistItem(), which returns true if the item exists, and false if it doesn't.
True and False basically come down to two things - 1 (true) and 0 (false).
As:
is the equivalent of:
You can see that we're comparing our result to 0 (false).
Going back to our conditional jump:
You can now see that we're jumping to our "on fail" code if the result of CUser::CheckExistItem() was EQUAL to false (0). As 004C5508 (our conditional jump's destination) isn't the next instruction, we'll continue on line by line with the "if the item -was- found" code.
If the item -was- found, we'll continue on with the two instructions we overwrote to jump to our code-cave to begin with.
00500130 is the address of memset(), a function that sets a block of memory of the specified length to the value you specify. I think the most common use is to null (0x00 [0]!) terminate strings. The end of a string is commonly determined with a null-terminator, which as I bracketed before, is basically the byte 0x00 (or just 0 in decimal). Note that it is NOT the actual number 0, that character is actually represented by the byte 0x30 (48 in decimal).
A normal call to memset() looks something like:
Broken down, the first parameter is the address of the block of memory that we're setting, the second parameter is the value we're filling it with, and the third and final parameter is how much of the block of memory we're setting, in this case, 20 bytes.
Say for instance our block of memory looks like this:
After calling memset() to basically replace the first 20 bytes with 0x00, our block of memory will look like this:
And that's basically how it works! (though you'd typically set the length of the WHOLE block of memory, otherwise you'll cause memory leaks - with strings)
With that in mind, we're passing it only one argument.. the other two have already been pushed onto the stack before the jump to our code-cave. This is why I mentioned that it was an "inconvenient place to patch" earlier. There's no problem at all with it if the player has the item and it continues along the original path of code... but what happens when the player hasn't got the item, and it jumps to the other code to fail - and never finishes calling memset()? More on this when we get there (very soon).
So, everything's fine, we'll continue on our merry way back to the original code path we were on!
If the user has hit this jump, it means that they have the item and we don't need to do a THING - we give control back to CUser::RecvChangeName() to do what it needs to do (change the name preferrably, otherwise error if the name is in use).
Moving onto the next line:
Now... remember our earlier conditional jump, that one that triggers if the item was not found? Well... it jumps here! At this point in time, the user hasn't got the item, so what we want to do is do nothing! However, doing nothing actually takes a lot of effort (doesn't it always).
So going back to our question, "what happens when the player hasn't got the item, and it jumps to the other code to fail - and never finishes calling memset()"..
The answer to this is that the two previous additions to the stack (two parameters of memset) are never taken off the stack. With our stack pointer (ESP) never being reverted to what it was before the additions to the stack (everything pushed onto the stack takes [data size of addition] off the stack pointer), the stack pointer is left completely off. When you take something off the stack (usually by popping them), you add the length of the data back onto ESP (our stack pointer), so...
Going back to our problem with two DWORDs (4 bytes each) being forgotten about and left on the stack, we need to take them off!
4 bytes * 2 = 8 bytes, so we'll need to add 8 bytes to the stack pointer (ESP).
So we do!
..and now all is be happy; the stack is exactly as it was before the memset() call!
With that problem out the way, we can then take a (short) jump to the end of CUser::RecvChangeName() - hence, we've done nothing in answer to the client. For the record, we don't particularly want to error as it will trigger an edit box to appear in the client (though of course, the player doesn't even have a name change scroll, so no matter what.. they won't be able to exploit name change - without a name change scroll!).
And we're done!
Code recap
Have fun!
[/quote]
The way the name change hack works is not specifically by EVT, instead by sending the "name change reply" packet to the server.
Name change should normally work like this:
1. Player clicks NPC,
2. Client sends the event ID as a request to Ebenezer,
3. This goes through the event logic and will finally trigger hit the EVT function that triggers name change,
4. The "call to name change" then tells the client to load up the name change edit box,
5. Player types their desired name in the edit box and it is sent to Ebenezer as a separate "reply" packet,
6. The server (CUser::RecvChangeName) then tells the client what the result was (if the name is in use, an edit box will be sent again to the client, otherwise it'll have succeeded and will take a name change scroll and change the name).
What the hack is doing is:
1. Player clicks NPC,
2. Client sends the event ID as a request to Ebenezer,
3. This goes through the event logic and will finally trigger hit the EVT function that triggers name change,
4. The "call to name change" then tells the client to load up the name change edit box,
5. Hack sends the desired name (actually, nothing/0x00 by default - though it could be sending the character name in the packet if it was a little smarter) to Ebenezer as a separate "reply" packet,
6. The server (CUser::RecvChangeName) then tells the client what the result was (if the name is in use, an edit box will be sent again FOR THE FIRST TIME to the client, otherwise it'll have succeeded and will take a name change scroll and change the name).
As you can see, the hack is skipping a whole load of steps there.
Now that we've figured out how the exploit works, let's see how we can patch it!
We should really start from the beginning. What checks is the hack actually skipping?
Well.. this is actually, really easy. If your EVT is scripted correctly, you should be checking to see if the user has a name change scroll!
So with this in mind, what we can do now, is add this check to CUser::RecvChangeName(). And this we shall do!
For this, we'll need to make use of our trusty CUser::CheckExistItem() function, which requires two parameters - the item ID that we're checking for, and the minimum count (stack size). As the name change scroll is a non-stackable item, we'll pass 1 for the latter. CUser::CheckExistItem() returns true or false, depending on whether or not the item was found or not (true in the event it was, false in the event it wasn't).
I, somewhat inconveniently, decided to patch a jump to our code-cave here:
- Kod:
004C53EE |. E9 F4000000 JMP 004C54E7
004C53F3 | 90 NOP
Going to our code-cave:-
Save the registers (so that we don't have to worry about changing anything that is used later on - so long as we restore them when we're done!).
- Kod:
004C54E7 |> 60 PUSHAD
We tend to work "backwards" when passing arguments to a function. So, we're storing argument 2 here - which is our minimum count (stack size!) - so that we can pass it as a full 4 bytes, rather than take the chance and have it think we're passing a byte.
- Kod:
004C54E8 |. B8 01000000 MOV EAX,1
Push our minimum count (stack size) onto the stack for use with CUser::CheckExistItem(). (CUser::CheckExistItem(
- Kod:
004C54ED |. 50 PUSH EAX
Push 2FAF8500 onto the stack. Wait... WHAT? As you may have guessed, this is hex. Olly uses numbers you give it in hex, not decimal - so, we pass 2FAF8500 instead of... 800032000! As 800032000 is the "Scroll of Identity", aka, name change scroll, we're now passing our FIRST argument (remember - we're working backwards) to CUser::CheckExistItem(). (CUser::CheckExistItem(800032000, 1)).
- Kod:
004C54EE |. 68 0085AF2F PUSH 2FAF8500
As we're now done with our parameters, we'll finally make our call to CUser::CheckExistItem(). Note: The return value will be stored in EAX.
- Kod:
004C54F3 |. E8 9DD5F3FF CALL 00402A95
The next step is checking the result of CUser::CheckExistItem(). To do this, we'll use "TEST". We could alternatively use "CMP EAX,0" here, but we're saving bytes in our code-cave. tongue.gif
This check doesn't completely make much sense without the conditional jump that follows it... so stay tuned... we're getting there!
- Kod:
004C54F8 |. 85C0 TEST EAX,EAX
Take the opportunity to restore the registers to how they were (so we don't have to do it twice after our conditional jump [if the condition matches and if it doesn't]!).
- Kod:
004C54FA |. 61 POPAD
Finally.. our conditional jump! Step two of the check two instructions above. We're checking to see if it was a match to what we were checking. If you recall:
- Kod:
TEST EAX,EAX
is the equivalent of:
- Kod:
CMP EAX,0
which is comparing EAX to 0, so:
- Kod:
004C54FB |. 74 0B JE SHORT 004C5508
will jump if they match (are EQUAL - JE = Jump if Equal).
Remember that EAX is the result of CUser::CheckExistItem(), which returns true if the item exists, and false if it doesn't.
True and False basically come down to two things - 1 (true) and 0 (false).
As:
- Kod:
TEST EAX,EAX
is the equivalent of:
- Kod:
CMP EAX,0
You can see that we're comparing our result to 0 (false).
Going back to our conditional jump:
- Kod:
004C54FB |. 74 0B JE SHORT 004C5508
You can now see that we're jumping to our "on fail" code if the result of CUser::CheckExistItem() was EQUAL to false (0). As 004C5508 (our conditional jump's destination) isn't the next instruction, we'll continue on line by line with the "if the item -was- found" code.
If the item -was- found, we'll continue on with the two instructions we overwrote to jump to our code-cave to begin with.
- Kod:
004C54FD |. 50 PUSH EAX
004C54FE |. E8 2DAC0300 CALL 00500130
00500130 is the address of memset(), a function that sets a block of memory of the specified length to the value you specify. I think the most common use is to null (0x00 [0]!) terminate strings. The end of a string is commonly determined with a null-terminator, which as I bracketed before, is basically the byte 0x00 (or just 0 in decimal). Note that it is NOT the actual number 0, that character is actually represented by the byte 0x30 (48 in decimal).
A normal call to memset() looks something like:
- Kod:
memset(someBlockOfMemory, 0x00, 20);
Broken down, the first parameter is the address of the block of memory that we're setting, the second parameter is the value we're filling it with, and the third and final parameter is how much of the block of memory we're setting, in this case, 20 bytes.
Say for instance our block of memory looks like this:
- Kod:
01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16
After calling memset() to basically replace the first 20 bytes with 0x00, our block of memory will look like this:
- Kod:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 14 15 16
And that's basically how it works! (though you'd typically set the length of the WHOLE block of memory, otherwise you'll cause memory leaks - with strings)
With that in mind, we're passing it only one argument.. the other two have already been pushed onto the stack before the jump to our code-cave. This is why I mentioned that it was an "inconvenient place to patch" earlier. There's no problem at all with it if the player has the item and it continues along the original path of code... but what happens when the player hasn't got the item, and it jumps to the other code to fail - and never finishes calling memset()? More on this when we get there (very soon).
So, everything's fine, we'll continue on our merry way back to the original code path we were on!
- Kod:
004C5503 |.^E9 ECFEFFFF JMP 004C53F4
If the user has hit this jump, it means that they have the item and we don't need to do a THING - we give control back to CUser::RecvChangeName() to do what it needs to do (change the name preferrably, otherwise error if the name is in use).
Moving onto the next line:
Now... remember our earlier conditional jump, that one that triggers if the item was not found? Well... it jumps here! At this point in time, the user hasn't got the item, so what we want to do is do nothing! However, doing nothing actually takes a lot of effort (doesn't it always).
So going back to our question, "what happens when the player hasn't got the item, and it jumps to the other code to fail - and never finishes calling memset()"..
The answer to this is that the two previous additions to the stack (two parameters of memset) are never taken off the stack. With our stack pointer (ESP) never being reverted to what it was before the additions to the stack (everything pushed onto the stack takes [data size of addition] off the stack pointer), the stack pointer is left completely off. When you take something off the stack (usually by popping them), you add the length of the data back onto ESP (our stack pointer), so...
Going back to our problem with two DWORDs (4 bytes each) being forgotten about and left on the stack, we need to take them off!
4 bytes * 2 = 8 bytes, so we'll need to add 8 bytes to the stack pointer (ESP).
So we do!
- Kod:
004C5508 83C4 08 ADD ESP,8
..and now all is be happy; the stack is exactly as it was before the memset() call!
With that problem out the way, we can then take a (short) jump to the end of CUser::RecvChangeName() - hence, we've done nothing in answer to the client. For the record, we don't particularly want to error as it will trigger an edit box to appear in the client (though of course, the player doesn't even have a name change scroll, so no matter what.. they won't be able to exploit name change - without a name change scroll!).
- Kod:
004C550B \.^EB D2 JMP SHORT 004C54DF
And we're done!
Code recap
- Kod:
004C53EE |. E9 F4000000 JMP 004C54E7
004C53F3 | 90 NOP
004C54E7 |> 60 PUSHAD
004C54E8 |. B8 01000000 MOV EAX,1
004C54ED |. 50 PUSH EAX
004C54EE |. 68 0085AF2F PUSH 2FAF8500
004C54F3 |. E8 9DD5F3FF CALL 00402A95
004C54F8 |. 85C0 TEST EAX,EAX
004C54FA |. 61 POPAD
004C54FB |. 74 0B JE SHORT 004C5508
004C54FD |. 50 PUSH EAX
004C54FE |. E8 2DAC0300 CALL 00500130
004C5503 |.^E9 ECFEFFFF JMP 004C53F4
004C5508 83C4 08 ADD ESP,8
004C550B \.^EB D2 JMP SHORT 004C54DF
Have fun!
[/quote]
Similar topics
» [1.298] Change seeking party's level limit from 80 to highe
» [1310] Change 17xx New Moradon Spawn 1310 Aujard
» [1310] Change 17xx New Moradon Spawn 1310 Aujard
EMO Style ForumPro - Hos Geldiniz :: Online Oyunlar :: Knight Online :: Knight Online Private Serverlar :: Prosedür ve Kod Paylasımları
1 sayfadaki 1 sayfası
Bu forumun müsaadesi var:
Bu forumdaki mesajlara cevap veremezsiniz
Cuma Ağus. 29, 2014 8:33 am tarafından Hello EMO
» goldenchase.net maden yaparak para kazanma
Cuma Ağus. 29, 2014 8:18 am tarafından Hello EMO
» etichal hacker görsel egitim seti
Çarş. Ağus. 06, 2014 4:57 am tarafından Hello EMO
» KO TBL Source C#
Ptsi Ara. 09, 2013 6:36 am tarafından Hello EMO
» x86 Registers
C.tesi Ağus. 24, 2013 5:02 am tarafından Hello EMO
» [Tutorial] Pegando Address, Pointers de WYD
Çarş. Tem. 10, 2013 7:25 am tarafından Hello EMO
» [Tutorial] Pegando Address, Pointers de CS Metodo²
Çarş. Tem. 10, 2013 7:23 am tarafından Hello EMO
» [Tutorial] Aprendendo basico deASM OLLYDBG
Çarş. Tem. 10, 2013 7:22 am tarafından Hello EMO
» Basic C# DLL injector
Ptsi Tem. 08, 2013 7:48 am tarafından Hello EMO