FIXING PRSPY >64p
- Daniel
- Posts: 2225
- Joined: 2010-04-15 16:28
- Contact:
Re: FIXING PRSPY >64p
From 99 players to 100 players the crash occurs, afaik, since the three-digit number (xxx) are not compatible with sth. in the engine... ?
-
bren
- Posts: 735
- Joined: 2013-08-01 05:46
Re: FIXING PRSPY >64p
turista, if you want to have FCV test it out send me a private message.
-
UTurista
- PR:BF2 Developer
- Posts: 985
- Joined: 2011-06-14 14:13
Re: FIXING PRSPY >64p
Day 433 - The fight continues...
These were my latest findings (Linux x64), after spending the last days looking at this. Hopefully some can find this helpful and go even further.
First I started by locating the function that handles game-spy queries, this was possible by locating which part of the memory stores the player's names and is accessed at the same time I query the server. In no time I obtain the following structure and conclusions, once I added the respectinve code vreaks.
The red is what was calling qr2_buffer_addA, the blue is a loop, in other words, every time it reaches the bottom it goes back to the offset <+1028> and in green is the famous "increment a value and compare it with the exit condition".
Unlike windows, the exit condition here is not a hard-coded value but a value stored in 0x5dc(%rsp), which was set in:
Which seems to go directly to the memory to obtain the array's size, so why does it stays at 64 players?
Started a server with 5 bots and searched for the number 5 in the game's memory, >17k occurrences, joined the game and search for positions that changed from 5 to 6 lowering the occurrences to 5 and from those 5 only 3 got left after leaving the server.
More breaks in those memory places and only 3 functions accessed them with one having the name _ZN4dice3hfe16ServerQueryCache6updateEv.
In red is where the memory is changed to have the new number and not to many instructions before we see the magical number, $0x40 and indeed by changing it to a lower number we change the 64's limitation to a lower limitation (yay??).
Unfortunately increasing the number is just not enough, the game is not ready and it crashes when we do it, so we need to increase the spaced used for the player's array and for that we need the function that allocates that memory, in other words more breaks:
Where 0x108b958 is the offset that always points to the beginning of the player's list[-]so if this is the attribution of that value it should mean that the location should be around here[/-]:
Unfortunately I need to leave this for another day, I leave this here for anyone to pick it up (and for me to not forget about this).
edit 19/01:
So it seems there's 2 attributions to this offset the first, above, is always the number 0xf6c6e8 while the second attribution is the actual memory position:
These were my latest findings (Linux x64), after spending the last days looking at this. Hopefully some can find this helpful and go even further.
First I started by locating the function that handles game-spy queries, this was possible by locating which part of the memory stores the player's names and is accessed at the same time I query the server. In no time I obtain the following structure and conclusions, once I added the respectinve code vreaks.
- strlen: is a know function from C wich returns a string size
- qr2_buffer_addA: is called several times from qr2_parse_queryA to add stuff in a certain part of the memory
- qr2_parse_queryA : is called only once, when we query the server
- qr2_think: systematically called, is the loop that listens the query port plus does the heartbeats to the MasterAerver.
Code: Select all
[color=royalblue] 0x0000000000822e64 <+1028>: mov 0x5c8(%rsp),%ebx[/color]
0x0000000000822e6b <+1035>: mov %r13d,%eax
0x0000000000822e6e <+1038>: sub %ebx,%eax
0x0000000000822e70 <+1040>: test %eax,%eax
0x0000000000822e72 <+1042>: jle 0x822da9 <qr2_parse_queryA+841>
0x0000000000822e78 <+1048>: mov 0x5e0(%rsp),%esi
[color=Green] 0x0000000000822e7f <+1055>: inc %esi
0x0000000000822e81 <+1057>: cmp 0x5dc(%rsp),%esi[/color]
0x0000000000822e88 <+1064>: mov %esi,0x5e0(%rsp)
0x0000000000822e8f <+1071>: jge 0x823056 <qr2_parse_queryA+1526>
0x0000000000822e95 <+1077>: mov 0x5d0(%rsp),%ecx
0x0000000000822e9c <+1084>: cmp $0x1,%ecx
0x0000000000822e9f <+1087>: jne 0x822e5b <qr2_parse_queryA+1019>
0x0000000000822ea1 <+1089>: mov 0x140(%rbp),%rcx
0x0000000000822ea8 <+1096>: lea 0x50(%rsp),%rdx
0x0000000000822ead <+1101>: mov %r12d,%edi
[color=Red]0x0000000000822eb0 <+1104>: callq *0x90(%rbp)[/color]
[color=RoyalBlue] 0x0000000000822eb6 <+1110>: jmp 0x822e64 <qr2_parse_queryA+1028>[/color]
Unlike windows, the exit condition here is not a hard-coded value but a value stored in 0x5dc(%rsp), which was set in:
Code: Select all
0x0000000000823198 <+1848>: callq *0xa8(%rbp)
0x000000000082319e <+1854>: mov %eax,0x5dc(%rsp)
0x00000000008231a5 <+1861>: jmpq 0x822cf9 <qr2_parse_queryA+665>
Started a server with 5 bots and searched for the number 5 in the game's memory, >17k occurrences, joined the game and search for positions that changed from 5 to 6 lowering the occurrences to 5 and from those 5 only 3 got left after leaving the server.
More breaks in those memory places and only 3 functions accessed them with one having the name _ZN4dice3hfe16ServerQueryCache6updateEv.
Code: Select all
[color=Green] 0x046e53e <+3230>: incl 0xc(%rsp)
0x046e542 <+3234>: cmpl $0x40,0xc(%rsp)[/color]
0x046e547 <+3239>: je 0x46e557 <_ZN4dice3hfe16ServerQueryCache6updateEv+3255>
0x046e549 <+3241>: lea 0x10(%rsp),%rax
0x046e54e <+3246>: cmp %rax,%r15
0x046e551 <+3249>: jne 0x46e2c0 <_ZN4dice3hfe16ServerQueryCache6updateEv+2592>
0x046e557 <+3255>: mov 0xc(%rsp),%eax
0x046e55b <+3259>: lea 0x10(%rsp),%rdi
[color=Red] 0x046e560 <+3264>: mov %eax,0x170(%r14)[/color]
0x046e567 <+3271>: callq 0x465510 <_ZNSt10_List_baseIPN4dice3hfe5world7IPlayerESaIS4_EE8_M_clearEv>
0x046e56c <+3276>: mov 0x30(%rsp),%rbx
0x046e571 <+3281>: sub $0x18,%rbx
0x046e575 <+3285>: cmp $0xf6c6d0,%rbx
0x046e57c <+3292>: jne 0x46e9fe <_ZN4dice3hfe16ServerQueryCache6updateEv+4446>
Unfortunately increasing the number is just not enough, the game is not ready and it crashes when we do it, so we need to increase the spaced used for the player's array and for that we need the function that allocates that memory, in other words more breaks:
Code: Select all
Hardware watchpoint 1: *0x108b958
Old value = 0
New value = 16172776
0x000000000046d48f in dice::hfe::ServerQueryCache::ServerQueryCache() ()
(gdb) bt 5
#0 0x000000000046d48f in dice::hfe::ServerQueryCache::ServerQueryCache() ()
#1 0x000000000046d55d in __static_initialization_and_destruction_0 ()
#2 0x0000000000b26a62 in __do_global_ctors_aux ()
#3 0x00000000004071a3 in _init ()
#4 0x0000000000000000 in ?? ()
Code: Select all
Dump of assembler code for function _ZN4dice3hfe16ServerQueryCacheC1Ev:
0x000000000046d430 <+0>: 41 54 push %r12
0x000000000046d432 <+2>: 55 push %rbp
0x000000000046d433 <+3>: 48 89 fd mov %rdi,%rbp
0x000000000046d436 <+6>: 53 push %rbx
0x000000000046d437 <+7>: 48 83 ec 10 sub $0x10,%rsp
0x000000000046d43b <+11>: e8 60 b5 20 00 callq 0x6789a0 <_ZN4dice3hfe17IServerQueryCacheC2Ev>
0x000000000046d440 <+16>: 48 8d 45 08 lea 0x8(%rbp),%rax
0x000000000046d444 <+20>: 48 c7 45 00 b0 27 b3 00 movq $0xb327b0,0x0(%rbp)
0x000000000046d44c <+28>: ba 2c 00 00 00 mov $0x2c,%edx
0x000000000046d451 <+33>: 48 ff ca dec %rdx
0x000000000046d454 <+36>: 48 c7 00 e8 c6 f6 00 movq $0xf6c6e8,(%rax)
0x000000000046d45b <+43>: 48 83 c0 08 add $0x8,%rax
0x000000000046d45f <+47>: 48 83 fa ff cmp $0xffffffffffffffff,%rdx
0x000000000046d463 <+51>: 75 ec jne 0x46d451 <_ZN4dice3hfe16ServerQueryCacheC1Ev+33>
0x000000000046d465 <+53>: 48 8d 8d 78 01 00 00 lea 0x178(%rbp),%rcx
0x000000000046d46c <+60>: c7 85 70 01 00 00 00 00 00 00 movl $0x0,0x170(%rbp)
0x000000000046d476 <+70>: be 40 00 00 00 mov $0x40,%esi
0x000000000046d47b <+75>: 66 66 90 data32 xchg %ax,%ax
0x000000000046d47e <+78>: 66 90 xchg %ax,%ax
0x000000000046d480 <+80>: 48 89 c8 mov %rcx,%rax
0x000000000046d483 <+83>: ba 08 00 00 00 mov $0x8,%edx
[b][color=SeaGreen] 0x000000000046d488 <+88>: 48 c7 00 e8 c6 f6 00 movq $0xf6c6e8,(%rax)[/color][/b]
=> 0x000000000046d48f <+95>: 48 83 c0 08 add $0x8,%rax
0x000000000046d493 <+99>: 48 ff ca dec %rdx
0x000000000046d496 <+102>: 75 f0 jne 0x46d488 <_ZN4dice3hfe16ServerQueryCacheC1Ev+88>
0x000000000046d498 <+104>: 48 83 c1 40 add $0x40,%rcx
0x000000000046d49c <+108>: 48 ff ce dec %rsi
0x000000000046d49f <+111>: 75 df jne 0x46d480 <_ZN4dice3hfe16ServerQueryCacheC1Ev+80>
0x000000000046d4a1 <+113>: 48 c7 85 78 11 00 00 00 00 00 00 movq $0x0,0x1178(%rbp)
0x000000000046d4ac <+124>: 4c 8d 65 10 lea 0x10(%rbp),%r12
0x000000000046d4b0 <+128>: e8 fb ee 07 00 callq 0x4ec3b0 <_ZN4dice3hfe11BuildNrUtil16getBuildNrStringEv>
0x000000000046d4b5 <+133>: 48 89 c3 mov %rax,%rbx
0x000000000046d4b8 <+136>: 48 89 c7 mov %rax,%rdi
0x000000000046d4bb <+139>: e8 b8 a3 f9 ff callq 0x407878 <strlen@plt>
0x000000000046d4c0 <+144>: 48 89 de mov %rbx,%rsi
0x000000000046d4c3 <+147>: 48 89 c2 mov %rax,%rdx
0x000000000046d4c6 <+150>: 4c 89 e7 mov %r12,%rdi
0x000000000046d4c9 <+153>: e8 5a ad f9 ff callq 0x408228 <_ZNSs6assignEPKcm@plt>
0x000000000046d4ce <+158>: 48 89 e7 mov %rsp,%rdi
0x000000000046d4d1 <+161>: e8 9a f1 07 00 callq 0x4ec670 <_ZN4dice3hfe5getOSEv>
0x000000000046d4d6 <+166>: 48 8d 7d 18 lea 0x18(%rbp),%rdi
0x000000000046d4da <+170>: 48 89 e6 mov %rsp,%rsi
0x000000000046d4dd <+173>: e8 56 ad f9 ff callq 0x408238 <_ZNSs6assignERKSs@plt>
0x000000000046d4e2 <+178>: 48 8b 1c 24 mov (%rsp),%rbx
0x000000000046d4e6 <+182>: 48 83 eb 18 sub $0x18,%rbx
0x000000000046d4ea <+186>: 48 81 fb d0 c6 f6 00 cmp $0xf6c6d0,%rbx
0x000000000046d4f1 <+193>: 75 09 jne 0x46d4fc <_ZN4dice3hfe16ServerQueryCacheC1Ev+204>
0x000000000046d4f3 <+195>: 48 83 c4 10 add $0x10,%rsp
0x000000000046d4f7 <+199>: 5b pop %rbx
0x000000000046d4f8 <+200>: 5d pop %rbp
0x000000000046d4f9 <+201>: 41 5c pop %r12
0x000000000046d4fb <+203>: c3 retq
0x000000000046d4fc <+204>: 48 8d 7b 10 lea 0x10(%rbx),%rdi
0x000000000046d500 <+208>: be ff ff ff ff mov $0xffffffff,%esi
0x000000000046d505 <+213>: e8 5e ae f9 ff callq 0x408368 <_ZN9__gnu_cxx18__exchange_and_addEPVii@plt>
0x000000000046d50a <+218>: 85 c0 test %eax,%eax
0x000000000046d50c <+220>: 7f e5 jg 0x46d4f3 <_ZN4dice3hfe16ServerQueryCacheC1Ev+195>
0x000000000046d50e <+222>: 48 8d 74 24 0f lea 0xf(%rsp),%rsi
0x000000000046d513 <+227>: 48 89 df mov %rbx,%rdi
0x000000000046d516 <+230>: e8 9d a6 f9 ff callq 0x407bb8 <_ZNSs4_Rep10_M_destroyERKSaIcE@plt>
0x000000000046d51b <+235>: eb d6 jmp 0x46d4f3 <_ZN4dice3hfe16ServerQueryCacheC1Ev+195>
End of assembler dump.edit 19/01:
So it seems there's 2 attributions to this offset the first, above, is always the number 0xf6c6e8 while the second attribution is the actual memory position:
Code: Select all
Hardware watchpoint 1: *0x108b958
[color=SeaGreen]Old value = 16172776 (Always this number)[/color]
New value = 384383720 (Random memory position)
#0 0x00007fee041ff4ad in std::string::assign(std::string const&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x000000000046e302 in dice::hfe::ServerQueryCache::update() ()
#2 0x000000000046cfc8 in dice::hfe::MatchMakingServer::update() ()
#3 0x00000000004613bf in dice::hfe::GameServer::update(int, float) ()
#4 0x00000000004db123 in dice::hfe::BF2Engine::mainLoop() ()
Last edited by UTurista on 2016-01-19 14:27, edited 7 times in total.

Dont question the wikipedia! Just because it reports different things on different languages does not make it unreliable source!

