[1.298] ban_knights exploit fix
The /ban_knights command is supposed to be used by the alliance leader to remove the selected clan leader's clan from the alliance.However, mgame failed yet again - the command was actually open to anybody at all, so long as the selected clan leader was in a clan and an alliance. This means that anybody could remove any clan from an alliance!
What we'll do for this one is add a check to see if the player that is trying to remove the alliance is the alliance leader.
We'll start off in CKnightsManager::KnightsAlliancePunish(), the function that's called when /ban_knights is used.
We might as well use the pointer to the clan struct that's being retrieved, so pretty much straight after the checks, we'll add a jump to our code-cave.
We'll overwrite this line here:00457D53 . 68 80276800 PUSH 00682780 ; /pCriticalSection = 00682780With a jump to our code-cave:
00457D53 E9 9E030000 JMP 004580F6In the following code, we'll have to mess with the registers a lot, which I'm sure the rest of CKnightsManager::KnightsAlliancePunish() will most certainly not like, so what we can do is "save" the state of the current registers and flags, which we'll use the following two lines for:004580F6 60 PUSHAD
004580F7 9C PUSHFDOnce we're done we'll need to remember to restore the state we saved here.
Now, this bit gets tricky, as we have a pointer to the selected clan leader's clan... but we actually need a pointer to the alliance leader's clan.
So, to do this, I took a bit of a look through the memory dump until I found the main alliance's clan ID. It was located at EAX-46.004580F8 0FB740 BA MOVZX EAX,WORD PTR DS:Now that we've got the main alliance's clan ID, it's just a matter of calling CEbenezerDlg::GetKnightsPtr(int clanid) to retrieve the pointer to the clan's struct (which we need to get the alliance leader's name!).
In CEbenezerDlg::GetKnightsPtr() we'll refer to ECX - this is the pointer to the instance of the class CEbenezerDlg. We need to pass this, so that anything in that function can still access what it needs in the instance of CEbenzerDlg.004580FD 8B4F 04 MOV ECX,DWORD PTR DS:Here we push EAX (that's the main alliance's clan ID!) onto the stack, which CEbenezerDlg::GetKnightsPtr() will use.004580FC 50 PUSH EAXCall CEbenezerDlg::GetKnightsPtr() to get the pointer to the main alliance's clan.00458100 E8 5F94FAFF CALL 00401564EAX will now be the return value of 00401564 (CEbenezerDlg::GetKnightsPtr()), which is the clan pointer.
We'll need to check to make sure that the pointer is actually valid (make sure that the clan was found).
00458105 85C0 TEST EAX,EAXIf the pointer (EAX) is 0, the pointer is obviously invalid, so we'll jump to a case I'll call "fail_return". We jump here in any case that something's wrong, and it will then as you will find out later, restore the registers & flags, and jump back to the end of CKnightsManager::KnightsAlliancePunish() - so it doesn't do anything.00458107 74 27 JE SHORT 00458130We'll use EBX to store the pointer to the class of the player that's trying to use /ban_knights.00458109 3E:8B5D 08 MOV EBX,DWORD PTR DS:Now we'll use EBX again (as we don't need it for anything else) to store the pointer to the character's name (the one who is trying to use /ban_knights).0045810D 8B9B 98800000MOV EBX,DWORD PTR DS:Here we push EBX (pointer to the character's name) onto the stack, for use with our call to strcmp() (which we'll use to make sure that the two character's names - the alliance leader's and the player who is trying to use /ban_knights - match).00458113 53 PUSH EBXSimply, we'll store the pointer to the alliance leader's name (EAX is the pointer to the clan struct, +26 is the offset from there to get to the clan leader's name) in EAX.00458114 8D40 26 LEA EAX,DWORD PTR DS:Now push the alliance leader's name onto the stack also (so we have both character names on the stack at the moment - the player who is trying to use /ban_knights, and the alliance leader!).
00458117 50 PUSH EAXNow that we've got all the data prepared, we can finally call strcmp() to compare the two character names!00458118 E8 339D0A00 CALL 00501E50Pop ECX (pointer to the instance of CEbenezerDlg) off the stack. (Clean-up)0045811D 59 POP ECX
Test EAX (return value of strcmp). If it's 0, it's a match. Plainly, it's non-zero, it isn't a match.
0045811E 85C0 TEST EAX,EAXMore clean-up.
00458120 59 POP ECXAs I said before, if EAX is 0, it's a match. If it's non-zero, it isn't a match. JNZ = Jump Not Zero, so if it's not a match, we'll jump to "fail_return", preventing the user from removing a clan from an alliance illegitimately.
00458121 75 0D JNZ SHORT 00458130Restore the saved flags & registers from before. Put it all back the way we left it! :)
00458123 9D POPFD
00458124 61 POPADThis is the code we patched over:00458125 BB 80276800 MOV EBX,00682780
0045812A 53 PUSH EBXAll is well, so jump back and continue executing the code resuming from the point we left off.0045812B ^E9 28FCFFFF JMP 00457D58...and here is fail_return!
Restore the flags & registers from our saved state.00458130 9D POPFD
00458131 61 POPADJump to the end of CKnightsManager::KnightsAlliancePunish(), so we skip doing anything like removing the clan from the alliance. :P00458132 ^EB A2 JMP SHORT 004580D6Code recapCKnightsManager::KnightsAlliancePunish()
00457D53 E9 9E030000 JMP 004580F6Code-cave:
004580F6 60 PUSHAD
004580F7 9C PUSHFD
004580F8 0FB740 BA MOVZX EAX,WORD PTR DS:
004580FC 50 PUSH EAX
004580FD 8B4F 04 MOV ECX,DWORD PTR DS:
00458100 E8 5F94FAFF CALL 00401564
00458105 85C0 TEST EAX,EAX
00458107 74 27 JE SHORT 00458130
00458109 3E:8B5D 08 MOV EBX,DWORD PTR DS:
0045810D 8B9B 98800000MOV EBX,DWORD PTR DS:
00458113 53 PUSH EBX
00458114 8D40 26 LEA EAX,DWORD PTR DS:
00458117 50 PUSH EAX
00458118 E8 339D0A00 CALL 00501E50
0045811D 59 POP ECX
0045811E 85C0 TEST EAX,EAX
00458120 59 POP ECX
00458121 75 0D JNZ SHORT 00458130
00458123 9D POPFD
00458124 61 POPAD
00458125 BB 80276800 MOV EBX,00682780
0045812A 53 PUSH EBX
0045812B ^E9 28FCFFFF JMP 00457D58
00458130 9D POPFD
00458131 61 POPAD
00458132 ^EB A2 JMP SHORT 004580D6
Have fun!
页:
[1]