project reality header
Go Back   Project Reality Forums > PR:BF2 Mod Forums > PR:BF2 General Discussion
29 Sep 2024, 00:00:00 (PRT)
Register Developer Blogs Members List Search Quick Links
PR:BF2 General Discussion General discussion of the Project Reality: BF2 modification.

Reply
 
Thread Tools Display Modes
Old 2015-01-11, 04:58   #41
Daniel
Banned
Supporting Member
Default 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... ?
Daniel is offline Reply With Quote
Old 2015-01-11, 08:03   #42
bren
Supporting Member

bren's Avatar
Default Re: FIXING PRSPY >64p

turista, if you want to have FCV test it out send me a private message.
bren is offline Reply With Quote
Old 2016-01-17, 23:29   #43
[R-DEV]​UTurista
PR:BF2 Developer
Supporting Member

UTurista's Avatar
Default 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.
  1. strlen: is a know function from C wich returns a string size
  2. qr2_buffer_addA: is called several times from qr2_parse_queryA to add stuff in a certain part of the memory
  3. qr2_parse_queryA : is called only once, when we query the server
  4. qr2_think: systematically called, is the loop that listens the query port plus does the heartbeats to the MasterAerver.

From here I was able to obtain which part of the code calls qr2_buffer_addA to add the player names and I arrived to the following snippet:

Code:
   0x0000000000822e64 <+1028>:	mov    0x5c8(%rsp),%ebx
   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
   0x0000000000822e7f <+1055>:	inc    %esi
   0x0000000000822e81 <+1057>:	cmp    0x5dc(%rsp),%esi
   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
   0x0000000000822eb0 <+1104>:	callq  *0x90(%rbp)
   0x0000000000822eb6 <+1110>:	jmp    0x822e64 <qr2_parse_queryA+1028>
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:
Code:
  
   0x0000000000823198 <+1848>:	callq  *0xa8(%rbp)
   0x000000000082319e <+1854>:	mov    %eax,0x5dc(%rsp)
   0x00000000008231a5 <+1861>:	jmpq   0x822cf9 <qr2_parse_queryA+665>
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.
Code:
  0x046e53e <+3230>:	incl   0xc(%rsp)
   0x046e542 <+3234>:	cmpl   $0x40,0xc(%rsp)
   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
   0x046e560 <+3264>:	mov    %eax,0x170(%r14)
   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>
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:
Code:
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 ?? ()
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:
Code:
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
   0x000000000046d488 <+88>:	48 c7 00 e8 c6 f6 00	movq   $0xf6c6e8,(%rax)
=> 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.
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:
Code:
Hardware watchpoint 1: *0x108b958

Old value = 16172776  (Always this number)
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() ()


Dont question the wikipedia! Just because it reports different things on different languages does not make it unreliable source!
UTurista is offline
Last edited by [R-DEV]UTurista; 2016-01-19 at 14:27..
Reply With Quote
Reply


Tags
&gt64p, >64p, fixed, fixing, prspy

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off



All times are GMT. The time now is 19:31.