Technical solution to eliminate desync in single-player sessions
"For three years and some change, I was a MOS 25U in the United States Army, working for a S6 shop, including a tour to Afghanistan. What I did in practice was much more similar to MOS 25B, because we had a lot of tech (Aviation unit) and only moderate amounts of radios (helicopter radios are their own MOS). Although I did do some radios too. I designed network topologies, routed a bunch of Ethernet cable, configured countless workstations, maintained a file server, configured switches, created user and email accounts, installed computerized communications systems in vehicles, made sure CNN was up for the operations people to watch, and pretty much solved any problem anyone had with any equipment which involved either a digital screen or network access. Everything about my job had information security at the forefront. Data encryption, voice encryption, smart card authentication, physical security, separation of Secret and non-Secret, secure passwords. It was my team's job to make sure the keys to our communication networks did not fall in enemy hands. A lot of people in my shop were kind laid-back. I wasn't. As a result, I ended up doing a lot of the work — in some months, with a shop of a dozen people, I had over 51% of the completed work tickets. I took care of everything I could; they didn't have to take care of much. Everyone was happy with that arrangement. I loved my job. Didn't code much. Wrote a very angry ping-sweeper this one time in Notepad (as a batch file, with text output). Had to, couldn't download, Internet was down, needed it to diagnose. That was about it. Decent at reading code though; I've done a lot of experimental Registry edits in my time trying to fix obscure problems. "Not as written. And no, I won't. I read your white paper, I researched your bitcoins, and I read your laughable code. That's enough investment with zero payoff out of me. I'm done with this thread. Your "deterministic simulation" idea is good, when properly applied to a client simulation with a server true gamestate; your "trust the client" idea is shit. Final answer. Find someone else to argue with. When Stephen Colbert was killed by HYDRA's Project Insight in 2014, the comedy world lost a hero. Since his life model decoy isn't up to the task, please do not mistake my performance as political discussion. I'm just doing what Steve would have wanted.
|
![]() |
qwave, I don't have time for a full post, but your timestamp signing is unneeded. Just instead of allowing the client to say that it attacked a target at time t with some result, just make the client say player initiated attack on a target at time t with some result. That way no speedhack can be used, because if the client said that you managed 2 attacks at the same time, the server would not be able to reproduce it with same commands, and would detect it.
|
![]() |
Haha, ScrotieMcB quits the thread once I write the code for the system. Classic. ;-)
Last edited by qwave#5074 on Nov 21, 2013, 12:34:17 AM
|
![]() |
" Since you very experience with security maybe instead of flaming him you should help him write a secure code? Take it as a challenge:D |
![]() |
The fail in this is astounding. Seriously.
Let's break this, shall we? " Overly simplistic. Seriously, a 32-bit integer as a seed? This is breakable (as in I can write a function to sniff data and reverse-engineer this) in microseconds. " Movespeed is not a constant. Quicksilver flasks, anyone? Or do you mean that the server generates and sends a new seed every time I drink a freaking flask? That's desync right there. " Mob location is always in an x, y format. I guess your 12 years in the computer industry never told you that cartesian coordinates need two numbers, otherwise you're stating a radius, not a location. " This assumes a few things: 1) The server date and time are completely, perfectly in sync with the client. The client cannot even be a second late or early. (Which is stupid, anyone with 12 years of computing experience knows how hard it is to keep two electronic clocks completely in sync all the time). 2) The server runs at the exact same speed as the client. Slower PC = slower delta, for the sheer reason that it's slower, dumbass, it can't run the code at the same speed as the server. 3) Nothing overwrites client date/time state while the game is playing. Looks like I need to turn off core windows services, like, I dunno, Windows Time? " I am pretty much sure that the targeting and attacking code is way more complex than this. Evasion? Armor? Range checks? How about block? Damage reduction? Pierce? Oh, and manual evade from movement too? Overly simplistic code is overly simplistic. Also, "Attack(clientSeed, mob, timestamp);" What's to prevent me from standing in place, and not attacking, while a background process does function DamageOptimizer { for(x= timestamp; x < timestamp + (arbitrary amount of time); x + (very small time increment){ Attack(clientSeed, mob, x); if(Attack.Damage=InstantKill){ waitFunctionToWaitUntilTimestampAndXAreTheSame(x, timestamp); return Attack(clientSeed, mob, x); break; } } } You did say that the client Seed was used to determine damage, right? Or will you pseudo-edit your quote here? " Your algorithm computed damage as a function of timestamp and seed. Vary the timestamp until you get an optimal result, and poof! Permanent critical! But wait! The timestamp is used to compute what your attack did? Then stop attacking! The increments across timestamps are infinitesimally small, so what does it matter if your attack is 5ms late if you deal twice as much damage? This is why engineers with 12 years of experience in coding games do not use time as a function to determine damage, because people will exploit that by playing only at times where damage is optimal. Remember, you said that you're using a "deterministic seed to generate pseudo-random numbers". Pseudo-random means that somewhere there you'll see an unusually high bunch of numbers. " I have a background process called InjectorForStupidAlgo. It does this var packet = new Packet { breakpoint Function_That_Waits_And_Stands_Still_Until_You_Get_To_The_Timestamp_You_Want(); " You said server validated if these calculations are performed or not. What prevents me from performing more than the usual number of calculations and looking for an optimal result? More complexity = more lag in the server, because every 5 computations you make the client do, the server has to do for each client that is connected to it. It therefore follows that the moment the advance computations become too taxing for the client to do, your server is already dead because it has to compute the same damned thing for THOUSANDS OF CLIENTS. " Trusting the client-appended timestamp, are we? Speedhax, I can easily forge a client timestamp. Remember, the client has both the seed, the timestamp, and the algorithm for hashing. Or are you saying that the client somehow magically does not have the seed or timestamp? This exercise in mediocrity just proves how stupid this idea is. Last edited by Sachiru#1510 on Nov 21, 2013, 12:37:02 AM
|
![]() |
Sachiru, I really don't understand how this continually goes over your head completely.
" The seed can be any value. It's not supposed to be secure. None of the client-side code can ever be secured, any hacker to get to these values. " Change the move speed then, it doesn't matter. I just defined it as a const in the code, but you can change it to whatever you want. The server will validate it. " These are distances. This is just example code. You have a complete misunderstanding of how the delta is calculated. It's 100% client-handled. " Go ahead and add all those values in. It doesn't change anything. " The timestamp doesn't matter, the delta does. The timestamp is generated so that the delta can be seeded. Again, you have not understood a single piece of this system, and you obviously have not run the code. Try to change the input/output, go ahead. Last edited by qwave#5074 on Nov 21, 2013, 12:43:39 AM
|
![]() |
" This is what I immediately noticed. That the seed is 32-bit, mobs are lined up in a 1 dimensional space instead of 2 dimensional, etc. is just for purposes of example. That's not a big deal. What I question is this:
Spoiler
// The server can now validate the signature to make sure this packet wasn't forged if (Hash(serverSeed.Next().ToString(), packet.Timestamp.ToString()) == packet.Signature) { Console.WriteLine("The client's packet is valid"); } else { Console.WriteLine("The client's packet is hacked."); } The signature is computed by the client using a hash of the timestamp and the next value of the RNG. The code above checks to see that the packet was not modified afterward ... provided that whoever modified it didn't have access to that RNG value (they do), the timestamp (they do), or the method by which the hash was computed (they do). As far as I can tell, this just stops some sort of man-in-the-middle attack from happening. Does this code have a purpose beyond that? IGN: SplitEpimorphism
|
![]() |
Just out of curiosity, what do you plan to hash against when I'm just moving, or attacking without a target (cleave, spec throw, etc)
|
![]() |
" And as I tell you, because the delta is just a series of bits in memory, I can change the delta to whatever the hell I want. It's simply a matter of computing the optimal delta, then WAITING. Delta is time elapsed, so simply WAIT UNTIL THE TIME ELAPSES for your time to match. [Removed by Admin] P.S. I am so totally submitting this to thedailywtf.com Last edited by Henry_GGG on Nov 21, 2013, 12:45:18 AM
|
![]() |
" The signature is an example of how to sign a packet. Technically you should probably sign the packet using the seed + timestamp + serialized packet. But I am just trying to illustrate how it's done. |
![]() |